bulltrackers-module 1.0.371 → 1.0.372

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.
@@ -82,43 +82,60 @@ async function getGcidForUser(dependencies, config, cid, username) {
82
82
  */
83
83
  async function getAdvancedAnalysisFromGemini(dependencies, snippet) {
84
84
  const { logger, geminiModel } = dependencies;
85
- if (!geminiModel) {
86
- return { overallSentiment: "Neutral", topics: [], isSpam: false, qualityScore: 0.5 };
85
+
86
+ if (!geminiModel) {
87
+ return { overallSentiment: "Neutral", topics: [], isSpam: false, qualityScore: 0.5 };
87
88
  }
88
89
 
89
90
  const prompt = `
90
91
  You are a strict financial content moderator and analyst. Analyze this social media post.
91
- Output a valid JSON object with these fields: "isSpam" (Boolean), "qualityScore" (0.0-1.0), "overallSentiment" ("Bullish", "Bearish", "Neutral"), "topics" (Array).
92
+ Output ONLY a valid JSON object with these fields:
93
+ - isSpam (Boolean)
94
+ - qualityScore (0.0-1.0)
95
+ - overallSentiment ("Bullish", "Bearish", "Neutral")
96
+ - topics (Array)
92
97
  Post: "${snippet}"
93
98
  `;
94
99
 
95
100
  try {
96
- const request = {
97
- contents: [{ role: "user", parts: [{ text: prompt }] }],
98
- generationConfig: { temperature: 0.1, maxOutputTokens: 256, responseMimeType: "application/json" }
101
+ const request = {
102
+ contents: [{ role: "user", parts: [{ text: prompt }] }],
103
+ generationConfig: {
104
+ temperature: 0.1,
105
+ maxOutputTokens: 256,
106
+ responseMimeType: "application/json"
107
+ }
99
108
  };
100
-
109
+
101
110
  const result = await geminiModel.generateContent(request);
102
- const text = result.response?.candidates?.[0]?.content?.parts?.[0]?.text?.trim();
103
111
 
104
- if (text) {
105
- try {
106
- const cleanJson = text.replace(/```json|```/g, '').trim();
107
- const parsed = JSON.parse(cleanJson);
108
- return {
109
- overallSentiment: parsed.overallSentiment || "Neutral",
110
- topics: parsed.topics || [],
111
- isSpam: !!parsed.isSpam,
112
- qualityScore: parsed.qualityScore || 0.5
113
- };
114
- } catch (e) {
115
- logger.log('WARN', '[Gemini AI] JSON parse error', e);
116
- }
112
+ // Gemini 2.5 Flash returns JSON directly in parts[0].json
113
+ const part = result?.response?.candidates?.[0]?.content?.parts?.[0];
114
+
115
+ let parsed;
116
+
117
+ if (part?.json) {
118
+ // Ideal case: model returned structured JSON
119
+ parsed = part.json;
120
+ } else if (part?.text) {
121
+ // Fallback: model returned text (rare with application/json)
122
+ const clean = part.text.replace(/```json|```/g, "").trim();
123
+ parsed = JSON.parse(clean);
124
+ } else {
125
+ throw new Error("No JSON or text returned from Gemini");
117
126
  }
127
+
128
+ return {
129
+ overallSentiment: parsed.overallSentiment || "Neutral",
130
+ topics: parsed.topics || [],
131
+ isSpam: !!parsed.isSpam,
132
+ qualityScore: parsed.qualityScore ?? 0.5
133
+ };
134
+
118
135
  } catch (e) {
119
- logger.log('ERROR', '[Gemini AI] Request failed', e);
136
+ logger.log("ERROR", "[Gemini AI] JSON handling failed", e);
137
+ return { overallSentiment: "Neutral", topics: [], isSpam: false, qualityScore: 0.5 };
120
138
  }
121
- return { overallSentiment: "Neutral", topics: [], isSpam: false, qualityScore: 0.5 };
122
139
  }
123
140
 
124
141
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulltrackers-module",
3
- "version": "1.0.371",
3
+ "version": "1.0.372",
4
4
  "description": "Helper Functions for Bulltrackers.",
5
5
  "main": "index.js",
6
6
  "files": [