Seedream 5.5 API-tutorial: genereren, bewerken en migreren

Genereer en bewerk afbeeldingen met de Seedream 5.5 API: model-ID, taakstatus, downloads met authenticatie, asynchroon pollen en valkuilen bij migratie.

AIHubMix10 min leestijd
Seedream 5.5 API-tutorial: genereren, bewerken en migreren

Een nuttige migratie naar Seedream 5.5 draait om een bestandsworkflow, niet alleen om het vervangen van een modelnaam: genereer een afbeelding, controleer de geretourneerde taak, sla de afbeelding op en stuur die opgeslagen bytes vervolgens als referentie mee voor een bewerking.

Seedream 5.5 op AIHubMix gebruikt momenteel doubao-seedream-5-5 en POST /ai/v1/images/generations. In deze tutorial maken we een productvisual van een keramische mok en vragen we daarna om alleen de kleur aan te passen.

Reikwijdte: de documentatie is gecontroleerd op 12 november 2026. De code is alleen lokaal gecontroleerd op syntax en offline hulpfuncties; er is geen generatieverzoek uitgevoerd. Deze controles zijn geen bewijs voor de kwaliteit van de uitvoer, de getrouwheid van bewerkingen, latentie of een daadwerkelijke rekening.

1. Bereid één kleine, expliciete aanvraag voor

Gebruik Python 3.10+ met requests. Installeer de afhankelijkheid in Bash en voer de sleutel in zonder de waarde in de shellgeschiedenis op te slaan:

python3 -m pip install requests
read -r -s -p 'AIHubMix API key: ' AIHUBMIX_API_KEY
printf '\n'
export AIHUBMIX_API_KEY

Injecteer de omgevingsvariabele in gedeployde code via je secretmanager. Zet de sleutel niet in bronbestanden, aanvraagvoorbeelden, logs, notebooks of browsercode. Schakel voordat je een van beide POST-aanvragen verstuurt de taakfunctie voor het account in, zoals vereist door de handleiding voor asynchrone taken. Deze voorwaarde geldt voor native mediatakeindpunten van /ai/v1, inclusief synchroon wachten; ze staat los van de keuze voor achtergrondverwerking.

Lees het huidige schema van het modeleindpunt en selecteer de vermelding op basis van path, niet op basis van de positie in de array. De modelspecifieke beperkingen gaan vóór een gedeelde parameterlijst.

Instelling Hier gebruikte waarde
Model doubao-seedream-5-5
Route POST /ai/v1/images/generations
Body Platte JSON
Formaat 2048x2048
Aantal afbeeldingen n = 1
Bestandsindeling png
Antwoordindeling url

Het schema vereist model en een niet-lege prompt, beperkt n tot 1 en vermeldt png en jpeg als uitvoerindelingen. Het accepteert een image-URL, Base64-invoer of een object van het type {url}; images accepteert een array met een gepubliceerde maximumlimiet van 14 referenties. Die limiet is hier niet in een runtime getest. Dit voorbeeld gebruikt één referentie en vermeldt expliciet het standaardformaat, zonder een buitenste input-object of extra-uitbreidingen.

2. Genereer, controleer de taak en sla de PNG op

De documentatie van de uniforme afbeeldings-API definieert een taakantwoord met id, object: image, model, status, output en error. Ga er niet van uit dat het antwoord de oude indeling data[0].url gebruikt.

Lees eerst de korte workflow; de volledige instel- en downloadhulpfunctie staat in de uitklapbare Bijlage hieronder. Laad dat bijlageblok één keer in dezelfde Python-sessie voordat je deze voorbeelden uitvoert. Het definieert settings, api_json en collect zonder een afbeeldingsverzoek in te dienen. Voer daarna de korte blokken op volgorde uit. Elke POST is een afzonderlijke betaalde handeling; voer deze niet opnieuw uit om een ontbrekend antwoord of een mislukte download te herstellen.

Dien het afbeeldingsverzoek één keer in

generation = {
    **settings,
    "prompt": "Product photograph of one matte blue ceramic mug on a cream tabletop, "
              "soft side lighting, plain warm-gray background, no text or logos.",
}
task = api_json("POST", IMAGES + "/generations", generation)

Controleer de taak en sla de PNG vervolgens op

Als je async weglaat, wordt er synchroon gewacht. Een HTTP-status 200 kan nog steeds status: failed bevatten. De hulpfunctie slaat de taak-ID op voordat de status wordt gecontroleerd: alleen bij completed gaat de download verder; failed, cancelled en onbekende statussen stoppen de verwerking. Voor pending en in_progress moet je de bestaande taak controleren, niet opnieuw een afbeelding genereren.

collect(task, "mug-blue")

Deze ene aanroep gebruikt de sleutel waarmee de taak is aangemaakt om de voltooide uitvoer op te halen, controleert of de bytes een PNG vormen en slaat het bestand op als mug-blue.png. Er wordt niet automatisch opnieuw geprobeerd een taak aan te maken en onverwachte downloadhosts of omleidingen worden geweigerd voordat de sleutel wordt doorgestuurd. De volledige implementatie staat in de bijlage; dit gedrag is gebaseerd op de documentatie en is geen geverifieerd generatieresultaat.

Volgens de modelhandleiding blijven uitvoer-URL's ongeveer 30 minuten beschikbaar. Download de afbeelding snel met dezelfde Bearer-header en sla de bytes zelf op. expires_at: null is geen toezegging dat de uitvoer permanent wordt bewaard. Als b64_json is ingevuld, decodeer dat dan in plaats van een URL te downloaden.

3. Bewerk het lokale bestand, niet de beveiligde download-URL

Bekijk de opgeslagen afbeelding zelf voordat je geld uitgeeft aan een bewerking. Een content_url die je met je geauthenticeerde client kunt downloaden, is niet noodzakelijkerwijs een openbare URL die de afbeeldingsaanbieder kan ophalen. Upload de lokale PNG opnieuw als Data URI:

reference = Path("mug-blue.png").read_bytes()
if not reference.startswith(b"\x89PNG\r\n\x1a\n"):
    raise SystemExit("The editing reference must be the saved PNG.")
edit = {
    **settings,
    "prompt": "Change only the mug color from blue to forest green. Preserve the mug shape, "
              "camera angle, tabletop, background, lighting, and shadows.",
    "image": "data:image/png;base64," + base64.b64encode(reference).decode("ascii"),
}
task = api_json("POST", IMAGES + "/generations", edit)
collect(task, "mug-green")

Hiermee wordt gevraagd om de afbeelding te behouden; het bewijst niet dat dit ook is gelukt. Controleer het resultaat voordat je een volgende betaalde ronde uitvoert. De volledige JSON-aanvraag, inclusief de inline codering, moet binnen 32 MiB blijven; daarnaast gelden de modelspecifieke medialimieten. Een echt openbare afbeeldings-URL die de aanbieder kan bereiken, is ook een geaccepteerde invoeroptie.

4. Optioneel: asynchroon wachten en herstel na onderbreking

De accountvoorwaarde in sectie 1 staat los van de uitvoeringsmodus. 403 async_not_enabled betekent dat de taakfunctie in de console moet worden geactiveerd. Alleen uitvoering op de achtergrond is optioneel.

Als je de voorkeur geeft aan achtergrondgeneratie, bouw dan dezelfde generation-dictionary op en gebruik de twee onderstaande regels in plaats van zowel de synchrone regel task = api_json(...) als de afzonderlijke aanroep van collect(...). Kies de modus voordat je de aanvraag indient; voer niet beide versies uit:

task = api_json("POST", IMAGES + "/generations", {**generation, "async": True})
collect(task, "mug-blue", poll=True)

De hulpfunctie voert ongeveer elke 15 seconden een aanvraag uit naar GET /ai/v1/images/{id}, totdat een eindstatus is bereikt. Dat is de aanbevolen pollingfrequentie volgens de documentatie, geen interval dat door de server wordt afgedwongen. Webhooks vereisen async: true; een ontvanger valt buiten deze tutorial.

Als het ophalen van het resultaat is gestopt, laad dan zo nodig in een nieuwe sessie alleen het gedeelde instel-/hulpfunctieblok uit de bijlage opnieuw, niet een aanmaakblok. Als er een ID is opgeslagen, hervat je zonder POST-aanvraag:

task_id = Path("mug-blue.task-id").read_text(encoding="utf-8").strip()
task = api_json("GET", IMAGES + "/" + quote(task_id, safe=""))
collect(task, "mug-blue", poll=True)

Gebruik de bijbehorende mug-green-bestandsnaamstam om de bewerking te herstellen. Als het aanmaakantwoord is verdwenen voordat een ID werd opgeslagen, controleer dan in plaats daarvan recente taken:

recent = api_json("GET", IMAGES + "?limit=20&order=desc")
for row in recent.get("data", []):
    print(row.get("id"), row.get("model"), row.get("status"), row.get("created_at"))

Zoek op basis van het model en het tijdstip van aanmaak; selecteer niet blindelings de nieuwste taak. Gebruik indien nodig next_after als cursor after voor de volgende aanvraag. Neem bij een onduidelijke overeenkomst contact op met support in plaats van de aanvraag opnieuw in te dienen. Een lijst is een momentopname; gebruik taakdetails om te pollen. output_error in een rij betekent dat de uitvoer niet kon worden gelezen, niet dat de generatie niets heeft opgeleverd of dat de kosten zijn gewijzigd.

Blijf de sleutel gebruiken waarmee de taak is aangemaakt. Toegang tot de lijst met uniforme taken, taakdetails en taakinhoud is met name geïsoleerd per token: een andere sleutel van hetzelfde account kan die taken niet lezen. Een lokale onderbreking bewijst niet dat de taak is mislukt of dat er geen kosten zijn gemaakt.

5. Migratiefouten en actuele fouten

De documentatie van de oude Doubao-adapter vermeldt oudere ID's onder /v1/models/doubao/<id>/predictions, met een input-omhulsel. In het overzicht staat 5.5 niet vermeld. Gebruik hier de vindbare 5.5-route en de platte body; er is geen mislukte generatie via de oude route getest. Neem de huidige ID met koppeltekens exact over en ga er niet van uit dat een schrijfwijze met punten een alias is.

Neem quality, background, aspect_ratio of seed niet over als velden op het hoogste niveau: ze ontbreken in het huidige schema van dit model. In de lanceringaankondiging van ByteDance wordt native RGBA-uitvoer met transparantie beschreven, maar het gatewayschema biedt noch background, noch layer_decomposition. Alleen PNG selecteren is geen geverifieerde methode om transparantie te krijgen.

Dit zijn gedocumenteerde fouten van de uniforme afbeeldings-API, geen fouten die bij 5.5 zijn waargenomen. Controleer de HTTP-status los van de taakstatus en kies de vervolgactie op basis van code, niet van een volledige foutmeldingstekst.

Waar Code Volgende stap
HTTP 400 schema_violation Corrigeer de schemavelden
HTTP 400 capability_not_supported Verwijder niet-ondersteunde opties
HTTP 504 sync_timeout Herstel de taak; neem contact op met support
HTTP 502 task_status_unavailable Dien de aanvraag niet opnieuw in
HTTP 422 output_blocked Pas de inhoud aan
HTTP 403 async_not_enabled Activeer de taakfunctie
Mislukte taak result_delivery_failed Onderzoek het bestaande resultaat

Over HTTP 502 task_status_unavailable vermeldt de handleiding:

De status van de taak bij de modelaanbieder kon niet worden bevestigd. Dien de aanvraag niet opnieuw in. Neem contact op met support en vermeld de taak-ID of aanvraag-ID.

Over de taakfout result_delivery_failed vermeldt de handleiding:

Het gegenereerde resultaat kon niet worden afgeleverd. Dien de aanvraag niet automatisch opnieuw in. Neem contact op met support en vermeld de taak-ID.

Een sync_timeout bewijst niet dat de uitvoering nooit heeft plaatsgevonden. Bewaar error.tid, gebruik alleen een taak-ID als die daadwerkelijk is geretourneerd en vraag support om onzekere uitkomsten op te helderen. Probeer bij een herstelbare downloadfout het resultaat opnieuw op te halen in plaats van de afbeelding opnieuw te genereren. 410 artifact_expired is iets anders: dat bestand kan niet meer worden opgehaald. Controleer eerst of je het bestand al hebt opgeslagen; als je nog steeds een vervanging nodig hebt, geef dan bewust toestemming voor een nieuwe betaalde generatie. Controleer bij 429 too_many_downloads of er opgeslagen kopieën zijn of neem contact op met support; wachten alleen garandeert geen nieuwe toegang.

De handleiding stelt expliciet dat de generatiekosten vervallen bij output_blocked, ook wanneer dit wordt gemeld bij een mislukte taak. Pas die uitzondering niet toe op elke mislukte of gemodereerde aanvraag; voor output_policy_violation gelden de bestaande factureringsregels voor moderatie.

6. Begroot voor de workflow, niet alleen voor één resultaat

In het lanceringsverslag van Sina Technology worden de kosten voor één vierkante bewerking op 2K-formaat geschat op ongeveer CNY 0.28, inclusief beeldinvoer en -uitvoer; teksttokens zijn gratis. Dit is berichtgeving in de pers, geen geverifieerde officiële tarievenlijst of prijsopgave van AIHubMix.

Een voorbeeldberekening: twee betaalde bewerkingsrondes van een bestaande afbeelding die elk overeenkomen met die afgeronde schatting, kosten ongeveer 2 × CNY 0.28 = CNY 0.56. De initiële generatie op basis van tekst, extra referentieafbeeldingen, aanvullende varianten en nieuwe pogingen zijn niet inbegrepen. Dit is geen gemeten rekening.

Gebruik voor dit voorbeeld met genereren en daarna bewerken de formule totaal = kosten voor de eerste generatie + kosten voor de bewerking met referentieafbeelding. Op basis van de onderzochte pagina's konden geen volledige officiële tarieven voor 5.5 worden vastgesteld. Daarom vermeldt deze tutorial geen vast totaalbedrag of nauwkeurige besparingsverhouding tussen oud en nieuw.

Controleer voordat je de aanvraag indient:

  • Controleer de actuele ID, route, platte body en het modelschema.
  • Bewaar de sleutel in de omgeving en houd taak-ID's bij om de taak te kunnen herstellen.
  • Behandel elke POST als een afzonderlijke betaalde handeling, nooit als een nieuwe downloadpoging.
  • Controleer de taakstatus en de opgeslagen afbeelding voordat je bewerkingen uitvoert.
  • Upload lokale bytes opnieuw met het juiste MIME-type.
  • Herstel onzekere taken voordat je een nieuwe generatie overweegt.

Begin met één afbeelding en één gerichte bewerking; voeg pas meer rondes toe nadat je de bestanden hebt gecontroleerd.

Bijlage: gedeelde configuratie en downloadhelper

Sla deze bijlage over als je de workflow leest. Vouw dit blok uit en laad het één keer in dezelfde Python-sessie voordat je de korte voorbeelden uitvoert. Het configureert de sessie en definieert functies zonder een afbeelding te genereren. Als je een onderbroken taak in een nieuwe sessie wilt herstellen, laad dan alleen dit blok opnieuw, niet een blok voor het maken of bewerken van afbeeldingen.

Volledige helper uitvouwen — laad deze één keer vóór de korte voorbeelden; doet geen afbeeldingsverzoek
import base64
import os
import time
from pathlib import Path
from urllib.parse import quote, urlsplit

import requests

BASE = "https://aihubmix.com"
IMAGES = "/ai/v1/images"
settings = {
    "model": "doubao-seedream-5-5",
    "size": "2048x2048",
    "n": 1,
    "output_format": "png",
    "response_format": "url",
}
client = requests.Session()
client.headers["Authorization"] = "Bearer " + os.environ["AIHUBMIX_API_KEY"]


def api_json(method, path, body=None):
    try:
        response = client.request(
            method, BASE + path, json=body,
            timeout=(15, 600), allow_redirects=False,
        )
    except requests.RequestException:
        raise SystemExit(
            "Connection interrupted. Recover the existing task before another POST."
        ) from None
    try:
        data = response.json()
    except ValueError:
        raise SystemExit(
            f"HTTP {response.status_code}: non-JSON response; recover before another POST."
        ) from None
    if not isinstance(data, dict):
        raise SystemExit("Unexpected response; recover before another POST.")
    if not 200 <= response.status_code < 300:
        error = data.get("error") or {}
        raise SystemExit(
            f"HTTP {response.status_code}: code={error.get('code')}, "
            f"tid={error.get('tid')}. No automatic generation retry."
        )
    return data


def collect(task, stem, poll=False):
    task_id = task.get("id")
    if not isinstance(task_id, str) or not task_id:
        raise SystemExit("No task ID returned. Recover from the task list; do not resubmit.")
    Path(stem + ".task-id").write_text(task_id + "\n", encoding="utf-8")
    while True:
        status = task.get("status")
        print("Task:", task_id, "status:", status)
        if status == "completed":
            break
        if status not in {"pending", "in_progress"}:
            error = task.get("error") or {}
            raise SystemExit(
                f"Stopped: status={status}, code={error.get('code')}; task={task_id}."
            )
        if not poll:
            raise SystemExit("Task still active. Query the saved ID; do not recreate it.")
        time.sleep(15)
        task = api_json("GET", IMAGES + "/" + quote(task_id, safe=""))

    output = task.get("output") or []
    if not output:
        raise SystemExit("Completed without readable output; investigate the saved task.")
    item = output[0]
    if item.get("b64_json"):
        image_bytes = base64.b64decode(item["b64_json"], validate=True)
    else:
        url = item.get("content_url")
        if not isinstance(url, str):
            raise SystemExit("Missing content_url; investigate the saved task.")
        parsed = urlsplit(url)
        if (parsed.scheme, parsed.netloc) != ("https", "aihubmix.com"):
            raise SystemExit("Unexpected download origin; key was not forwarded.")
        try:
            response = client.get(url, timeout=(15, 120), allow_redirects=False)
        except requests.RequestException:
            raise SystemExit("Download interrupted; recover this task, not a new generation.") from None
        if not 200 <= response.status_code < 300:
            try:
                detail = response.json()
            except ValueError:
                detail = {}
            error = detail.get("error", {}) if isinstance(detail, dict) else {}
            code = error.get("code") if isinstance(error, dict) else None
            if response.status_code == 410 or code == "artifact_expired":
                raise SystemExit("Artifact expired; retrieval cannot recover it. Check saved files first.")
            if code == "too_many_downloads":
                raise SystemExit("Download allowance exhausted; check saved files or contact support.")
            raise SystemExit(
                f"Download HTTP {response.status_code}, code={code}; "
                "inspect the saved task. Retry retrieval only if recoverable."
            )
        image_bytes = response.content
    if not image_bytes.startswith(b"\x89PNG\r\n\x1a\n"):
        raise SystemExit("Expected PNG bytes; stopped before saving or reusing the result.")
    destination = Path(stem + ".png")
    destination.write_bytes(image_bytes)
    print("Saved:", destination)
    return destination

De read-time-out van 600 seconden is een keuze aan de clientzijde, geen belofte over de latentie van de service. De PNG-controle past bij het expliciete uitvoerformaat in deze tutorial; pas deze aan als je JPEG kiest.

Veelgestelde vragen

Welke model-ID en welk eindpunt moet Seedream 5.5 gebruiken?
Gebruik doubao-seedream-5-5 met POST /ai/v1/images/generations en platte JSON. Ga er niet van uit dat een andere schrijfwijze of een legacy-adapter gelijkwaardig is.

Bevat deze tutorial geteste generatieresultaten?
Nee. De code is gebaseerd op de documentatie en is alleen gecontroleerd op lokale syntaxis en offline helpers. Er is geen inferentieverzoek uitgevoerd en er zijn geen metingen gedaan van beeldkwaliteit, latentie of facturering.

Is async vereist?
Nee; standaard wordt er synchroon gewacht. Voor uitvoering op de achtergrond gebruik je Boolean async: true. Activering van de taakfunctionaliteit op accountniveau is een vereiste voor de native eindpunten voor mediataken, ook als je synchroon wacht.

Betekent HTTP 200 dat de afbeelding is gegenereerd?
Nee. Controleer de taakstatus en eventuele foutmelding. Een taak kan mislukken terwijl het HTTP-verzoek slaagt; download de afbeelding pas nadat de taak is voltooid.

Kan een download-URL van een resultaat als volgende bewerkingsreferentie dienen?
Ga daar niet van uit. Download het bestand met de sleutel waarmee het is gemaakt en codeer de lokale afbeelding vervolgens als een Data URI, of gebruik een daadwerkelijk openbare afbeeldings-URL.

Wat moet je doen na een time-out of een verloren antwoord?
Herhaal de generatie niet automatisch. Controleer de opgeslagen taak-ID of haal de taak op uit de afbeeldingenlijst met de sleutel waarmee die is gemaakt. Bewaar request-ID's en neem contact op met support als de uitkomst onzeker is.

Garandeert de keuze voor PNG transparante uitvoer of een rekening van CNY 0.28?
Geen van beide. Het schema biedt geen geverifieerde instelling voor transparantie. CNY 0.28 is een bij benadering genoemde prijs voor een bewerkingsvoorbeeld van 2K in de pers, geen prijsopgave van AIHubMix of een vaste prijs voor tekst-naar-afbeelding plus bewerking.

Lees verder: de Seedream 5.5-serie

Bronnen

  1. Aankondiging van de lancering van Seedream 5.5 — ByteDance Seed; claims van de leverancier over mogelijkheden.
  2. Actueel schema van het Seedream 5.5-eindpunt — AIHubMix; aanvraagvelden en modelspecifieke beperkingen.
  3. Uniforme API voor beeldgeneratie — AIHubMix; taken, downloads en actuele fouten.
  4. Handleiding voor het Seedream 5.5-model — AIHubMix; model-ID en kortdurende downloads waarvoor authenticatie nodig is; raadpleeg het document over de uniforme API voor foutmeldingen per route.
  5. Berichtgeving over de lancering van Seedream 5.5 — Sina Technology; scenario met geschatte bewerkingskosten, geen officieel tarief.

Eén gateway naar meerdere AI-aanbieders. Gebouwd voor productie.

Bezoek AIHubMix