• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

super3 / feed / 16862056219

10 Aug 2025 01:31PM UTC coverage: 84.818% (-8.6%) from 93.419%
16862056219

push

github

developeratexample
Implement AI Filtering Queue System (Section #7)

- Create /api/filter-queue.js with comprehensive queue management endpoints
  - POST /add: Queue posts for filtering
  - GET /next: Fetch next item for processing
  - POST /result: Submit filtering results
  - GET /status: Check queue statistics
  - POST /cleanup: Clean old completed items
  - POST /reset-stuck: Reset stuck processing items

- Implement filter-client.js worker script for LM Studio server
  - Polls queue for work and processes posts with AI
  - Configurable via environment variables
  - Includes health checks and error recovery
  - Supports multiple concurrent workers

- Update /api/filter-context.js to use queue system
  - Modified to queue posts instead of direct filtering
  - GET method retrieves filtering results

- Add queue management UI
  - Display queue statistics (pending/processing/completed)
  - Real-time polling for status updates
  - Visual feedback during processing

- Write comprehensive test coverage
  - 25 tests for filter-queue.js endpoints
  - 17 tests for filter-client.js worker
  - Fix bug in reset-stuck endpoint

- Update plan.md with completed tasks and deployment instructions

All tests pass (192 total). Queue system ready for distributed AI filtering.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

305 of 385 branches covered (79.22%)

Branch coverage included in aggregate %.

121 of 175 new or added lines in 2 files covered. (69.14%)

533 of 603 relevant lines covered (88.39%)

10.04 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/api/filter-context.js
NEW
1
const { getStorage } = require('../lib/storage');
×
NEW
2
const { success, methodNotAllowed, badRequest, serverError } = require('../lib/utils/error-handler');
×
NEW
3
const logger = require('../lib/logger');
×
4

NEW
5
module.exports = async (req, res) => {
×
NEW
6
  res.setHeader('Access-Control-Allow-Origin', '*');
×
NEW
7
  res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS');
×
NEW
8
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
×
9

NEW
10
  if (req.method === 'OPTIONS') {
×
NEW
11
    return res.status(200).end();
×
12
  }
13

NEW
14
  const storage = getStorage();
×
NEW
15
  await storage.init();
×
16

NEW
17
  if (req.method === 'POST') {
×
NEW
18
    try {
×
NEW
19
      const { keyword, context, posts } = req.body;
×
20

NEW
21
      if (!keyword || !context) {
×
NEW
22
        return badRequest(res, 'Keyword and context are required');
×
23
      }
24

NEW
25
      if (!posts || !Array.isArray(posts)) {
×
NEW
26
        return badRequest(res, 'Posts array is required');
×
27
      }
28

NEW
29
      const postsToQueue = posts.map(post => ({
×
30
        id: post.id,
31
        title: post.title,
32
        selftext: post.selftext || ''
×
33
      }));
34

NEW
35
      const response = await fetch(`${req.headers.host ? 'http://' + req.headers.host : ''}/api/filter-queue/add`, {
×
36
        method: 'POST',
37
        headers: { 'Content-Type': 'application/json' },
38
        body: JSON.stringify({
39
          posts: postsToQueue,
40
          keyword: `${keyword} (context: ${context})`
41
        })
42
      });
43

NEW
44
      if (!response.ok) {
×
NEW
45
        throw new Error('Failed to add posts to queue');
×
46
      }
47

NEW
48
      const result = await response.json();
×
49

NEW
50
      for (const post of posts) {
×
NEW
51
        const keys = await storage.keys(`posts:${keyword}:*`);
×
NEW
52
        for (const key of keys) {
×
NEW
53
          const data = await storage.get(key);
×
NEW
54
          if (!data || !data.posts) continue;
×
55
          
NEW
56
          const postIndex = data.posts.findIndex(p => p.id === post.id);
×
NEW
57
          if (postIndex !== -1) {
×
NEW
58
            data.posts[postIndex] = {
×
59
              ...data.posts[postIndex],
60
              filterContext: context,
61
              filterStatus: 'queued',
62
              queuedAt: new Date().toISOString()
63
            };
NEW
64
            await storage.set(key, data);
×
NEW
65
            break;
×
66
          }
67
        }
68
      }
69

NEW
70
      logger.info(`Queued ${posts.length} posts for filtering with context: ${context}`);
×
71
      
NEW
72
      return success(res, {
×
73
        message: 'Posts queued for filtering',
74
        count: result.count,
75
        queueItems: result.items
76
      });
77

78
    } catch (error) {
NEW
79
      return serverError(res, error, { 
×
80
        context: 'Failed to queue posts for filtering'
81
      });
82
    }
83
  }
84

NEW
85
  if (req.method === 'GET') {
×
NEW
86
    try {
×
NEW
87
      const { postId } = req.query;
×
88
      
NEW
89
      if (!postId) {
×
NEW
90
        const stats = await storage.get('queue:stats') || { total: 0, pending: 0, processed: 0, failed: 0 };
×
NEW
91
        return success(res, { stats });
×
92
      }
93

NEW
94
      const resultKey = `queue:results:${postId}`;
×
NEW
95
      const result = await storage.get(resultKey);
×
96
      
NEW
97
      if (!result) {
×
NEW
98
        const queueKeys = await storage.keys(`queue:filter:*:${postId}`);
×
NEW
99
        if (queueKeys.length > 0) {
×
NEW
100
          const queueItem = await storage.get(queueKeys[0]);
×
NEW
101
          if (queueItem) {
×
NEW
102
            return success(res, {
×
103
              postId,
104
              status: queueItem.status,
105
              queuedAt: queueItem.addedAt
106
            });
107
          }
108
        }
109
        
NEW
110
        return success(res, {
×
111
          postId,
112
          status: 'not_queued'
113
        });
114
      }
115

NEW
116
      return success(res, {
×
117
        postId,
118
        status: 'completed',
119
        relevant: result.relevant,
120
        reasoning: result.reasoning,
121
        confidence: result.confidence,
122
        completedAt: result.completedAt
123
      });
124

125
    } catch (error) {
NEW
126
      return serverError(res, error, { 
×
127
        context: 'Failed to get filter results'
128
      });
129
    }
130
  }
131

NEW
132
  return methodNotAllowed(res, ['POST', 'GET', 'OPTIONS']);
×
133
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc