Tutoriale
API text-to-video PixVerse V6: un esempio curl e Python funzionante
- Modello
- pixverse-v6
Generare un video con pixverse-v6/text-to-video su hiapi è essenzialmente una POST /v1/tasks più un ciclo di polling—esattamente lo stesso pattern di attività asincrona usato da ogni modello generativo della piattaforma. Questo articolo ti fornisce esempi curl e Python pronti da copiare, i campi di input che l'endpoint valida realmente, e il ciclo di vita dell'attività e le insidie che ho registrato durante una generazione realmente riuscita.
Cosa serve prima di iniziare
- Una chiave API hiapi. Creala nella console e passala nell'header
Authorization: Bearer sk-<la tua key>. Il formato dell'header è nella documentazione di autenticazione. - Il model id è
pixverse-v6/text-to-video. Mantieni la barra centrale—fa parte dell'id, non è un percorso URL. - curl non richiede installazioni; l'esempio Python usa solo la libreria standard più
requests.
PixVerse V6 text-to-video trasforma un prompt testuale in una clip video da 1 a 15 secondi, da 360p a 1080p. Usa l'interfaccia asincrona unificata delle attività: invia l'attività → esegui il polling del risultato → scarica il video prima che l'URL di output scada.
Richiesta minima funzionante (curl)
Invia l'attività a POST /v1/tasks:
curl -s -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer sk-<la tua key>" \
-H "Content-Type: application/json" \
-d '{
"model": "pixverse-v6/text-to-video",
"input": {
"prompt": "清晨阳光下,一只红色的狐狸小跑着穿过新雪,电影质感,慢动作",
"aspect_ratio": "16:9",
"duration": 5,
"resolution": "720p"
}
}'
Nella risposta ottieni un id attività:
{ "code": 200, "data": { "taskId": "tk-hiapi-...." }, "message": "success" }
Poi esegui il polling di GET /v1/tasks/<taskId> finché data.status non diventa success:
curl -s https://api.hiapi.ai/v1/tasks/tk-hiapi-.... \
-H "Authorization: Bearer sk-<la tua key>"
In caso di successo, l'URL del video finito è in data.output[0].url:
{
"code": 200,
"data": {
"status": "success",
"storage": "temp",
"output": [
{ "type": "video", "url": "https://temp.hiapi.ai/....mp4", "expireAt": 1793036664 }
]
},
"message": "success"
}
Questo URL di output è temporaneo—include un timestamp expireAt (misurato: 7 giorni dopo la generazione). Scarica subito il file .mp4 e salvalo nel tuo object storage; non fare hotlink diretto a questo indirizzo.
Lo stesso flusso (Python)
import time, requests
BASE = "https://api.hiapi.ai/v1/tasks"
HEADERS = {"Authorization": "Bearer sk-<la tua key>", "Content-Type": "application/json"}
def create_task():
payload = {
"model": "pixverse-v6/text-to-video",
"input": {
"prompt": "清晨阳光下,一只红色的狐狸小跑着穿过新雪,电影质感,慢动作",
"aspect_ratio": "16:9",
"duration": 5,
"resolution": "720p",
},
}
r = requests.post(BASE, json=payload, headers=HEADERS, timeout=60)
r.raise_for_status()
data = r.json()
task_id = (data.get("data") or {}).get("taskId")
if not task_id:
raise RuntimeError(f"创建失败: {data}")
return task_id
def wait_for(task_id, timeout_s=600):
deadline = time.time() + timeout_s
while time.time() < deadline:
try:
r = requests.get(f"{BASE}/{task_id}", headers=HEADERS, timeout=30)
task = (r.json().get("data") or {})
except requests.RequestException:
time.sleep(5) # 单次网络抖动不该让整个轮询中止
continue
status = task.get("status")
if status == "success":
return task["output"][0]["url"]
if status == "fail":
raise RuntimeError(f"任务失败: {task.get('error')}")
time.sleep(5) # 还在排队/渲染——用同一个 task_id 继续轮询
raise TimeoutError(task_id)
task_id = create_task()
url = wait_for(task_id)
video = requests.get(url, timeout=120).content
open("out.mp4", "wb").write(video)
print("已保存 out.mp4")
Il ciclo di polling valuta solo i due stati terminali success e fail, e per qualsiasi altro stato continua ad attendere—così, che durante il rendering venga riportato handling o archiving, il codice non sbaglierà mai. Punto chiave: se una singola richiesta di polling fallisce, aspetta un po' e interroga di nuovo usando lo stesso task_id già salvato, non reinviare l'attività—reinviarla eseguirebbe un'altra generazione e addebiterebbe un altro costo.
I parametri che pixverse-v6/text-to-video valida realmente
Questi sono i campi che l'endpoint accetta realmente. Ognuno l'ho confermato inviando un valore non valido e rileggendo il suo errore di validazione, e ho fatto un controllo incrociato con la documentazione del modello:
| Campo | Tipo | Valori / intervallo | Valore predefinito | Descrizione |
|---|---|---|---|---|
prompt |
string | da 1 a 2048 byte UTF-8 (1 ideogramma cinese = 3 byte, circa 682 caratteri) | — | Obbligatorio. |
aspect_ratio |
enum | 16:9, 4:3, 1:1, 3:4, 9:16, 2:3, 3:2, 21:9 |
16:9 |
Nota che supporta 21:9 (ultrawide) e 2:3/3:2. |
duration |
integer | 1–15 |
5 |
Unità in secondi, deve essere un intero, non una stringa. |
resolution |
enum | 360p, 540p, 720p, 1080p |
720p |
Risoluzione di output. |
generate_audio |
boolean | true / false |
false |
Se generare anche musica di sottofondo, effetti sonori e dialoghi; disattivato per impostazione predefinita, per l'audio va attivato esplicitamente. |
negative_prompt |
string | massimo 2048 byte UTF-8 | — | Opzionale; i contenuti da evitare. |
seed |
integer | qualsiasi intero | — | Opzionale; stesso seed + stesso prompt consentono di riprodurre lo stesso risultato. |
style |
enum | anime, 3d_animation, clay, comic, cyberpunk |
nessuno | Preset di stile opzionale; se lasciato vuoto mantiene uno stile naturale. |
Se vuoi usare un callback invece del polling, allo stesso livello di input puoi anche includere un oggetto callback: url (indirizzo di callback HTTPS) + when (al momento solo final, ovvero callback allo stato terminale dell'attività).
Come scriverlo in produzione
- Questo è uno schema chiuso. Qualsiasi campo non presente nella tabella viene rifiutato direttamente con
invalid input: <root>: additional properties '<campo>' not allowed. In realtà è un bene: i campi digitati male o inventati falliscono in modo evidente già all'invio, invece di essere ignorati silenziosamente. durationè un intero, diversamente da alcuni modelli video della piattaforma che accettano stringhe ("6"). Inviando"5"otterraiinvalid input: duration: got string, want integer; i valori fuori intervallo ti comunicano direttamente i limiti, ad esempioduration: maximum: got 999, want 15,duration: minimum: got 0, want 1.- L'errore riporta un solo campo alla volta, e l'envelope è piatto:
{"code":400,"error_code":"INVALID_REQUEST","message":"invalid input: aspect_ratio: value must be one of ..."}. Correggi il campo segnalato e reinvia; il prossimo campo non valido (se presente) emergerà alla chiamata successiva. - Quando un'attività fallisce, l'HTTP resta comunque 200. L'informazione di fallimento è in
data.status: "fail"nel corpo della risposta; quello che devi valutare è il campo status, non il codice di stato HTTP. - Polling o callback? Per script leggeri il polling è il più semplice; per scalare e non voler tenere connessioni aperte, usa il
callback. In entrambi i casi, appena ottienioutput[0].urlscaricalo subito—l'URL includeexpireAte dopo la scadenza restituisce 404.
Registro empirico: l'ho davvero eseguito una volta
Questo articolo non è solo una sonda in sola lettura—ho eseguito l'intero ciclo di vita con una richiesta reale, ed ecco il registro:
- Creazione: inviata la richiesta 720p / 5 secondi / 16:9 di cui sopra, è tornato immediatamente
{"code":200,"data":{"taskId":"tk-hiapi-01M5AM..."},"message":"success"}. Nota che il taskId è una stringa con prefissotk-hiapi-, non un UUID. - Polling: il
data.statusdiGET /v1/tasks/<id>è passato in sequenza perhandling→archiving→success; l'intera clip da 5 secondi, dalla creazione al completamento, ha impiegato circa 74 secondi. - Output: nello stato terminale
data.output[0]è{"type":"video","url":"https://temp.hiapi.ai/....mp4","expireAt":...,"artifactId":"...","storage":"temp"}.expireAtmeno l'ora di creazione dà esattamente 604800 secondi, cioè 7 giorni. - Artefatto: una HEAD su quell'URL di output ha restituito
content-type: video/mp4, dimensione di circa 2.2 MB, confermando che è un file mp4 valido.
Una correzione sull'audio merita una nota a parte: ho sondato con valori non validi alcuni nomi di campo adiacenti—generate_audio ha risposto got string, want boolean (segno che è un campo booleano valido), mentre sound e audio hanno risposto additional properties not allowed (non esistono). In altre parole, l'audio è controllato dall'interruttore generate_audio, predefinito false; anche la pagina dei prezzi ha di conseguenza le due fasce «Sound On / Sound Off». In questa prova non ho attivato generate_audio, quindi il risultato è una clip muta.
Non ho espresso valutazioni soggettive sulla qualità delle immagini (questa volta ho verificato solo il contratto della richiesta, il ciclo di vita dell'attività e che l'artefatto fosse un mp4 valido); per questa parte, genera concretamente con i tuoi prompt e giudica tu.
Come si calcola il costo
pixverse-v6/text-to-video è fatturato al secondo (il fattore di fatturazione è proprio duration); più lunga è la durata, più costa; a risoluzione più alta e attivando generate_audio in fascia «Sound On», il prezzo al secondo aumenta ulteriormente. Le tariffe precise al secondo sono quelle in tempo reale della pagina dei prezzi; dagli un'occhiata prima di generare in batch.
Link correlati
- PixVerse V6 text-to-video — pagina del modello
- PixVerse V6 text-to-video — documentazione API
- Riferimento API: creazione attività e dettaglio attività
- Avvio rapido e autenticazione
- Vuoi partire da un'immagine per fare un video? Guarda PixVerse V6 image-to-video
- Prezzi
Domande frequenti
duration è in secondi o in frame? In secondi—qualsiasi intero tra 1 e 15, predefinito 5.
Si possono generare video con audio? Sì. Imposta generate_audio su true e il modello genererà insieme musica di sottofondo, effetti sonori e dialoghi; il valore predefinito è false (muto). Attivare l'audio ricade in una fascia di prezzo più alta, vedi la pagina dei prezzi.
Quanto può essere lungo un prompt? Il limite è 2048 byte UTF-8. Un carattere cinese conta 3 byte, quindi si arriva a circa 682 ideogrammi cinesi.
Che differenza c'è con image-to-video? Questo endpoint (pixverse-v6/text-to-video) parte solo da un prompt testuale. Image-to-video è un altro model id: riceve un'immagine iniziale e la anima—se vuoi animare un'immagine già pronta invece di generarla dal nulla, usa quello.
Perché la mia richiesta restituisce "additional properties not allowed"? Hai inviato un campo non presente nello schema. L'input accetta solo prompt, aspect_ratio, duration, resolution, generate_audio, negative_prompt, seed e style.
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