import { GoogleGenAI } from "@google/genai"; import { KBArticle, Ticket, TicketStatus } from "../types"; // The API key must be obtained exclusively from the environment variable process.env.API_KEY. const apiKey = process.env.API_KEY || ''; // Initialize AI only if key exists to prevent immediate instantiation errors let ai: GoogleGenAI | null = null; if (apiKey) { try { ai = new GoogleGenAI({ apiKey }); } catch (e) { console.warn("Failed to initialize GoogleGenAI", e); } } /** * Agent 1: Customer Support Chat * Uses the KB to answer questions. */ export const getSupportResponse = async ( userQuery: string, chatHistory: string[], knowledgeBase: KBArticle[] ): Promise => { if (!ai || !apiKey) { return "L'assistente AI non è configurato o la chiave API è mancante. Contatta l'amministratore."; } // Prepare Context from KB const kbContext = knowledgeBase.map(a => { if (a.type === 'url') { return `Fonte Esterna [${a.category}]: ${a.title} - URL: ${a.url}\nContenuto Estratto: ${a.content}`; } return `Articolo [${a.category}]: ${a.title}\nContenuto: ${a.content}`; }).join('\n\n'); const systemInstruction = ` Sei "OmniSupport AI", un assistente clienti virtuale globale. IL TUO COMPITO: Rispondere alle domande dei clienti basandoti ESCLUSIVAMENTE sulla seguente Base di Conoscenza (KB) fornita in ITALIANO. GESTIONE LINGUA (IMPORTANTE): 1. Rileva automaticamente la lingua utilizzata dall'utente nel suo ultimo messaggio. 2. Anche se la KB è in Italiano, devi tradurre mentalmente la richiesta, cercare la risposta nella KB Italiana, e poi RISPONDERE NELLA LINGUA DELL'UTENTE. BASE DI CONOSCENZA (ITALIANO): ${kbContext} REGOLE: 1. Se la risposta è nella KB, forniscila. 2. Se l'articolo è una fonte web (URL), usa il "Contenuto Estratto" per rispondere e fornisci anche il link originale all'utente. 3. Se la risposta NON si trova nella KB, ammettilo gentilmente (nella lingua dell'utente) e consiglia di aprire un ticket. 4. Sii cortese, professionale e sintetico. `; try { const response = await ai.models.generateContent({ model: 'gemini-3-flash-preview', contents: [ ...chatHistory.map(msg => ({ role: 'user', parts: [{ text: msg }] })), { role: 'user', parts: [{ text: userQuery }] } ], config: { systemInstruction: systemInstruction, temperature: 0.3, } }); return response.text || "Mi dispiace, non riesco a generare una risposta al momento."; } catch (error) { console.error("Gemini Error:", error); return "Si è verificato un errore nel servizio AI."; } }; /** * Agent 2: Knowledge Extraction */ export const generateNewKBArticle = async ( resolvedTickets: Ticket[], existingArticles: KBArticle[] ): Promise<{ title: string; content: string; category: string } | null> => { if (!ai || !apiKey) return null; // Filter only resolved tickets const relevantTickets = resolvedTickets.filter(t => t.status === TicketStatus.RESOLVED); if (relevantTickets.length === 0) return null; // Aggregate ticket conversations const transcripts = relevantTickets.map(t => { const convo = t.messages.map(m => `${m.role.toUpperCase()}: ${m.content}`).join('\n'); return `TICKET ID: ${t.id}\nOGGETTO: ${t.subject}\nCONVERSAZIONE:\n${convo}\n---`; }).join('\n'); const existingTitles = existingArticles.map(a => a.title).join(', '); const prompt = ` Sei un Knowledge Manager AI esperto. Analizza i seguenti ticket risolti e confrontali con gli articoli esistenti nella Knowledge Base. ARTICOLI ESISTENTI: ${existingTitles} TICKET RISOLTI RECENTI: ${transcripts} OBIETTIVO: 1. Identifica un problema ricorrente o una soluzione tecnica presente nei ticket risolti MA NON coperta dagli articoli esistenti. 2. Se trovi una lacuna, scrivi un NUOVO articolo di Knowledge Base per colmarla. 3. Restituisci il risultato ESCLUSIVAMENTE in formato JSON. SCHEMA JSON RICHIESTO: { "foundGap": boolean, "title": "Titolo del nuovo articolo", "content": "Contenuto dettagliato in formato Markdown", "category": "Categoria suggerita" } `; try { const response = await ai.models.generateContent({ model: 'gemini-3-pro-preview', contents: prompt, config: { responseMimeType: "application/json" } }); const text = response.text; if (!text) return null; const result = JSON.parse(text); if (result.foundGap) { return { title: result.title, content: result.content, category: result.category }; } return null; } catch (error) { console.error("Knowledge Agent Error:", error); return null; } };