Tutorial
Happyhorse Image-to-Video API: Verfügbare curl- und Python-Beispiele (hiapi)
Du möchtest ein Standbild aus deinem eigenen Code in ein zusammenhängendes kurzes Video verwandeln. Das Modell happyhorse-1.1/image-to-video auf hiapi macht genau das: Übergib eine Bild-URL und einen optionalen Bewegungs-Prompt, und innerhalb von Sekunden erhältst du eine MP4 in 720p oder 1080p. Dieser Leitfaden ist der kürzeste funktionierende Weg – echte Request-Bodies, echte Fehlermeldungen, sowohl curl als auch Python –, damit du heute live gehen kannst, ohne mit Feldnamen zu kämpfen.
Was du vor dem Start brauchst
- Einen hiapi-API-Key. Hole ihn dir im hiapi-Dashboard – er sieht aus wie
sk-...und gehört in den HeaderAuthorization: Bearer .... - Eine erreichbare Bild-URL (öffentliches HTTPS). Lokale Dateien funktionieren nicht; das Modell ruft diese URL selbst ab.
- Eine in Worten ausgedrückte Bewegungsabsicht (optional, aber empfohlen). Je klarer die Verben, desto besser die Bewegung.
Das Modell wird pro Videosekunde abgerechnet; die Preise stehen auf der hiapi-Preisseite; der restliche Modellkatalog findest du unter hiapi models – schau dir beides an, bevor du die Stapelgröße erhöhst.
Die minimale funktionierende Anfrage (curl)
Jedes Video auf hiapi läuft über den asynchronen /v1/tasks-Endpunkt: Du POSTest zunächst eine Erstellungsanfrage, erhältst eine taskId zurück und pollst dann entweder GET /v1/tasks/{taskId} oder empfängst einen Callback bei Abschluss.
Aufgabe erstellen:
curl -X POST "https://api.hiapi.ai/v1/tasks" \
-H "Authorization: Bearer sk-your-key" \
-H "Content-Type: application/json" \
-d '{
"model": "happyhorse-1.1/image-to-video",
"input": {
"image_urls": ["https://example.com/your-still.jpg"],
"prompt": "the cat slowly turns its head toward the camera and blinks",
"resolution": "1080p",
"duration": 5
}
}'
Eine erfolgreiche Antwort sieht so aus:
{
"code": 200,
"data": { "taskId": "tk-hiapi-01KW3D..." },
"message": "success"
}
Jetzt pollst du das Ergebnis (alle 5 Sekunden reicht – die meisten Clips sind in zwei Minuten fertig):
curl "https://api.hiapi.ai/v1/tasks/tk-hiapi-01KW3D..." \
-H "Authorization: Bearer sk-your-key"
Während der Ausführung erhältst du "status": "handling". Bei Abschluss erhältst du:
{
"code": 200,
"data": {
"status": "success",
"model": "happyhorse-1.1/image-to-video",
"output": [
{
"type": "video",
"url": "https://temp.hiapi.ai/.../01KW....mp4",
"expireAt": 1783131245
}
],
"taskId": "tk-hiapi-01KW3D..."
}
}
Diese url ist die, die du herunterladen musst – und zwar sofort, denn expireAt ist ein Unix-Zeitstempel, der angibt, wann der temporäre Speicher sie löscht.
Python: Pollen bis zum Erfolg
Dies ist ein vollständiges, lauffähiges Skript – trage einfach deinen Key und die Bild-URL ein.
import os
import time
import requests
API = "https://api.hiapi.ai/v1/tasks"
TOKEN = os.environ["HIAPI_KEY"] # sk-...
def create_video(image_url: str, prompt: str, duration: int = 5,
resolution: str = "1080p") -> str:
"""Submit an image-to-video task. Returns the taskId."""
r = requests.post(
API,
headers={"Authorization": f"Bearer {TOKEN}",
"Content-Type": "application/json"},
json={
"model": "happyhorse-1.1/image-to-video",
"input": {
"image_urls": [image_url], # exactly one URL
"prompt": prompt, # optional
"resolution": resolution, # "720p" or "1080p"
"duration": duration, # int, 3..15
},
},
timeout=60,
)
body = r.json()
if body.get("code") != 200:
raise RuntimeError(f"create failed: {body}")
return body["data"]["taskId"]
def wait_for_video(task_id: str, timeout_s: int = 600,
poll_s: int = 5) -> str:
"""Block until the task succeeds, fails, or times out. Returns the MP4 URL."""
deadline = time.time() + timeout_s
while time.time() < deadline:
r = requests.get(
f"{API}/{task_id}",
headers={"Authorization": f"Bearer {TOKEN}"},
timeout=30,
)
task = r.json().get("data") or {}
status = task.get("status")
if status == "success":
return task["output"][0]["url"]
if status == "fail":
raise RuntimeError(f"task failed: {task.get('error')}")
time.sleep(poll_s)
raise TimeoutError(f"task {task_id} did not finish in {timeout_s}s")
def download(url: str, path: str) -> None:
with requests.get(url, stream=True, timeout=120) as r:
r.raise_for_status()
with open(path, "wb") as f:
for chunk in r.iter_content(1 << 16):
f.write(chunk)
if __name__ == "__main__":
task_id = create_video(
image_url="https://example.com/your-still.jpg",
prompt="the dancer spins once and ends in a pose",
duration=5,
resolution="1080p",
)
print("submitted:", task_id)
mp4_url = wait_for_video(task_id)
download(mp4_url, "out.mp4")
print("saved out.mp4")
Das Ganze umfasst etwa 50 Zeilen und ist die gesamte produktionsreife Schnittstelle – kein SDK, keine Hintergrundwarteschlange, kein Streaming-Protokoll. Führe es mit HIAPI_KEY=sk-... python video.py aus.
Produktion: Callbacks statt Polling
Polling ist für einmalige Aufgaben und Tests in Ordnung. Für Serverlast möchtest du, dass die Plattform dich zurückruft, sobald der Clip fertig ist – das spart die Schleife, skaliert ohne zusätzlichen Aufwand, und der Request-Stream kehrt sofort zurück.
Füge auf der Stammebene des Request-Bodys (nicht innerhalb von input) ein callback-Objekt hinzu:
curl -X POST "https://api.hiapi.ai/v1/tasks" \
-H "Authorization: Bearer sk-your-key" \
-H "Content-Type: application/json" \
-d '{
"model": "happyhorse-1.1/image-to-video",
"input": {
"image_urls": ["https://example.com/still.jpg"],
"prompt": "slow zoom out from the subject",
"resolution": "1080p",
"duration": 6
},
"callback": {
"url": "https://your-app.example.com/webhooks/hiapi",
"when": "final"
}
}'
Wenn die Aufgabe einen Endzustand erreicht, POSTet hiapi das Aufgabenobjekt, das du auch per Polling erhalten hättest (status, output[].url, error usw.), an deine URL. when: "final" bedeutet, dass du nur bei Erfolg oder Fehlschlag einen Callback erhältst – kein Fortschrittsrauschen.
Ein paar Regeln, die dir echte Debug-Zeit ersparen:
- Mach deinen Webhook idempotent. Dieselbe
taskIdkann zweimal eintreffen (Netzwerk-Retries gibt es wirklich). Prüfe vor der Verarbeitung in deiner Datenbank, ob diese Aufgabe bereits existiert. - Hoste die MP4 im Handler neu. Die URL, die hiapi dir gibt, zeigt auf temporären Speicher mit einem
expireAt-Feld; streame sie beim ersten Empfang in deinen eigenen Bucket, sonst verlierst du sie. - Bestätige schnell. Gib schnell
2xxzurück und erledige die schwere Arbeit asynchron. Langsame Webhooks riskieren Retries. - Nutze Polling als Fallback. Verpacke die
taskIdin eine verzögerte Aufgabe und polle nach 10 Minuten erneut, falls der Webhook verloren geht. Wenn du das ständig erlebst, lies unter Gründe, warum hiapi-Task-Callbacks möglicherweise nicht ausgelöst werden die häufigen Ursachen nach.
Fehlermeldungen, denen du begegnen wirst
Dies sind die exakten Strings, die die API zurückgibt; sie in deinem Code abzugleichen ist zuverlässiger, als sie zu erraten.
| Situation | HTTP | Form des Antwort-Bodys |
|---|---|---|
| Falscher oder widerrufener Key | 401 | {"error":{"code":"permission_denied","message":"This API key cannot use the selected model...","type":"hiapi_error"}} |
| Pflichtfeld fehlt | 400 | {"code":400,"error_code":"INVALID_REQUEST","message":"invalid input: image_urls: missing required field \"image_urls\""} |
resolution ungültig |
400 | ... resolution: value must be one of '720p', '1080p' |
| Dauer außerhalb des Bereichs | 400 | ... duration: minimum: got 2, want 3 / duration: maximum: got 30, want 15 |
image_urls falsche Länge |
400 | ... image_urls: maxItems: got 2, want 1 (oder minItems: got 0, want 1) |
Unbekanntes Feld auf Stammebene oder in input |
400 | ... additional properties 'identity_preserving' not allowed |
| Aufgabe selbst schlägt nach Einreichung fehl | 200 (Task-GET) mit data.status == "fail" und data.error.{code,message} |
Authentifizierungs- und Validierungsfehler bedeuten, dass du nicht erneut versuchen solltest; alles andere (5xx der Plattform, Netzwerk-Timeouts während des Pollings, vorübergehende task fail mit wiederholbarem Code) eignet sich für einen Retry mit kleinem Backoff.
Ausgabe abstimmen
Es gibt vier Regler, die wirklich etwas bewirken – alles andere (seed, aspect_ratio, fps, cfg_scale, negative_prompt) wird derzeit als unbekanntes Feld abgelehnt. Bleib innerhalb dieser Menge:
image_urls– eine HTTPS-URL. Seitenverhältnis und Komposition der Ausgabe folgen diesem Bild.prompt– eine kurze Bewegungsbeschreibung ("she smiles and tilts her head"). Filmische, verbgetriebene Prompts schlagen Adjektivlisten.resolution–"720p"zum Prototyping und für Vorschaubilder,"1080p"für die Auslieferung.duration– ganzzahlige Sekunden von3bis15. Längere Clips kosten mehr Zeit und Geld; wähle die kürzeste Dauer, die die Geschichte erzählt.
Für Projekte, die Start- und Endbild benötigen, siehe happyhorse-1.1 reference-to-video. Für reines Text-to-Video ohne Quellbild ist happyhorse-1.1 text-to-video der Schwesterartikel. Stöbere im hiapi models catalogue oder in der Rezept-Sektion des Blogs nach dem Rest.
FAQ
Kann ich zwei Bilder übergeben, um erstes und letztes Frame zu steuern?
Auf happyhorse-1.1/image-to-video nicht – image_urls hat höchstens ein Element (maxItems: 1). Wenn du das brauchst, nutze happyhorse-1.1/reference-to-video oder baue mit happyhorse-1.1 reference-to-video.
Welche Auflösung hat die MP4, die ich tatsächlich zurückbekomme?
Die Ausgabe folgt dem Seitenverhältnis deines Eingabebildes und dem von dir gesetzten resolution-Flag. "1080p" liefert die höhere der beiden; "720p" ist für Tests schneller und günstiger.
Warum bekomme ich 401 permission_denied, obwohl mein Key bei anderen Modellen funktioniert?
Einige Modelle sind pro Key eingeschränkt. Sieh dir die Modellseite im hiapi-Dashboard an – wenn happyhorse-1.1/image-to-video nicht auf deiner Allowlist steht, erzeuge einen neuen Key oder kontaktiere den Support mit der request_id aus dem Fehler.
Gibt es Streaming-/SSE-Antworten? Nein. Jedes Videomodell verwendet das asynchrone Aufgabenmuster aus diesem Artikel. Wähle je nachdem, ob du den Server kontrollierst, Polling oder Callback.
Wo sehe ich die tatsächlichen Kosten pro Clip?
Auf der hiapi-Preisseite. Die Kosten werden pro Videosekunde berechnet, daher bestimmt die von dir übergebene duration direkt die Ausgaben – halte Entwicklungs-/Testclips bei duration: 3, um das Budget zu schonen.
Die Ausgabe-URL funktioniert nach einem Tag nicht mehr.
Das ist erwartetes Verhalten – die URL ist temporärer Speicher, und die Antwort enthält einen expireAt-Unix-Zeitstempel. Lade die MP4 immer in dem Moment herunter, in dem die Aufgabe erfolgreich ist (oder streame sie über dein eigenes CDN).
Ä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