HiAPI
Blog

Tutorial

So verwenden Sie kling-3.0-omni/image-to-video über die HiAPI API: curl- und Python-Leitfaden

Nov 3, 2026
扁平液状色块交叠的抽象封面图,墨色底上点缀青瓷绿与石板灰,用于该教程文章。

Was der image-to-video-Endpunkt tut

Die Videogenerierung ist kein einzelner synchroner Aufruf. Auf HiAPI folgt kling-3.0-omni/image-to-video dem Muster erst einreichen, dann abfragen: Sie senden eine HTTP-Anfrage, die die Aufgabe beschreibt, die API nimmt sie an und gibt eine Aufgabenkennung zurück, danach fragen Sie diese Aufgabe ab, bis das Video fertig generiert ist.

Diese zweistufige Struktur hat gute Gründe. Das Rendern eines Videos aus einem Standbild braucht Zeit – weit mehr, als ein typischer HTTP-Request offen bleiben sollte. Wenn der Endpunkt blockieren würde, bis die Datei bereit ist, würden Sie bei jedem Aufruf auf Gateway-Timeouts und Verbindungsabbrüche stoßen. Indem die API sofort einen Aufgaben-Handle zurückgibt, überlässt sie Ihrem Code die Entscheidung, wie lange gewartet, wie oft geprüft und was im Fehlerfall getan werden soll.

Eine typische Aufgabe besteht aus drei logischen Teilen:

  • Eingabemedien – das Bild (oder die Bildmenge), das der Aufnahme als Anker dient.
  • Generierungseinstellungen – Prompt-Text, bewegungsbezogene Optionen, Audio- und Auflösungswahl.
  • Lebenszyklus – die Einreichungsantwort mit der Aufgaben-ID, gefolgt von Statusprüfungen, die schließlich eine Video-URL oder einen Fehlergrund liefern.

Es hilft, sich diesen Endpunkt als Warteschlange mit Quittung vorzustellen. Der Einreichungsaufruf ist Ihre Auftragsabgabe; die Quittung ist die Aufgaben-ID; der Abfrageaufruf ist Ihre Nachfrage am Schalter, ob die Bestellung fertig ist. Beim Einreichen kommt kein Video selbst zurück, daher sollte jeder Client, den Sie schreiben, von Anfang an um diese beiden Phasen herum aufgebaut sein.

Daraus ergeben sich zwei Konsequenzen. Erstens muss Ihre Fehlerbehandlung getrennt werden: Ein abgelehnter Request-Body ist ein Problem beim Einreichen, das sich im Code beheben lässt; ein Render-Fehler ist ein Problem auf Aufgabenebene, das sich nicht durch wiederholtes Senden desselben Bodys lösen lässt. Zweitens brauchen Sie einen Ort, um die Aufgaben-ID zu speichern – eine Logzeile, eine Datenbankzeile, eine Variable im Skript –, denn sie ist der einzige Handle auf Ihre laufende Arbeit.

Wenn dieses mentale Modell steht, ist der Rest dieses Leitfadens vor allem Fleißarbeit: die Anfrage bauen und dann korrekt auf sie warten.

Einen funktionierenden curl-Request bauen

Beginnen Sie mit der kleinstmöglichen funktionierenden Anfrage, bestätigen Sie deren Annahme und fügen Sie erst dann Optionen hinzu. Die genauen JSON-Feldnamen und der Endpunktpfad sind auf der Referenzseite dieses Modells bei HiAPI definiert – konsultieren Sie diese Seite für das aktuelle Schema, statt Snippets aus Blogbeiträgen (auch diesem) zu vertrauen.

Der Einreichungsaufruf hat eine vorhersehbare Struktur. Sie authentifizieren sich mit einem HiAPI-API-Key im Header Authorization, geben Content-Type: application/json an und senden einen JSON-Body. Konzeptionell sieht der Body so aus:

{
  "model": "kling-3.0-omni/image-to-video",
  "input": {
    "image": "https://your-cdn.example.com/frame-first.jpg",
    "prompt": "A slow dolly-in as morning light crosses the room"
  }
}

Die Struktur ist wichtiger als die konkreten Werte: der Modellbezeichner, ein Eingabeobjekt mit Bildreferenz und Prompt sowie Platz für Generierungsoptionen. Verifizieren Sie alles gegen die aktuelle Dokumentation, bevor Sie jeden Schlüssel hartkodieren.

Der entsprechende curl-Aufruf folgt dem üblichen Muster:

curl -sS -X POST "$HIAPI_BASE_URL/v1/video/generations" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d @request.json

Den Body in request.json statt inline zu halten, macht die Iteration deutlich einfacher – Sie bearbeiten eine Datei statt eines Eintrags in der Shell-History.

Die Antwort lesen

Eine erfolgreiche Einreichung ist bewusst unspektakulär. Erwartet wird eine Aufgabenkennung und ein Status, der „angenommen, aber nicht abgeschlossen“ ausdrückt. Parsen, ausgeben und speichern:

curl -sS -X POST "$HIAPI_BASE_URL/v1/video/generations" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d @request.json | tee submit.json

Prüfen Sie zuerst den HTTP-Statuscode. 4xx bedeutet, die Anfrage selbst wurde abgelehnt – falscher Key, fehlerhaftes JSON, nicht unterstützte Optionen, ungültige Bild-URL. 2xx bedeutet, die Aufgabe ist im System; ab diesem Moment kommt das nützliche Signal aus dem Aufgabenstatus, nicht aus dem HTTP-Statuscode.

Führen Sie vor dem Schreiben von Abfragecode eine Einreichung manuell aus. Bestätigen Sie, dass Sie die Aufgaben-ID in der Ausgabe sehen. Dieser manuelle Durchlauf deckt die meisten Konfigurationsfehler früh auf.

Eingaben für erstes und letztes Frame handhaben

Das gesendete Bild ist nicht bloß eine Referenz – es legt den Startpunkt der Aufnahme fest. Dieser Unterschied bestimmt den Großteil der Designentscheidungen in diesem Abschnitt.

Nur erstes Frame

Wenn Sie ein einzelnes Bild liefern, behandeln Sie es als Eröffnungsframe. Der Prompt beschreibt dann, was ab diesem Frame geschehen soll: Kamerabewegung, Handlung des Motivs, Lichtveränderungen, Tempo. Da das Modell alles nach dem ersten Frame erzeugen muss, funktionieren Prompts, die eine Bewegung beschreiben, besser als solche, die eine statische Szene beschreiben. „Bewegungslos bleiben, sieht schön aus“ gibt dem Modell nichts Animierbares; „sie wendet sich dem Fenster zu, und das Licht wird wärmer“ gibt ihm eine Richtung.

Ein letztes Frame hinzufügen

Ein Eingang für das letzte Frame macht die Aufgabe zu einem Interpolationsproblem. Sie liefern zwei Endpunkte, und das Modell erzeugt den Weg dazwischen. Das ist mächtig für kontrollierte Übergänge – ein Produkt dreht sich von der Vorder- zur Rückansicht, eine Figur wechselt zwischen zwei Posen –, weil der Endpunkt festgelegt statt erdacht wird.

Drei praktische Hinweise:

  • Halten Sie beide Frames kompatibel. Ähnliche Bildkomposition, Perspektive und Proportionen des Motivs machen die Interpolation glaubwürdig. Stark abweichende Kompositionen zwingen das Modell, eine Brücke zu erfinden, die es womöglich nicht gibt.
  • Schreiben Sie den Prompt um. Mit zwei Frames sollte Ihr Text die Bewegung zwischen ihnen beschreiben, nicht die Endpunkte. Einen Bewegungsstil und eine Dauer zu nennen, ist natürlicher, als den bereits gelieferten Endzustand zu erzählen.
  • Rechnen Sie mit einer Änderung der Request-Struktur. Das letzte Frame ist ein eigenes Eingabefeld, Ihr Body hat also einen Schlüssel mehr. Bauen Sie das Request-Objekt so, dass optionale Felder ohne Umbau ergänzt werden können.

Behandeln Sie die Frames im Code als kleine Menge benannter Eingaben statt als lose URL-Sammlung:

inputs = {"image": first_frame_url}
if last_frame_url:
    inputs["last_frame"] = last_frame_url

Diese Bedingung hält Einzel- und Zwei-Frame-Aufrufe auf demselben Codepfad, was wichtig wird, sobald Sie Varianten erzeugen.

Zuletzt sollten die Frames an einem zuverlässig erreichbaren Ort gehostet werden. Eine URL, die mitten in der Aufgabe abläuft, führt zu einem Fehler nach der Einreichung, und der Fehler sieht wie ein Generierungsfehler aus statt wie ein Ressourcenproblem.

Audio und Ausgabeauflösung konfigurieren

Audio und Auflösung sind Entscheidungen pro Anfrage, keine globalen Einstellungen. Sie legen sie pro Aufgabe fest, was bedeutet, dass sie in den Body-Builder neben den Prompt gehören und nicht in eine Konfigurationskonstante, die man einmal setzt und vergisst.

Audio

Die Audio-Option erlaubt üblicherweise, dem Video eine Tonspur hinzuzufügen oder sie wegzulassen. Betrachten Sie das als Modellierungsentscheidung je nach Anwendungsfall: Ein Social-Clip kann von generiertem Audio profitieren, während ein Clip, den Sie im Editor vertonen, kein Audio tragen sollte. Audio anzufordern, das Sie nie verwenden, verschwendet Generierungszeit ohne Nutzen.

Da das Audio-Verhalten einer der Bereiche ist, die sich am ehesten weiterentwickeln, sollten Sie keine Annahmen über den Inhalt der Tonspur oder ihren Bezug zum Prompt hartkodieren. Lesen Sie die aktuelle Modelldokumentation und validieren Sie die Ausgabe mit einer echten Aufgabe, bevor Sie nachgelagerte Prozesse darauf aufbauen.

Auflösung

Höhere Auflösung bedeutet mehr Pixel pro Frame und deutlich mehr Rechenaufwand. Ein praktischer Workflow: Iterieren Sie mit moderater Auflösung, während Sie Prompt und Frame-Auswahl abstimmen, und generieren Sie die gewinnende Konfiguration anschließend in der finalen Auflösung neu. Ein gutes Ergebnis neu zu generieren ist viel günstiger, als am Ende festzustellen, dass Ihr bestes Ergebnis mit falschen Einstellungen entstanden ist.

Ein paar lohnende Gewohnheiten:

  • Vor dem Einreichen validieren. Wenn das Modell die übergebene Auflösung nicht unterstützt, möchten Sie eine klare Ablehnung beim Einreichen statt eines verwirrenden Fehlers auf Aufgabenebene Minuten später.
  • Einstellungen zusammen mit der Aufgabe speichern. Wenn Sie mehrere Ergebnisse vergleichen, müssen Sie wissen, mit welcher Auflösung und Audio-Wahl jedes entstanden ist.
  • Keine Gleichheit zwischen Frames annehmen. Eine Zwei-Frame-Aufgabe mit großen Quellbildern kann sich anders verhalten als eine Einzel-Frame-Aufgabe; testen Sie beide Pfade.

Wo diese im Code hingehören

Gruppieren Sie die Generierungsoptionen in einem eigenen Objekt, damit die Absicht offensichtlich wird und Sie Standardwerte an einer Stelle ersetzen können:

options = {
    "resolution": "1080p",   # confirm supported values in the model docs
    "audio": True,
}

Fügen Sie Kommentare zu Zeilen hinzu, die von dokumentierten Werten abhängen. Ihr zukünftiges Ich – oder ein Teammitglied – sollte sofort erkennen, welche Felder sicher sind und welche vor einer Veröffentlichung gegen die Referenzseite geprüft werden müssen. Im Zweifel ist die Modelldokumentation auf HiAPI die Quelle der Wahrheit, nicht ein Beispiel-Body.

Den Abschluss in Python abfragen

Abfragecode ist der Ort, an dem die meisten Integrationen stillschweigend fragil werden. Das Ziel ist ein kleiner, wiederverwendbarer Client, der die Aufgabe einreicht und mit vernünftigen Grenzen auf sie wartet – statt eines Skripts, das Sie jedes Mal kopieren, einfügen und anpassen.

Minimale Client-Struktur

import os, time, requests

BASE = os.environ["HIAPI_BASE_URL"]
KEY = os.environ["HIAPI_API_KEY"]
HEADERS = {"Authorization": f"Bearer {KEY}"}

def submit(payload: dict) -> str:
    r = requests.post(f"{BASE}/v1/video/generations",
                      headers=HEADERS, json=payload, timeout=30)
    r.raise_for_status()
    return r.json()["id"]

def wait(task_id: str, interval: float = 5.0, max_wait: float = 600.0) -> dict:
    deadline = time.monotonic() + max_wait
    while time.monotonic() < deadline:
        r = requests.get(f"{BASE}/v1/video/generations/{task_id}",
                         headers=HEADERS, timeout=30)
        r.raise_for_status()
        job = r.json()
        if job["status"] in ("succeeded", "failed"):
            return job
        time.sleep(interval)
    raise TimeoutError(f"task {task_id} not finished in {max_wait}s")

Vier Details in diesem Code tragen den Großteil der Verantwortung:

  • Explizite Timeouts bei jedem HTTP-Aufruf. Ein hängender Request ist schlimmer als ein fehlgeschlagener.
  • Maximale Wartezeit. Eine unbegrenzte Schleife macht aus einer hängenden Aufgabe einen hängenden Dienst.
  • Prüfung auf Endzustände. Stoppen Sie erst, wenn der Status wirklich final ist; behandeln Sie alles andere als noch laufend, einschließlich Status, die Sie nicht kennen.
  • Das gesamte Aufgabenobjekt zurückgeben. Aufrufer brauchen meist die Ausgabe-URL und etwaige Fehlerdetails, nicht nur einen Boolean.

Abfragerhythmus

Für Videoaufgaben sind fünf Sekunden ein vernünftiger Standardwert. Alle 200 ms abzufragen verbraucht Kontingent ohne Nutzen, da das Rendern ohnehin Minuten dauert. Wenn Sie viele Aufgaben einreichen, legen Sie die Abfrageschleife in einen Worker statt in den Request-Handler und lassen Sie bei lang laufenden Aufgaben etwas mehr Pause.

Alles verbinden

payload = {
    "model": "kling-3.0-omni/image-to-video",
    "input": {"image": first_frame_url, "prompt": prompt},
    "options": options,
}

job = wait(submit(payload))
if job["status"] == "failed":
    raise RuntimeError(job.get("error") or "generation failed")
print(job["output"]["url"])

Da submit einen einfachen String und wait ein Dict zurückgibt, können Sie jede Hälfte separat testen: Simulieren Sie Einreichungsantworten, um die Abfragelogik zu testen, und rufen Sie submit allein auf, um den Body gegen die Live-API zu prüfen.

Häufige Fehler debuggen

Fehler konzentrieren sich auf drei Ebenen; die Ebene zu erkennen, ist schon der größte Teil der Diagnose.

Ebene 1: Ablehnung beim Einreichen

Diese erscheinen als 4xx-Antworten, bevor eine Aufgabe überhaupt existiert. Häufige Ursachen:

  • Authentifizierung – fehlender Header, falsch formatiertes Bearer-Token, Key nicht in der Umgebung exportiert, die Sie annehmen.
  • Body-Struktur – Feld falsch geschrieben, String an einer Array-Position, falsche Verschachtelungstiefe der Optionen.
  • Nicht unterstützte Werte – Auflösung oder Audio-Kombination, die das Modell nicht akzeptiert.
  • Ressourcenprobleme – nicht erreichbare, abgelaufene oder keine Bilddatei-URL.

Lesen Sie den Fehler-Body. Die API benennt meist das problematische Feld, und die schnellste Lösung ist oft die in der Meldung vorgeschlagene. Reproduzieren Sie den fehlgeschlagenen Aufruf in curl, um zu bestätigen, dass das Problem im Body liegt und nicht im Client-Code.

Ebene 2: Übertragungsprobleme

Das Netzwerk liegt zwischen Ihrem Code und dem Aufgabenlebenszyklus. Timeouts und Verbindungsabbrüche beim Einreichungsaufruf sind mehrdeutig: Die Aufgabe kann erzeugt worden sein oder auch nicht. Wenn Sie blind wiederholen, können doppelte Aufgaben entstehen.

Das sichere Muster ist, nur idempotent sichere Operationen zu wiederholen und jeden Einreichungsversuch samt Antwort zu protokollieren. Wenn Sie wirklich nicht feststellen können, ob die Einreichung erfolgreich war, prüfen Sie den Aufgabenverlauf, bevor Sie erneut einreichen. Beim Abfragen gilt: Eine fehlgeschlagene Statusprüfung ist kein fehlgeschlagener Task – Ausnahme abfangen, warten, erneut fragen.

Ebene 3: Fehler auf Aufgabenebene

Diese erreichen eine ursprünglich angenommene Aufgabe als Endstatus. Sie bedeuten meist, dass der Inhalt nicht wie angegeben generiert werden kann: Die beiden Frames sind zu verschieden für eine Interpolation, der Prompt passt nicht zum Quellbild, oder es gab einen internen Fehler beim Rendern.

Unterscheiden Sie diese in Ihrem Code klar, denn die Abhilfen sind verschieden. 4xx heißt Anfrage korrigieren. Ein fehlgeschlagener Task heißt Eingaben ändern oder erneut versuchen – scheitert derselbe Body zweimal, hören Sie auf zu wiederholen und ändern Sie etwas: Prompt vereinfachen, näher beieinanderliegende Frames wählen, Auflösung senken.

Schnelle Triage-Checkliste

  1. Ist der HTTP-Status 4xx? Body oder Anmeldedaten korrigieren; nicht abfragen.
  2. Erfolgreich eingereicht, aber die Aufgabe wird nie fertig? Ihr Wartelimit ist zu kurz oder die Aufgabe hängt – Aufgaben-ID protokollieren und untersuchen, statt endlos zu schleifen.
  3. Ist die Aufgabe fehlgeschlagen? Fehlerdetails lesen und dann die Eingaben anpassen, statt unverändert erneut einzureichen.
  4. Erfolgreich, aber das Video ist falsch? Das ist ein Prompt- und Frame-Auswahlproblem, kein API-Problem.

Veröffentlichen: Produktions-Checkliste

Härten Sie die Teile, die stillschweigend versagen, bevor Benutzer sie erreichen.

Konfiguration. Base-URL und API-Key in Umgebungsvariablen oder einem Secret-Manager halten, niemals im Quellcode. Fehlt eines von beiden, scheitern Sie beim Start schnell – nicht erst bei der ersten Benutzeranfrage.

Timeouts und Retries. Jeder ausgehende Aufruf braucht ein explizites Timeout. Wiederholen Sie Einreichungen nur dort, wo Duplikate tolerierbar sind, und behandeln Sie Abfrage-Wiederholungen als sicher – idempotente Statusauslesungen. Begrenzen Sie die Gesamtwartezeit und melden Sie dem Aufrufer ein klares Timeout.

Die Aufgaben-ID ist der Beleg. Persistieren Sie die Aufgaben-ID zusammen mit dem eingereichten Body: Frames, Prompt, Auflösung, Audio-Wahl und Zeitstempel. Wenn jemand zwei Wochen später fragt, warum das Video falsch aussieht, ist diese Zeile die vollständige Antwort.

Die Ausgabe ist temporär. Behandeln Sie die zurückgegebene Video-URL als flüchtig. Sobald eine Aufgabe erfolgreich ist, laden Sie sie herunter, legen Sie sie in Ihrem eigenen dauerhaften Speicher ab und protokollieren Sie den Speicherort an der Aufgabe.

Kostenbewusstsein. Videogenerierung wird nach generierter Ausgabe abgerechnet, daher sind Auflösung, Dauer und Anzahl der Generierungen die entscheidenden Hebel. Iterieren Sie mit niedriger Auflösung, generieren Sie die endgültige Fassung bewusst und protokollieren Sie die Einstellungen, damit sich Ausgaben einem Anwendungsfall zuordnen lassen, statt erst auf der Rechnung aufzufallen.

Beobachtbarkeit. Geben Sie bei Einreichung und bei Endstatus Logzeilen mit Aufgaben-ID, Latenz und Status aus. Eine einfache Erfolgsquoten-Metrik pro Modell zeigt Ihnen, wann Prompt-Änderungen oder Optionsanpassungen beginnen, Aufgaben scheitern zu lassen.

Gegen die Dokumentation validieren, nicht gegen Beispiele. Bestätigen Sie vor jeder Veröffentlichung, die Audio, Auflösung oder Frame-Eingaben betrifft, auf der Modellreferenzseite die Feldnamen und akzeptierten Werte, denn diese Einstellungen driften am ehesten.

Mit dem Client, der Abfrageschleife und diesen Schutzmaßnahmen wird kling-3.0-omni/image-to-video zu einer vorhersagbaren Komponente statt zu einem Skript, bei dem Sie beten, dass es noch funktioniert.

Ä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