Files
sibilla/docs/ALEXA_SKILL.md

29 KiB

🎙️ 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
  2. Architettura di Sistema
  3. Flusso dei Dati
  4. Requisiti
  5. Interaction Model
  6. Lambda Function Design
  7. SSML e Voce Italiana
  8. Sicurezza
  9. Costi
  10. Piano di Implementazione
  11. Rischi e Mitigazioni
  12. 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": "<speak>I buchi neri sono regioni dello spaziotempo con una gravità così intensa che nulla, nemmeno la luce, può sfuggire. <break time='500ms'/> Ho trovato 2 fonti principali su Wikipedia e INAF.</speak>"
       },
       "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 Gratuito
AWS Account 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)

{
  "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

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

# 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" <break time='500ms'/>"
                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

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"<speak>{text}</speak>"
        },
        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

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"<speak>{escape_ssml(text)}</speak>"
    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("&", "&amp;")
        .replace("<", "&lt;")
        .replace(">", "&gt;")
        .replace('"', "&quot;")
        .replace("'", "&apos;")
    )

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

<speak>
  <!-- Pausa naturale tra pensieri -->
  I buchi neri sono regioni dello spaziotempo 
  <break time="400ms"/>
  con una gravità così intensa che nulla, nemmeno la luce, può sfuggire.
  
  <!-- Enfasi su una parola -->
  <emphasis level="moderate">Attenzione</emphasis>: questa è una teoria scientifica.
  
  <!-- Pronuncia di parole straniere -->
  Il modello <lang xml:lang="en-US">Gemini 2.5 Flash</lang> ha analizzato le fonti.
  
  <!-- Pausa prima delle fonti -->
  <break time="600ms"/>
  Ho consultato 3 fonti.
</speak>

Strategia per Sibilla

  1. speakable_text è già pulito — niente markdown, URL, grassetti. Solo testo naturale.
  2. Aggiungere pausa prima delle fonti — <break time="500ms"/> 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 <token>)
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)

# 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

Tutorial Consigliati


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 <token> è 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