Pro API: Bilder generieren und retuschieren
Ein Bild kostet 1 Credit, unabhängig vom Modus. Generierung aus einem Prompt und die Retusche eines eigenen Bildes laufen über dieselbe Route.
POST /images/quote nimmt denselben Body und gibt den Preis zurück, ohne etwas zu erstellen, immer
{ "cost": 1, ... }. Das existiert aus Symmetriegründen mit Videos, wo der Preis variieren kann.
Ein Bild einreichen
POST /images
{ "prompt": "portrait of a woman in a rainy street at night, neon reflections, cinematic",
"width": 832, "height": 1216 }| Feld | Typ | Standard | Bedeutung |
|---|---|---|---|
prompt | string | erforderlich | Die Szene. Englisch liefert die präzisesten Ergebnisse. |
width, height | int | 1024 x 1024 | Pixelgröße. Gute Formate: 1024 x 1024 (quadratisch), 832 x 1216 (Hochformat), 1216 x 832 (Querformat). |
mode | string | generation | edit, img2img oder inpaint, siehe unten. Fehlt der Wert, wird aus dem Prompt generiert. |
image_b64 | string | Quellbild in base64 (PNG oder JPEG), von allen drei Retuschiermodi benötigt. Maximal 12 MB dekodiert. | |
mask_b64 | string | Maske in base64: von inpaint benötigt, für edit optional. Male die zu retuschierenden Bereiche rot, in der Größe des Quellbilds. | |
lora | string | Ein trainierter Charakter auf dem Account: der name, den GET /loras zurückgibt. Trage den trigger im Prompt ein. | |
lora2, lora2_strength | string, number | Ein zweiter Charakter und seine Stärke (0 bis 1, Standard 1) für eine Szene mit zwei Personen. | |
count | int | 1 | Wie viele Bilder aus dieser einen Anfrage gerendert werden sollen, 1 bis 8. Jedes bekommt seinen eigenen frischen Seed; mit seed nehmen sie seed, seed+1, seed+2... Das entspricht dem Bilder pro Generation-Selektor in der App. |
seed | int | zufällig | Seed des Renders, von 0 bis 4294967295. Gleicher seed, gleicher Prompt und gleiche Einstellungen: das gleiche Ergebnis, mit minimalen Unterschieden bei anderer Grafikkarte. Den seed behalten und den Prompt anpassen ergibt eine Variation, die die Komposition beibehält. |
steps | int | engine | Leer lassen. Die Engine kennt ihren eigenen Wert. |
Die Antwort:
{ "jobId": "test-79634842-4586-46d4-ad52-d9ea236ae00d", "seed": 178078967, "cost": 1 }Der seed wird in der Antwort zurückgegeben, egal ob du ihn angegeben hast oder er zufällig gezogen wurde: bewahre ihn, um dasselbe Bild oder eine Variation davon erneut zu rendern.
Mehrere auf einmal anfordern
Mit count über 1 startet eine Anfrage mehrere Renders, jeder mit eigenem Seed, und die
Antwort listet sie alle auf:
{ "count": 4, "requested": 4, "cost_total": 4,
"jobs": [ { "jobId": "...", "seed": 178078967, "cost": 1 }, { "jobId": "...", "seed": 903412, "cost": 1 } ],
"errors": [],
"jobId": "...", "seed": 178078967, "cost": 1 }Zwei Dinge, die du genau lesen solltest.
Die jobId, der seed und der cost des ersten Renders werden auf der obersten Ebene wiederholt. Das ist so, damit Clients, die vor der Batch-Funktion geschrieben wurden, unverändert weiter funktionieren, nicht weil der erste Render wichtiger wäre. Verarbeite jeden Eintrag in jobs, nicht nur diesen einen.
Und vergleiche count mit requested. Eine Ablehnung mitten im Prozess, wegen fehlender Credits oder weil der Schlüssel sein Tageslimit erreicht hat, stoppt den Batch an dieser Stelle: requested ist das, was du angefragt hast, count ist das, was tatsächlich gestartet wurde, und errors erklärt, warum es gestoppt hat. Ein Client, der davon ausgeht, dass beide Werte gleich sind, verliert still und leise Renders.
POST /images/quote akzeptiert ebenfalls count und berechnet den Preis für den gesamten Batch. Videos haben kein count: eine Anfrage, ein Clip.
Die drei Retuschiermodi
Alle drei verwenden dieselbe instruktionsgesteuerte Bearbeitungs-Engine, die das Aussehen des
Quellbilds beibehält. Wenn du ein Quellbild übergibst, werden width und height direkt aus dem Bild ausgelesen und müssen nicht mitgeschickt werden.
mode | Eingaben | Was die Engine tut |
|---|---|---|
edit | image_b64 + prompt (+ optionale mask_b64) | Wendet die Anweisung auf das gesamte Bild an ("add sunglasses", "make it snow"). Mit einer Maske konzentriert sich die Änderung auf den roten Bereich. |
inpaint | image_b64 + mask_b64 + prompt | Regeneriert ausschließlich den roten Bereich der Maske, entsprechend der Anweisung. Der Rest wird pixelgenau neu zusammengesetzt. |
img2img | image_b64 + prompt | Überarbeitet das gesamte Bild gemäß dem Prompt, behält dabei Komposition und Aussehen bei: eine Variation. |
Bei edit wählt der Server selbst den besten Weg für die Bearbeitung, wie die App:
- mit Maske: Er liest die Anweisung und entscheidet zwischen Ersetzen des Bereichsinhalts (ein anderes Objekt, ein anderes Kleidungsstück, ein Gesicht: der Bereich wird nach dem neu gezeichnet, was dort erscheinen soll) und Verändern dessen, was dort ist (Farbe, Material, Licht). Mit einem Charakter-
lorawird der Bereich immer neu gezeichnet, Gesicht inklusive; - ohne Maske, mit einem Charakter-
lora("replace the woman with kara..."): Der Server findet die Person auf dem Foto und zeichnet sie als den Charakter neu; findet er niemanden, gilt die Anweisung wie bisher für das ganze Bild.
Gleicher Preis in jedem Fall (1 Credit pro Bild). Die Wahl zeigt sich im Ergebnis, nicht in der Antwort.
IMG=$(base64 -w0 photo.png)
curl -s $B/images -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d "{\"mode\":\"edit\",\"prompt\":\"add a red scarf, keep everything else identical\",\"image_b64\":\"$IMG\"}"Ein Bild mit Charakteren, Objekten und einem Ort erstellen
Füge POST /images ein multiref-Objekt hinzu, und der Server lässt deine Charaktere (Charaktere), deine Objekte und Tiere und einen Ort (Motive) gemeinsam in einem einzigen Bild auftreten, jeden erkennbar, wie der Bildschirm „Bild erstellen“ der App. Rufe jeden mit @Name im Prompt auf, auf Englisch.
{ "prompt": "@Mia hands a cup of coffee to @Tom on a sunny terrace, both smiling",
"multiref": {
"characters": [
{ "character_id": "chr_8f3a...", "name": "Mia", "view": 1 },
{ "character_id": "chr_21bc...", "name": "Tom", "lora": "tom_v1", "strength": 1.0, "lora_pass": 0.55 }
],
"subjects": [ { "subject_id": "sub_...", "name": "Mug" } ],
"location": { "subject_id": "sub_...", "name": "Terrace" }
},
"width": 1344, "height": 768, "seed": 42, "count": 1 }Feld von multiref | Was es tut |
|---|---|
characters[].character_id, name | Ein Charakter aus GET /characters; name ist das Wort, das nach @ steht (Buchstaben, Ziffern, _). |
characters[].view | Die Ansicht seines Sheets, die ihn darstellt, 1 bis 5 (standardmäßig 1, die Büste von vorn). |
characters[].sheet_id | Optional: das zu verwendende Sheet (standardmäßig das neueste). |
characters[].lora | Optional: sein Bild-LoRA, ein Name aus der Liste image von GET /loras. Der Charakter wird dann von seinem LoRA gespielt, nicht von seiner Ansicht. |
characters[].strength | Stärke des LoRA, 0 bis 1,5 (standardmäßig 1). |
characters[].lora_pass | Anteil des Bildes, den sein LoRA-Durchgang neu malt, 0,3 bis 0,9 (standardmäßig 0,55); nützlich bei mehreren Motiven. |
characters[].description | Optional, auf Englisch: Outfit, Alter... |
subjects[] | Objekte und Tiere aus /subjects: subject_id, name (standardmäßig das erste Wort seines Namens), description, image (welches seiner Bilder, standardmäßig 1). |
location | Ein Ort aus /subjects (subject_id, name) oder ein einmaliger Hintergrund: background_b64 und background_description. |
count | 1 oder 2: Die Bilder werden nacheinander gerendert. |
- Höchstens 4 Motive (Charaktere, Objekte und Tiere). Ohne LoRA, nur aus Bildern: höchstens 4 Referenzen, den Ort eingeschlossen. Der Server wählt die Methode anhand der Referenzen und platziert jede in der Reihenfolge von
characters, dannsubjects, von links nach rechts. - Ein
@Name, der keiner Referenz entspricht, wird abgelehnt (unknown_mention); eine Referenz, die im Prompt fehlt, wird trotzdem mitgeschickt. - Preis: Ein Durchgang kostet den Preis eines Bildes (1 Credit). Ein einfaches Bild ist 1 Durchgang; mehrere Charaktere, die von einem LoRA gespielt werden, 1 plus ein Durchgang pro LoRA (höchstens 4); nur aus Bildern, ein Durchgang pro Referenz über die erste hinaus; eine Mischung, beides. Die Summe (Durchgänge x
count) wird beim Einreichen reserviert und nur einmal abgebucht, beim fertigen Bild: Ein Fehlschlag oder ein Abbruch kostet nichts.POST /images/quotemit demselben Body gibt den genauen Preis, die Methode und ihre Durchgänge zurück, ohne etwas zu starten. - Antwort
202:{ "jobId": "mri_...", "seed", "cost", "method", "passes", "billed_passes" }(mitcount2:jobsundcost_total). Polling, Download und Abbruch laufen über die üblichen Routen unten; während des Renderns gibtprogressden laufenden Durchgang an ("2/3"). Ein Bild dauert 1 bis 3 Minuten. - Das fertige Bild bleibt 1 Stunde verfügbar, und 10 Minuten nach seinem ersten Download. Ein fehlgeschlagener Durchgang ergibt
status: "failed"mitreason: "render_failed"; ein Abbruchreason: "cancelled". - Fehler:
invalid_count,invalid_view,invalid_lora_pass,invalid_subject_image,invalid_size,character_not_ready, dazu die von Multi-Ref (unknown_character,unknown_subject,unknown_lora,unknown_mention,multiref_too_many_references,invalid_strength...). Siehe Limits und Fehler.
Polling
GET /images/{jobId}
| Antwort | Bedeutung |
|---|---|
{ "status": "pending", "phase": "IN_QUEUE" } | In der Warteschlange |
{ "status": "pending", "phase": "IN_PROGRESS" } | Wird gerendert |
{ "status": "completed", "cost": 1, "file_url": "/pro/v1/images/{jobId}/file", ... } | Fertig, Datei bereit |
{ "status": "failed", "detail": "..." } | Fehlgeschlagen, und es wird nichts berechnet |
Alle 3 Sekunden abfragen, nicht öfter: die Warteschlange wird geteilt.
Download
GET /images/{jobId}/file
Das PNG selbst, als Response-Body (Content-Type: image/png). Verfügbar, sobald der
Status completed ist, und 404 media_unavailable, sobald der Render nicht mehr vorhanden ist. Lade es sofort herunter, es wird nicht archiviert.
Abbrechen
POST /images/{jobId}/cancel
Bricht einen wartenden oder laufenden Render ab. Antwortet mit { "ok": true }. Es wird nichts berechnet, und der für das Tageslimit des Schlüssels reservierte Betrag wird zurückgegeben.