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
|
-
|
|
113
|
+
result = await geminiModel.generateContent(request);
|
|
111
114
|
|
|
112
115
|
// Gemini 2.5 Flash returns JSON directly in parts[0].json
|
|
113
|
-
|
|
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",
|
|
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
|
-
|
|
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,
|
|
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;
|