From 3662a26a841a29db48b5266ac4b2db138d3eccaf Mon Sep 17 00:00:00 2001 From: AtharvaKalekar Date: Sat, 26 Sep 2026 05:06:57 +0530 Subject: [PATCH 1/2] =?UTF-8?q?fix(ai):=20enforce=20Indian=20Rupee=20symbo?= =?UTF-8?q?l=20(=E2=82=B9)=20and=20clean=20markdown=20prompt=20instruction?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/services/ai.service.js | 7 +++++-- src/services/aiGuardrail.service.js | 11 +++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/services/ai.service.js b/src/services/ai.service.js index 7eda734..94fe86a 100644 --- a/src/services/ai.service.js +++ b/src/services/ai.service.js @@ -218,11 +218,14 @@ export const aiService = { { parts: [ { - text: `You are FinTrack AI, an intelligent personal finance assistant for mobile users. + text: `You are FinTrack AI, an intelligent personal finance assistant for mobile users in India. Context of user's real account ledger data: ${JSON.stringify(contextData)}. User prompt: "${prompt}". -Provide a comprehensive, friendly, and highly actionable financial response grounded strictly in the user's real transactions and claims data above. Include specific numbers, categories, and tips. Avoid generic or filler disclaimers.`, +CRITICAL RESPONSE RULES: +1. CURRENCY: Always format currency amounts using the Indian Rupee symbol (₹). NEVER use $ or USD under any circumstances. +2. FORMATTING: Structure your response with clean Markdown headers (### Header), bold key terms (**Term:** value), bullet points (* Item), and numbered action steps. +3. ACCURACY: Provide a friendly, actionable financial response grounded strictly in the user's real transactions and claims data above.`, }, ], }, diff --git a/src/services/aiGuardrail.service.js b/src/services/aiGuardrail.service.js index 034e23f..911950b 100644 --- a/src/services/aiGuardrail.service.js +++ b/src/services/aiGuardrail.service.js @@ -63,6 +63,17 @@ export const aiGuardrailService = { response.complianceCode = response.complianceCode || aiGuardrailService.COMPLIANCE_CODE; response.isGrounded = true; + // Convert any $ or USD to ₹ in response strings + if (typeof response.reply === 'string') { + response.reply = response.reply.replace(/\$/g, '₹').replace(/\bUSD\b/gi, '₹'); + } + if (typeof response.intro === 'string') { + response.intro = response.intro.replace(/\$/g, '₹').replace(/\bUSD\b/gi, '₹'); + } + if (typeof response.tipBox === 'string') { + response.tipBox = response.tipBox.replace(/\$/g, '₹').replace(/\bUSD\b/gi, '₹'); + } + // If response has items, verify they don't contain hallucinated non-existent transaction data if (Array.isArray(response.items) && response.items.length > 0) { if (groundedTransactions.length > 0) { From 76485aea442984c7aae7e2fac02ab99a03f42001 Mon Sep 17 00:00:00 2001 From: AtharvaKalekar Date: Sat, 26 Sep 2026 05:11:43 +0530 Subject: [PATCH 2/2] feat(ai): integrate ultra-fast Groq LPU inference with Gemini and rule engine fallbacks --- src/services/ai.service.js | 128 +++++++++++++++++++++++++++++++++---- 1 file changed, 116 insertions(+), 12 deletions(-) diff --git a/src/services/ai.service.js b/src/services/ai.service.js index 94fe86a..4ed9482 100644 --- a/src/services/ai.service.js +++ b/src/services/ai.service.js @@ -53,19 +53,34 @@ export const aiService = { const isSavingsQuery = query.includes('saving') || query.includes('goal') || query.includes('reach'); const isSubscriptionQuery = query.includes('subscript') || query.includes('recurring') || query.includes('netflix') || query.includes('spotify'); - // 2. Try Gemini / Vertex AI LLM Generation (SCRUM-170) if GEMINI_API_KEY is configured - const apiKey = process.env.GEMINI_API_KEY; - if (apiKey) { + // 2. Try Groq LPU Instant LLM Generation (High Speed ~250ms) if GROQ_API_KEY is configured + const groqKey = process.env.GROQ_API_KEY; + const contextObj = { + totalTransactionsAmount, + categoryTotals, + transactionsCount: transactions.length, + claimsCount: claims.length, + approvedClaimsCount: approvedClaims.length, + pendingClaimsCount: pendingClaims.length, + budgets, + }; + + if (groqKey) { try { - const llmResult = await aiService._callGeminiApi(apiKey, prompt, { - totalTransactionsAmount, - categoryTotals, - transactionsCount: transactions.length, - claimsCount: claims.length, - approvedClaimsCount: approvedClaims.length, - pendingClaimsCount: pendingClaims.length, - budgets, - }); + const groqResult = await aiService._callGroqApi(groqKey, prompt, contextObj); + if (groqResult) { + return aiGuardrailService.sanitizeEgressResponse(groqResult, transactions); + } + } catch (err) { + console.warn('Groq LPU API call failed, attempting Gemini fallback:', err.message); + } + } + + // 3. Fallback to Gemini Generative AI if configured + const geminiKey = process.env.GEMINI_API_KEY; + if (geminiKey) { + try { + const llmResult = await aiService._callGeminiApi(geminiKey, prompt, contextObj); if (llmResult) { return aiGuardrailService.sanitizeEgressResponse(llmResult, transactions); } @@ -200,6 +215,95 @@ export const aiService = { return aiGuardrailService.sanitizeEgressResponse(rawResult, transactions); }, + /** + * High-Performance Ultra-Fast Groq LPU Inference Service (~250ms Response) + */ + _callGroqApi: async (apiKey, prompt, contextData) => { + const candidateModels = [ + 'openai/gpt-oss-120b', + 'openai/gpt-oss-20b', + 'qwen/qwen3.8-27b', + ]; + + for (const model of candidateModels) { + try { + const bodyPayload = JSON.stringify({ + model, + messages: [ + { + role: 'system', + content: `You are FinTrack AI, an ultra-fast intelligent personal finance assistant for mobile users in India. +CRITICAL RESPONSE RULES: +1. CURRENCY: Always format currency amounts using the Indian Rupee symbol (₹). NEVER use $ or USD under any circumstances. +2. FORMATTING: Structure your response with clean Markdown headers (### Header), bold key terms (**Term:** value), bullet points (* Item), and numbered action steps. +3. ACCURACY: Provide a friendly, actionable financial response grounded strictly in the user's real transactions and claims data provided.`, + }, + { + role: 'user', + content: `Context of user's real account ledger data: ${JSON.stringify(contextData)}.\nUser question: "${prompt}".`, + }, + ], + temperature: 0.3, + }); + + const result = await new Promise((resolve, reject) => { + const req = http.request( + 'https://api.groq.com/openai/v1/chat/completions', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${apiKey}`, + 'Content-Length': Buffer.byteLength(bodyPayload), + }, + }, + (res) => { + let body = ''; + res.on('data', (chunk) => (body += chunk)); + res.on('end', () => { + if (res.statusCode === 200) { + try { + const data = JSON.parse(body); + const text = data?.choices?.[0]?.message?.content; + if (text && text.trim().length > 0) { + resolve({ + alertTag: 'FINTRACK INSTANT AI', + alertSub: 'Groq LPU ~250ms', + intro: 'AI Financial Analysis:', + reply: text.trim(), + items: [], + badgeSuccess: 'Powered by Groq LPU Ultra-Fast Hardware', + footerNote: 'Grounded in your real financial transactions', + }); + } else { + reject(new Error('Empty completion choice')); + } + } catch (e) { + reject(e); + } + } else { + reject(new Error(`Groq HTTP ${res.statusCode}: ${body.slice(0, 100)}`)); + } + }); + } + ); + + req.on('error', (e) => reject(e)); + req.write(bodyPayload); + req.end(); + }); + + if (result) { + return result; + } + } catch (err) { + console.warn(`Groq model ${model} attempt failed:`, err.message); + } + } + + return null; + }, + /** * Private helper to call Gemini Generative AI REST API with model fallback */