Web App e Agenti AI con Google Apps Script
I due tutorial operativi del Lab: prima una web app che legge e scrive su Google Sheets, poi un agente AI collegato a Gemini. Sono la parte pratica della Guida LAB AI 2026.
Crea la Tua Prima Web App con Google Apps Script
Dalla prima riga di codice all’URL pubblico condivisibile con il team. Zero server, zero costi, zero installazioni.
Una web app completa con: una pagina HTML, un backend che legge/scrive su Google Sheets, un URL pubblico accessibile da chiunque. Tempo stimato: 20-30 minuti.
Prima di iniziare
- Account Google (Gmail o Google Workspace)
- Browser Chrome o Firefox aggiornato
- Un Google Sheet vuoto già creato (opzionale ma consigliato)
- 10 minuti di concentrazione — si fa tutto online, nessuna installazione
Apri Google Apps Script Setup
Vai su script.google.com con il tuo account Google. Vedrai la dashboard con i tuoi progetti. Se è la prima volta, la vedrai vuota.
Clicca il pulsante “Nuovo Progetto” in alto a sinistra. Si apre l’editor online con un file Codice.gs già creato.
Scrivi il Backend — Code.gs Backend
Il file Code.gs è il cervello dell’app. Contiene il codice JavaScript che gira sui server di Google. La funzione più importante è doGet(e): viene chiamata ogni volta che qualcuno apre l’URL della tua app.
Cancella tutto il contenuto del file e incolla questo codice:
// ============ CONFIGURAZIONE ============
const CONFIG = {
SHEET_ID: 'INCOLLA-QUI-ID-DEL-TUO-SHEET', // vedi Step 4
SHEET_NAME: 'Dati'
};
// ============ ENTRY POINT ============
function doGet(e) {
return HtmlService
.createTemplateFromFile('Index')
.evaluate()
.setTitle('La Mia WebApp')
.addMetaTag('viewport', 'width=device-width, initial-scale=1')
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}
// Helper per includere altri file HTML
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
// ============ LEGGI DATI DAL FOGLIO ============
function getDati() {
const sheet = SpreadsheetApp
.openById(CONFIG.SHEET_ID)
.getSheetByName(CONFIG.SHEET_NAME);
const dati = sheet.getDataRange().getValues();
return JSON.stringify(dati);
}
// ============ SALVA UN RECORD ============
function salvaRiga(nome, valore) {
const sheet = SpreadsheetApp
.openById(CONFIG.SHEET_ID)
.getSheetByName(CONFIG.SHEET_NAME);
const oggi = new Date().toLocaleDateString('it-IT');
sheet.appendRow([oggi, nome, valore]);
return 'OK';
}
Sostituisci 'INCOLLA-QUI-ID-DEL-TUO-SHEET' con l’ID reale del tuo Google Sheet (vedi Step 4 su come trovarlo).
Crea il Frontend — Index.html Frontend
Ora aggiungi il file HTML che gli utenti vedranno. Clicca il pulsante “+” accanto a “File” nel pannello di sinistra → scegli “HTML” → chiama il file Index (senza .html, lo aggiunge da solo).
Incolla questo codice nel nuovo file Index.html:
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>La Mia WebApp</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
<style>
:root { --primary: #2FA3A8; }
* { margin:0; padding:0; box-sizing:border-box; }
body { font-family: 'Inter', sans-serif; background: #f8fafc; color: #1e293b; }
.header {
background: linear-gradient(135deg, #0d1117, #083A3E);
color: white; padding: 24px 32px;
display: flex; align-items: center; gap: 14px;
}
.header h1 { font-size: 22px; font-weight: 700; }
.container { max-width: 700px; margin: 0 auto; padding: 32px 20px; }
.card {
background: white; border-radius: 14px;
padding: 28px; box-shadow: 0 2px 12px rgba(0,0,0,0.07);
margin-bottom: 24px; border: 1px solid #E6F0F0;
}
.card h2 { font-size: 18px; margin-bottom: 20px; color: var(--primary); }
.form-group { margin-bottom: 18px; }
label { font-size: 14px; font-weight: 600; color: #374151; display: block; margin-bottom: 6px; }
input {
width: 100%; padding: 12px 14px; border: 1px solid #d1d5db;
border-radius: 8px; font-size: 15px; font-family: inherit;
transition: border-color .2s;
}
input:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px rgba(47,163,168,0.15); }
.btn {
background: var(--primary); color: white; border: none;
padding: 13px 32px; border-radius: 8px; font-size: 15px;
font-weight: 600; cursor: pointer; font-family: inherit;
transition: all .2s; width: 100%;
}
.btn:hover { background: #239e90; transform: translateY(-1px); }
.btn:disabled { opacity: .6; cursor: not-allowed; transform: none; }
.status {
margin-top: 14px; padding: 12px 16px; border-radius: 8px;
font-size: 14px; display: none;
}
.status.ok { background: #ecfdf5; border: 1px solid #6ee7b7; color: #065f46; }
.status.fail { background: #fef2f2; border: 1px solid #fca5a5; color: #7f1d1d; }
#lista { }
.item {
padding: 12px 16px; border-radius: 8px; margin-bottom: 8px;
background: #f8fafc; border: 1px solid #E6F0F0;
display: grid; grid-template-columns: auto 1fr 1fr;
gap: 16px; align-items: center; font-size: 14px;
}
.item .data { color: #93AEAE; font-size: 12px; }
.item .nome { font-weight: 600; }
.item .val { color: var(--primary); font-weight: 600; text-align: right; }
#loading { text-align: center; color: #93AEAE; padding: 24px; }
</style>
</head>
<body>
<div class="header">
<svg width="32" height="32" viewBox="0 0 32 32" fill="none">
<circle cx="16" cy="16" r="16" fill="rgba(47,163,168,0.3)"/>
<path d="M10 16l4 4 8-8" stroke="#2FA3A8" stroke-width="2.5" stroke-linecap="round"/>
</svg>
<h1>La Mia Prima WebApp</h1>
</div>
<div class="container">
<!-- FORM INSERIMENTO -->
<div class="card">
<h2>Inserisci un dato</h2>
<div class="form-group">
<label for="nome">Nome</label>
<input type="text" id="nome" placeholder="Es. Temperatura frigo A">
</div>
<div class="form-group">
<label for="valore">Valore</label>
<input type="text" id="valore" placeholder="Es. 4°C">
</div>
<button class="btn" id="btnSalva" onclick="salva()">Salva sul foglio</button>
<div class="status" id="status"></div>
</div>
<!-- LISTA DATI -->
<div class="card">
<h2>Dati salvati</h2>
<div id="lista"><div id="loading">Caricamento...</div></div>
</div>
</div>
<script>
// Carica i dati all'avvio
window.onload = function() { caricaDati(); };
function caricaDati() {
google.script.run
.withSuccessHandler(function(json) {
const dati = JSON.parse(json);
const lista = document.getElementById('lista');
if (dati.length === 0) {
lista.innerHTML = '<p style="color:#93AEAE;text-align:center;padding:20px">Nessun dato ancora.</p>';
return;
}
lista.innerHTML = dati.slice().reverse().slice(0,20).map(r => `
<div class="item">
<span class="data">${r[0]}</span>
<span class="nome">${r[1]}</span>
<span class="val">${r[2]}</span>
</div>`).join('');
})
.withFailureHandler(function(err) {
document.getElementById('lista').innerHTML = '<p style="color:#ef4444">Errore: ' + err.message + '</p>';
})
.getDati();
}
function salva() {
const nome = document.getElementById('nome').value.trim();
const valore = document.getElementById('valore').value.trim();
const status = document.getElementById('status');
const btn = document.getElementById('btnSalva');
if (!nome || !valore) {
status.className = 'status fail';
status.textContent = 'Compila tutti i campi prima di salvare.';
status.style.display = 'block';
return;
}
btn.disabled = true;
btn.textContent = 'Salvataggio...';
google.script.run
.withSuccessHandler(function() {
status.className = 'status ok';
status.textContent = '✓ Dato salvato correttamente!';
status.style.display = 'block';
document.getElementById('nome').value = '';
document.getElementById('valore').value = '';
btn.disabled = false;
btn.textContent = 'Salva sul foglio';
caricaDati();
})
.withFailureHandler(function(err) {
status.className = 'status fail';
status.textContent = 'Errore: ' + err.message;
status.style.display = 'block';
btn.disabled = false;
btn.textContent = 'Salva sul foglio';
})
.salvaRiga(nome, valore);
}
</script>
</body>
</html>
Collega Google Sheets Dati
La tua app salverà i dati su un Google Sheet. Segui questi passi:
- Vai su sheets.google.com e crea un nuovo foglio
- Nella prima riga aggiungi le intestazioni: Data | Nome | Valore
- Chiama il foglio (tab in basso) Dati (esatto, con la D maiuscola)
- Copia l’ID dallo URL: è la stringa lunga tra
/d/e/edit
Torna su Code.gs e sostituisci 'INCOLLA-QUI-ID-DEL-TUO-SHEET' con il tuo ID.
SpreadsheetApp.create('Nome Foglio') — ma per i principianti è più semplice crearlo a mano e copiare l’ID.Configura appsscript.json Configurazione
Questo file definisce come si comporta la tua app quando viene pubblicata. Per vederlo, clicca l’icona Impostazioni (⚙️ ingranaggio) nella barra laterale sinistra e attiva “Mostra file manifest appsscript.json”.
Sostituisci il contenuto con:
{
"timeZone": "Europe/Rome",
"dependencies": {},
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8",
"oauthScopes": [
"https://www.googleapis.com/auth/spreadsheets",
"https://www.googleapis.com/auth/script.external_request"
],
"webapp": {
"executeAs": "USER_DEPLOYING",
"access": "ANYONE_ANONYMOUS"
}
}executeAs: USER_DEPLOYING — l’app gira con il tuo account, gli utenti non devono fare login.access: ANYONE_ANONYMOUS — chiunque può aprire l’URL, anche chi non ha un account Google aziendale.
Salva e Fai il Deploy Deploy
Ora pubblichiamo l’app. Segui questa sequenza precisa:
- Clicca Ctrl+S (o Cmd+S su Mac) per salvare tutti i file
- Clicca il pulsante “Deploy” in alto a destra → “Nuova distribuzione”
- Nella finestra che si apre: clicca l’icona ⚙️ accanto a “Seleziona tipo” → scegli “App web”
- Campo “Descrizione”: scrivi “v1.0 – Prima versione”
- Campo “Esegui come”: Me (il tuo indirizzo email)
- Campo “Chi può accedere”: Chiunque
- Clicca “Esegui il deploy”
Google chiederà di autorizzare l’app ad accedere ai tuoi Sheets. Clicca “Autorizza accesso” → scegli il tuo account Google → clicca “Avanzate” → “Vai a [nome progetto] (non sicuro)” → “Consenti”. Questo messaggio appare perché l’app non è verificata da Google, ma è normale per le app personali.
https://script.google.com/macros/s/[ID-LUNGO]/execTesta la Web App Test
Apri l’URL copiato nel browser. Dovresti vedere la tua web app con il form. Prova a:
- Inserire un nome e un valore nel form
- Cliccare “Salva sul foglio”
- Verificare che il dato appaia nella lista
- Aprire Google Sheets e controllare che la riga sia stata aggiunta
- Aprire lo stesso URL da smartphone — deve funzionare!
Hai costruito la tua prima web app con GAS. Da qui puoi espanderla: aggiungi campi al form, crea nuove funzioni backend, aggiungi tabelle o grafici al frontend. Ogni modifica richiede un nuovo deploy.
Aggiornare l’App dopo le Modifiche Workflow
Ogni volta che modifichi il codice, devi fare un nuovo deploy per vedere i cambiamenti online:
- Modifica il codice in Code.gs o Index.html
- Salva con Ctrl+S
- Clicca “Deploy” → “Gestisci distribuzioni”
- Clicca l’icona ✏️ (matita) accanto alla tua distribuzione
- Cambia la versione da “Nuova versione” a quella desiderata
- Aggiorna la descrizione (es. “v1.1 – Aggiunto campo email”)
- Clicca “Esegui il deploy” — stessa URL, nuova versione
Usa l’AI per Scrivere il Codice GAS
Non devi imparare JavaScript. Descrivi cosa vuoi e chiedi a Claude o ChatGPT di scrivere il codice per te. Poi incollalo in GAS e fai il deploy.
Prompt per Claude
Errori Comuni → Soluzioni
- “Accesso negato” → rilancia il deploy con accesso “Chiunque”
- Pagina bianca → controlla che il file si chiami esattamente “Index” (con I maiuscola)
- Errore Sheet → controlla che l’ID sia corretto e il foglio si chiami “Dati”
- Modifiche non visibili → hai fatto il nuovo deploy? Controlla “Gestisci distribuzioni”
- Autorizzazione loop → svuota la cache del browser e riprova
Idee di App da Costruire
- Registro presenze con QR code
- Form ordini fornitore con approvazione
- Dashboard KPI estratta da Sheets
- Sistema mance con calcolo automatico
- Checklist apertura/chiusura locale
Funzioni GAS Utili
- MailApp.sendEmail() — manda email
- CalendarApp.getEvents() — legge Calendar
- DriveApp.createFile() — crea file Drive
- UrlFetchApp.fetch() — chiama API esterne
- Utilities.formatDate() — formatta date
Trigger Automatici
- onEdit — si attiva quando modifichi lo sheet
- onOpen — si attiva all’apertura del file
- Time-driven — ogni ora/giorno/settimana
- onFormSubmit — a ogni invio form
Crea il Tuo Agente AI con GAS + Gemini
Prendi la web app GAS che hai già costruito e aggiungi un cervello AI. Con poche righe di codice colleghi Gemini 2.0 Flash e ottieni un agente che risponde, analizza e ragiona — tutto su infrastruttura Google, tutto gratis.
Ottieni la chiave da Google AI Studio
L’API key è la “password” che permette al tuo script GAS di parlare con Gemini. È gratuita, si crea in 1 minuto.
- Vai su aistudio.google.com con il tuo account Google
- Clicca “Get API Key” in alto a sinistra → “Create API key”
- Copia la chiave generata (inizia con
AIza...) — salvala in un posto sicuro - Ora vai nel tuo progetto GAS → Impostazioni Progetto (icona ingranaggio ⚙️ in basso a sinistra)
- Scorri fino a “Proprietà dello script” → clicca “Aggiungi proprietà”
- Nome:
GEMINI_API_KEY— Valore: incolla la tua API key → Salva
Non mettere mai l’API key direttamente nel codice — chiunque abbia accesso al progetto potrebbe vederla. Con PropertiesService la key è crittografata e invisibile, anche se condividi il progetto.
Il backend completo dell’agente
Sostituisci il Code.gs della tua app con questo. Contiene tutto: la web app, la chiamata a Gemini e la gestione della cronologia della chat.
// ============ CONFIGURAZIONE AGENTE ============
const CONFIG = {
GEMINI_MODEL: 'gemini-2.0-flash', // oppure 'gemini-2.5-flash'
GEMINI_URL: 'https://generativelanguage.googleapis.com/v1beta/models/',
MAX_TOKENS: 1024,
TEMPERATURE: 0.7,
// ← Personalizza il carattere del tuo agente qui
SYSTEM_PROMPT: `Sei un assistente aziendale di Gruppo Ethos.
Conosci i 5 locali: Acqua e Farina, Birrificio di Como, Fabbrica Libera,
Agriturismo Brusignone, Essenza Bistrot.
Rispondi sempre in italiano, in modo professionale ma diretto.
Sei specializzato in: operatività ristorazione, gestione del personale,
food & beverage, procedure HACCP.
Se non conosci qualcosa, dillo chiaramente senza inventare.`
};
// ============ ENTRY POINT WEB APP ============
function doGet(e) {
return HtmlService
.createTemplateFromFile('Index')
.evaluate()
.setTitle('Agente AI — Gruppo Ethos')
.addMetaTag('viewport', 'width=device-width, initial-scale=1')
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}
// ============ CHIAMATA A GEMINI ============
function chiediAgente(messaggioUtente, cronologia) {
const apiKey = PropertiesService.getScriptProperties()
.getProperty('GEMINI_API_KEY');
if (!apiKey) return '⚠️ API key non configurata. Vai in Impostazioni Progetto → Proprietà Script.';
const url = CONFIG.GEMINI_URL + CONFIG.GEMINI_MODEL + ':generateContent?key=' + apiKey;
// Costruisci la cronologia conversazione
const contents = (cronologia || []).map(function(msg) {
return { role: msg.ruolo, parts: [{ text: msg.testo }] };
});
// Aggiungi il messaggio corrente
contents.push({ role: 'user', parts: [{ text: messaggioUtente }] });
const payload = {
system_instruction: { parts: [{ text: CONFIG.SYSTEM_PROMPT }] },
contents: contents,
generationConfig: {
temperature: CONFIG.TEMPERATURE,
maxOutputTokens: CONFIG.MAX_TOKENS
}
};
const options = {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify(payload),
muteHttpExceptions: true
};
try {
const risposta = UrlFetchApp.fetch(url, options);
const dati = JSON.parse(risposta.getContentText());
if (dati.error) return 'Errore API: ' + dati.error.message;
return dati.candidates[0].content.parts[0].text;
} catch(err) {
return 'Errore di connessione: ' + err.message;
}
}
// ============ LOG SU SHEETS (opzionale) ============
function logConversazione(domanda, risposta) {
try {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName('Log') || ss.insertSheet('Log');
const ora = new Date().toLocaleString('it-IT');
sheet.appendRow([ora, domanda, risposta]);
} catch(e) { /* log opzionale, ignora errori */ }
}
La chat completa del tuo agente
Crea il file Index.html nel progetto GAS e incolla questo codice. Ottieni una chat moderna con cronologia, indicatore di caricamento e invio con Invio.
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Agente AI</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
:root { --ai:#2FA3A8; --user:#3b82f6; --bg:#0d1117; --bg2:#0e1a2a; }
* { margin:0; padding:0; box-sizing:border-box; }
body { font-family:'Inter',sans-serif; background:var(--bg); color:#E6F0F0; height:100vh; display:flex; flex-direction:column; }
/* Header */
.header {
background:var(--bg2); border-bottom:1px solid rgba(47,163,168,0.2);
padding:16px 24px; display:flex; align-items:center; gap:12px; flex-shrink:0;
}
.header-dot { width:10px; height:10px; border-radius:50%; background:var(--ai); box-shadow:0 0 8px rgba(47,163,168,.6); animation:pulse 2s infinite; }
@keyframes pulse { 0%,100%{opacity:1} 50%{opacity:.4} }
.header h1 { font-size:16px; font-weight:700; color:#fff; }
.header p { font-size:12px; color:#64748b; margin-top:1px; }
/* Chat area */
.chat { flex:1; overflow-y:auto; padding:24px 16px; display:flex; flex-direction:column; gap:16px; }
.msg { display:flex; gap:10px; max-width:80%; }
.msg.user { align-self:flex-end; flex-direction:row-reverse; }
.msg.ai { align-self:flex-start; }
.avatar {
width:34px; height:34px; border-radius:50%; flex-shrink:0;
display:flex; align-items:center; justify-content:center; font-size:15px;
}
.msg.ai .avatar { background:rgba(47,163,168,0.2); border:1px solid rgba(47,163,168,0.4); }
.msg.user .avatar { background:rgba(59,130,246,0.2); border:1px solid rgba(59,130,246,0.4); }
.bubble {
padding:12px 16px; border-radius:14px;
font-size:14px; line-height:1.7; white-space:pre-wrap; word-break:break-word;
}
.msg.ai .bubble { background:#083A3E; border:1px solid rgba(47,163,168,0.15); border-radius:4px 14px 14px 14px; }
.msg.user .bubble { background:rgba(59,130,246,0.15); border:1px solid rgba(59,130,246,0.25); border-radius:14px 4px 14px 14px; }
.typing { display:flex; gap:4px; padding:14px 18px; align-items:center; }
.typing span { width:7px; height:7px; border-radius:50%; background:var(--ai); animation:bounce .9s infinite; }
.typing span:nth-child(2){animation-delay:.2s}
.typing span:nth-child(3){animation-delay:.4s}
@keyframes bounce { 0%,60%,100%{transform:translateY(0)} 30%{transform:translateY(-8px)} }
/* Input area */
.input-area {
padding:16px 20px; background:var(--bg2);
border-top:1px solid rgba(47,163,168,0.15); flex-shrink:0;
}
.input-wrap { display:flex; gap:10px; max-width:800px; margin:0 auto; }
textarea {
flex:1; background:#084247; border:1px solid rgba(47,163,168,0.25);
color:#E6F0F0; border-radius:10px; padding:12px 16px; font-family:inherit;
font-size:14px; resize:none; min-height:48px; max-height:140px; line-height:1.6;
transition:border-color .2s;
}
textarea:focus { outline:none; border-color:var(--ai); }
textarea::placeholder { color:#475569; }
.send-btn {
background:linear-gradient(135deg,#1a8a7d,#4FD8DE); color:#fff; border:none;
width:48px; height:48px; border-radius:10px; cursor:pointer; flex-shrink:0;
display:flex; align-items:center; justify-content:center; transition:all .2s;
align-self:flex-end;
}
.send-btn:hover:not(:disabled) { transform:scale(1.05); box-shadow:0 4px 16px rgba(79,216,222,0.3); }
.send-btn:disabled { opacity:.4; cursor:not-allowed; }
.hint { text-align:center; font-size:11px; color:#334155; margin-top:8px; }
</style>
</head>
<body>
<div class="header">
<div class="header-dot"></div>
<div>
<h1>Agente AI — Gruppo Ethos</h1>
<p>Powered by Gemini 2.0 Flash · Sempre disponibile</p>
</div>
</div>
<div class="chat" id="chat">
<div class="msg ai">
<div class="avatar">🤖</div>
<div class="bubble">Ciao! Sono il tuo assistente AI. Come posso aiutarti oggi?</div>
</div>
</div>
<div class="input-area">
<div class="input-wrap">
<textarea id="input" placeholder="Scrivi la tua domanda..." rows="1"></textarea>
<button class="send-btn" id="btn" onclick="invia()">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2.5">
<line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/>
</svg>
</button>
</div>
<p class="hint">Premi Invio per inviare · Shift+Invio per andare a capo</p>
</div>
<script>
// Cronologia conversazione (mantiene il contesto)
const cronologia = [];
const chatEl = document.getElementById('chat');
const inputEl = document.getElementById('input');
const btnEl = document.getElementById('btn');
// Auto-resize textarea
inputEl.addEventListener('input', function() {
this.style.height = 'auto';
this.style.height = Math.min(this.scrollHeight, 140) + 'px';
});
// Invio con tasto Enter (Shift+Enter va a capo)
inputEl.addEventListener('keydown', function(e) {
if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); invia(); }
});
function aggiungiMessaggio(testo, tipo) {
const div = document.createElement('div');
div.className = 'msg ' + tipo;
div.innerHTML = `
<div class="avatar">${tipo === 'ai' ? '🤖' : '👤'}</div>
<div class="bubble">${testo.replace(/&/g,'&').replace(/</g,'<').replace(/\n/g,'<br>')}</div>`;
chatEl.appendChild(div);
chatEl.scrollTop = chatEl.scrollHeight;
return div;
}
function mostraTyping() {
const div = document.createElement('div');
div.className = 'msg ai'; div.id = 'typing';
div.innerHTML = '<div class="avatar">🤖</div><div class="bubble"><div class="typing"><span></span><span></span><span></span></div></div>';
chatEl.appendChild(div);
chatEl.scrollTop = chatEl.scrollHeight;
}
function invia() {
const testo = inputEl.value.trim();
if (!testo) return;
aggiungiMessaggio(testo, 'user');
cronologia.push({ ruolo: 'user', testo: testo });
inputEl.value = '';
inputEl.style.height = 'auto';
btnEl.disabled = true;
mostraTyping();
google.script.run
.withSuccessHandler(function(risposta) {
document.getElementById('typing')?.remove();
aggiungiMessaggio(risposta, 'ai');
cronologia.push({ ruolo: 'model', testo: risposta });
btnEl.disabled = false;
inputEl.focus();
})
.withFailureHandler(function(err) {
document.getElementById('typing')?.remove();
aggiungiMessaggio('⚠️ Errore: ' + err.message, 'ai');
btnEl.disabled = false;
})
.chiediAgente(testo, cronologia.slice(-10)); // passa max 10 msg di storia
}
</script>
</body>
</html>
Cambia il System Prompt → cambia l’agente
Il campo SYSTEM_PROMPT in Code.gs è il carattere dell’agente. Basta modificarlo per creare agenti completamente diversi.
Agente HR — Selezione e Policy
Agente F&B — Cucina e Menu
Agente FAQ — Assistente Cliente
Agente Dati — Analisi KPI
gemini-2.0-flash
Consigliato per iniziare
- Velocissimo (risposta in 1-2 sec)
- Gratuito con limiti generosi
- Ottimo per chat, FAQ, testo
- Contesto 1M token
gemini-2.5-flash
Per analisi complesse
- Ragionamento avanzato
- Migliore con dati e calcoli
- Thinking mode attivabile
- Leggermente più lento
Come cambiare modello
Basta modificare una riga in Code.gs:
1. Ottieni API key su aistudio.google.com → 2. Salvala in Proprietà Script GAS (nome: GEMINI_API_KEY) → 3. Incolla Code.gs e Index.html → 4. Personalizza il SYSTEM_PROMPT → 5. Deploy → il tuo agente è live con URL condivisibile.
Torna alla guida
Metodo, sette strumenti, prompt e missioni stanno nella guida principale.