Tutoriale
Come usare qwen-audio-3.0-tts-plus tramite l'API hiapi: sintesi vocale con curl e Python
qwen-audio-3.0-tts-plus è un modello di sintesi vocale accessibile tramite la coda di attività asincrona unificata della piattaforma hiapi — utilizza lo stesso endpoint POST /v1/tasks della generazione di immagini e video, non un'API audio separata. Invii il testo, ricevi immediatamente un taskId, poi esegui il polling o attendi un callback per ottenere l'URL del file audio scaricabile. Questa guida ti accompagna nella creazione di una richiesta funzionante in curl e Python (verificata end-to-end contro l'API live), per poi illustrare i pattern di produzione di cui hai davvero bisogno: callback vs. polling, retry idempotenti e le forme esatte degli errori da gestire.
Cosa costruirai
Uno script che invia il testo a qwen-audio-3.0-tts-plus, attende il completamento dell'attività e scarica l'audio generato — oltre a un riferimento dei parametri e a pattern di gestione degli errori per trasformare lo script in una vera integrazione.
Prerequisiti: una chiave API hiapi. Ottienila dalla dashboard hiapi — ogni richiesta seguente si autentica con Authorization: Bearer sk-<your-key>.
Esempio minimo funzionante
curl
Crea l'attività:
curl -s -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer $HIAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "qwen-audio-3.0-tts-plus",
"input": {
"text": "Welcome to hiapi, the unified API for AI models.",
"voice": "longanlingxin"
}
}'
{"code": 200, "data": {"taskId": "tk-hiapi-01KZ59B7ZJ7012PXB5J9GE1QE7"}, "message": "success"}
Poi esegui il polling di GET /v1/tasks/<taskId> con lo stesso bearer token finché data.status non esce da "processing". Per questo modello, nei test sono serviti circa 5 secondi:
curl -s https://api.hiapi.ai/v1/tasks/tk-hiapi-01KZ59B7ZJ7012PXB5J9GE1QE7 \
-H "Authorization: Bearer $HIAPI_KEY"
{
"code": 200,
"data": {
"taskId": "tk-hiapi-01KZ59B7ZJ7012PXB5J9GE1QE7",
"status": "success",
"model": "qwen-audio-3.0-tts-plus",
"storage": "temp",
"created": 1785810231,
"completed": 1785810236,
"output": [{"type": "audio", "url": "https://temp.hiapi.ai/.../01KZ59B7ZJ7012PXB5J9GE1QE7-0.mp3", "artifactId": "66654", "expireAt": 1786415036}]
},
"message": "success"
}
output[0].url è un MP3 realmente scaricabile (content-type: audio/mpeg — confermato con un download diretto). È un link temporaneo: quando storage resta al valore predefinito "temp", expireAt cade quasi esattamente 7 giorni dopo created, quindi se devi conservare l'audio a lungo termine scarica i byte e archiviali tu stesso.
Python
import os
import time
import requests
API_BASE = "https://api.hiapi.ai/v1/tasks"
headers = {"Authorization": f"Bearer {os.environ['HIAPI_KEY']}"}
resp = requests.post(
API_BASE,
headers={**headers, "Content-Type": "application/json"},
json={
"model": "qwen-audio-3.0-tts-plus",
"input": {
"text": "Welcome to hiapi, the unified API for AI models.",
"voice": "longanlingxin",
},
},
timeout=30,
)
resp.raise_for_status()
task_id = resp.json()["data"]["taskId"]
while True:
task = requests.get(f"{API_BASE}/{task_id}", headers=headers, timeout=30).json()["data"]
if task["status"] == "success":
audio_url = task["output"][0]["url"]
break
if task["status"] == "fail":
raise RuntimeError(task["error"])
time.sleep(2)
audio_bytes = requests.get(audio_url, timeout=60).content
with open("output.mp3", "wb") as f:
f.write(audio_bytes)
Pattern per l'uso in produzione
Schema completo dell'input
L'oggetto input accetta solo i seguenti campi — l'API rifiuta con 400 qualsiasi altro campo, quindi non riutilizzare nomi di parametri presi da altri fornitori TTS:
| Campo | Obbligatorio | Tipo / valori |
|---|---|---|
text |
Sì | stringa |
voice |
Sì | uno tra "longanlingxin", "longanlufeng" (attualmente questo modello ha solo due voci disponibili) |
format |
No | uno tra "pcm", "wav", "mp3", "opus" — se omesso, il valore predefinito è mp3 |
sample_rate |
No | uno tra 8000, 16000, 22050, 24000, 44100, 48000 |
pitch |
No | numero, 0.5–2 |
volume |
No | numero, 0–100 |
Ogni limite ed enumerazione riportati sopra deriva dagli errori di validazione dell'API stessa — se passi un voice non valido o un pitch fuori intervallo, hiapi ti indica esattamente i valori ammessi:
{"code": 400, "data": null, "error_code": "INVALID_REQUEST", "message": "invalid input: voice: value must be one of 'longanlingxin', 'longanlufeng'"}
Questo modello non ha campi di controllo come emotion, speed o in stile SSML — le richieste che li includono falliscono con "additional properties '...' not allowed".
Callback vs. polling
Per qualsiasi scenario che va oltre un semplice script, evita il polling e lascia che hiapi invii il risultato. Aggiungi un oggetto callback alla richiesta di creazione dell'attività:
{
"model": "qwen-audio-3.0-tts-plus",
"callback": {"url": "https://example.com/hiapi/callback", "when": "final"},
"input": {"text": "Welcome to hiapi.", "voice": "longanlingxin"}
}
"final" è attualmente l'unico valore supportato per when — hiapi esegue un POST verso il tuo callback.url una sola volta, sia che l'attività riesca sia che fallisca, e dal payload leggi la stessa forma dei dettagli dell'attività che ottieni con il polling di GET /v1/tasks/<taskId>. Ometti del tutto callback e gestisci il polling da solo, come nell'esempio precedente.
Vale anche la pena sapere: l'output delle attività è per impostazione predefinita storage: "temp" (i file durano circa una settimana, come mostrato dal valore expireAt sopra). Se hai bisogno che l'audio resti recuperabile a lungo, imposta "storage": "persistent" sull'attività — l'archiviazione persistente viene fatturata in base alle dimensioni, quindi per generazioni una tantum di solito è più economico scaricare e archiviare da soli.
Idempotenza e retry
POST /v1/tasks accetta l'header Idempotency-Key (massimo 255 byte). Ripetere la stessa richiesta con la stessa chiave sotto lo stesso account crea l'attività una sola volta — il replay restituisce il taskId originale, non una seconda generazione fatturata. Usalo per ritentare dopo un timeout o un 5xx, quando non sai con certezza se la prima richiesta è arrivata:
curl -s -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer $HIAPI_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: tts-job-42" \
-d '{"model": "qwen-audio-3.0-tts-plus", "input": {"text": "...", "voice": "longanlingxin"}}'
Gestione degli errori
Una chiave non valida o non autorizzata restituisce HTTP 401 con la busta di errore standard di hiapi (verificata direttamente su questo modello):
{"error": {"code": "permission_denied", "message": "This API key cannot use the selected model...", "request_id": "...", "type": "hiapi_error"}}
Un payload input errato restituisce HTTP 400 con error_code: "INVALID_REQUEST" e un message che indica il campo non valido, come mostrato nella sezione schema sopra — gestisci il flusso in base a error_code / error.code, non al testo del messaggio leggibile. Se l'attività raggiunge lo stato terminale "fail" invece di fallire alla creazione, la risposta con i dettagli dell'attività riporta la stessa forma sotto data.error (code + message), non nella chiave error di primo livello.
Letture correlate
- Dashboard hiapi — crea e gestisci le chiavi API.
- Documentazione sulla creazione di attività — il contratto completo di
POST /v1/tasks, inclusi header, callback e idempotenza. - Documentazione sui dettagli dell'attività — l'endpoint di polling usato sopra.
- Documentazione sull'autenticazione hiapi — come funzionano l'header
Authorizatione gli scope delle chiavi su tutta la piattaforma. - Documentazione sui limiti di frequenza hiapi — comportamento
429eRetry-After. - Modelli audio su hiapi — esplora gli altri modelli vocali e audio della piattaforma.
- I prezzi attuali di questo modello sono nella pagina dei prezzi aggiornata in tempo reale e non vengono ripetuti qui.
Domande frequenti
La generazione audio è diversa dall'API delle attività immagini/video di hiapi?
No — stessa coda POST /v1/tasks, stesso flusso crea-poi-polling o callback, stessa forma output[0].url. Cambiano solo output[0].type (qui "audio") e lo schema input in base al modello.
Cosa succede se non imposto format?
Ottieni un MP3 — nei test l'omissione lo ha confermato. Se ti serve wav, pcm o opus, imposta format esplicitamente.
Posso ricevere l'audio in streaming invece di attendere il completamento dell'attività? No. Questo modello espone solo il flusso standard creazione/polling/callback — non ci sono parametri di streaming nel suo schema di input, e la generazione è abbastanza veloce (pochi secondi per testi brevi) che un polling ogni 1-2 secondi di solito è sufficiente.
Per quanto tempo rimane valido l'URL di output?
Circa 7 giorni per impostazione predefinita (storage: "temp"), in base all'intervallo tra i timestamp created ed expireAt dell'attività. Scarica l'audio per tempo, oppure imposta "storage": "persistent" sull'attività se hai bisogno di una recuperabilità più lunga.
Perché la mia richiesta fallisce con "additional properties ... not allowed"?
Lo schema è rigido — questo modello accetta solo text, voice, format, sample_rate, pitch e volume. I parametri di altre API TTS (come emotion o speed) non sono riconosciuti qui e restituiscono 400.
Dove trovo i prezzi attuali? Nella pagina dei prezzi — questo tutorial evita deliberatamente di codificare un costo per carattere o per richiesta, perché i prezzi possono cambiare.
Articoli correlati
Vedi tutti gli articoli →-
Tutoriale
Come chiamare hailuo-2.3-fast/image-to-video tramite l'API HiAPI: pratica con curl e Python
La prima richiesta funzionante per il livello image-to-video veloce ed economico — dall'ID del modello al download di un MP4
-
Tutoriale
Come chiamare hailuo-2.3/text-to-video tramite l'API HiAPI: curl, Python ed esempi di richiesta eseguibili
-
Tutoriale
Utilizzare Kandinsky 6.0 Pro su HiAPI per la generazione di video da testo: tutorial con curl e Python
Dimostrazione pratica guidata dalla richiesta: costruire la chiamata da prompt a clip video, inviare la richiesta, monitorare lo stato di completamento e scaricare il risultato