bulltrackers-module 1.0.449 → 1.0.451

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -97,6 +97,9 @@ async function getAdvancedAnalysisFromGemini(dependencies, snippet) {
97
97
  Post: "${snippet}"
98
98
  `;
99
99
 
100
+ let result = null;
101
+ let part = null;
102
+
100
103
  try {
101
104
  const request = {
102
105
  contents: [{ role: "user", parts: [{ text: prompt }] }],
@@ -107,10 +110,10 @@ async function getAdvancedAnalysisFromGemini(dependencies, snippet) {
107
110
  }
108
111
  };
109
112
 
110
- const result = await geminiModel.generateContent(request);
113
+ result = await geminiModel.generateContent(request);
111
114
 
112
115
  // Gemini 2.5 Flash returns JSON directly in parts[0].json
113
- const part = result?.response?.candidates?.[0]?.content?.parts?.[0];
116
+ part = result?.response?.candidates?.[0]?.content?.parts?.[0];
114
117
 
115
118
  let parsed;
116
119
 
@@ -133,7 +136,25 @@ async function getAdvancedAnalysisFromGemini(dependencies, snippet) {
133
136
  };
134
137
 
135
138
  } catch (e) {
136
- logger.log("ERROR", "[Gemini AI] JSON handling failed", e);
139
+ logger.log("ERROR", "[Gemini AI] JSON handling failed", {
140
+ error: e.message,
141
+ stack: e.stack,
142
+ snippet: snippet.substring(0, 100),
143
+ part: part ? {
144
+ hasJson: !!part.json,
145
+ hasText: !!part.text,
146
+ textPreview: part.text ? part.text.substring(0, 200) : null
147
+ } : null,
148
+ resultStructure: result?.response ? {
149
+ hasCandidates: !!result.response.candidates,
150
+ candidatesLength: result.response.candidates?.length,
151
+ firstCandidate: result.response.candidates?.[0] ? {
152
+ hasContent: !!result.response.candidates[0].content,
153
+ hasParts: !!result.response.candidates[0].content?.parts,
154
+ partsLength: result.response.candidates[0].content?.parts?.length
155
+ } : null
156
+ } : null
157
+ });
137
158
  return { overallSentiment: "Neutral", topics: [], isSpam: false, qualityScore: 0.5 };
138
159
  }
139
160
  }
@@ -235,21 +256,36 @@ exports.handleSocialTask = async (message, context, config, dependencies) => {
235
256
  existingDocs.forEach(d => existingIds.add(d.id));
236
257
  }
237
258
 
259
+ // Filter and prepare posts: only new posts in English
260
+ const newPostsWithDiscussion = discussions
261
+ .filter(d => {
262
+ const post = d.post;
263
+ if (!post || !post.id || !post.message?.text || existingIds.has(post.id)) return false;
264
+ const lang = (post.message.languageCode || 'unknown').toLowerCase();
265
+ return lang === 'en' || lang === 'en-gb';
266
+ })
267
+ // Sort by text length (longer posts are generally more useful for analysis)
268
+ .sort((a, b) => (b.post.message.text?.length || 0) - (a.post.message.text?.length || 0));
269
+
270
+ // COST OPTIMIZATION: Cap AI processing to top 5 posts per user to reduce costs
271
+ // Remaining posts will be stored with default AI values
272
+ const MAX_POSTS_FOR_AI = 5;
273
+ const postsForAI = newPostsWithDiscussion.slice(0, MAX_POSTS_FOR_AI);
274
+ const postsWithoutAI = newPostsWithDiscussion.slice(MAX_POSTS_FOR_AI);
275
+
276
+ logger.log('INFO', `[SocialTask/${taskId}] Filtered ${newPostsWithDiscussion.length} new posts. Sending ${postsForAI.length} to AI, ${postsWithoutAI.length} without AI.`);
277
+
238
278
  const batch = db.batch();
239
279
  let pageBatchCount = 0;
240
280
 
241
- for (const discussion of discussions) {
281
+ // Process posts that will get AI analysis (top 5 by text length)
282
+ for (const discussion of postsForAI) {
242
283
  if (totalSaved + pageBatchCount >= MAX_POSTS_TO_STORE) {
243
284
  keepFetching = false;
244
285
  break;
245
286
  }
246
287
 
247
288
  const post = discussion.post;
248
- if (!post || !post.id || !post.message?.text || existingIds.has(post.id)) continue;
249
-
250
- const lang = (post.message.languageCode || 'unknown').toLowerCase();
251
- if (lang !== 'en' && lang !== 'en-gb') continue;
252
-
253
289
  const snippet = post.message.text.substring(0, 500);
254
290
  const aiResult = await getAdvancedAnalysisFromGemini(dependencies, snippet);
255
291
 
@@ -260,7 +296,7 @@ exports.handleSocialTask = async (message, context, config, dependencies) => {
260
296
  username: post.owner?.username,
261
297
  createdAt: post.created,
262
298
  fetchedAt: FieldValue.serverTimestamp(),
263
- snippet: snippet, // Added for debugging
299
+ snippet: snippet,
264
300
  stats: {
265
301
  likes: discussion.emotionsData?.like?.paging?.totalCount || 0,
266
302
  comments: discussion.summary?.totalCommentsAndReplies || 0
@@ -274,6 +310,40 @@ exports.handleSocialTask = async (message, context, config, dependencies) => {
274
310
  pageBatchCount++;
275
311
  }
276
312
 
313
+ // Process remaining posts WITHOUT AI analysis (to avoid costs, but still store them)
314
+ for (const discussion of postsWithoutAI) {
315
+ if (totalSaved + pageBatchCount >= MAX_POSTS_TO_STORE) {
316
+ keepFetching = false;
317
+ break;
318
+ }
319
+
320
+ const post = discussion.post;
321
+ const docData = {
322
+ postId: post.id,
323
+ text: post.message.text,
324
+ ownerId: post.owner?.id,
325
+ username: post.owner?.username,
326
+ createdAt: post.created,
327
+ fetchedAt: FieldValue.serverTimestamp(),
328
+ snippet: post.message.text.substring(0, 500),
329
+ stats: {
330
+ likes: discussion.emotionsData?.like?.paging?.totalCount || 0,
331
+ comments: discussion.summary?.totalCommentsAndReplies || 0
332
+ },
333
+ aiAnalysis: {
334
+ overallSentiment: "Neutral",
335
+ topics: [],
336
+ isSpam: false,
337
+ qualityScore: 0.5
338
+ }, // Default values when AI is skipped to reduce costs
339
+ tags: post.tags?.map(t => t.market?.symbolName).filter(Boolean) || []
340
+ };
341
+
342
+ batch.set(db.collection(targetCollectionPath).doc(post.id), docData);
343
+ batch.set(processedRef.doc(post.id), { processedAt: FieldValue.serverTimestamp() });
344
+ pageBatchCount++;
345
+ }
346
+
277
347
  if (pageBatchCount > 0) {
278
348
  await batch.commit();
279
349
  totalSaved += pageBatchCount;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulltrackers-module",
3
- "version": "1.0.449",
3
+ "version": "1.0.451",
4
4
  "description": "Helper Functions for Bulltrackers.",
5
5
  "main": "index.js",
6
6
  "files": [