Inizia in 5 minuti
Dalla chiave al primo video parlante in sei comandi. Copiali, incollali, funzionano — non sono esempi decorativi.
# le due variabili di tutti gli esempi che seguono
export BASE=https://api.agiletav.agile.software # in locale: http://127.0.0.1:8000
export CHIAVE=atv_LA_TUA_CHIAVE
I sei comandi
-
Il servizio è vivo? —
GET /salute, senza chiaveÈ l'unica rotta aperta. Serve a sorvegliare il servizio, non a usarlo: dice quali motori sono pronti davvero e perché quelli che mancano mancano.
curl -s $BASE/salute{"stato":"ok","round":1, "codice":{"dichiarato":true,"sha":"2a04a8c06f23","ramo":"master", ...}, "motori":{"voce":{"pronto":true,"motore":"agiletts", ...}, "volto":{"pronto":true,"motore":"agilevolto-rapido2","round_attivo":2, ...}, "ascolto":{"pronto":true,"motore":"agileascolto", ...}, "cervello":{"pronto":true, ...}, "vista":{"pronto":true,"motore":"agilevista/leggero-opencv", ...}, "clona":{"pronto":false,"nota":"i sorgenti di OpenVoice non ci sono: esegui `AGILETAV_CLONA=1 make pesi` (a runtime non si scarica niente)"}, ...}, "api":{"contratto":"/v1 (POSTA §8.1)","documentazione":"/docs","guida":"/inizia", "chiavi":{"archivio_presente":true,"chiavi_attive":229, ...}}}Questo è il corpo vero, accorciato, di una risposta di questo servizio: un motore
pronto:falseporta sempre la suanota, e la nota dice che cosa fare.codicedice quale sha sta rispondendo, così una misura si può attribuire a una versione. -
La chiave funziona? —
GET /v1/chiaveLa prova più economica che c'è: nessun file, nessuna GPU. Ti dice anche quanta quota ti resta per oggi.
curl -s -H "X-API-Key: $CHIAVE" $BASE/v1/chiave{"chiave":"k_1a2b3c4d5e6f","sviluppatore":"ADP","quota_giorno":200, "usate_oggi":1,"residue_oggi":199,"azzeramento":"mezzanotte UTC", "voce_predefinita":"it_IT-serena-medium"}Senza intestazione, o con una chiave revocata, arriva 401 con scritto quale dei due casi è.
-
Carica la foto —
POST /v1/riferimentiUna foto frontale, meglio se il volto occupa buona parte dell'inquadratura. Formati:
png jpg jpeg webp bmp(e i videomp4 mov webm mkv, conservati ma non ancora usabili: l'identità da video è del round 2).RIF=$(curl -s -H "X-API-Key: $CHIAVE" \ -F file=@volto.png \ $BASE/v1/riferimenti | python3 -c 'import json,sys;print(json.load(sys.stdin)["id"])') echo "riferimento: $RIF"Dove finisce quella foto. Su questo disco, in una cartella della tua chiave, con permessi0600. Non viene inviata a nessun servizio esterno, non entra in nessun addestramento, non è visibile alle altre chiavi. La cancelli tu con il passo 6; se te ne dimentichi, sparisce da sola dopo 24 ore. -
Apri la sessione —
POST /v1/sessioniLa sessione lega la foto a una voce e a una lingua. Non consuma GPU: è un registro.
SES=$(curl -s -H "X-API-Key: $CHIAVE" -H 'Content-Type: application/json' \ -d "{\"persona\":\"Carla\",\"riferimento\":\"$RIF\",\"lingua\":\"it\"}" \ $BASE/v1/sessioni | python3 -c 'import json,sys;print(json.load(sys.stdin)["id"])') echo "sessione: $SES"voceè facoltativa: senza, si usa quella caricata dal servizio (la vedi inGET /v1/chiave). Al round 1 la lingua èit— e lo diciamo, invece di leggere l'italiano con una voce inglese. -
Falla parlare —
POST /v1/sessioni/{id}/parlaTesto dentro,
video/mp4fuori. Le misure viaggiano nelle intestazioniX-…, così il banco può cronometrare senza aprire il video.curl -s -D intestazioni.txt -o risposta.mp4 \ -H "X-API-Key: $CHIAVE" \ -F testo="Buongiorno, sono una persona digitale di AgileVolto." \ -F px=512 -F max_secondi=10 \ $BASE/v1/sessioni/$SES/parla grep -i '^x-' intestazioni.txtx-motore-voce: piper/it_IT-serena-medium x-motore-volto: agilevolto-r1 x-tempo-voce-ms: 612 x-tempo-volto-ms: 1804 x-tempo-totale-ms: 2510 x-secondi: 4.123 x-quota-residue: 197In alternativa al testo puoi mandare un audio già pronto con
-F audio=@domanda.wav: al round 1 quell'audio si usa così com'è — non c'è ascolto e non c'è cervello, quelli sono il round 3. -
Chiudi, e i file spariscono —
DELETE /v1/sessioni/{id}curl -s -X DELETE -H "X-API-Key: $CHIAVE" $BASE/v1/sessioni/$SES{"id":"s_1a2b3c4d5e6f","chiusa":true,"turni":1, "riferimenti_rimossi":1,"byte_liberati":184320, "spiegazione":"sessione chiusa e riferimenti cancellati dal disco"}Il numero di file rimossi è dichiarato, non promesso: se un riferimento resta in piedi perché un'altra sessione aperta lo sta usando, la risposta lo scrive in
riferimenti_trattenuticon il motivo.
Il flusso eventi (SSE)
Mentre la sessione lavora puoi restare in ascolto su
GET /v1/sessioni/{id}/eventi. Quattro tipi di evento, nessuno di più:
| evento | quando | dati utili |
|---|---|---|
pronto | la sessione è aperta e accetta /parla | persona, voce, lingua |
parla | un turno è cominciato | turno, caratteri, lingua, px |
fine | il turno è finito, o la sessione è stata chiusa | ms, byte, secondi — oppure motivo |
errore | quel turno è fallito | errore, spiegazione |
# -N disattiva il buffering di curl: senza, gli eventi si vedono tutti alla fine
curl -N -H "X-API-Key: $CHIAVE" "$BASE/v1/sessioni/$SES/eventi?da=0"
retry: 3000
: flusso eventi della sessione s_1a2b3c4d5e6f
id: 1
event: pronto
data: {"sessione":"s_1a2b3c4d5e6f","voce":"it_IT-serena-medium","lingua":"it", ...}
id: 2
event: parla
data: {"turno":1,"sorgente":"testo","caratteri":52,"lingua":"it","px":512, ...}
id: 3
event: fine
data: {"turno":1,"ms":2510,"byte":184320,"secondi":4.123, ...}
Chi si collega a metà riceve prima lo storico (fino a 200 eventi) e poi il seguito.
Per riprendere da dove si era rimasti: ?da=<ultimo id>, oppure
l'intestazione standard Last-Event-ID. Ogni 15 secondi passa un commento
: battito che tiene viva la connessione attraverso i proxy.
Quota, e cosa succede quando finisce
Ogni chiave ha un tetto di chiamate al giorno, che si azzera a mezzanotte UTC. Ogni risposta te lo ricorda:
X-Quota-Giorno: 200
X-Quota-Usate: 43
X-Quota-Residue: 157
Superato il tetto arriva 429 con Retry-After in
secondi. I rifiuti per quota non consumano quota: altrimenti il contatore
direbbe «1000 su 200» e non vorrebbe dire più niente.
Gli errori, e come si leggono
Ogni rifiuto ha la stessa forma: una errore stabile che puoi confrontare
nel codice, e una spiegazione in italiano che puoi leggere a occhio.
| codice | errore | che cosa è successo |
|---|---|---|
| 401 | chiave_mancante | non hai messo l'intestazione X-API-Key |
| 401 | chiave_sconosciuta | quella chiave non risulta in archivio |
| 401 | chiave_revocata | il portale l'ha revocata; non si riattiva |
| 401 | archivio_assente | il servizio non ha ancora un archivio di chiavi: /v1 è chiuso — è la posizione sicura, non un guasto |
| 404 | riferimento_sconosciuto | quell'id non è di questa chiave |
| 404 | sessione_sconosciuta | idem, per le sessioni |
| 409 | sessione_chiusa | hai già fatto DELETE: apri una sessione nuova |
| 410 | riferimento_scomparso | il file non è più su disco (scaduto o cancellato) |
| 422 | manca_la_domanda | né testo né audio |
| 422 | domanda_ambigua | tutti e due insieme |
| 422 | lingua_non_disponibile | al round 1 il motore parla solo italiano |
| 429 | quota_esaurita | tetto giornaliero raggiunto; vedi Retry-After |
| 503 | motore_voce_non_in_servizio | i pesi non ci sono: make pesi |
| 503 | catena_non_completa | un motore che serve a quella chiamata non è in servizio su questa macchina: la risposta porta motori_mancanti e perche, motore per motore |
/conversa e /vede rispondono: gli organi
ci sono tutti (GET /salute li elenca uno per uno, ed è lui la fonte,
non questa pagina). Quello che manca è altro, e sono tre cose precise.
La voce clonata: su questa macchina il motore clona non
è in servizio, quindi una sessione con clonazione: "obbligatoria" prende
503 catena_non_completa con
"motori_mancanti": ["clona"]; con "facoltativa" la sessione
si apre e parla con una voce di catalogo.
La vista col modello grande: dove il VLM non è in servizio risponde il
motore «leggero», che conta e dichiara invece di descrivere una scena — nel corpo c'è
motore, e dice quale dei due ha risposto.
Il ferro: i motori del volto stanno su un pod che si accende e si
spegne, e a pod spento le rotte che lo vogliono rispondono 503 dicendo
quale motore manca. Non è un guasto ed è voluto: una risposta finta costerebbe
più di un rifiuto onesto.
Dove continuare
- /docs — lo schema OpenAPI navigabile, generato dal codice: ogni campo, ogni codice di errore, e un Prova che esegue la chiamata dal browser con la tua chiave (il video compare lì dentro). Pagina nostra, senza CDN: si legge anche a rete chiusa.
- /openapi.json — lo schema, se preferisci generarti un client.
- /salute — lo stato reale, senza chiave.
- /sito/ — che cos'è AgileVolto, in 27 lingue.