HiAPI
Blog

Tutorial

So verwendest du nano-banana über die HiAPI API: curl, Python und lauffähige Anfragen

Der komplette Praxisablauf von der ersten Anfrage bis zum heruntergeladenen Ergebnis

Oct 31, 2026
博客封面图:错位叠放的骨白色纸张,炭灰边缘,夹一张锈红色纸片,扁平投影。

So sieht eine nano-banana-Anfrage aus

Bevor du Code schreibst, ist es hilfreich, den Lebenszyklus eines nano-banana-Aufrufs auf HiAPI zu verstehen. Jede Anfrage folgt demselben Muster: Du sendest einen JSON-Anfragekörper, der beschreibt, was du willst, HiAPI nimmt den Auftrag an, und dann bekommst du entweder direkt das fertige Ergebnis zurück oder ein Auftrags-Handle, mit dem du den Fertigstellungsstatus abfragst.

Einige Merkmale definieren seine Form:

  • Ein Endpunkt, ein API-Schlüssel. Der gesamte nano-banana-Datenverkehr läuft über die einheitliche HiAPI-Schnittstelle. Du authentifizierst dich mit deinem HiAPI-Schlüssel und kommst nie direkt mit dem Upstream in Berührung.
  • JSON rein, JSON raus. Der Anfragekörper ist JSON. Die Antwort ist ebenfalls JSON und enthält entweder ein Inline-Ergebnis oder eine Auftrags-ID plus ein Statusfeld.
  • Text Pflicht, Bild optional. Mindestens musst du einen Prompt senden. Du kannst Referenzbilder hinzufügen, um Motiv, Stil oder Figur zu lenken.
  • Asynchron-freundlich. Die Bilderzeugung kann länger dauern als ein typisches HTTP-Timeout, daher unterstützt die API asynchrone Aufträge, die du abfragen kannst, bis sie abgeschlossen sind.

Die ungefähre Struktur des Anfragekörpers:

{
  "model": "nano-banana",
  "prompt": "a description of the image you want",
  "image_input": ["https://.../reference.jpg"],
  "consistency": "character",
  "async": true
}

Die Antwort im asynchronen Fall:

{
  "id": "job_abc123",
  "status": "queued",
  "created_at": "..."
}

Wenn der Auftrag abgeschlossen ist und du ihn abrufst, wird status zu succeeded (oder failed), und die Ergebnisnutzlast enthält die Ausgabe-URL. Behalte dieses zweistufige Modell im Kopf, denn alles Weitere in diesem Tutorial baut darauf auf.

Eine lauffähige curl-Anfrage

Dies ist die minimale Anfrage, die ein Bild erzeugt. Sie setzt voraus, dass HIAPI_API_KEY in deiner Shell exportiert wurde:

curl -X POST https://api.hiapi.ai/v1/images/generations \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "nano-banana",
    "prompt": "a cozy reading nook by a rain-streaked window, warm lamp light, watercolor style",
    "async": true
  }'

Feld für Feld erklärt:

  • model — auf nano-banana setzen. HiAPI nutzt es, um die Anfrage zu routen.
  • prompt — das einzige strikt erforderliche kreative Feld. Beschreibe Motiv, Komposition und Stil konkret; vage Prompts sind die häufigste Ursache für enttäuschende Ergebnisse.
  • async — bei true gibt die API sofort ein Auftrags-Handle zurück. Wenn du blockieren möchtest, bis der Auftrag fertig ist, setze es auf false, aber stelle dich auf längere Antwortzeiten ein.
  • image_input — ein optionales Array von Referenzbild-URLs. Lass es weg, wenn du rein aus Text generierst.
  • consistency — optionale Steuerung von Figur oder Motiv über mehrere Bilder hinweg; Details weiter unten.

Wenn du unsicher bist, welche optionalen Parameter die aktuelle Version unterstützt, schau zuerst auf der Dokumentationsseite des Modells bei HiAPI nach, bevor du Felder hinzufügst — unbekannte Felder können je nach Parameter ignoriert oder abgelehnt werden.

Führe den Befehl aus und prüfe das JSON. Angenommen async ist true, bekommst du ein Auftragsobjekt statt eines Bildes zurück. Speichere die id; das ist dein Handle für den nächsten Schritt.

Die Anfrage nach Python portieren

Der curl-Aufruf lässt sich direkt übersetzen. Das Ziel ist hier nicht nur ein Einmalskript, sondern ein wiederverwendbarer Wrapper, den du in eine Pipeline einbauen kannst.

import os
import time
import requests

BASE = "https://api.hiapi.ai"
HEADERS = {
    "Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}",
    "Content-Type": "application/json",
}

def create_image(prompt, image_input=None, consistency=None, async_job=True):
    body = {"model": "nano-banana", "prompt": prompt, "async": async_job}
    if image_input:
        body["image_input"] = image_input
    if consistency:
        body["consistency"] = consistency

    resp = requests.post(
        f"{BASE}/v1/images/generations",
        headers=HEADERS,
        json=body,
        timeout=60,
    )
    if resp.status_code >= 400:
        raise RuntimeError(f"create failed: {resp.status_code} {resp.text}")
    return resp.json()

Folgende Punkte machen es robust und nicht nur benutzbar:

  • Explizites Timeout. Übergib immer eines; der Standardwert „ewig warten“ verwandelt ein vorübergehendes Netzwerkproblem in einen hängenden Prozess.
  • Status vor der Auswertung prüfen. Bei fehlerhaften Antworten eine Exception werfen, damit eine fehlerhafte Anfrage nicht stillschweigend einen JSON-Körper zurückgibt, auf den du anschließend zugreifst.
  • Optionale Felder weglassen statt auf null setzen. Statt "image_input": null zu senden, füge den Schlüssel nur hinzu, wenn ein Wert vorhanden ist. Das macht Logs lesbarer und vermeidet die Mehrdeutigkeit, ob null „keine“ oder „nicht gesetzt“ bedeutet.

Durch das Verpacken in eine Funktion werden auch Wiederholungen einfach: Da die Funktion bei Fehlern eine Exception wirft, kann der Aufrufer sie in eine Retry-Schleife packen, ohne den Anfragecode anzufassen. Sobald du von einzelnen Bildern zur Stapelverarbeitung übergehst, zahlt sich diese Trennung aus.

Text- und Bildeingaben senden

Text-zu-Bild ist der einfache Fall. Der interessante Teil von nano-banana liegt darin, Prompt und Referenzbilder in einer einzigen Anfrage zu kombinieren. Du übergibst image_input als URL-Array, und der Prompt beschreibt, wie damit umzugehen ist.

result = create_image(
    prompt="the person in the first image standing in a Tokyo alley at night, neon reflections, cinematic",
    image_input=["https://example.com/portrait.jpg"],
)

Praktische Tipps für gemischte Modalitäten:

  • Rollen eindeutig machen. Wenn du mehrere Bilder sendest, gib im Prompt an, welches das Motiv, welches den Stil und welches den Hintergrund liefert. „Kombiniere diese Bilder“ ist vage; „Verwende das Gesicht aus Bild eins und die Beleuchtung aus Bild zwei“ ist es nicht.
  • Erreichbare und stabile URLs verwenden. Die API muss die Bilder abrufen können. Signierte URLs, die nach einigen Minuten ablaufen, sind für Live-Aufrufe in Ordnung, versagen aber, wenn du einen in der Warteschlange befindlichen Auftrag später erneut versuchst.
  • Saubere Referenzen bevorzugen. Klare, gut beleuchtete Porträts erzielen eine treuere Ähnlichkeit als überfüllte Gruppenfotos. Garbage in, garbage out zeigt sich bei der Bildkonditionierung deutlicher als bei Text.
  • Zuerst den Prompt iterieren, nicht das Referenzbild. Wenn die Ähnlichkeit nicht stimmt, passe zuerst die Art an, wie du das Motiv beschreibst, bevor du das Quellbild austauschst — das ist meist die einfachere Änderung.

Wenn das Referenzbild eine Person enthält, die du über mehrere Generierungen hinweg wiederverwenden willst, betrittst du das Gebiet der Figurenkonsistenz, also den nächsten Abschnitt.

Optionen für Figurenkonsistenz

Figurenkonsistenz beantwortet ein konkretes Bedürfnis: mehrere Bilder zu erzeugen, die scheinbar dieselbe Figur oder dasselbe Motiv zeigen. nano-banana stellt dies als optionale Steuerung bereit, nicht als separates Modell.

Im Großen und Ganzen sehen die Abwägungen so aus:

  • Keine Konsistenzsteuerung. Am besten für einmalige Bilder. Schnell und einfach, aber bei Neugenerierung kann die Figur abweichen. Für Hintergründe, Objekte und eigenständige Illustrationen geeignet.
  • Referenzbasierte Konsistenz. Du gibst ein oder mehrere Bilder der Figur an und setzt die Konsistenzoption, damit das Modell sich an ihnen verankert. Das ist die richtige Wahl für Storyboards, Comics und Produktserien, bei denen die Identität über die Frames hinweg erhalten bleiben muss. Der Preis dafür ist, dass du zuerst ein gutes Referenzbild haben musst.
  • Konsistenz durch Textbeschreibung. Du beschreibst die Figur in jedem Prompt ausführlich — Haarfarbe, Kleidung, Statur, auffällige Merkmale — ohne Referenz zu verwenden. Nützlich, wenn du kein Quellfoto hast, erfordert aber Disziplin: Lege die Beschreibung in einer wiederverwendbaren Konstante ab, damit sie zwischen Aufrufen nicht abweicht.

Ein pragmatischer Workflow für eine Serie:

  1. Erzeuge den ersten Frame ohne Konsistenz und iteriere den Prompt, bis die Figur richtig aussieht.
  2. Verwende diese Ausgabe als dein Referenzbild.
  3. Aktiviere die Konsistenzsteuerung und erzeuge die folgenden Frames, wobei die Referenz fest bleibt.
  4. Wenn die Figur immer noch abweicht, kürze den Prompt und lass die Referenz mehr Arbeit leisten — lange Prompts, die der Referenz widersprechen, verwirren das Modell.

Konsistenz ist ein Stellknopf, keine Garantie. Rechne auch in einer gut abgestimmten Pipeline damit, Ausgaben zu prüfen und einen kleinen Teil der Frames neu zu generieren.

Asynchrone Aufträge abfragen

Wenn du mit async: true einreichst, bekommst du eine Auftrags-ID zurück. Das Abfragen ist unkompliziert, aber die Details sind wichtiger, als es scheint.

Ein minimaler und korrekter Poller:

def wait_for_job(job_id, timeout=300, initial_delay=2, max_delay=15):
    deadline = time.time() + timeout
    delay = initial_delay
    while time.time() < deadline:
        resp = requests.get(
            f"{BASE}/v1/images/generations/{job_id}",
            headers=HEADERS,
            timeout=30,
        )
        resp.raise_for_status()
        data = resp.json()

        status = data.get("status")
        if status == "succeeded":
            return data
        if status in ("failed", "cancelled"):
            raise RuntimeError(f"job {job_id} ended as {status}: {data}")

        time.sleep(delay)
        delay = min(delay * 1.5, max_delay)

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

Die Begründung für jede Entscheidung:

  • Begrenzter annähernd exponentieller Backoff. Starte bei einigen Sekunden und multipliziere mit 1,5 bis zur Obergrenze. Ein festes Abfragen im Sekundentakt bei einem dreißigsekündigen Auftrag verschwendet Dutzende Anfragen; festes Abfragen alle dreißig Sekunden fügt schnellen Aufträgen unnötige Latenz hinzu.
  • Harte Frist. Ohne sie blockiert ein hängender Auftrag deinen Worker auf unbestimmte Zeit. Besser laut scheitern.
  • Behandlung von Endzuständen. Behandle failed und cancelled als Ausnahmen, nicht als Zustände, die weiter abgefragt werden. Ein Auftrag im Fehlerzustand wird beim nächsten Abfragen niemals erfolgreich.
  • In jeder Iteration einen neuen GET ausführen. Cache nicht die erste Antwort und nimm nicht an, dass sie sich aktualisiert.

Für die Stapelverarbeitung: Reiche zuerst alle Aufträge ein, sammle die IDs und frage sie dann in einer Schleife ab — so überlappt die Generierungszeit über die Aufträge hinweg, statt serialisiert zu werden.

Ausgaben herunterladen und verifizieren

Nach einem erfolgreichen Auftrag enthält die Ergebnisnutzlast eine Ausgabe-URL. Das Herunterladen ist ein gewöhnlicher GET, aber bevor du prüfst, solltest du nicht annehmen, dass diese Bytes ein Bild sind.

def download_image(url, path):
    with requests.get(url, stream=True, timeout=60) as r:
        r.raise_for_status()
        content_type = r.headers.get("Content-Type", "")
        if not content_type.startswith("image/"):
            raise RuntimeError(f"unexpected content type: {content_type}")
        with open(path, "wb") as f:
            for chunk in r.iter_content(chunk_size=8192):
                f.write(chunk)
    return path

Plausibilitätsprüfungen, die sich bei jedem Download lohnen:

  • Content-Type. Wenn du ein Bild anforderst, aber application/json oder text/html bekommst, hast du tatsächlich eine Fehlerseite erhalten. Die Header-Prüfung fängt das ab, bevor du eine beschädigte Datei schreibst.
  • Streaming. Schreibe gestreamt auf die Festplatte, statt den gesamten Antwortkörper in den Speicher zu laden; das hält den Speicher stabil, wenn du parallel herunterlädst.
  • Größe ungleich null. Eine Datei mit null Bytes bedeutet, dass etwas schiefgelaufen ist, selbst wenn der HTTP-Status normal ist.
  • Prüfsumme oder Byte-Anzahl im Log protokollieren. Notiere sie zusammen mit der Auftrags-ID, damit du eine beschädigte Datei einer bestimmten Generierung zuordnen kannst.

Die Ausgabe-URL kann temporär sein. Wenn du Ergebnisse behalten willst, lade sie noch in demselben Lauf in deinen eigenen Speicher herunter, statt den Link für später zu speichern.

Häufige Fehlerquellen

Die meisten Probleme fallen in einige wenige Kategorien. Prüfe diese, bevor du annimmst, dass sich das Modell seltsam verhält.

Authentifizierung und Routing

  • Ein fehlender oder fehlerhaft formatierter Authorization-Header führt zu einem Authentifizierungsfehler statt zu einem Bild. Stelle sicher, dass der Header Bearer <key> lautet, mit einem Leerzeichen dazwischen.
  • Ein falscher model-Wert wird an die falsche Stelle geroutet oder schlägt direkt fehl. Er sollte genau nano-banana sein.

Probleme mit dem Anfragekörper

  • Vage Prompts. Die häufigste einzelne Ursache für „schlechte Ausgabe“. Füge Kompositions-, Beleuchtungs- und Stildetails hinzu, bevor du irgendetwas anderes änderst.
  • Nicht erreichbare Bild-URLs. Referenz-URLs, die 404 zurückgeben, Authentifizierung erfordern oder auf lokale Pfade zeigen, schlagen fehl oder werden stillschweigend ignoriert. Rufe die URL einmal selbst ab, um zu bestätigen, dass sie funktioniert.
  • async: false mit einem langen Prompt senden und dabei das Client-Timeout erreichen. Wechsle zu asynchron und frage ab, statt das Timeout zu erhöhen.

Auftragsverarbeitung

  • Einen Auftrag abfragen, der nie existierte. Ein Tippfehler in der Auftrags-ID erzeugt einen Nicht-gefunden-Fehler, der wie ein Fehlschlag aussieht; protokolliere die ID, die du eingereicht hast.
  • failed behandeln, als würde es noch laufen. Verlasse die Poll-Schleife immer bei einem Endzustand.
  • Keine Frist. Der teuerste Bug in Stapelaufträgen: Ein hängendes Bild bremst den gesamten Lauf aus.

Ausgabeverarbeitung

  • Content-Type nicht prüfen. Wie oben erwähnt, sieht eine mit der Erweiterung .png gespeicherte Fehlerseite später wie ein beschädigtes Bild aus.
  • Sich Stunden nach der Generierung auf abgelaufene Ergebnis-URLs verlassen. Lade zeitnah herunter.

Wenn du in der Reihenfolge Authentifizierung, Anfragekörper, Auftragslebenszyklus, Download systematisch vorgehst, sind die meisten Fehler in wenigen Minuten behoben.

Ä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