HiAPI
Blog

Tutoriale

Come chiamare gemini-3.1-flash-tts su HiAPI: curl, Python e una richiesta eseguibile

Oct 31, 2026
深靛蓝色背景上多层嵌套的宽箭头依次向右上方推进,箭头前缘为杏橙色,构成规整的信号流示意图形,这是文章的封面图。

Cosa può fare gemini-3.1-flash-tts per te su HiAPI

gemini-3.1-flash-tts è un modello di sintesi vocale (text-to-speech) fornito tramite l'API unificata di HiAPI. Invii il testo e la configurazione vocale, e la piattaforma restituisce l'audio generato. Poiché è esposto tramite un'interfaccia unica e coerente, non è necessario integrare ogni modello separatamente: gli stessi header di autenticazione, lo stesso URL di base e lo stesso modello di attività asincrona valgono per tutti i modelli TTS della piattaforma.

Puoi scegliere questo modello quando hai bisogno di:

  • Narrazione multi-speaker. Script, dialoghi o contenuti in stile podcast, in cui segmenti diversi devono suonare come voci diverse.
  • Tempi di risposta rapidi. La serie flash è pensata per la generazione a bassa latenza, particolarmente importante per applicazioni interattive o processi batch con SLA stringenti.
  • Un'interfaccia di integrazione prevedibile. Un'unica forma di richiesta copre tutti i casi, da una singola riga di testo agli scenari multi-speaker.

Se la tua applicazione chiama già altri modelli HiAPI, aggiungere la funzionalità vocale richiede solo di sostituire l'identificatore del modello e modificare il corpo della richiesta: nessun nuovo SDK, nessun nuovo flusso di credenziali.

Prerequisiti e configurazione dell'autenticazione

Prima della prima chiamata, assicurati di avere:

  1. Un account HiAPI e una chiave API. Genera la chiave dalla console. Trattala come un segreto: non salvarla nel controllo del codice sorgente.
  2. L'URL di base di HiAPI. Tutte le richieste vanno allo stesso host; solo il percorso di ciascun endpoint cambia.
  3. Uno strumento per effettuare richieste HTTP. curl per test rapidi, e Python 3.9+ con la libreria requests per gli script.

L'autenticazione avviene tramite un token bearer nell'header Authorization:

Authorization: Bearer $HIAPI_API_KEY

Salva la chiave in una variabile d'ambiente, non codificarla direttamente:

export HIAPI_API_KEY="your_key_here"

Ogni endpoint descritto di seguito — invio dell'attività, controllo dello stato e recupero del file — usa lo stesso header. Se ricevi 401, significa che l'header è mancante, malformato oppure che la chiave è stata revocata. Ruota la chiave dalla console invece di condividere la stessa tra ambienti diversi.

Costruire il corpo della richiesta per voci multi-speaker

Il corpo della richiesta è JSON. Come minimo deve contenere l'identificatore del modello e il contenuto di input. Per l'output multi-speaker, devi aggiungere una configurazione degli speaker che mappa gli speaker nominati alle voci, e contrassegnare il testo di input con i tag degli speaker.

Un corpo di richiesta tipico è il seguente:

{
  "model": "gemini-3.1-flash-tts",
  "input": {
    "text": "[Host] Welcome back to the show. [Guest] Thanks for having me.",
    "multi_speaker": true,
    "speakers": [
      { "name": "Host", "voice": "voice_a" },
      { "name": "Guest", "voice": "voice_b" }
    ]
  }
}

Punti chiave che causano errori:

  • I nomi degli speaker devono corrispondere esattamente. Il campo name nell'array speakers deve coincidere esattamente con il tag usato nel testo (in questo esempio, tra parentesi quadre). Un errore di maiuscole/minuscole è la causa più comune di errori nel rendering multi-speaker.
  • Ogni tag deve essere dichiarato. Se il testo fa riferimento a [Narrator] ma non viene definito uno speaker con name: "Narrator", la richiesta verrà rifiutata.
  • Gli identificatori vocali provengono dal catalogo voci della piattaforma. Usa gli identificatori forniti da HiAPI, non inventarli. Per le attività a singolo speaker, ometti multi_speaker e speakers e imposta invece un singolo campo voice.
  • Il testo viene inviato come singola stringa. Gli script lunghi non sono un problema, ma tieni presente i limiti per richiesta documentati sulla piattaforma.

Una volta superata la validazione, l'attività viene accettata e viene restituito un identificatore di attività, che userai per il polling.

Esecuzione con curl

Salva il corpo della richiesta sopra in payload.json, poi invialo:

curl -X POST "$HIAPI_BASE_URL/v1/audio/speech/jobs" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d @payload.json

La risposta contiene un oggetto attività con i campi id e status (di solito queued o processing):

{ "id": "job_abc123", "status": "queued" }

Per controllare l'avanzamento, recupera l'attività tramite l'ID:

curl "$HIAPI_BASE_URL/v1/audio/speech/jobs/job_abc123" \
  -H "Authorization: Bearer $HIAPI_API_KEY"

Quando status diventa succeeded, la risposta contiene un riferimento al file audio (URL o ID file), che puoi scaricare con una richiesta successiva — vedi la sezione sul polling più avanti. Se l'attività fallisce, status sarà failed e ci sarà un campo error che ne spiega il motivo.

Per esperimenti rapidi, puoi saltare il file e usare JSON inline:

curl -X POST "$HIAPI_BASE_URL/v1/audio/speech/jobs" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"gemini-3.1-flash-tts","input":{"text":"Hello from HiAPI.","voice":"voice_a"}}'

Esecuzione con Python

La versione Python usa requests e una piccola funzione di supporto per mantenere leggibile il ciclo di polling. Il corpo della richiesta è identico all'esempio curl.

import os
import time
import requests

API_KEY = os.environ["HIAPI_API_KEY"]
BASE_URL = os.environ["HIAPI_BASE_URL"]
HEADERS = {"Authorization": f"Bearer {API_KEY}"}

payload = {
    "model": "gemini-3.1-flash-tts",
    "input": {
        "text": "[Host] Welcome back to the show. [Guest] Thanks for having me.",
        "multi_speaker": True,
        "speakers": [
            {"name": "Host", "voice": "voice_a"},
            {"name": "Guest", "voice": "voice_b"},
        ],
    },
}

resp = requests.post(
    f"{BASE_URL}/v1/audio/speech/jobs",
    headers={**HEADERS, "Content-Type": "application/json"},
    json=payload,
    timeout=30,
)
resp.raise_for_status()
job = resp.json()
job_id = job["id"]
print("submitted", job_id)

while True:
    r = requests.get(f"{BASE_URL}/v1/audio/speech/jobs/{job_id}", headers=HEADERS, timeout=30)
    r.raise_for_status()
    status = r.json()
    if status["status"] in ("succeeded", "failed"):
        break
    time.sleep(2)

if status["status"] == "failed":
    raise RuntimeError(status.get("error"))

print("audio ready:", status["output"])

Note:

  • I timeout sono importanti. Imposta esplicitamente un timeout per ogni richiesta; un ciclo di polling bloccato è peggio di uno fallito.
  • Non fare polling troppo frequentemente. Un intervallo di due secondi va bene per script brevi; per script lunghi è meglio un backoff.
  • Metti il corpo della richiesta in una funzione. Nel codice reale, parametrizza testo, speaker e voce, così puoi riutilizzare la stessa logica di invio per attività a singolo speaker.

Polling delle attività asincrone e download dell'audio

La generazione vocale è asincrona: invii l'attività, poi controlli lo stato finché non raggiunge uno stato finale. Esistono due stati finali: succeeded e failed. Tutti gli altri stati vanno considerati come "continua ad attendere".

Un programma di polling robusto dovrebbe:

  1. Limitare il tempo totale di attesa. Anche un modello veloce può essere in coda dopo altro lavoro. Fermati dopo un limite ragionevole ed esponi l'ID dell'attività, così il chiamante può riprovare.
  2. Backoff esponenziale. Inizia da uno o due secondi e raddoppia progressivamente fino a un limite massimo. Questo evita di sovraccaricare l'API durante attività lunghe.
  3. Gestire esplicitamente gli errori. Quando status == "failed", leggi e registra il campo error: di solito indica un problema nel corpo della richiesta (speaker non dichiarato, testo vuoto, voce non supportata).

Quando l'attività ha successo, la risposta di stato contiene un riferimento all'output. Scaricalo con gli stessi header di autenticazione:

out = status["output"]
audio = requests.get(out["url"], headers=HEADERS, timeout=60)
audio.raise_for_status()
with open("narration.wav", "wb") as f:
    f.write(audio.content)

Se la risposta restituisce un ID file invece di un URL, recuperalo tramite l'endpoint file corrispondente su HiAPI. Conserva l'ID originale dell'attività insieme al file salvato: è l'unico modo affidabile per risalire in seguito a un rendering scadente e alla sua richiesta.

Capire la fatturazione per carattere

gemini-3.1-flash-tts su HiAPI viene fatturato in base al numero di caratteri del testo di input. Non ci sono componenti per richiesta o per minuto da modellare: il costo dell'attività scala con la quantità di testo inviata, il che rende la stima semplice: il numero totale di caratteri di tutti gli script moltiplicato per la tariffa corrente per carattere.

Implicazioni pratiche:

  • Stima prima di andare in produzione. Somma il volume di testo mensile previsto e confrontalo con la tariffa corrente mostrata nel pannello dei prezzi. Non codificare la tariffa nel codice; leggila dalla piattaforma in fase di build oppure salvala in configurazione.
  • I contenuti lunghi dominano i costi. Una narrazione di dieci minuti è principalmente un costo di testo. Se devi generare audiolibri o materiale didattico, modella prima i volumi.
  • I tentativi falliti generano costi. Le attività che falliscono dopo la generazione possono comunque essere fatturate, a seconda della modalità di errore. Valida lato client prima dell'invio: verifica che ogni tag speaker sia dichiarato e che il testo non sia vuoto.
  • Usa attivamente la cache. Se lo stesso script viene renderizzato ripetutamente (ad esempio in demo o fixture di test), salva l'audio generato e riutilizzalo, invece di addebitare ripetutamente gli stessi caratteri.

Per le tariffe correnti e eventuali livelli di volume, consulta il pannello dei prezzi sul sito: è l'unica fonte di verità.

Punti di errore comuni e come risolverli

La maggior parte dei problemi di integrazione rientra in poche categorie. Esaminale in ordine.

401 Non autorizzato

Il tuo header Authorization è mancante o malformato. Verifica che la chiave sia impostata nell'ambiente e che il contenuto dell'header sia esattamente Bearer <key>. Se la chiave è stata ruotata, aggiorna il tuo ambiente.

400 Bad Request — speaker sconosciuto

Il testo contiene un tag [Name] non dichiarato in speakers, oppure con maiuscole/minuscole diverse. Rendi tag e campo name identici byte per byte.

400 Bad Request — input vuoto o troppo grande

Un testo vuoto non supera immediatamente la validazione. Script molto lunghi possono superare il limite per richiesta; suddividili in più attività invece di troncarli.

400 Bad Request — identificatore vocale non valido

I nomi delle voci devono provenire dal catalogo della piattaforma. Copia esattamente gli identificatori; non inventare nomi descrittivi.

Attività bloccata in stato processing

Di solito si tratta di coda, non di un bug. Applica backoff e un timeout totale. Se persiste molto oltre il tempo normale, registra l'ID dell'attività e riprova una volta con un corpo di richiesta più piccolo, per capire se la dimensione è il problema.

Attività failed con errore di generazione

Leggi il campo error. Di solito indica un problema di contenuto o configurazione, non un guasto transitorio. Correggi il corpo della richiesta, invia di nuovo ed evita cicli di retry ciechi: ogni tentativo può essere fatturato per carattere.

L'audio si scarica ma non si riproduce

Prima di dare per scontato che il file sia danneggiato, controlla il content-type del file scaricato. Salvalo con l'estensione corretta corrispondente al formato restituito e verifica che la lunghezza in byte non sia zero. Un file troncato di solito significa che la richiesta di download è stata interrotta: riprova il download, non la generazione.

Con questi controlli, la maggior parte dei problemi di integrazione del primo giorno si risolve in pochi minuti invece che in ore.

Inizia a creare con artefatti IA persistenti

Ottieni la tua chiave API e chiama modelli di immagini, video e audio tramite un'unica API basata sui task.

Leggi la documentazione API