Tutorial
So verwendest du die hailuo 2.3 Image-to-Video API: curl, Python und ein lauffähiges Request-Beispiel
Zusammenfassung
- Was das ist: Ein lauffähiges Rezept zur Verwendung der hailuo-2.3/image-to-video API auf hiapi – verwandle ein statisches Bild in einen kurzen Clip: Task erstellen, Task abfragen,
.mp4herunterladen. - Endpunkt:
POST https://api.hiapi.ai/v1/tasksmit"model": "hailuo-2.3/image-to-video"im Request-Body, dannGET /v1/tasks/<taskId>abfragen, bis der Task einen Endzustand erreicht. - Zwei Pflicht-Eingabefelder:
promptundimage_url– eine einzelne öffentliche URL zu deinem ersten Frame (kein Array). durationist ein String, keine Zahl:"6"oder"10". Ein Integer6wird mit 400 abgelehnt.- Das Schema ist strikt. Es gibt keine Parameter
motion_strength,camera_movementoderresolution– wer sie sendet, erhält 400. Bewegung wird ausschließlich über den Prompt gesteuert.
Was du baust und was du vorbereiten musst
Du hast ein statisches Bild – ein Produktfoto, ein Charakter-Rendering, ein Foto – und möchtest, dass hailuo-2.3 es zum Leben erweckt und einen Videoclip erzeugt, der genau bei diesem Frame beginnt. hailuo-2.3 ist bekannt für physikalisch glaubwürdige Bewegung (Stoff, Haare, Körpermchanik), eignet sich also hervorragend, um statische Bilder zu beleben.
Du brauchst zwei Dinge:
- Einen hiapi API-Key. Erstelle ihn im Dashboard. Der Key sieht aus wie
sk-...und gehört in den HeaderAuthorization: Bearer. - Eine öffentlich erreichbare URL für das erste Frame. Die API lädt das Bild von
image_url, daher muss es ohne Authentifizierung erreichbar sein – S3-/R2-/CDN-Links funktionieren;localhost-Pfade oder abgelaufene signierte URLs nicht.
Wie jedes generative Modell auf hiapi nutzt auch dieses die asynchrone Task-Schnittstelle: Du POSTest einen Task, erhältst sofort eine taskId und holst das Ergebnis danach per Polling oder Callback. Für Videos gibt es keinen synchronen Endpunkt – das Rendern eines Clips dauert länger als typische HTTP-Timeouts.
Request-Schema
Das vollständige Eingabeschema für hailuo-2.3/image-to-video – gegen die Live-API verifiziert:
| Feld | Typ | Erforderlich | Beschreibung |
|---|---|---|---|
prompt |
string | ✅ | Beschreibe die Bewegung, nicht die Szene – die Szene kommt aus deinem Bild. |
image_url |
string | ✅ | Eine öffentliche URL, das erste Frame. Singular – nicht image_urls. |
duration |
string | optional | "6" oder "10" (Sekunden). Muss ein String sein. |
prompt_optimizer |
boolean | optional | Lässt die Plattform deinen Prompt vor der Generierung erweitern. |
Das Schema ist strikt: Alles, was nicht in dieser Tabelle steht, wird abgelehnt. Sendest du motion_strength, camera_movement oder resolution, erhältst du genau das zurück:
{
"code": 400,
"error_code": "INVALID_REQUEST",
"message": "invalid input: <root>: additional properties 'resolution', 'camera_movement', 'motion_strength' not allowed"
}
Zwei Konsequenzen solltest du dir merken:
- Kein Regler für Bewegungsstärke. Die Bewegungsphysik von hailuo-2.3 wird ausschließlich durch den Prompt gesteuert – siehe den Abschnitt zum Prompt-Schreiben unten.
- Keine Kontrolle über Auflösung oder Seitenverhältnis an diesem Endpunkt. Baue keine UI für Parameter, die die API mit 400 ablehnt.
Minimales lauffähiges Beispiel: curl
Task erstellen:
curl -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer sk-<your-key>" \
-H "Content-Type: application/json" \
-d '{
"model": "hailuo-2.3/image-to-video",
"input": {
"prompt": "The woman turns toward the camera and smiles; wind gently moves her hair; slow cinematic push-in",
"image_url": "https://your-cdn.example.com/first-frame.jpg",
"duration": "6",
"prompt_optimizer": true
}
}'
Die Antwort (Auszug) enthält die Task-ID unter data.taskId:
{ "data": { "taskId": "..." } }
Task abfragen:
curl -s https://api.hiapi.ai/v1/tasks/<taskId> \
-H "Authorization: Bearer sk-<your-key>"
Während der Clip gerendert wird, meldet data.status einen Nicht-Endzustand. Sobald es auf "success" wechselt, steht die Video-URL in data.output[0].url; bei "fail" erklären data.error.code und data.error.message den Grund.
Lade die Datei sofort nach erfolgreichem Task herunter. Die Ausgabe-URL ist signiert und hat ein Ablaufdatum (expireAt) – speichere die Bytes in deinem eigenen Speicher und verlinke niemals direkt auf die Task-URL.
Minimales lauffähiges Beispiel: Python
Vollständiges Skript für denselben Ablauf – erstellen, abfragen, herunterladen:
import time
import requests
API_BASE = "https://api.hiapi.ai/v1/tasks"
API_KEY = "sk-<your-key>"
HEADERS = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
def create_task() -> str:
payload = {
"model": "hailuo-2.3/image-to-video",
"input": {
"prompt": (
"The cat stretches, hops off the windowsill, and walks toward "
"the camera; soft afternoon light, subtle handheld camera sway"
),
"image_url": "https://your-cdn.example.com/first-frame.jpg",
"duration": "6", # string, not int: "6" or "10"
"prompt_optimizer": True,
},
}
r = requests.post(API_BASE, json=payload, headers=HEADERS, timeout=30)
task_id = (r.json().get("data") or {}).get("taskId")
if not task_id:
raise RuntimeError(f"create failed ({r.status_code}): {r.text[:300]}")
return task_id
def wait_task(task_id: str, timeout_s: int = 900, poll_s: int = 10) -> dict:
deadline = time.time() + timeout_s
while time.time() < deadline:
r = requests.get(f"{API_BASE}/{task_id}", headers=HEADERS, timeout=30)
task = r.json().get("data") or {}
status = task.get("status")
if status == "success":
return task
if status == "fail":
err = task.get("error") or {}
raise RuntimeError(f"task failed: {err.get('code')}: {err.get('message')}")
time.sleep(poll_s)
raise TimeoutError(f"task {task_id} not finished after {timeout_s}s")
def main() -> None:
task_id = create_task()
print("task created:", task_id)
task = wait_task(task_id)
url = task["output"][0]["url"]
# The URL is signed and expires -- download immediately, store the bytes yourself.
video = requests.get(url, timeout=120).content
with open("hailuo-output.mp4", "wb") as f:
f.write(video)
print("saved hailuo-output.mp4")
if __name__ == "__main__":
main()
Video-Tasks laufen deutlich länger als Bild-Tasks, daher fragt das Skript alle 10 Sekunden ab und setzt ein großzügiges Limit von 15 Minuten. Frage nicht aggressiver als etwa alle 5 Sekunden ab – das macht das Rendern nicht schneller.
Prompts schreiben, die Bewegung steuern
Da es keine Bewegungsparameter gibt, ist der Prompt dein einziges Steuerrad – und für hailuo-2.3 reicht das aus. Drei Faustregeln:
- Beschreibe Bewegung, nicht Aussehen. Das Modell hat dein Bild bereits gesehen.
"a beautiful woman in a red dress"verschwendet den Prompt;"she turns her head slowly to the left as the camera pushes in"nutzt ihn gut. - Beschreibe Kamerabewegung in einfacher Sprache.
"slow push-in","orbit right","handheld sway","static camera"– solche Angaben gehören in den Prompt-Text, nicht in ein (nicht existierendes) Feldcamera_movement. - Lass bei Unsicherheit
prompt_optimizerhelfen. Mit"prompt_optimizer": trueerweitert die Plattform kurze Prompts vor der Generierung – ein guter Standard für kurze Eingaben. Wenn du eine sorgfältig formulierte Beschreibung strikt befolgen willst, schalte ihn ab.
Hinweise für den Produktivbetrieb
Bevorzuge Callbacks statt Polling. Gib beim Erstellen des Tasks einen Callback mit, und hiapi POSTet das Endergebnis an deinen Endpunkt, sodass du keine offene Schleife aufrechterhalten musst:
{
"model": "hailuo-2.3/image-to-video",
"input": { "...": "..." },
"callback": { "url": "https://your-app.example.com/hooks/hiapi", "when": "final" }
}
"when": "final" wird nur einmal im Endzustand ausgelöst. Polling eignet sich für Skripte und Notebooks; Callbacks sind die richtige Form für Server – das Rendern von Videos dauert lang genug, dass ein Worker, der beim Polling blockiert, echte Kosten verursacht.
Behandle diese Fehler explizit:
401mit"code": "permission_denied"– der Key ist fehlerhaft, oder der Key darf dieses Modell nicht verwenden. Die Meldung enthält einerequest_id, die du an den Support senden kannst.400 INVALID_REQUEST– Schema-Verstoß. Die Meldung ist präzise, z. B.duration: got number, want stringoderimage_url: missing required field "image_url". Protokolliere sie unverändert.402beim Erstellen des Tasks – unzureichendes Guthaben. Beachte, dass Videos pro Task teurer sind als Bilder, sodass ein Key, mit dem Bild-Tasks noch funktionieren, bei Video-Tasks bereits fehlschlagen kann. Lade Guthaben auf oder prüfe den Verbrauch im Dashboard.- Der Task erreicht
"fail"– Fehler auf der Generierungsseite; prüfedata.error. Ein häufiger Grund speziell bei Image-to-Video:image_urlkann nicht geladen werden (privater Bucket, abgelaufene signierte URL).
Mache den Ablauf rund um Wiederholungen idempotent. Wenn dein Prozess zwischen Erstellen und Herunterladen abstürzt, erzeugt ein naiver Neustart ein zweites (kostenpflichtiges) Rendering. Persistiere die taskId sofort nach der Rückkehr von create_task und fahre beim Neustart mit dem Polling fort, statt neu zu erstellen.
Weiterführende Lektüre
- hailuo-2.3/image-to-video Modellseite – Playground, sekundengenaue Abrechnung und Live-Schema.
- hailuo-2.3-fast/image-to-video – Variante mit niedriger Latenz, gleicher Task-Workflow.
- hailuo-2.3/text-to-video – ohne Quellbild, nur aus dem Prompt generiert.
- hiapi-Dokumentation – vollständige Beschreibung der Task-Schnittstelle, inklusive Callbacks.
- Preise – aktuelle sekundengenaue Videotarife für alle Modelle.
Häufige Fragen
Welche Dauern unterstützt hailuo-2.3 Image-to-Video?
Zwei: "6" und "10" Sekunden, übergeben als String. Jeder andere Wert – oder derselbe Wert als Zahl – führt zu 400 INVALID_REQUEST.
Warum schlägt "duration": 6 fehl, während "duration": "6" funktioniert?
Das Schema definiert duration als String-Enum. Die API sagt es dir eindeutig: duration: got number, want string. Das ist der häufigste 400 an diesem Endpunkt.
Kann ich die Ausgabeauflösung oder das Seitenverhältnis festlegen?
Nein. Der Endpunkt stellt keine Felder resolution oder aspect_ratio bereit; eines davon zu senden ergibt 400 – das Schema lehnt unbekannte Eigenschaften ab, statt sie zu ignorieren.
Wie steuere ich Kamerabewegung oder Bewegungsstärke?
Über den Prompt. Es gibt keine Parameter camera_movement oder motion_strength – schreibe Kamera- und Bewegungsanweisungen in einfacher Sprache ("slow push-in", "she walks toward the camera").
Kann ich mehrere Referenzbilder übergeben?
Nein – image_url ist ein einzelner String, das erste Frame. Das unterscheidet sich von einigen anderen Modellen auf hiapi, die ein Array image_urls entgegennehmen; das Schema wird pro Modell definiert, sieh dir also unbedingt die Modellseite an.
Welche Bildformate werden für das erste Frame unterstützt? Standard-Webformate (JPEG/PNG), bereitgestellt über eine öffentlich erreichbare URL. Wenn die Plattform die URL nicht laden kann, schlägt der Task nach der Erstellung fehl – prüfe daher vor dem Absenden, dass der Link öffentlich erreichbar ist.
Worin unterscheidet sich das von hailuo-2.3/text-to-video?
Text-to-Video erfindet die Szene allein aus deinem Prompt; Image-to-Video fixiert das erste Frame an dein Bild und beginnt die Animation von dort. Der Task-Lebenszyklus ist identisch – nur das Eingabeschema unterscheidet sich (hier ist image_url erforderlich, während Text-to-Video überhaupt kein Bildfeld hat).
Was kostet das? Videos werden nach Ausgabesekunden abgerechnet, und die Tarife ändern sich – sieh auf der hailuo-2.3/image-to-video Modellseite und der Preisseite nach den aktuellen Werten.
Ähnliche Artikel
Alle Artikel ansehen →-
Tutorial
So rufen Sie hailuo-2.3-fast/image-to-video über die HiAPI API auf: curl und Python in der Praxis
Die erste lauffähige Anfrage für die schnelle, kostengünstige Bild-zu-Video-Stufe – von der Modell-ID bis zum heruntergeladenen MP4
-
Tutorial
So rufen Sie hailuo-2.3/text-to-video über die HiAPI API auf: curl, Python und lauffähige Anfragebeispiele
-
Tutorial
Kandinsky 6.0 Pro Text-zu-Video auf HiAPI: curl- und Python-Tutorial
Eine anfrageorientierte praktische Demonstration: Aufbau des Aufrufs vom Prompt zum Videoclip, Absenden der Anfrage, Abfragen des Fertigstellungsstatus und Herunterladen des Ergebnisses