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
Cosa fa la richiesta kandinsky-6.0-pro/text-to-video
kandinsky-6.0-pro/text-to-video converte un prompt testuale in una breve clip video. Invii il prompt e alcuni parametri di generazione, e il modello produce un file video che puoi salvare e riprodurre. Questo è l'intero prodotto: input un prompt, output una clip video.
Il dettaglio architetturale chiave è che questa non è una chiamata sincrona. Non ottieni il video direttamente nel corpo della risposta alla prima richiesta. Invece, crei un job, l'API restituisce l'identificatore di quel job e il modello lavora in background. Il tuo codice deve controllare lo stato del job finché non riporta il completamento, momento in cui il risultato è disponibile per il download.
Questo pattern ha diverse conseguenze da progettare fin dall'inizio:
- Il client deve effettuare polling. Un singolo
POSTnon può restituire un video completato, quindi qualsiasi integrazione richiede un ciclo di polling dello stato o una ricontrollata simile a un webhook. - La richiesta dovrebbe essere idempotente dal tuo lato. Se lo script si blocca dopo l'invio, non vuoi creare silenziosamente un secondo job. Cattura l'identificatore del job e rendilo persistente.
- La latenza è variabile. La generazione video è più lenta delle chiamate a immagini o testo, quindi l'attesa è normale, non un difetto.
Il resto del tutorial segue questo ciclo di vita in ordine: preparazione, invio con curl, polling, download, poi ricostruzione dello stesso flusso in Python. Considera il codice come uno scheletro funzionante: i percorsi degli endpoint e i nomi dei campi vanno sempre verificati con la documentazione API del modello, perché questi dettagli cambiano con l'evoluzione della piattaforma.
Prima di inviare la prima richiesta
Servono quattro cose prima della prima chiamata.
1. Account HiAPI e chiave API
Autenticati con una chiave API emessa dal tuo account HiAPI. Tieni la chiave fuori dal controllo di versione e dalla cronologia della shell per quanto possibile. La pratica abituale è esportarla come variabile d'ambiente e lasciare che il codice la legga da lì:
export HIAPI_API_KEY="your-key-here"
Ogni richiesta seguente presume che la chiave sia inviata come bearer token nell'header Authorization. Se non hai ancora creato una chiave, fallo prima nella dashboard dell'account.
2. Client HTTP
curl basta per verificare che la richiesta funzioni. Per qualsiasi operazione da ripetere, usa Python 3 con la libreria requests: una sola dipendenza, codice leggibile e facile da inserire in uno scheduler o in un servizio in seguito:
python3 -m pip install requests
3. Dove salvare l'output
I file video sono molto più grandi delle risposte JSON. Decidi in anticipo se scrivere su una directory locale o fare streaming verso un object storage. In questo tutorial va bene una directory locale ./output:
mkdir -p output
4. Conosci il tuo prompt
Scrivi il prompt prima del codice. Un prompt specifico e descrittivo — soggetto, azione, comportamento della camera, stile visivo — ti fornisce una baseline da confrontare quando qualcosa va storto. Quando il prompt è una costante nominata nello script, anziché una stringa digitata al prompt della shell, cambiare una variabile alla volta è molto più semplice.
Questa è la lista completa dei prerequisiti. Nessun SDK da installare, nessun passaggio di build; la piattaforma è accessibile via normale HTTPS.
La richiesta curl funzionante
Il primo obiettivo è ottenere un comando che restituisca un job (non un video). Fai funzionare questo prima di aggiungere qualsiasi codice.
La richiesta ha tre parti: l'endpoint del modello, l'header Authorization e il corpo JSON con prompt e parametri di generazione.
curl -X POST "https://api.hiapi.ai/v1/models/kandinsky-6.0-pro/text-to-video/jobs" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "A slow drone shot over a misty pine forest at sunrise, soft golden light, cinematic",
"duration_seconds": 5,
"aspect_ratio": "16:9"
}'
Leggi attentamente la risposta. Devi cercare:
- Un identificatore del job — l'handle che userai per il polling. Può chiamarsi
id,job_ido simile. - Un campo stato iniziale, di solito simile a
queuedoprocessing. - Eventuali parametri restituiti, utili per confermare che il corpo della richiesta sia stato interpretato come previsto.
Una risposta che restituisce un identificatore di job e uno stato non di errore significa che la richiesta è stata accettata. Se quella risposta contenesse direttamente un file video, significherebbe che sta succedendo qualcosa di diverso da quanto descritto qui.
Conferma il contratto prima di costruirci sopra
I nomi dei campi sopra — percorso dell'endpoint, duration_seconds, aspect_ratio, chiave dell'identificatore — sono i dettagli più suscettibili di cambiare tra modelli e nel tempo. La fonte affidabile è la pagina di riferimento API del modello. Verifica una volta, copia i nomi esatti come costanti nello script e struttura il codice in modo che un cambio di nome sia una modifica di una riga, non una ricerca in tutto il codebase.
Se ricevi un 4xx, il corpo della risposta di errore dà più informazioni del codice di stato. 401 significa chiave errata o mancante; gli errori di validazione tipo 422 di solito indicano il campo problematico.
Invia e monitora il job fino al completamento
Una volta che la chiamata di invio funziona, il ciclo di vita è: invia, cattura l'identificatore, effettua polling, fermati allo stato terminale.
Invio
Il POST della sezione precedente crea il job. Qualunque cosa faccia il codice dopo, dovrebbe memorizzare l'identificatore restituito in una posizione persistente — una variabile nello script, una riga in una tabella di job, un messaggio in una coda. Se il processo muore dopo aver ricevuto la risposta di invio ma prima di aver reso persistente l'identificatore, perdi la possibilità di interrogare quel job.
Polling
Il polling è una richiesta GET alla risorsa del job, usando l'identificatore catturato:
curl "https://api.hiapi.ai/v1/models/kandinsky-6.0-pro/text-to-video/jobs/$JOB_ID" \
-H "Authorization: Bearer $HIAPI_API_KEY"
La risposta riporta lo stato attuale del job. Nell'uso reale vedrai pochi stati: in coda o in attesa, in elaborazione, completato e qualche forma di fallimento o annullamento. Progetta il ciclo su queste categorie anziché sulle stringhe esatte — mappa qualsiasi cosa restituisca l'API ai tuoi running, done, failed nel codice, così un rinominamento non rompe la logica di retry.
Decidere quanto attendere
Due numeri contano: l'intervallo di polling e il timeout complessivo.
- Intervallo. Effettua polling ogni pochi secondi, non in un ciclo serrato. Un ciclo serrato non porta benefici extra e può attivare i limiti di rate. Per i job video, un intervallo di alcuni secondi tra le richieste è ragionevole.
- Timeout. Imposta un limite. La generazione video richiede tempo, ma "attendere per sempre" non è una risposta accettabile per uno script di produzione. Scegli un budget massimo realistico e tratta il superamento come un fallimento da registrare e ritentare consapevolmente.
Un pattern che regge l'uso reale
In produzione, il passo di polling è di solito disaccoppiato da quello di invio, anziché dentro un processo in sleep. Un worker invia, registra il job ed esce; un ricontrollo periodico preleva i job incompleti e li interroga. Questo è più robusto ai riavvii e più facile da osservare. Per questo tutorial basta un semplice ciclo in un singolo processo — basta organizzarlo come funzioni anziché codice inline, e spostarlo in seguito in un worker schedulato periodicamente sarà semplice.
Scarica la clip video generata
Un job completato non è ancora un file sul tuo disco. La risposta di stato del job completato punta all'output — di solito un URL, a volte un oggetto annidato contenente l'URL. Leggi quel campo e usalo come input per il passo di download.
curl -L "$OUTPUT_URL" -o output/clip.mp4
Verifica i seguenti punti per confermare che il download sia effettivamente riuscito:
- Segui i redirect. Gli URL di output sono spesso serviti tramite redirect; curl lo gestisce con
-L, Python conallow_redirects=True. - Verifica il content type. Un job completato dovrebbe produrre un payload video. Se ciò che viene salvato come
clip.mp4è in realtà JSON o una pagina di errore HTML, il problema è nel download, non nella generazione. - Controlla la dimensione. File da zero byte o sospettosamente piccoli indicano un download fallito. Se gli header di risposta sono disponibili, confronta i byte con la dimensione dichiarata negli header.
- Considera la scadenza. Gli URL di output di solito hanno un limite di tempo. Scarica subito dopo il completamento e, se ti serve persistenza, copia il file nel tuo storage anziché conservare l'URL come riferimento permanente.
Per qualsiasi uso oltre il tutorial, fai streaming del download verso la destinazione anziché caricare l'intero file in memoria, e scrivi prima su un nome file temporaneo e poi rinomina — così un download incompleto non apparirà mai al codice a valle come un file completo.
Implementare la stessa richiesta in Python
Ecco il flusso curl ricostruito in una funzione richiamabile: invio, polling, download. I nomi da adattare sono raccolti in cima come costanti.
import os
import time
import requests
API_BASE = "https://api.hiapi.ai/v1"
MODEL_PATH = "/models/kandinsky-6.0-pro/text-to-video"
API_KEY = os.environ["HIAPI_API_KEY"]
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
RUNNING_STATES = {"queued", "pending", "processing", "running"}
DONE_STATES = {"completed", "succeeded", "done"}
FAILED_STATES = {"failed", "cancelled", "error"}
def generate_clip(prompt, out_path, timeout_s=600, interval_s=5):
# 1. submit
resp = requests.post(
API_BASE + MODEL_PATH + "/jobs",
headers={**HEADERS, "Content-Type": "application/json"},
json={"prompt": prompt, "duration_seconds": 5, "aspect_ratio": "16:9"},
timeout=30,
)
resp.raise_for_status()
job = resp.json()
job_id = job["id"]
print(f"submitted job {job_id}")
# 2. poll
deadline = time.monotonic() + timeout_s
while time.monotonic() < deadline:
status_resp = requests.get(
f"{API_BASE}{MODEL_PATH}/jobs/{job_id}",
headers=HEADERS,
timeout=30,
)
status_resp.raise_for_status()
data = status_resp.json()
state = str(data.get("status", "")).lower()
if state in DONE_STATES:
break
if state in FAILED_STATES:
raise RuntimeError(f"job {job_id} ended in state {state}: {data}")
time.sleep(interval_s)
else:
raise TimeoutError(f"job {job_id} did not finish within {timeout_s}s")
# 3. download
url = data["output"]["url"] if isinstance(data.get("output"), dict) else data["output"]
with requests.get(url, stream=True, allow_redirects=True, timeout=60) as r:
r.raise_for_status()
tmp = out_path + ".part"
with open(tmp, "wb") as f:
for chunk in r.iter_content(chunk_size=1 << 16):
f.write(chunk)
os.replace(tmp, out_path)
print(f"saved {out_path}")
return job_id
if __name__ == "__main__":
generate_clip(
"A slow drone shot over a misty pine forest at sunrise, soft golden light, cinematic",
"output/clip.mp4",
)
Perché è scritto così
- Usa insiemi di stati anziché corrispondenza esatta. Mappare gli stati restituiti su running/done/failed significa che nuovi stati intermedi non rompono il ciclo.
- Scadenza monotona.
time.monotonic()non risente delle regolazioni dell'orologio, quindi il timeout è accurato. - Scrittura atomica. Scrivere su
.parte poi rinominare significa che un download interrotto non lascia mai un file troncato che sembra valido. - Restituisce l'ID del job. Il chiamante può registrarlo, memorizzarlo e interrogarlo di nuovo se necessario — è il primo passo per spostare il polling fuori da questo processo.
Adatta il percorso dell'endpoint, i nomi dei campi della richiesta e le chiavi della risposta per corrispondere al riferimento API del modello. Tutto il resto — ciclo, timeout, download — è generico.
Stati di errore e checklist di debug
Quando un'esecuzione fallisce, isola prima la fase prima di cambiare qualsiasi cosa. Ogni fase ha una firma di fallimento diversa.
Fallimenti di autenticazione
Un 401 o 403 all'invio significa che la chiave è mancante, errata o non inviata. Controlla che la variabile d'ambiente sia effettivamente impostata nella shell o nel processo che esegue il codice — una chiave esportata in un terminale è invisibile a un job cron. Stampa i primi caratteri della chiave per confermare che sia stata risolta, mai la chiave completa.
Formato della richiesta errato
Errori tipo 400 o 422 all'invio significano che il corpo della richiesta non ha superato la validazione. Il corpo della risposta di solito indica il campo. Cause comuni: parametro scritto male, durata fuori dall'intervallo supportato o prompt vuoto. Confronta il tuo JSON campo per campo con il riferimento API; una singola chiave rinominata è la causa più frequente.
Il job resta bloccato in stato running
Se il polling non raggiunge mai uno stato terminale, verifica tre cose: l'identificatore che interroghi è quello che hai inviato; l'intervallo di polling non è così frequente da attivare i limiti di rate; il timeout è abbastanza lungo per il modello. Registra la risposta di stato grezza a ogni polling per vedere se lo stato avanza o è congelato.
Il job si completa ma il download fallisce
Un job completato con download fallito è un problema di gestione file, non di generazione. Verifica che i redirect siano seguiti, che l'URL non sia scaduto e che il content type sia video anziché JSON. Prova l'URL separatamente con curl -L per isolarlo dallo script.
Lo stesso prompt fallisce ripetutamente
Se un prompt continua a fallire mentre altri riescono, sospetta prima le policy sui contenuti o la lunghezza del prompt, non l'infrastruttura. Cambia una variabile — accorcia il prompt, semplifica la descrizione della scena — e riprova.
Una regola generale
Registra quattro cose per ogni job: identificatore del job, stato finale, tempo effettivo impiegato e stato HTTP del download. Questi quattro valori trasformano la maggior parte dei report "non ha funzionato" in una fase concreta e riparabile in meno di un minuto.
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
Come usare kling-4.0/text-to-video tramite l'API HiAPI: curl, Python e un esempio di richiesta funzionante
Guida pratica per sviluppatori: prompt cinematografici, audio sincronizzato, polling asincrono e download dell'output