import { GoogleGenAI } from "@google/genai"; import { AggregatedData } from "../types"; const SYSTEM_INSTRUCTION = ` You are an expert Data Analyst Assistant for "Craze Analytix". You have access to a structured dataset of sales performance including Revenue (Sell Out), Units, Product Lines, and Seasonality. Your Capabilities: 1. **Analyze Trends**: Use the provided Seasonality and Yearly Breakdown data. 2. **Perform Calculations**: You have access to detailed Product Line totals. You MUST calculate growth percentages, market shares, and sums dynamically if the user asks. 3. **Compare**: Compare performance between years (e.g., 2024 vs 2025). Rules: - If the user asks for a calculation (e.g., "What is the % share of Line X?"), perform the math using the provided numbers. - Always format currency as € (e.g., €1,200) and units with 'u' or 'units' (e.g., 500 units). - Be concise but insightful. Point out significant growth or decline. - If data is missing for a specific query, state clearly that it is not in the current filtered view. `; const formatCurrency = (val: number) => `€${val.toLocaleString(undefined, {minimumFractionDigits: 0, maximumFractionDigits: 0})}`; const formatUnits = (val: number) => `${val.toLocaleString()} units`; export const queryGemini = async ( apiKey: string, question: string, context: AggregatedData, filteredRecordCount: number ): Promise => { if (!apiKey) { return "Please provide your Gemini API Key in the settings to enable the AI assistant."; } try { // Ensure the key is clean of whitespace const ai = new GoogleGenAI({ apiKey: apiKey.trim() }); // --- CONTEXT GENERATION --- // We construct a structured report mirroring the dashboard charts // 1. Totals by Year (KPI Cards) const yearlySummary = Object.entries(context.totalsByYear) .sort((a, b) => parseInt(b[0]) - parseInt(a[0])) // Descending years .map(([year, data]) => ` - ${year}: ${formatCurrency(data.sellOut)} | ${formatUnits(data.units)}`) .join('\n'); // 2. Seasonality (Line Chart Data) const seasonalitySummary = context.seasonality.map(p => { const yearValues = context.availableYears.map(y => `${y}: ${formatCurrency(p[y] as number || 0)}`).join(', '); return ` - ${p.name}: [${yearValues}]`; }).join('\n'); // 3. Growth/Decline const growthSummary = context.topMovers.slice(0, 10).map(m => ` - ${m.line}: +€${m.sellOutGrowthValue.toLocaleString()} (${m.sellOutGrowthPercentage.toFixed(1)}%)` ).join('\n'); const declineSummary = context.bottomMovers.slice(0, 10).map(m => ` - ${m.line}: -€${Math.abs(m.sellOutGrowthValue).toLocaleString()} (${m.sellOutGrowthPercentage.toFixed(1)}%)` ).join('\n'); // 4. DETAILED BREAKDOWN (For Calculations) // We provide a JSON-like structure of ALL top product lines so the AI can compute shares/totals. // We limit this to top 100 to avoid token limits, which covers most relevant data. const detailedLines = context.byLine.slice(0, 100).map(l => ({ name: l.name, revenue: l.value, units: l.units })); const fullReport = ` REPORT CONTEXT (Based on Current Filters): ------------------------------------------ GLOBAL METRICS: Total Sell Out: ${formatCurrency(context.totalSellOut)} Total Units: ${formatUnits(context.totalUnits)} Records Analyzed: ${filteredRecordCount} Years Available: ${context.availableYears.join(', ')} YEARLY TOTALS: ${yearlySummary} MONTHLY TRENDS (Seasonality): ${seasonalitySummary} TOP PERFORMERS (Growth YoY): ${growthSummary} WORST PERFORMERS (Decline YoY): ${declineSummary} DETAILED PRODUCT LINE DATA (Use this for specific calculations): ${JSON.stringify(detailedLines, null, 2)} `; const response = await ai.models.generateContent({ model: 'gemini-3-pro-preview', // Updated to the latest capable model for complex reasoning contents: [ { role: 'user', parts: [{ text: `Context Data:\n${fullReport}\n\nUser Question: ${question}` }] } ], config: { systemInstruction: SYSTEM_INSTRUCTION, } }); return response.text || "I couldn't generate a response based on the data provided."; } catch (error: any) { console.error("Gemini API Error:", error); if (error.message && error.message.includes("403")) { return "Error 403: Invalid API Key. Please check your key in the settings."; } if (error.message && error.message.includes("429")) { return "Error 429: Quota exceeded. You are sending too many requests."; } return `Error: ${error.message || "An unexpected error occurred while analyzing the data."}`; } };