Update geminiService.ts

This commit is contained in:
fcarraUniSa
2026-02-17 10:08:11 +01:00
committed by GitHub
parent 83b0a6bcbd
commit e7e1837fae

View File

@@ -1,5 +1,30 @@
import { GoogleGenAI } from "@google/genai";
import { KBArticle, Ticket, TicketStatus } from "../types";
import { AiProvider, KBArticle, Ticket, TicketStatus } from "../types";
// --- OPENROUTER / OPENAI COMPATIBLE FETCH ---
async function callOpenRouter(apiKey: string, model: string, messages: any[]) {
const response = await fetch("https://openrouter.ai/api/v1/chat/completions", {
method: "POST",
headers: {
"Authorization": `Bearer ${apiKey}`,
"Content-Type": "application/json",
"HTTP-Referer": window.location.origin, // Required by OpenRouter
"X-Title": "OmniSupport AI" // Optional
},
body: JSON.stringify({
model: model || "openai/gpt-3.5-turbo",
messages: messages
})
});
if (!response.ok) {
const err = await response.text();
throw new Error(`OpenRouter API Error: ${err}`);
}
const data = await response.json();
return data.choices[0]?.message?.content || "";
}
/**
* Agent 1: Customer Support Chat
@@ -9,15 +34,14 @@ export const getSupportResponse = async (
apiKey: string,
userQuery: string,
chatHistory: string[],
knowledgeBase: KBArticle[]
knowledgeBase: KBArticle[],
provider: AiProvider = AiProvider.GEMINI,
model: string = 'gemini-3-flash-preview'
): Promise<string> => {
if (!apiKey) {
return "L'assistente AI non è configurato (API Key mancante). Contatta l'amministratore.";
}
try {
const ai = new GoogleGenAI({ apiKey });
// Prepare Context from KB
const kbContext = knowledgeBase.map(a => {
if (a.type === 'url') {
@@ -26,7 +50,7 @@ export const getSupportResponse = async (
return `Articolo [${a.category}]: ${a.title}\nContenuto: ${a.content}`;
}).join('\n\n');
const systemInstruction = `
const systemInstructionText = `
Sei "OmniSupport AI", un assistente clienti virtuale globale.
IL TUO COMPITO:
@@ -46,22 +70,38 @@ export const getSupportResponse = async (
4. Sii cortese, professionale e sintetico.
`;
try {
if (provider === AiProvider.OPENROUTER || provider === AiProvider.OPENAI || provider === AiProvider.DEEPSEEK) {
// Logic for OpenRouter/OpenAI compatible APIs
const messages = [
{ role: "system", content: systemInstructionText },
...chatHistory.map(msg => ({ role: "user", content: msg })),
{ role: "user", content: userQuery }
];
const response = await callOpenRouter(apiKey, model, messages);
return response || "Mi dispiace, non riesco a generare una risposta al momento.";
} else {
// Default to Google Gemini
const ai = new GoogleGenAI({ apiKey });
const response = await ai.models.generateContent({
model: 'gemini-3-flash-preview',
model: model,
contents: [
...chatHistory.map(msg => ({ role: 'user', parts: [{ text: msg }] })),
{ role: 'user', parts: [{ text: userQuery }] }
],
config: {
systemInstruction: systemInstruction,
systemInstruction: systemInstructionText,
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 (Verifica API Key o connessione).";
console.error("AI Service Error:", error);
return "Si è verificato un errore nel servizio AI (Verifica API Key, Provider o connessione).";
}
};
@@ -71,13 +111,12 @@ export const getSupportResponse = async (
export const generateNewKBArticle = async (
apiKey: string,
resolvedTickets: Ticket[],
existingArticles: KBArticle[]
existingArticles: KBArticle[],
provider: AiProvider = AiProvider.GEMINI,
model: string = 'gemini-3-pro-preview'
): Promise<{ title: string; content: string; category: string } | null> => {
if (!apiKey) return null;
try {
const ai = new GoogleGenAI({ apiKey });
// Filter only resolved tickets
const relevantTickets = resolvedTickets.filter(t => t.status === TicketStatus.RESOLVED);
@@ -91,7 +130,7 @@ export const generateNewKBArticle = async (
const existingTitles = existingArticles.map(a => a.title).join(', ');
const prompt = `
const systemPrompt = `
Sei un Knowledge Manager AI esperto.
Analizza i seguenti ticket risolti e confrontali con gli articoli esistenti nella Knowledge Base.
@@ -103,7 +142,7 @@ export const generateNewKBArticle = async (
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.
3. Restituisci il risultato ESCLUSIVAMENTE in formato JSON valido. Non aggiungere markdown code blocks.
SCHEMA JSON RICHIESTO:
{
@@ -114,18 +153,29 @@ export const generateNewKBArticle = async (
}
`;
try {
let rawText = "";
if (provider === AiProvider.OPENROUTER || provider === AiProvider.OPENAI || provider === AiProvider.DEEPSEEK) {
const messages = [{ role: "system", content: systemPrompt }];
rawText = await callOpenRouter(apiKey, model, messages);
} else {
const ai = new GoogleGenAI({ apiKey });
const response = await ai.models.generateContent({
model: 'gemini-3-pro-preview',
contents: prompt,
config: {
responseMimeType: "application/json"
}
model: model,
contents: systemPrompt,
config: { responseMimeType: "application/json" }
});
rawText = response.text || "";
}
const text = response.text;
if (!text) return null;
if (!rawText) return null;
const result = JSON.parse(text);
// Clean markdown if present (sometimes models add ```json ... ```)
// We escape the backticks in the regex to ensure safety in all environments
const cleanedText = rawText.replace(/\`\`\`json/g, '').replace(/\`\`\`/g, '').trim();
const result = JSON.parse(cleanedText);
if (result.foundGap) {
return {
title: result.title,
@@ -134,6 +184,7 @@ export const generateNewKBArticle = async (
};
}
return null;
} catch (error) {
console.error("Knowledge Agent Error:", error);
return null;