HiAPI
Blog

Tutorial

kandinsky-6.0-pro/image-to-video auf HiAPI: Tutorial mit curl und Python

Eine funktionierende Bild-zu-Video-Anfrage auf HiAPI ausführen: vom Upload des ersten Frames über asynchrones Polling bis zum finalen Download

Nov 3, 2026
深色底上青绿与石板灰的扁平液态色块相互交叠,构成 kandinsky-6.0-pro 视频教程的封面图。

Überblick über den image-to-video-Ablauf auf HiAPI

Jeder Bild-zu-Video-Aufruf auf HiAPI folgt demselben dreiphasigen Lebenszyklus. Wer das vorab versteht, erlebt den Rest des Tutorials als planmäßige Abfolge statt als Mysterium.

Phase 1: Aufgabe einreichen

Du sendest einen POST-Request an den kandinsky-6.0-pro/image-to-video-Endpunkt und übergibst dabei das erste Frame-Bild sowie einen kurzen Prompt, der die gewünschte Bewegung beschreibt. Die Antwort liefert keinen Videobytestrom, sondern nimmt die Aufgabe an und gibt eine Aufgabenkennung zurück — ein Handle, über das alle weiteren Operationen laufen.

Phase 2: Status abfragen

Die Videogenerierung braucht Zeit, deshalb ist der Endpunkt asynchron. Mit der Aufgabenkennung rufst du die Status-Route auf; sie meldet den aktuellen Zustand der Aufgabe: in der Warteschlange, in Bearbeitung, erfolgreich oder fehlgeschlagen. Du wiederholst die Prüfung in kurzen Abständen, bis der Status einen Endzustand erreicht.

Phase 3: Ausgabe abholen

Sobald die Aufgabe als erfolgreich gemeldet wird, enthält die Status-Payload den Speicherort des fertigen Videos. Du lädst es herunter und schreibst es auf die Festplatte. Das ist der gesamte Vertrag.

Warum diese Form wichtig ist

Die Trennung von Einreichen und Abfragen ist kein Zufall. Sie bedeutet, dass dein HTTP-Client den Socket nicht während der gesamten Rendering-Zeit offen halten muss, und dass du die Aufgabenkennung persistieren kannst, um später wieder anzuknüpfen. Im Fehlerfall sagt dir das Statusfeld, wo etwas schiefgelaufen ist — das ist deutlich nützlicher als ein undurchsichtiger Timeout.

Merke dir diese drei Phasen: einreichen, abfragen, herunterladen. Die folgenden curl- und Python-Beispiele sind nur zwei Schreibweisen derselben Sequenz.

Erstes Frame und API-Anmeldedaten vorbereiten

Es gibt nur zwei Stellen, an denen vor dem ersten Aufruf typischerweise etwas schiefgeht: der Schlüssel und das Bild. Kläre beides jetzt, dann läuft der Rest des Tutorials reibungslos.

API-Schlüssel als Umgebungsvariable setzen

Klebe den Schlüssel nicht in Quelldateien. Exportiere ihn in der Shell, sodass curl und Python darauf zugreifen können, ohne dass irgendetwas hartkodiert wird:

export HIAPI_API_KEY="your_api_key_here"

In der Windows PowerShell lautet die entsprechende Schreibweise $env:HIAPI_API_KEY="your_api_key_here". Bestätige vor dem Weitergehen, dass die Shell ihn lesen kann:

echo "$HIAPI_API_KEY" | head -c 4; echo

Du solltest die ersten Zeichen des Schlüssels sehen. Wenn nichts erscheint, wurde die Variable nicht in der aktuellen Shell-Sitzung persistiert — eine häufige Ursache für spätere 401-Antworten.

Ein gültiges erstes Frame wählen

Das erste Frame bestimmt Motiv, Bildkomposition und Seitenverhältnis des gesamten Videos. Ein paar praktische Einschränkungen ersparen die meisten Ablehnungen:

  • Format: Verwende ein gängiges Web-Bildformat wie JPEG oder PNG. Vermeide exotische Codecs, Progressive-Randfälle oder CMYK-Farbprofile.
  • Erreichbarkeit: Die API muss die Bytes tatsächlich lesen können. Gibst du eine URL an, stelle sicher, dass sie öffentlich erreichbar oder korrekt authentifiziert ist; gibst du Inline-Daten an, stelle sicher, dass die Kodierung vollständig ist.
  • Größe: Bilder mit vernünftigen Abmessungen werden am schnellsten validiert. Sehr große Dateien verzögern die Anfrage und sind häufig die Ursache für Upload-Fehler.
  • Inhalt: Wähle ein Frame, das als Ausgangspunkt für Bewegung sinnvoll ist — klares Motiv, aufgeräumter Hintergrund. Der Bewegungs-Prompt beschreibt, wie man sich von diesem Frame wegbewegt, daher erzeugen unruhige Frames unruhige Videos.

Entscheiden, wie das Bild referenziert wird

Der Request-Body erlaubt dir, das erste Frame per URL oder per inline kodierten Daten anzugeben. Entscheide je nachdem, wo das Bild liegt:

  • Ist die Datei bereits gehostet und öffentlich lesbar, ist die URL die sauberste Option.
  • Liegt das Bild lokal oder privat, machst du die Anfrage mit Inline-Kodierung vollständig eigenständig — auf Kosten einer größeren Payload.

Halte die Bildreferenz in beiden Fällen in curl und Python in derselben Variablenform, damit beide Beispiele direkt vergleichbar bleiben.

Anfrage mit curl senden

Dies ist eine vollständige Einreichungsanfrage. Ersetze die Bildreferenz und den Prompt durch deine eigenen und führe sie aus.

curl -sS -X POST "https://api.hiapi.ai/v1/kandinsky-6.0-pro/image-to-video" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "image": "https://your-host.example/first-frame.jpg",
    "prompt": "slow dolly-in on the subject, gentle ambient motion, stable camera",
    "duration": 5,
    "aspect_ratio": "16:9"
  }'

Was die einzelnen Teile bewirken

  • URL zeigt gezielt auf das Modell kandinsky-6.0-pro/image-to-video. Die Modellwahl steckt im Pfad, nicht im Request-Body — ein Tippfehler hier führt zu einem 404 statt zu einer freundlichen Validierungsmeldung.
  • Authorization trägt das Bearer-Token aus der von dir exportierten Umgebungsvariable. Nichts anderes authentifiziert den Aufruf.
  • Content-Type: application/json ist bei jedem POST mit JSON-Body wichtig; lässt du es weg, können manche Proxies die Payload verstümmeln, bevor sie die API erreicht.
  • image ist deine Referenz auf das erste Frame — hier in URL-Form, bei privaten Bildern als inline kodierter String.
  • prompt beschreibt die Bewegung. Halte ihn auf Bewegung und Kameravorhalten bezogen, statt zu wiederholen, was das Bild ohnehin schon enthält.
  • duration und aspect_ratio formen die Ausgabe. Das Seitenverhältnis sollte zum ersten Frame passen; Abweichungen führen zu Zuschnitt oder schwarzen Rändern. Die Abrechnung richtet sich nach der erzeugten Ausgabe, daher bestimmen diese Einstellungen auch deine Kosten.

Die Antwort lesen

Eine erfolgreiche Einreichung liefert die Aufgaben-Payload, nicht das Video. Fange daraus die Aufgabenkennung ab — du übergibst sie später an den Status-Endpunkt:

curl -sS -X POST "https://api.hiapi.ai/v1/kandinsky-6.0-pro/image-to-video" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d @body.json | jq -r '.id'

Mit einer Datei body.json anstelle von inline -d bleiben lange Prompts und kodierte Bilder lesbar. jq ist optional, verwandelt die Antwort aber in eine einzige Zeile, die sich direkt in den nächsten Aufruf einfügen lässt.

Denselben Endpunkt mit Python aufrufen

Die Python-Version ist dieselbe Anfrage mit demselben Body, nur in eine Funktion gekapselt, damit sie wiederverwendbar ist. Halte den Body identisch zur curl-Version — genau das ist der Sinn, beide zu zeigen.

import os
import json
import requests

API_BASE = "https://api.hiapi.ai/v1"
ENDPOINT = f"{API_BASE}/kandinsky-6.0-pro/image-to-video"

def submit_video_job(image_ref: str, prompt: str, duration: int = 5, aspect_ratio: str = "16:9") -> str:
    """Submit a first-frame image-to-video job and return the job id."""
    api_key = os.environ.get("HIAPI_API_KEY")
    if not api_key:
        raise RuntimeError("HIAPI_API_KEY is not set in this environment")

    body = {
        "image": image_ref,
        "prompt": prompt,
        "duration": duration,
        "aspect_ratio": aspect_ratio,
    }

    response = requests.post(
        ENDPOINT,
        headers={
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json",
        },
        json=body,
        timeout=60,
    )

    if response.status_code >= 400:
        raise RuntimeError(f"submit failed: {response.status_code} {response.text}")

    payload = response.json()
    return payload["id"]

if __name__ == "__main__":
    job_id = submit_video_job(
        image_ref="https://your-host.example/first-frame.jpg",
        prompt="slow dolly-in on the subject, gentle ambient motion, stable camera",
    )
    print(json.dumps({"job_id": job_id}, indent=2))

Hinweise zur Python-Version

  • Schnelles Scheitern bei fehlendem Schlüssel. Die explizite Umgebungsprüfung verwandelt den häufigsten Fehler in einen klaren lokalen Fehler statt in einen entfernten 401.
  • json=body versus data=json.dumps(body). Mit json= setzt requests den Inhaltstyp für dich, wodurch die Header minimal bleiben. Bei data= setze Content-Type explizit.
  • Großzügiges Timeout. Das Einreichen von Videos umfasst manchmal die Übertragung großer Bild-Payloads. Ein zu kurzes Timeout erzeugt falsche Fehler.
  • Antwort-Body bei Fehlern lesen. Statuscode und Antwort-Body gemeinsam zu werfen bedeutet, dass die Fehlermeldung dir tatsächlich sagt, was die API ablehnt.

Ist das erste Frame eine lokale Datei, lies sie ein, kodiere sie mit base64 und ersetze image_ref innerhalb von submit_video_job durch diesen String. Die Funktionssignatur bleibt unverändert — deshalb teilen sich beide Aufrufstile dieselbe Body-Definition.

Aufgabe abfragen und Video herunterladen

Eine eingereichte Aufgabe ist noch kein fertiges Video. Frage ab, bis die Aufgabe einen Endzustand erreicht, und lade dann herunter.

Die Polling-Schleife

import time
import requests

def wait_for_video(job_id: str, interval: float = 10.0, max_wait: float = 600.0) -> str:
    """Poll the job until it finishes; return the output URL."""
    import os
    api_key = os.environ["HIAPI_API_KEY"]
    url = f"https://api.hiapi.ai/v1/kandinsky-6.0-pro/image-to-video/{job_id}"
    headers = {"Authorization": f"Bearer {api_key}"}

    deadline = time.time() + max_wait
    while time.time() < deadline:
        response = requests.get(url, headers=headers, timeout=30)
        response.raise_for_status()
        payload = response.json()
        status = payload.get("status")

        if status == "succeeded":
            return payload["output"]
        if status == "failed":
            raise RuntimeError(f"job failed: {payload.get('error', 'unknown error')}")

        time.sleep(interval)

    raise TimeoutError(f"job {job_id} did not finish within {max_wait}s")

Drei Details lassen diese Schleife gut funktionieren:

  • Mit Abstand zurückhaltend statt auf Glück setzen. Ein fester Sleep von etwa zehn Sekunden ist ein sinnvoller Ausgangspunkt; hämmere nicht in einer engen Schleife auf den Endpunkt ein.
  • Jeden Endzustand behandeln. succeeded liefert dir die Ausgabe, failed die Fehlermeldung. Beide sollten als Abbruch gelten. Eine Schleife, die nur Erfolg prüft, dreht sich bei einer toten Aufgabe bis zur Deadline weiter.
  • Wartezeit begrenzen. max_wait garantiert, dass das Skript endet, statt hinter einer hängenden Aufgabe ewig weiterzulaufen.

Das fertige Video herunterladen

Sobald du die Ausgabe-URL hast, schreibe sie streamend auf die Festplatte, statt die ganze Datei in den Speicher zu laden:

def download_video(output_url: str, path: str = "result.mp4") -> str:
    with requests.get(output_url, stream=True, timeout=120) as response:
        response.raise_for_status()
        with open(path, "wb") as handle:
            for chunk in response.iter_content(chunk_size=8192):
                if chunk:
                    handle.write(chunk)
    return path

Alles zusammenfügen:

job_id = submit_video_job(
    image_ref="https://your-host.example/first-frame.jpg",
    prompt="slow dolly-in on the subject, gentle ambient motion, stable camera",
)
output_url = wait_for_video(job_id)
saved = download_video(output_url, "kandinsky_result.mp4")
print(f"saved to {saved}")

Persistiere in der Produktion die job_id in dem Moment, in dem die Einreichung erfolgreich ist. Startet der Prozess neu, kannst du mit der gespeicherten Kennung wieder in die Polling-Schleife einsteigen, statt für eine neue Einreichung zu bezahlen.

Häufige Anfrage- und Aufgabenfehler beheben

Die meisten Fehler fallen in drei Kategorien: Schlüssel, Bild oder Aufgabenstatus. Isoliere die Kategorie, bevor du irgendetwas anderes änderst.

Schlüssel abgelehnt

Symptom: Authentifizierungs- oder Autorisierungsfehler, bevor irgendeine Aufgabe erstellt wird.

  • Stelle sicher, dass die Variable tatsächlich in der aktuellen Shell exportiert ist: echo "$HIAPI_API_KEY".
  • Prüfe, ob Leerzeichen oder Zeilenumbrüche mit dem Schlüssel eingefügt wurden; entferne sie.
  • Verifiziere, dass der Header Authorization heißt und der Wert mit Bearer gefolgt von einem Leerzeichen beginnt.
  • Funktioniert curl, aber Python nicht, gib os.environ.get("HIAPI_API_KEY") aus derselben Interpreter-Instanz aus — die Variable existiert vielleicht in deiner Shell, aber nicht in der Umgebung, die das Skript erbt.

Bild abgelehnt

Symptom: Validierungsfehler beim Einreichen oder sofort fehlgeschlagene Aufgabe.

  • Falsches oder exotisches Format. Exportiere erneut als Standard-JPEG oder -PNG und versuche es noch einmal. CMYK-Profile und ungewöhnliche Codecs sind häufige Übeltäter.
  • URL nicht erreichbar. Öffne deine Bild-URL in einem Inkognito-Browserfenster; wenn du die Bytes nicht bekommst, bekommt sie die API auch nicht.
  • Inline-Kodierung beschädigt. Wenn du lokal base64 kodierst, dekodiere den String einmal und bestätige, dass es ein gültiges Bild ist, bevor du ihn sendest.
  • Seitenverhältnis passt nicht. Kommt das Video zugeschnitten oder mit schwarzen Rändern zurück, richte aspect_ratio am ersten Frame aus, statt dich nachträglich mit der Ausgabe herumzuschlagen.

Aufgabe endet nicht oder schlägt fehl

Symptom: Der Status bleibt bei queued/processing stehen oder meldet failed.

  • Das error-Feld lesen. Fehlgeschlagene Aufgaben enthalten eine Meldung. Sie weist meist auf das fehlerhafte Feld oder die Bedingung hin. Rate nicht — protokolliere die gesamte Status-Payload.
  • Das asynchrone Design respektieren. Ein paar Sekunden bis zur nächsten Prüfung zu warten ist normal. Eine enge Retry-Schleife, die nach zwei Sekunden aufgibt, ist kein Status-Mechanismus.
  • Wartezeit begrenzen. Überschreitet eine Aufgabe eine sinnvolle Obergrenze, behandle sie als fehlgeschlagen, gib die Aufgaben-ID aus und reiche eine neue Aufgabe ein, statt endlos zu pollen.
  • Mit einem bekannt funktionierenden Aufruf vergleichen. Schlägt ein eigenes Bild fehl, führe den exakten curl aus dem früheren Teil dieses Tutorials mit einem kleinen öffentlichen Bild und einem kurzen Prompt aus. Gelingt das, liegt das Problem in deiner Eingabe; schlägt auch das fehl, liegt es an den Anmeldedaten oder der Anfrageform.

Download-Fehler nach Erfolg

Meldet die Aufgabe succeeded, aber der Download schlägt fehl, ist die Ausgabe-URL möglicherweise abgelaufen oder zugriffskontrolliert. Frage die Aufgabe erneut ab, um einen neuen Ausgabeort zu erhalten, statt die abgelaufene URL zu wiederholen.

Arbeite diese Kategorien der Reihe nach ab — Schlüssel, dann Bild, dann Aufgabenstatus —, und jeder Fehler lässt sich schnell auf eine Ursache eingrenzen. Das ist der ganze Kreislauf: erstes Frame einreichen, bis zur Fertigstellung abfragen, Ergebnis herunterladen.

Ähnliche Artikel

Alle Artikel ansehen →

Starte mit persistenten KI-Artefakten

Hol dir deinen API-Key und rufe Bild-, Video- und Audiomodelle über eine einzige task-basierte API auf.

API-Dokumentation lesen