Tutorial
HappyHorse 1.1 Referenz-zu-Video API: direkt ausführbares curl + Python Tutorial
HappyHorse 1.1 R2V verwandelt bis zu neun Referenzbilder plus einen Text-Prompt in ein kurzes Video und sorgt dabei über mehrere Einstellungen hinweg für konsistentes Subjekt, konsistente Kleidung und konsistenten Szenenstil. Auf HiAPI wird dieses Modell über einen einheitlichen asynchronen Task-Endpunkt bereitgestellt; die zugehörige Modell-ID lautet happyhorse-1.1/reference-to-video. Dieses Tutorial zeigt zuerst die minimal lauffähige Anfrage und danach eine produktionsreife Version mit Callback.
Ziel und Voraussetzungen
Du wirst Folgendes umsetzen:
- 1-9 Referenzbilder auf HTTPS-URLs hochladen (oder bereits hosten), die für die API erreichbar sind.
- Eine Task an
https://api.hiapi.ai/v1/tasksper POST senden, die auf diese URLs verweist. - Sobald die Task den Status
successerreicht, die endgültige MP4-Adresse ausdata.output[0].urlauslesen.
Voraussetzungen:
- Ein HiAPI-Konto und ein API-Key, der mit
sk-beginnt. Du erhältst ihn in der HiAPI-Konsole; die Regeln zu Request-Headern findest du in der Dokumentation zur Authentifizierung. Der Schlüssel muss alsAuthorization: Bearer sk-...übergeben werden und darf niemals in Client-Code stehen. - Anforderungen an das Bild-Hosting: Jedes Referenzbild muss im Format JPEG, PNG oder WEBP vorliegen, die kürzeste Seite ≥ 400px und ≤ 20MB betragen. Öffentliche CDN-URLs sind zulässig; signierte S3-URLs ebenfalls, solange der Task-Ausführer darauf zugreifen kann.
Minimal lauffähige Anfrage (curl)
Dies ist der kleinste Request-Body, den das Schema akzeptiert. Er nutzt die Standardausgabe 1080p / 16:9 / 5 Sekunden, daher musst du nur die Felder prompt und reference_image setzen.
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/reference-to-video",
"input": {
"prompt": "Die Figur aus [Image 1] läuft durch eine Szene im Stil von [Image 2], filmische Kameraführung",
"reference_image": [
"https://static.hiapi.ai/example/ref-1.jpg",
"https://static.hiapi.ai/example/ref-2.jpg"
]
}
}'
Die Antwort ist der Task-Umschlag; das einzige Feld, das du tatsächlich brauchst, ist data.taskId:
{
"code": 200,
"data": { "taskId": "task_xxx", "status": "queued" }
}
Polling bis zum Endzustand:
curl https://api.hiapi.ai/v1/tasks/task_xxx \
-H "Authorization: Bearer sk-YOUR_KEY"
Wenn data.status zu success wird, liegt die Video-URL in data.output[0].url. Diese URL trägt einen expireAt-Zeitstempel; lade die Datei daher sofort herunter oder übertrage sie in persistenten Speicher – verlinke die Adresse nicht direkt (Hotlinking) auf deiner Website.
Parameter
Der R2V-Endpunkt validiert Eingaben streng; unbekannte Felder führen zu 400 INVALID_REQUEST. Das vollständige Schema (live gegen POST /v1/tasks verifiziert):
| Feld | Typ | Erforderlich | Zulässige Werte | Standardwert |
|---|---|---|---|---|
model |
string | Ja | happyhorse-1.1/reference-to-video (fester Wert) |
- |
input.prompt |
string | Ja | Referenzbilder mit [Image 1], [Image 2]…… referenzieren, in derselben Reihenfolge wie reference_image |
- |
input.reference_image |
string[] | Ja | 1-9 HTTPS-URLs, Format JPEG/PNG/WEBP, kürzeste Seite ≥ 400px, jedes ≤ 20MB | - |
input.resolution |
enum | Nein | 720p, 1080p |
1080p |
input.aspect_ratio |
enum | Nein | 16:9, 9:16, 3:4, 4:3, 4:5, 5:4, 1:1, 9:21, 21:9 |
16:9 |
input.duration |
integer | Nein | 3-15 (Sekunden) | 5 |
callback.url |
string | Nein | HTTPS-URL, die Endzustandsereignisse der Task empfängt | - |
callback.when |
enum | Nein | final (derzeit einziger Wert) |
final |
Einige weniger intuitive Validierungsregeln, die du kennen solltest, bevor sie dir Ärger bereiten:
- Übergib
reference_imageauch dann als Array, wenn es nur eine Referenzbild-URL gibt. Ein direkter String führt zureference_image: got string, want array. durationmuss eine Ganzzahl zwischen 3 und 15 (einschließlich) sein.999und1liefern beide eine klare Grenzwert-Fehlermeldung.- Auf oberster Ebene gibt es kein
seed,negative_prompt,fps,cfg_scaleodersteps. Die API lehnt unbekannte Eigenschaften ab.
Die vollständige Preisgestaltung nach Kombinationen aus Auflösung und Dauer findest du auf der HiAPI-Preisseite – die Kosten variieren mit beiden Parametern resolution und duration.
Python: End-to-End + Polling
Der folgende Codeblock ist ein eigenständiger Generator, der eine Task einreicht, bis zum Endzustand pollt und das Video herunterlädt. Er ist bewusst abhängigkeitsfrei (nur requests), damit du ihn in jeden Service kopieren kannst. Eine ausführlichere Beschreibung des Request-Lebenszyklus findest du im Quickstart.
import os
import time
import requests
API = "https://api.hiapi.ai/v1/tasks"
HEADERS = {"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}"}
def submit_r2v(prompt: str, reference_images: list[str], duration: int = 5,
resolution: str = "1080p", aspect_ratio: str = "16:9") -> str:
if not 1 <= len(reference_images) <= 9:
raise ValueError("reference_image must contain 1-9 URLs")
payload = {
"model": "happyhorse-1.1/reference-to-video",
"input": {
"prompt": prompt,
"reference_image": reference_images,
"resolution": resolution,
"aspect_ratio": aspect_ratio,
"duration": duration,
},
}
r = requests.post(API, json=payload, headers=HEADERS, timeout=60)
r.raise_for_status()
data = r.json()
if data.get("code") != 200:
raise RuntimeError(f"create failed: {data}")
return data["data"]["taskId"]
def wait_for_video(task_id: str, timeout_s: int = 600, poll_s: int = 5) -> str:
deadline = time.time() + timeout_s
while time.time() < deadline:
r = requests.get(f"{API}/{task_id}", headers=HEADERS, timeout=30)
r.raise_for_status()
task = r.json()["data"]
status = task["status"]
if status == "success":
return task["output"][0]["url"]
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} did not finish in {timeout_s}s")
def download(url: str, path: str) -> None:
with requests.get(url, stream=True, timeout=300) 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 = submit_r2v(
prompt="Behalte das Subjekt-Design aus [Image 1] bei, es läuft in der Atmosphäre von [Image 2]",
reference_images=[
"https://static.hiapi.ai/example/char.jpg",
"https://static.hiapi.ai/example/mood.jpg",
],
duration=5,
resolution="720p",
aspect_ratio="9:16",
)
print("submitted", task_id)
video_url = wait_for_video(task_id)
print("ready", video_url)
download(video_url, "out.mp4")
Dieser Code tut bewusst Folgendes:
- Er liest den Schlüssel aus der Umgebungsvariable
HIAPI_API_KEY, sodass er niemals in git oder Container-Logs landet. - Er nutzt
r.raise_for_status(), um Transportfehler zu erfassen, bevor JSON geparst wird. - Er betrachtet nur
successundfailals Endzustände – alle anderen Status (queued,processingusw.) lassen die Schleife weiterlaufen. - Er lädt die Ausgabe-URL sofort herunter. Ausgabe-URLs sind signierte Adressen und laufen ab; wenn du die Datei später brauchst, übertrage sie in persistenten Speicher oder kopiere sie in deinen eigenen Bucket.
Produktion: von Polling auf Webhook umstellen
Alle 5 Sekunden zu pollen ist für ein Notebook oder einen Worker mit geringem Traffic in Ordnung. Für echte Services registriere beim Erstellen der Task einen Callback, damit HiAPI Endzustandsereignisse an deinen Endpunkt pusht – so bleiben deine Worker untätig und du zahlst nicht mehr für leere GET-Anfragen. Das vollständige Request-Schema findest du unter Task erstellen, das ergänzende Polling unter Task-Details abrufen.
payload = {
"model": "happyhorse-1.1/reference-to-video",
"input": {
"prompt": "Die Figur aus [Image 1] läuft durch die Stadtstraße aus [Image 2]",
"reference_image": [
"https://cdn.example.com/char.jpg",
"https://cdn.example.com/street.jpg",
],
"resolution": "1080p",
"aspect_ratio": "16:9",
"duration": 8,
},
"callback": {
"url": "https://your-domain.com/hiapi/callback",
"when": "final",
},
}
Der empfangende Endpunkt muss zwei Dinge berücksichtigen:
- Idempotenz nach
taskId.successundfailsind beides Endzustände; HiAPIs Wiederholungen (oder Duplikate aus deiner eigenen Retry-Schicht) stellen dieselbetaskIderneut zu. Dedupliziere, bevor du Nebenwirkungen auslöst (S3-Kopie, Slack-Nachricht, Abrechnungsereignis). - Ergänzendes Abgleich-Polling. Wenn dein Endpunkt ausfällt, gehen Callbacks verloren. Halte eine leichte Abgleich-Task bereit, die für alle Tasks, die länger als die worst-case-Generierungszeit im Status
processinghängen,GET /v1/tasks/<id>aufruft.
Fehler, die du tatsächlich antreffen wirst
Diese solltest du explizit behandeln; alles andere sind vorübergehende 5xx-Fehler, die das SDK oder dein HTTP-Client mit Backoff wiederholen sollte.
401 permission_denied– DerAuthorization-Header fehlt, ist falsch formatiert oder der Schlüssel wurde widerrufen. Fordere in der Konsole einen neuen Schlüssel an, statt den Header zu reparieren.400 INVALID_REQUESTmit Feldpfad – Die Fehlermeldung sagt dir genau, was fehlgeschlagen ist, z. B.reference_image: maxItems: got 10, want 9oderaspect_ratio: value must be one of .... Validiere Eingaben, bevor dein Worker sie einreicht, damit du lokal schnell fehlschlägst.task failed(Endzustand) – Polling/Callback liefertstatus: "fail"samterror.codeunderror.message. Häufige Ursachen: Referenzbild-URL, die der Worker nicht abrufen kann, ausgelöste NSFW-Prüfung oder ein Bild, dessen kürzeste Seite unter dem Schwellenwert von 400px liegt.
Häufige Fragen
Kann ich mehr als 9 Bilder referenzieren? Nein. Das Schema beschränkt reference_image auf maximal 9. Wenn du mehr Variationen brauchst, kombiniere außerhalb der Plattform ein dichteres Referenzbild (Rasterbild oder Storyboard) und verwende es als einzelne Eingabe.
Müssen im Prompt die [Image N]-Marker verwendet werden? Diese Marker sind deine Möglichkeit, auf bestimmte Referenzbilder zu verweisen. Ein Prompt ohne jegliche Bildangabe ist ebenfalls zulässig, aber das Modell mischt dann alle Referenzbilder frei – für Szenarien mit Multi-Shot-Konsistenz ist das meist nicht das gewünschte Ergebnis.
Warum erhalte ich 503 nsfw_moderation_unavailable? Dies ist ein vorübergehender Plattformfehler des Moderationsdienstes und hat nichts mit deiner Anfrage zu tun. Wiederhole die Anfrage nach kurzem Backoff.
Sollte ich 720p oder 1080p verwenden? 1080p ist der Standard und hat die bessere Bildqualität, ist aber teurer und langsamer beim Rendern. Für vertikale Social-Media-Clips, bei denen der Player ohnehin heruntersampelt, ist 720p mit aspect_ratio: 9:16 meist der bessere Kompromiss.
Kann ich seed übergeben, um Ausgaben reproduzierbar zu machen? Derzeit nicht. Die API betrachtet seed als unbekannte Eigenschaft und lehnt sie ab. Wenn du Reproduzierbarkeit brauchst, lege prompt, reference_image, aspect_ratio, resolution und duration exakt fest und akzeptiere eine gewisse Abweichung zwischen den Läufen.
Wo liegen die Ausgabe-URLs und wie lange sind sie gültig? Es sind signierte URLs mit kurzer TTL; die Antwort enthält expireAt. Lade die Datei nach erfolgreicher Task sofort herunter oder übertrage sie in persistenten Speicher.
Ä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