Chiamata base
Una chiamata singola a Gemini richiede un system_instruction e un array contents
con il messaggio dell'utente.
Basic call
A single call to Gemini requires a system_instruction and a contents array
with the user's message.
async function askGemini(userMessage, systemPrompt) {
const GEMINI_KEY = '[GEMINI_API_KEY]';
const MODEL = 'gemini-2.5-flash-lite';
const ENDPOINT = `https://generativelanguage.googleapis.com/v1beta/models/${MODEL}:generateContent?key=${GEMINI_KEY}`;
const response = await fetch(ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
system_instruction: { parts: [{ text: systemPrompt }] },
contents: [{ parts: [{ text: userMessage }] }]
})
});
const data = await response.json();
if (!response.ok) throw new Error(data?.error?.message || 'Errore API');
return data.candidates[0].content.parts[0].text;
}
Attenzione: non mettere mai la API key direttamente nel frontend di un'app pubblica. Per un gestionale interno ad accesso limitato è un tradeoff accettabile; in alternativa, salvala come variabile d'ambiente su Netlify e fai le chiamate tramite una Netlify Function proxy.
Warning: never put the API key directly in the frontend of a public app. For an internal panel with restricted access it's an acceptable tradeoff; alternatively, store it as a Netlify environment variable and call it via a Netlify Function proxy.
System prompt dinamico da stato Firebase
La chiave è costruire il system prompt al volo, serializzando lo stato corrente già presente in memoria
(sincronizzato da Firebase), senza fare query aggiuntive ad ogni messaggio.
Dynamic system prompt from Firebase state
The key is building the system prompt on the fly, serializing the current state already held in memory
(synced from Firebase), without extra queries on every message.
function buildSystemPrompt() {
const mese = getCurrentMonthLabel(); // es. "Giugno 2026"
const utente = sessionStorage.getItem('panelUser') || 'Sconosciuto';
// Classifica operatori con totali per categoria — già in memoria, no query
const rankingText = Object.entries(state.operatori)
.map(([nome, dati]) =>
`${nome}: ${dati.totale} ordini (Cat-A: ${dati.catA}, Cat-B: ${dati.catB})`
).join('\n');
return `Sei un assistente interno. Rispondi sempre in italiano, in modo diretto e professionale.
=== CONTESTO ATTUALE ===
Utente connesso: ${utente}
Mese di riferimento: ${mese}
=== OPERATORI E RISULTATI ===
${rankingText}
=== CONOSCENZA AZIENDALE ===
[Blocco statico — procedure, prodotti, glossario]
`;
}
Conoscenza statica vs live: nel blocco statico vanno le cose che cambiano raramente (struttura prodotti, procedure core, glossario) — scritte direttamente come stringa nel sorgente. Nel blocco dinamico va tutto ciò che cambia quotidianamente (chi ha venduto cosa, lead del mese), letto da Firebase al volo.
Static vs live knowledge: the static block holds things that change rarely (product structure, core procedures, glossary) — written directly as a string in the source. The dynamic block holds everything that changes daily (who sold what, this month's leads), read from Firebase on the fly.
Conversazione multi-turn: accodare i messaggi
Gemini API non ha memoria propria. Per simulare una conversazione con più scambi, ogni chiamata successiva
deve includere nell'array contents tutti i messaggi precedenti — alternando
role: "user" e role: "model".
Multi-turn conversation: queuing messages
The Gemini API has no memory of its own. To simulate a multi-exchange conversation, each subsequent call
must include in the contents array all previous messages — alternating
role: "user" and role: "model".
let conversationHistory = []; // resettata all'apertura del pannello
async function sendAiMessage(userText) {
// Aggiunge il turno utente alla storia
conversationHistory.push({
role: 'user',
parts: [{ text: userText }]
});
const response = await fetch(ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
system_instruction: { parts: [{ text: buildSystemPrompt() }] },
contents: conversationHistory // intera storia ad ogni chiamata
})
});
const data = await response.json();
const aiText = data.candidates[0].content.parts[0].text;
// Aggiunge la risposta del modello alla storia
conversationHistory.push({
role: 'model',
parts: [{ text: aiText }]
});
return aiText;
}
Versioning modelli: Gemini deprecca i modelli rapidamente per i nuovi account. Verifica sempre la disponibilità del modello scelto prima di metterlo in produzione — un nome modello valido oggi può restituire 404 tra qualche settimana.
Model versioning: Gemini deprecates models quickly for new accounts. Always verify the chosen model's availability before shipping to production — a valid model name today can return a 404 in a few weeks.
Articolo correlato
Assistente AI nel gestionale con Gemini API — system prompt dinamico da Firebase
Related article
AI assistant in the management panel with Gemini API — dynamic system prompt from Firebase
→