# ποΈ Sibilla Alexa Skill β Brainstorming & Architettura
> **Versione documento:** 0.1.0
> **Stato:** π§ Brainstorming / Pianificazione
> **Autore:** Sibilla Team
> **Data:** 18 Luglio 2026
---
## Indice
1. [Panoramica: Come funziona una Skill Alexa](#panoramica)
2. [Architettura di Sistema](#architettura-di-sistema)
3. [Flusso dei Dati](#flusso-dei-dati)
4. [Requisiti](#requisiti)
5. [Interaction Model](#interaction-model)
6. [Lambda Function Design](#lambda-function-design)
7. [SSML e Voce Italiana](#ssml-e-voce-italiana)
8. [Sicurezza](#sicurezza)
9. [Costi](#costi)
10. [Piano di Implementazione](#piano-di-implementazione)
11. [Rischi e Mitigazioni](#rischi-e-mitigazioni)
12. [Riferimenti](#riferimenti)
---
## Panoramica
### Cos'Γ¨ una Skill Alexa?
Una **Skill Alexa** Γ¨ un'applicazione vocale che permette agli utenti di interagire con i dispositivi Amazon Echo (Echo Dot, Echo Show, ecc.) usando solo la voce. Γ l'equivalente di una "app" per lo store di Alexa.
### Come funziona (versione semplificata)
```
Tu dici: "Alexa, chiedi a Sibilla qual Γ¨ l'ultimo film sull'Odissea"
β
Alexa: Converte voce β testo, capisce l'intenzione (intent)
β
AWS Lambda: Riceve un JSON con la tua domanda, chiama l'API Sibilla
β
Sibilla API: Cerca nel web, sintetizza con Gemini, restituisce la risposta
β
AWS Lambda: Prende `speakable_text`, lo avvolge in SSML, risponde ad Alexa
β
Alexa: Converte testo β voce e te lo dice
```
### PerchΓ© Γ¨ giΓ quasi pronto
Sibilla **ha giΓ tutto il necessario** per una skill Alexa:
| Cosa serve | Sibilla ce l'ha? |
|-----------|-----------------|
| API REST per query testuali | β
`GET/POST /api/v1/query` |
| CORS abilitato | β
`Access-Control-Allow-Origin: *` |
| Testo pulito per TTS | β
Campo `speakable_text` (strip_markdown) |
| Risposta in italiano | β
Prompt e risposte in italiano |
| Open source, self-hosted | β
Nessun costo API di terze parti |
L'unica cosa da costruire Γ¨ il "ponte" tra Alexa e Sibilla: una **Lambda AWS** che fa da intermediario.
---
## Architettura di Sistema
```
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SIBILLA ALEXA SKILL β
β β
β ββββββββββββ βββββββββββββββββ ββββββββββββββββββββββββ β
β β β β β β β β
β β Alexa ββββββΆβ Alexa Cloud ββββββΆβ AWS Lambda β β
β β Device β β (Amazon) β β (ask-sibilla) β β
β β βββββββ βββββββ β β
β ββββββββββββ βββββββββββββββββ ββββββββββββ¬ββββββββββββ β
β β β
β β HTTPS β
β β β
β ββββββββββββΌββββββββββββ β
β β β β
β β Sibilla Server β β
β β /api/v1/query β β
β β β β
β ββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
```
### Componenti
| Componente | Ruolo | Hosting | Costo |
|-----------|-------|---------|-------|
| **Alexa Device** | Input/output vocale | Casa dell'utente | Hardware |
| **Alexa Cloud** | Speech-to-text, routing, TTS | Amazon (gratuito) | $0 |
| **AWS Lambda** | Logica della skill (bridge) | AWS | Gratuito (1M richieste/mese) |
| **Sibilla Server** | Ricerca web + sintesi AI | Tuo server / VPS | ~β¬5-10/mese (VPS) |
### PerchΓ© AWS Lambda?
1. **Gratuito** β 1 milione di richieste/mese nel free tier, piΓΉ che sufficiente
2. **Nativamente integrato con Alexa** β l'ASK SDK Γ¨ pensato per Lambda
3. **Nessun server da gestire** β solo codice Python
4. **ScalabilitΓ automatica** β se 100 persone chiamano Sibilla contemporaneamente, Lambda scala da solo
### β οΈ CriticitΓ : Il Problema del Timeout
Alexa impone un **limite invalicabile di 8 secondi** tra la richiesta e la risposta. Se la Lambda non risponde entro 8s, la connessione viene troncata e l'utente sente: "Mi dispiace, la skill non risponde."
La pipeline Sibilla attuale puΓ² facilmente superare questo limite:
```
Query Expansion (LLM) ~1-2s
Web Search (Degoog/DDG) ~1-2s
Fetch contenuti pagine ~2-4s β il collo di bottiglia!
Sintesi LLM (Gemini) ~2-4s
βββββββββββββββββββββββββββββββββ
TOTALE ~6-12s β spesso oltre gli 8s!
```
### π« PerchΓ© NON si puΓ² fare async ("fire and forget")
L'idea di "lancio la richiesta, chiudo, e quando Sibilla risponde chiamo Alexa" **NON funziona** con le skill Alexa. Il modello Γ¨ **esclusivamente request-response sincrono**. Non esiste un meccanismo per cui un server esterno "spinge" una risposta vocale ad Alexa mentre l'utente ascolta.
L'unica via "async" ufficiale sono le **Proactive Events API** (notifiche), ma:
- L'utente deve **abilitare le notifiche** manualmente nell'app Alexa
- La risposta arriva come **anello giallo** sul dispositivo, non come voce
- L'utente deve dire *"Alexa, cosa c'Γ¨ di nuovo?"* per sentirla
- Risultato: **3 turni** (domanda β attesa β notifica β "cosa c'Γ¨ di nuovo?" β risposta)
- Amazon **rifiuta la certificazione** se usi le notifiche come risposta a domande
**Conclusione:** L'unica strada Γ¨ **stare dentro gli 8 secondi**. Ecco come.
**Soluzione: Progressive Response (riempie il silenzio) + Fast Path (riduce i tempi)** (vedi sezione dedicata sotto).
---
## Flusso dei Dati
### Step-by-step di una richiesta
```
1οΈβ£ UTENTE PARLA
"Alexa, chiedi a Sibilla cosa sono i buchi neri"
2οΈβ£ ALEXA CLOUD β SPEECH-TO-TEXT
{
"intent": "AskSibillaIntent",
"slots": {
"query": { "value": "cosa sono i buchi neri" }
},
"locale": "it-IT"
}
3οΈβ£ ALEXA CLOUD β LAMBDA (JSON POST)
https://lambda.aws.amazon.com/ask-sibilla
4οΈβ£ LAMBDA β SIBILLA API
GET https://mioserver.com/api/v1/query?q=cosa+sono+i+buchi+neri
Risposta in ~3-5 secondi:
{
"query": "cosa sono i buchi neri",
"answer": "I **buchi neri** sono regioni dello spaziotempo...",
"speakable_text": "I buchi neri sono regioni dello spaziotempo...",
"sources": [
{"index": 1, "title": "Buco nero - Wikipedia", "url": "..."},
{"index": 2, "title": "Cosa sono i buchi neri - INAF", "url": "..."}
],
"model": "gemini-2.5-flash",
"tokens_used": 1200
}
5οΈβ£ LAMBDA β ALEXA CLOUD (JSON Response)
{
"version": "1.0",
"response": {
"outputSpeech": {
"type": "SSML",
"ssml": "I buchi neri sono regioni dello spaziotempo con una gravità così intensa che nulla, nemmeno la luce, può sfuggire. Ho trovato 2 fonti principali su Wikipedia e INAF."
},
"shouldEndSession": true
}
}
6οΈβ£ ALEXA CLOUD β TEXT-TO-SPEECH
Alexa dice (in italiano, voce naturale):
"I buchi neri sono regioni dello spaziotempo con una gravitΓ
così intensa che nulla, nemmeno la luce, può sfuggire."
```
### Gestione degli errori
```
Se Sibilla non risponde entro 5 secondi:
Alexa dice: "Mi dispiace, Sibilla non Γ¨ raggiungibile in questo momento.
Riprova piΓΉ tardi."
Se tutti i motori di ricerca sono down (HTTP 502):
Alexa dice: "Non riesco a cercare sul web in questo momento.
Controlla che i motori di ricerca siano attivi."
Se la query Γ¨ vuota:
Alexa dice: "Cosa vuoi chiedere a Sibilla?"
(riapre la sessione per riprovare)
```
---
## Requisiti
### Account e strumenti gratuiti
| Requisito | Come ottenerlo | Costo |
|-----------|---------------|-------|
| **Amazon Developer Account** | [developer.amazon.com](https://developer.amazon.com) | Gratuito |
| **AWS Account** | [aws.amazon.com](https://aws.amazon.com) | Gratuito (free tier) |
| **ASK CLI** | `npm install -g ask-cli` | Gratuito |
| **Python 3.10+** | GiΓ installato | Gratuito |
| **Sibilla Server** | GiΓ avviato su VPS/home server | Esistente |
### Dipendenze Python per la Lambda
```
ask-sdk-core # Alexa Skills Kit SDK (handler, intent, slot)
requests # Per chiamare l'API Sibilla (o urllib3 built-in)
boto3 # AWS SDK (se serve logging/DynamoDB)
```
File `requirements.txt` della Lambda:
```
ask-sdk-core>=1.0
```
> **Nota:** `requests` puΓ² essere evitato usando `urllib.request` (built-in). Meno dipendenze = Lambda piΓΉ leggera.
### Configurazione Sibilla Server
Il server Sibilla deve essere:
- **Raggiungibile da internet** (IP pubblico o dominio con HTTPS)
- **Connessione stabile** (la Lambda ha timeout 8 secondi)
- **HTTPS consigliato** (anche se tecnicamente Lambda puΓ² chiamare HTTP)
---
## Interaction Model
L'Interaction Model definisce **cosa** l'utente puΓ² dire e **come** Alexa lo interpreta. Si configura in un file JSON.
### Intents
Un **Intent** Γ¨ un'azione che l'utente vuole compiere.
#### 1. `AskSibillaIntent` β Principale
L'utente fa una domanda a Sibilla. Supporta sia domanda libera (`query`) che un topic opzionale (`topic`).
**Utterances (frasi di esempio):**
```
chiedi a Sibilla {query}
domanda a Sibilla {query}
cerca con Sibilla {query}
interroga l'oracolo {query}
cosa dice Sibilla su {query}
sibilla cosa sai di {query}
sibilla parlami di {query}
sibilla {query}
```
**Slots:**
| Slot | Tipo | Obbligatorio | Descrizione |
|------|------|:---:|-------------|
| `query` | `AMAZON.SearchQuery` | β
| La domanda completa dell'utente |
`AMAZON.SearchQuery` Γ¨ uno slot type built-in di Amazon che cattura frasi intere β perfetto per domande libere.
#### 2. `AMAZON.HelpIntent` β Built-in
Attivato quando l'utente chiede aiuto:
```
aiuto
cosa puoi fare
come funzioni
```
**Risposta suggerita:**
> "Sono Sibilla, l'oracolo AI. Puoi chiedermi qualsiasi cosa e io cercherΓ² nel web per darti una risposta. Prova a dirmi 'chiedi a Sibilla qual Γ¨ l'ultimo film sull'Odissea' o semplicemente 'Sibilla, cosa sono i raggi cosmici?'."
#### 3. `AMAZON.StopIntent` / `AMAZON.CancelIntent` β Built-in
```
stop
basta
esci
cancella
```
**Risposta suggerita:**
> "Va bene, alla prossima consultazione!"
#### 4. `AMAZON.FallbackIntent` β Built-in
Quando Alexa non capisce cosa l'utente vuole (nessun intent match).
**Risposta suggerita:**
> "Non ho capito. Puoi ripetere la domanda per Sibilla?"
### Skill Manifest (`skill.json`)
```json
{
"manifest": {
"publishingInformation": {
"locales": {
"it-IT": {
"name": "Sibilla β L'Oracolo AI",
"summary": "Interroga Sibilla, l'oracolo AI che cerca nel web e risponde alle tue domande.",
"description": "Sibilla Γ¨ un assistente AI che cerca nel web in tempo reale...",
"examplePhrases": [
"Alexa, chiedi a Sibilla qual Γ¨ l'ultimo film sull'Odissea",
"Alexa, domanda a Sibilla cosa sono i buchi neri",
"Alexa, sibilla parlami delle piramidi"
],
"keywords": ["ricerca", "intelligenza artificiale", "web", "oracolo"]
}
}
},
"apis": {
"custom": {
"endpoint": {
"uri": "arn:aws:lambda:eu-west-1:123456789:function:ask-sibilla"
},
"interfaces": []
}
},
"permissions": []
}
}
```
---
## β‘ Fast Path + Progressive Response β La Soluzione Completa
Due tecniche che insieme risolvono il problema: **Progressive Response** (riempie il silenzio) e **Fast Path** (riduce i tempi sotto gli 8s).
### Progressive Response: riempire il silenzio
Mentre la Lambda aspetta la risposta da Sibilla, l'utente sentirebbe **silenzio**. Con le Progressive Responses, la Lambda puΓ² dire ad Alexa di iniziare subito a parlare:
```
0.0s Lambda riceve la richiesta
0.2s Lambda invia Progressive Response β Alexa dice: "Sto cercando..." π
ββ L'utente sente subito qualcosa, l'attesa Γ¨ tollerabile
0.3s Lambda chiama Sibilla FAST PATH
4.0s Sibilla risponde
4.2s Lambda restituisce risposta finale β Alexa dice la risposta π
```
Richiede il permesso `alexa::async_event:send_progressive_response` nel manifest.
### Fast Path: endpoint ottimizzato su Sibilla
Per rispettare il limite degli 8 secondi, serve un **endpoint ottimizzato** che salti i passaggi piΓΉ lenti della pipeline:
### Cosa va aggiunto a Sibilla: `GET /api/v1/voice-query`
```
Pipeline FAST (vocale):
1. Web Search (Degoog/DDG) ~1-2s
2. Sintesi LLM solo su snippet ~2-3s β NO fetch pagine complete!
βββββββββββββββββββββββββββββββββββββ
TOTALE ~3-5s β
dentro gli 8s!
Pipeline STANDARD (web):
1. Query Expansion (LLM) ~1-2s
2. Web Search (Degoog/DDG) ~1-2s
3. Fetch contenuti pagine ~2-4s β collo di bottiglia
4. Sintesi LLM su contenuti ~2-4s
βββββββββββββββββββββββββββββββββββββ
TOTALE ~6-12s β troppo lento per voce
```
**Differenza chiave:** l'endpoint vocale usa solo gli **snippet** (i riassunti forniti dal motore di ricerca) invece di scaricare le pagine web complete. Perde un po' di profonditΓ ma guadagna velocitΓ .
### Prompt TTS-optimized
```python
VOICE_SYSTEM_PROMPT = """\
Sei Sibilla, un assistente vocale AI. Rispondi a voce in modo discorsivo e naturale,
come se stessi parlando con una persona. Regole fondamentali:
- Usa frasi brevi e chiare (max 3 frasi per concetto)
- NON usare elenchi puntati, tabelle, URL, markdown, asterischi
- NON nominare le fonti nel testo ("secondo Wikipedia...") β le fonti sono gestite a parte
- Se ci sono date, numeri o nomi propri, pronunciali in italiano
- Risposte entro 400-500 caratteri; se l'argomento Γ¨ complesso, fai un riassunto
"""
```
---
## Lambda Function Design
### Struttura del codice
```
lambda/
βββ lambda_function.py # Entry point (handler principale)
βββ sibilla_client.py # Client HTTP per chiamare l'API Sibilla
βββ speech_builder.py # Costruzione risposte SSML
βββ requirements.txt # ask-sdk-core
βββ .env # (opzionale) SIBILLA_API_URL
```
### lambda_function.py β Schema
```python
# Pseudo-codice della struttura
from ask_sdk_core.skill_builder import SkillBuilder
from ask_sdk_core.handler_input import HandlerInput
from ask_sdk_core.dispatch_components import AbstractRequestHandler
from ask_sdk_core.utils import get_slot_value
from ask_sdk_model import Response
from ask_sdk_model.ui import SsmlOutputSpeech
import ask_sdk_core.utils as ask_utils
# ββ Costanti ββββββββββββββββββββββββββββββββββββββββββββ
SIBILLA_URL = "https://tuo-server.com/api/v1/voice-query" # endpoint FAST
TIMEOUT = 5 # secondi (max Alexa: 8s, teniamo margine)
FALLBACK_LONG_ANSWER = 500 # caratteri
# ββ Handlers βββββββββββββββββββββββββββββββββββββββββββ
class AskSibillaIntentHandler(AbstractRequestHandler):
def can_handle(self, handler_input):
return ask_utils.is_intent_name("AskSibillaIntent")(handler_input)
def handle(self, handler_input):
# 1. Estrai la query
query = get_slot_value(handler_input, "query")
if not query:
return speak(handler_input, "Cosa vuoi chiedere a Sibilla?", keep_open=True)
# 2. Invia SUBITO un "thinking sound" (Progressive Response)
# così l'utente non sente il silenzio durante l'attesa
send_progressive_response(handler_input, "Sto cercando...")
# 3. Chiama l'endpoint vocale FAST di Sibilla
try:
result = call_sibilla_voice(query)
except TimeoutError:
return speak(handler_input,
"Mi dispiace, la ricerca sta impiegando troppo tempo. "
"Prova con una domanda piΓΉ specifica.")
except ConnectionError:
return speak(handler_input,
"Sibilla non Γ¨ raggiungibile in questo momento. "
"Controlla che il server sia acceso e riprova.")
# 4. Prendi il testo parlato
speakable = result["speakable_text"]
# 5. Se troppo lungo, tronca con garbo
if len(speakable) > FALLBACK_LONG_ANSWER:
speakable = speakable[:FALLBACK_LONG_ANSWER] + "."
speakable += " La risposta completa Γ¨ molto lunga. Puoi chiedermi di approfondire."
# 6. Aggiungi nota sulle fonti (solo numero, niente URL)
if result.get("sources"):
n = len(result["sources"])
fonti_principali = ", ".join(
s["title"].split(" - ")[0]
for s in result["sources"][:2]
)
speakable += (
f" "
f"Ho consultato {n} fonti, tra cui {fonti_principali}."
)
# 7. Restituisci risposta SSML
return speak(handler_input, speakable)
# Registra tutti gli handler
sb = SkillBuilder()
sb.add_request_handler(AskSibillaIntentHandler())
sb.add_request_handler(HelpIntentHandler())
sb.add_request_handler(CancelOrStopIntentHandler())
sb.add_request_handler(FallbackIntentHandler())
lambda_handler = sb.lambda_handler()
```
### sibilla_client.py β Schema
```python
import json
import urllib.request
import urllib.parse
import ssl
from typing import Optional
SIBILLA_URL = "https://tuo-server.com/api/v1/query"
TIMEOUT = 6
def call_sibilla_voice(query: str) -> dict:
"""Chiama l'endpoint FAST di Sibilla per uso vocale."""
params = urllib.parse.urlencode({"q": query})
url = f"{SIBILLA_URL}?{params}"
req = urllib.request.Request(url, method="GET")
# API Key per sicurezza (obbligatoria in produzione!)
req.add_header("Authorization", f"Bearer {SIBILLA_API_KEY}")
ctx = ssl.create_default_context()
with urllib.request.urlopen(req, timeout=TIMEOUT, context=ctx) as resp:
data = json.loads(resp.read().decode())
return data
def send_progressive_response(handler_input, text: str):
"""Invia un messaggio vocale immediato mentre la ricerca Γ¨ in corso.
Questa Γ¨ una Progressive Response β Alexa la riproduce subito,
prima ancora che la Lambda abbia finito. Essenziale per non far
sentire il silenzio all'utente durante l'attesa.
Richiede il permesso 'alexa::async_event:send_progressive_response'
nel manifest della skill.
"""
import ask_sdk_model_interfaces as ifaces
request_envelope = handler_input.request_envelope
directive = ifaces.connections.SendRequestDirective(
name="ProgressiveResponse",
payload={
"speech": f"{text}"
},
token=request_envelope.request.request_id,
)
# Nota: la directive va inviata tramite l'API Alexa, non come
# risposta diretta. Richiede una chiamata HTTP separata usando
# l'API endpoint dal contesto della richiesta.
```
### speech_builder.py β Schema
```python
from ask_sdk_model.ui import SsmlOutputSpeech
from ask_sdk_model import Response
from ask_sdk_core.handler_input import HandlerInput
def speak(handler_input: HandlerInput, text: str, keep_open: bool = False) -> Response:
"""Costruisce una risposta Alexa con SSML."""
ssml = f"{escape_ssml(text)}"
return (
handler_input.response_builder
.speak(ssml)
.set_should_end_session(not keep_open)
.response
)
def escape_ssml(text: str) -> str:
"""Escapa caratteri speciali per SSML."""
return (
text.replace("&", "&")
.replace("<", "<")
.replace(">", ">")
.replace('"', """)
.replace("'", "'")
)
```
---
## SSML e Voce Italiana
### PerchΓ© SSML?
SSML (Speech Synthesis Markup Language) permette di controllare **come** Alexa parla:
- Pause naturali tra frasi
- Enfasi su parole importanti
- Pronuncia corretta di termini tecnici o stranieri
### Tag SSML utili per Sibilla
```xml
I buchi neri sono regioni dello spaziotempo
con una gravità così intensa che nulla, nemmeno la luce, può sfuggire.
Attenzione: questa Γ¨ una teoria scientifica.
Il modello Gemini 2.5 Flash ha analizzato le fonti.
Ho consultato 3 fonti.
```
### Strategia per Sibilla
1. **`speakable_text` Γ¨ giΓ pulito** β niente markdown, URL, grassetti. Solo testo naturale.
2. **Aggiungere pausa prima delle fonti** β `` prima di "Ho consultato X fonti."
3. **Risposte troppo lunghe** β troncare a ~500 caratteri e suggerire di approfondire
4. **Numeri e date** β giΓ in formato parlato dal LLM
### Voce italiana
Alexa supporta nativamente l'italiano con voci naturali (Carla, Giorgio, Bianca). La skill verrΓ configurata con `locale: it-IT`.
---
## Sicurezza
### Comunicazione Lambda β Sibilla
| Area | Rischio | Mitigazione |
|------|---------|-------------|
| **Esposizione API** | Chiunque puΓ² chiamare `/api/v1/query` | API key condivisa (header `Authorization: Bearer `) |
| **HTTPS** | Dati in chiaro tra Lambda e Sibilla | Obbligatorio in produzione (Let's Encrypt gratuito) |
| **DDoS** | Troppe richieste crashano il server | Rate limiting su Sibilla (Flask-Limiter) |
| **Timeout** | Sibilla impiega >8s a rispondere | Timeout Lambda a 7s, graceful degradation |
| **Injection** | Input malevolo nella query | Sanitizzazione giΓ in Sibilla + strip su Lambda |
### API Key su Sibilla (da aggiungere)
```python
# In app.py β middleware di autenticazione API
@app.before_request
def require_api_key():
if request.path.startswith("/api/v1/"):
api_key = request.headers.get("Authorization", "").replace("Bearer ", "")
if api_key != os.environ.get("SIBILLA_API_KEY", ""):
return jsonify({"error": "Unauthorized"}), 401
```
Poi la Lambda passerΓ l'API key nell'header.
---
## Costi
### Stima mensile (uso personale / familiare)
| Servizio | Uso stimato | Costo |
|----------|-------------|-------|
| **Alexa Cloud** (speech-to-text, TTS) | Gratuito | $0 |
| **AWS Lambda** | ~1,000 chiamate/mese | $0 (free tier: 1M) |
| **Sibilla Server** (VPS 2GB) | Hetzner / DigitalOcean | ~β¬5-10/mese |
| **Gemini API** (2.5 Flash) | ~1,000 query/mese | $0 (free tier ampio) |
| **TOTALE** | | **~β¬5-10/mese** (solo VPS) |
> Se il server Sibilla Γ¨ giΓ in esecuzione (come ora), il costo aggiuntivo per la skill Alexa Γ¨ **$0**.
---
## Piano di Implementazione
### Fase 1 β Prototipo locale (1-2 ore)
- [ ] Installare ASK CLI: `npm install -g ask-cli`
- [ ] Configurare credenziali AWS: `ask configure`
- [ ] Creare skill da template: `ask new --skill-name sibilla-skill`
- [ ] Definire interaction model (intent + utterances) nel developer console
- [ ] Scrivere `lambda_function.py` con handler minimale (solo `AskSibillaIntent`)
- [ ] Scrivere `sibilla_client.py` che chiama `localhost:5000` (per test)
- [ ] Testare con `ask dialog` (simulatore testuale)
### Fase 2 β Deploy su AWS (1 ora)
- [ ] Modificare `sibilla_client.py` per puntare al server pubblico
- [ ] Caricare Lambda con `ask deploy`
- [ ] Testare su dispositivo Echo reale: "Alexa, chiedi a Sibilla..."
### Fase 3 β Raffinamento (1-2 ore)
- [ ] Aggiungere gestione timeout e retry
- [ ] Aggiungere SSML con pause naturali
- [ ] Gestire risposte troppo lunghe
- [ ] Aggiungere intent di follow-up ("approfondisci", "fonti")
- [ ] Aggiungere API key su Sibilla per sicurezza
### Fase 4 β Pubblicazione (opzionale, 2-4 ore)
- [ ] Tradurre descrizione e keywords per lo store Alexa
- [ ] Creare icone (108x108 e 512x512)
- [ ] Scrivere privacy policy (richiesta per la pubblicazione)
- [ ] Sottoporre per certificazione Amazon
---
## Rischi e Mitigazioni
| Rischio | ProbabilitΓ | Impatto | Mitigazione |
|--------|:---:|:---:|-------------|
| **Timeout Alexa (8s invalicabile)** β pipeline standard ~6-12s | **Alta** | **Critico** | Fast Path vocale (salta fetch pagine), Progressive Responses, timeout Lambda a 5s |
| **Sibilla server down** | Bassa | Alto | Health check, messaggio vocale di cortesia, retry |
| **Gemini API rate limit** | Bassa | Medio | Caching risposte frequenti, query expansion giΓ limita |
| **Risposte non adatte al TTS** (troppo tecniche) | Media | Medio | `speakable_text` giΓ pulito; prompt di sistema puΓ² enfatizzare risposte discorsive |
| **Skill non certificata da Amazon** | Media | Basso | Solo uso personale (beta testing), la certificazione Γ¨ opzionale |
| **VPS non raggiungibile da Lambda** | Bassa | Alto | Dominio pubblico, HTTPS, IP statico o DDNS |
---
## Differenze dalla Web UI
| Aspetto | Web UI (`/`) | Skill Alexa |
|---------|-------------|-------------|
| **Input** | Testo scritto (textarea) | Voce β testo (Alexa) |
| **Output** | HTML con markdown renderizzato, fonti cliccabili | Solo voce (TTS), niente fonti visibili |
| **Lunghezza risposta** | Illimitata | ~500 caratteri parlati (poi "chiedimi di approfondire") |
| **Fonti** | Link cliccabili, snippet | "Ho consultato 3 fonti: Wikipedia, INAF..." |
| **Conversazione** | Singola domanda | Potenziale multi-turno (follow-up) |
| **Latenza percepita** | Spinner visivo | Silenzio β attesa snervante β serve thinking sound |
| **Errori** | Messaggio a schermo | Messaggio vocale + suggerimento di riprovare |
### Cosa aggiungere al prompt di sistema per la skill vocale?
Attualmente Sibilla usa prompt generici. Per la skill Alexa, potremmo aggiungere un **prompt TTS-optimized**:
```
Sei Sibilla, un assistente vocale AI. Rispondi in modo discorsivo e naturale,
come se stessi parlando con una persona. Usa frasi brevi e chiare.
Evita elenchi puntati, tabelle, URL, e gergo eccessivamente tecnico.
Se la risposta Γ¨ molto lunga, dai prima un riassunto di 2-3 frasi,
poi offri di approfondire.
```
Questo prompt verrebbe passato via header o parametro all'API, oppure si puΓ² creare un endpoint dedicato `/api/v1/voice-query`.
---
## Riferimenti
### Documentazione Ufficiale
- [Alexa Skills Kit SDK for Python](https://developer.amazon.com/en-US/docs/alexa/alexa-skills-kit-sdk-for-python/overview.html)
- [ASK CLI Command Reference](https://developer.amazon.com/en-US/docs/alexa/smapi/ask-cli-command-reference.html)
- [SSML Reference](https://developer.amazon.com/en-US/docs/alexa/custom-skills/speech-synthesis-markup-language-ssml-reference.html)
- [Skill Manifest Schema](https://developer.amazon.com/en-US/docs/alexa/smapi/skill-manifest.html)
- [Request/Response JSON Format](https://developer.amazon.com/en-US/docs/alexa/custom-skills/request-and-response-json-reference.html)
### Tutorial Consigliati
- [Develop Your First Skill (Python)](https://developer.amazon.com/en-US/docs/alexa/alexa-skills-kit-sdk-for-python/develop-your-first-skill.html)
- [Build an Alexa Skill with AWS Lambda](https://developer.amazon.com/en-US/docs/alexa/custom-skills/host-a-custom-skill-as-an-aws-lambda-function.html)
---
## Domande Aperte per la prossima fase
1. **Sibilla sarΓ self-hosted su VPS o su rete domestica?** Se domestica, serve IP pubblico/DDNS.
2. **Vuoi pubblicare la skill sullo store Alexa o solo uso personale?** Cambia i requisiti di privacy e certificazione.
3. **Serve supporto multi-turno?** Es: "Alexa, approfondisci le fonti" dopo la prima risposta.
4. **OK a creare l'endpoint fast-path `/api/v1/voice-query` su Sibilla?** Salta il fetch delle pagine e usa solo snippet + sintesi LLM veloce.
5. **Serve caching per domande frequenti?** Riduce latenza e costi Gemini.
6. **Quale authentication per la API?** L'API key via header `Authorization: Bearer ` Γ¨ la soluzione piΓΉ semplice per il caso d'uso Lambda β Sibilla.
## Prossimi Passi Concreti
### Su Sibilla (backend)
1. Aggiungere endpoint `GET /api/v1/voice-query` β fast path senza fetch pagine
2. Aggiungere prompt TTS-optimized per risposte vocali
3. Aggiungere autenticazione API key su `/api/v1/*`
### Sulla Skill Alexa (nuovo progetto)
1. `ask new` β creare il progetto skill da template Python
2. Configurare interaction model con `AskSibillaIntent` + `AMAZON.SearchQuery`
3. Scrivere `lambda_function.py` con handler, Progressive Response, chiamata a `/api/v1/voice-query`
4. Deploy con `ask deploy` e test su Echo Dot