HiAPI
Blog

Tutoriale

API text-to-video PixVerse V6: un esempio curl e Python funzionante

Oct 20, 2026
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" otterrai invalid input: duration: got string, want integer; i valori fuori intervallo ti comunicano direttamente i limiti, ad esempio duration: 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 ottieni output[0].url scaricalo subito—l'URL include expireAt e 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 prefisso tk-hiapi-, non un UUID.
  • Polling: il data.status di GET /v1/tasks/<id> è passato in sequenza per handling → 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"}. expireAt meno 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

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.

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