Przydatna migracja Seedream 5.5 dotyczy przepływu pracy z plikami, a nie tylko zamiany nazwy modelu: wygeneruj obraz, sprawdź zwrócone zadanie, zapisz obraz, a następnie prześlij zapisane bajty jako odniesienie do edycji.
Seedream 5.5 w AIHubMix korzysta obecnie z doubao-seedream-5-5 i POST /ai/v1/images/generations. W tym samouczku utworzymy wizualizację produktu — ceramicznego kubka — a następnie poprosimy o zmianę wyłącznie jego koloru.
Zakres: dokumentację sprawdzono 12 listopada 2026 r. Kod przeszedł jedynie lokalną kontrolę składni i testy pomocnicze offline; nie wykonano żadnego żądania generowania. Nie stanowi to dowodu jakości wyników, wierności edycji, opóźnienia ani rzeczywistej opłaty.
1. Przygotuj jedno krótkie, precyzyjne żądanie
Użyj Pythona 3.10+ i requests. W Bash zainstaluj zależność i wprowadź klucz tak, aby jego wartość nie trafiła do historii powłoki:
python3 -m pip install requests
read -r -s -p 'AIHubMix API key: ' AIHUBMIX_API_KEY
printf '\n'
export AIHUBMIX_API_KEY
W kodzie wdrożonym w środowisku produkcyjnym wstrzyknij zmienną środowiskową za pośrednictwem menedżera sekretów. Nie umieszczaj klucza w plikach źródłowych, przykładach żądań, logach, notatnikach ani kodzie po stronie przeglądarki. Przed wykonaniem któregokolwiek żądania POST włącz funkcję zadań na koncie, zgodnie z wymaganiami przewodnika po zadaniach asynchronicznych. Ten warunek wstępny dotyczy natywnych punktów końcowych zadań multimedialnych /ai/v1, także tych z synchronicznym oczekiwaniem; jest niezależny od wyboru wykonywania w tle.
Sprawdź aktualny schemat punktu końcowego modelu, wybierając wpis według path, a nie pozycji w tablicy. Ograniczenia właściwe dla danego modelu mają pierwszeństwo przed wspólną listą parametrów.
| Ustawienie | Użyta wartość |
|---|---|
| Model | doubao-seedream-5-5 |
| Trasa | POST /ai/v1/images/generations |
| Treść żądania | Płaski JSON |
| Rozmiar | 2048x2048 |
| Liczba obrazów | n = 1 |
| Format pliku | png |
| Format odpowiedzi | url |
Schemat wymaga pól model i niepustego prompt, ogranicza n do 1 oraz wymienia formaty wyjściowe png i jpeg. Akceptuje adres URL image, dane wejściowe w Base64 lub obiekt {url}; pole images przyjmuje tablicę z maksymalnie 14 opublikowanymi odwołaniami. Tego limitu nie przetestowano w działającym systemie. Ten przykład używa jednego odwołania i jawnie ustawia domyślny rozmiar, bez zewnętrznego obiektu input ani rozszerzeń extra.
2. Wygeneruj obraz, sprawdź zadanie i zapisz plik PNG
Dokumentacja ujednoliconego API obrazów definiuje odpowiedź zadania zawierającą pola id, object: image, model, status, output i error. Nie należy interpretować jej jako starszego formatu data[0].url.
Najpierw zapoznaj się z krótkim przebiegiem pracy; pełny blok konfiguracji i funkcji pomocniczej do pobierania znajduje się w zwiniętym Dodatku poniżej. Przed uruchomieniem tych przykładów wczytaj raz blok z dodatku do tej samej sesji Pythona. Definiuje on settings, api_json i collect bez wysyłania żądania wygenerowania obrazu. Następnie uruchamiaj krótkie bloki po kolei. Każde żądanie POST to osobna płatna operacja; nie uruchamiaj go ponownie, aby naprawić brak odpowiedzi lub nieudane pobieranie.
Wyślij żądanie wygenerowania obrazu jeden raz
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)
Sprawdź zadanie, a następnie zapisz plik PNG
Pominięcie async oznacza synchroniczne oczekiwanie. Odpowiedź HTTP 200 nadal może zawierać status: failed. Funkcja pomocnicza zapisuje identyfikator zadania przed sprawdzeniem statusu: pobieranie rozpoczyna się tylko dla completed; stany failed, cancelled i nieznane przerywają działanie. Stany pending i in_progress wymagają sprawdzenia istniejącego zadania, a nie kolejnego generowania.
collect(task, "mug-blue")
To pojedyncze wywołanie używa klucza, który utworzył zadanie, aby pobrać ukończony wynik, sprawdza bajty PNG i zapisuje plik jako mug-blue.png. Nie ponawia automatycznie tworzenia zadania i odrzuca nieoczekiwane hosty pobierania lub przekierowania, zanim przekaże klucz dalej. Pełna implementacja znajduje się w dodatku; opisuje ona zachowanie oparte na dokumentacji, a nie zweryfikowany wynik generowania.
Przewodnik po modelu podaje, że adresy URL wyników są ważne przez około 30 minut. Pobierz plik szybko, używając tego samego nagłówka Bearer, i samodzielnie zapisz bajty. expires_at: null nie oznacza gwarancji bezterminowego przechowywania. Jeśli pole b64_json jest wypełnione, zdekoduj jego zawartość zamiast pobierać plik z adresu URL.
3. Edytuj plik lokalny, a nie chroniony adres URL pobierania
Samodzielnie sprawdź zapisany obraz, zanim zapłacisz za edycję. To, że uwierzytelniony klient może pobrać content_url, nie oznacza, że jest to publiczny adres URL, z którego dostawca obrazów może pobrać plik. Prześlij lokalny plik PNG jako 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")
To żądanie prosi o zachowanie obrazu, ale nie dowodzi, że faktycznie je uzyskano. Sprawdź wynik przed kolejną płatną rundą. Całe żądanie JSON, w tym kodowanie wbudowane, musi mieścić się w limicie 32 MiB; obowiązują też limity multimediów właściwe dla modelu. Inną akceptowaną opcją jest publiczny adres URL obrazu, do którego dostawca ma dostęp.
4. Opcjonalnie: oczekiwanie asynchroniczne i odzyskiwanie po przerwaniu
Warunek wstępny dotyczący konta opisany w sekcji 1 jest niezależny od trybu wykonywania. Komunikat 403 async_not_enabled oznacza, że funkcję zadań trzeba aktywować w konsoli. Opcjonalne jest tylko wykonywanie w tle.
Jeśli wolisz generowanie w tle, przygotuj ten sam słownik generation, a następnie użyj dwóch poniższych wierszy zamiast synchronicznego wiersza task = api_json(...) i osobnego wywołania collect(...). Wybierz tryb przed wysłaniem żądania; nie uruchamiaj obu wersji:
task = api_json("POST", IMAGES + "/generations", {**generation, "async": True})
collect(task, "mug-blue", poll=True)
Funkcja pomocnicza odpytuje GET /ai/v1/images/{id} co około 15 sekund, aż zadanie osiągnie stan końcowy. To zalecana w dokumentacji częstotliwość odpytywania, a nie odstęp wymuszany przez serwer. Webhooki wymagają async: true; konfiguracja odbiornika wykracza poza zakres tego samouczka.
Jeśli pobieranie wyników zostało przerwane, w razie potrzeby wczytaj ponownie w nowej sesji wyłącznie wspólny blok konfiguracji i funkcji pomocniczej z dodatku, a nie blok tworzenia zadania. Jeśli zapisano identyfikator, wznów pracę bez żadnego żądania POST:
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)
Aby odzyskać wynik edycji, użyj odpowiedniego prefiksu mug-green. Jeśli odpowiedź z tworzenia zadania zniknęła, zanim zapisano identyfikator, sprawdź zamiast tego ostatnie zadania:
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"))
Dopasuj model i czas utworzenia; nie wybieraj bez zastanowienia najnowszego zadania. W razie potrzeby użyj next_after jako kursora after w kolejnym żądaniu. Jeśli nie da się jednoznacznie dopasować zadania, skontaktuj się z pomocą techniczną zamiast wysyłać żądanie ponownie. Lista jest migawką; do odpytywania używaj szczegółów zadania. output_error w wierszu oznacza, że nie można odczytać wyniku, a nie że generowanie niczego nie zwróciło lub że zmieniły się opłaty.
Nadal używaj klucza, który utworzył zadanie. W szczególności dostęp do listy ujednoliconych zadań, ich szczegółów i treści jest izolowany według tokenu: inny klucz na tym samym koncie nie może odczytać tych zadań. Lokalna przerwa nie dowodzi, że zadanie się nie powiodło ani że nie naliczono opłat.
5. Błędy migracji i aktualne błędy
Dokumentacja starszego adaptera Doubao wymienia starsze identyfikatory pod ścieżką /v1/models/doubao/<id>/predictions z obiektem nadrzędnym input. W wykazie nie ma wersji 5.5. Użyj dostępnej trasy 5.5 i płaskiej treści żądania pokazanej tutaj; nie testowano niepowodzeń generowania za pomocą starszego interfejsu. Skopiuj dokładnie aktualny identyfikator z łącznikami, zamiast zakładać, że zapis z kropkami jest jego aliasem.
Nie przenoś parametrów najwyższego poziomu quality, background, aspect_ratio ani seed: nie występują w aktualnym schemacie tego modelu. Informacja ByteDance o premierze opisuje natywny eksport z przezroczystością RGBA, ale schemat bramki nie udostępnia ani background, ani layer_decomposition. Sam wybór PNG nie jest zweryfikowanym sposobem uzyskania przezroczystości.
To udokumentowane błędy ujednoliconego API obrazów, a nie błędy zaobserwowane w odpowiedziach Seedream 5.5. Sprawdzaj status HTTP niezależnie od statusu zadania i podejmuj decyzje na podstawie pola code, a nie całego ciągu komunikatu.
| Gdzie | Kod | Następne działanie |
|---|---|---|
| HTTP 400 | schema_violation | Popraw pola zgodnie ze schematem |
| HTTP 400 | capability_not_supported | Usuń nieobsługiwane opcje |
| HTTP 504 | sync_timeout | Odzyskaj zadanie; skontaktuj się z pomocą techniczną |
| HTTP 502 | task_status_unavailable | Nie wysyłaj żądania ponownie |
| HTTP 422 | output_blocked | Zmień treść |
| HTTP 403 | async_not_enabled | Aktywuj funkcję zadań |
| Nieudane zadanie | result_delivery_failed | Sprawdź istniejący wynik |
W przypadku HTTP 502 task_status_unavailable przewodnik podaje:
Nie udało się potwierdzić stanu zadania po stronie dostawcy modelu. Nie wysyłaj go ponownie. Skontaktuj się z pomocą techniczną, podając identyfikator zadania lub żądania.
W przypadku błędu na poziomie zadania result_delivery_failed podano:
Nie udało się dostarczyć wygenerowanego wyniku. Nie ponawiaj automatycznie żądania. Skontaktuj się z pomocą techniczną, podając identyfikator zadania.
sync_timeout nie dowodzi, że zadanie w ogóle nie zostało wykonane. Zachowaj error.tid; użyj identyfikatora zadania tylko wtedy, gdy rzeczywiście został zwrócony, i poproś pomoc techniczną o rozstrzygnięcie niepewnego wyniku. W przypadku możliwego do naprawienia błędu pobierania ponów pobieranie, a nie generowanie. 410 artifact_expired oznacza coś innego: danego artefaktu nie można już pobrać. Najpierw sprawdź zapisane pliki; jeśli nadal potrzebujesz zamiennika, świadomie autoryzuj nowe, płatne generowanie. W przypadku 429 too_many_downloads sprawdź zapisane kopie lub skontaktuj się z pomocą techniczną; samo odczekanie nie gwarantuje ponownego dostępu.
Przewodnik wyraźnie zwalnia z opłaty za generowanie w przypadku output_blocked, także gdy ten błąd zgłoszono w nieudanym zadaniu. Nie zakładaj, że wyjątek dotyczy każdego nieudanego lub moderowanego żądania; do output_policy_violation stosuje się obowiązujące zasady naliczania opłat za moderację.
6. Planuj budżet na cały przepływ pracy, a nie tylko jeden wynik
Relacja Sina Technology z premiery podaje koszt około 0.28 CNY za jedną edycję kwadratowego obrazu 2K, uwzględniający obraz wejściowy i wyjściowy; tokeny tekstowe są bezpłatne. To informacja prasowa, a nie zweryfikowany oficjalny cennik ani wycena AIHubMix.
Przykładowe wyliczenie: dwie płatne rundy edycji istniejącego obrazu, każda odpowiadająca temu zaokrąglonemu scenariuszowi, kosztują około 2 × CNY 0.28 = CNY 0.56. Nie obejmuje to początkowego generowania obrazu z tekstu, dodatkowych obrazów referencyjnych, kolejnych propozycji ani ponowień. To nie jest zmierzona opłata.
W tym przykładzie, który obejmuje generowanie, a następnie edycję, użyj wzoru łączny koszt = opłata za początkowe generowanie + opłata za edycję z obrazem referencyjnym. Na podstawie przeanalizowanych stron nie ustalono pełnego oficjalnego cennika 5.5, dlatego ten samouczek nie podaje ani stałego łącznego kosztu, ani dokładnego stosunku oszczędności względem poprzedniej wersji.
Przed wysłaniem żądania:
- Potwierdź aktualny identyfikator, trasę, płaską treść żądania i schemat modelu.
- Trzymaj klucz w zmiennej środowiskowej; zachowuj identyfikatory zadań na potrzeby odzyskiwania.
- Traktuj każde żądanie POST jako osobną płatną operację, nigdy jako ponowienie pobierania.
- Sprawdź status zadania i zapisaną grafikę przed edycją.
- Prześlij ponownie lokalne dane w bajtach, podając prawidłowy typ MIME.
- Odzyskaj zadania o niepewnym statusie, zanim rozważysz ponowne wygenerowanie.
Zacznij od jednego obrazu i jednej przemyślanej edycji; dodawaj kolejne rundy dopiero po sprawdzeniu plików.
Dodatek: wspólna konfiguracja i funkcja pobierania
Pomiń ten dodatek podczas czytania instrukcji pracy. Przed uruchomieniem krótkich przykładów rozwiń ten blok i wczytaj go raz do tej samej sesji Pythona. Konfiguruje on sesję i definiuje funkcje, nie generując obrazu. Aby odzyskać przerwane zadanie w nowej sesji, wczytaj ponownie tylko ten blok — nie blok tworzenia ani edycji.
Rozwiń pełny zestaw funkcji pomocniczych — wczytaj raz przed krótkimi przykładami; bez żądania wygenerowania obrazu
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
Limit czasu odczytu wynoszący 600 sekund to wybór po stronie klienta, a nie obietnica dotycząca opóźnienia usługi. Sprawdzenie PNG odpowiada jawnemu formatowi wyjściowemu użytemu w tym samouczku; dostosuj je, jeśli wybierzesz JPEG.
FAQ
Jakiego identyfikatora modelu i punktu końcowego użyć z Seedream 5.5?
Użyj doubao-seedream-5-5 z POST /ai/v1/images/generations i płaskim obiektem JSON. Nie zakładaj, że inny zapis nazwy lub starszy adapter będzie działać tak samo.
Czy ten samouczek zawiera przetestowane wyniki generowania?
Nie. Kod opiera się na dokumentacji; sprawdzono jedynie składnię i funkcje pomocnicze lokalnie, bez połączenia z usługą. Nie wysłano żądania wnioskowania ani nie przeprowadzono pomiarów jakości obrazu, opóźnienia czy rozliczeń.
Czy asynchroniczność jest wymagana?
Nie; domyślnie oczekiwanie odbywa się synchronicznie. Wykonanie w tle włącza wartość logiczna async: true. Aktywacja funkcji zadań na poziomie konta jest warunkiem wstępnym korzystania z natywnych punktów końcowych zadań multimedialnych, nawet przy synchronicznym oczekiwaniu.
Czy kod HTTP 200 oznacza, że obraz został wygenerowany pomyślnie?
Nie. Sprawdź status zadania i ewentualny błąd. Zadanie może zakończyć się niepowodzeniem mimo powodzenia żądania HTTP; pobieraj obraz dopiero po zakończeniu zadania.
Czy adres URL do pobrania wyniku może posłużyć jako odwołanie do kolejnej edycji?
Nie zakładaj, że tak. Pobierz obraz za pomocą klucza użytego do jego utworzenia, a następnie zakoduj lokalny obraz jako Data URI albo podaj rzeczywiście publiczny adres URL obrazu.
Co zrobić po przekroczeniu limitu czasu lub utracie odpowiedzi?
Nie ponawiaj automatycznie generowania. Sprawdź zapisany identyfikator zadania lub odzyskaj zadanie z listy obrazów za pomocą klucza użytego do jego utworzenia. Zachowaj identyfikatory żądań i skontaktuj się z pomocą techniczną, jeśli wynik jest niepewny.
Czy wybór PNG gwarantuje przezroczyste tło lub rachunek na 0.28 CNY?
Ani jedno, ani drugie. Schemat nie udostępnia potwierdzonej opcji sterowania przezroczystością. Kwota 0.28 CNY to przybliżony koszt edycji w 2K podany w prasie — nie oferta AIHubMix ani stała cena za generowanie obrazu z tekstu połączone z edycją.
Czytaj dalej: seria Seedream 5.5
- Zanim zmienisz istniejący proces oparty na wersji 5.0 Pro, rozważ, czy warto go ulepszyć: Seedream 5.5 a 5.0 Pro: czy warto przejść na nowszą wersję?
- Jeśli w tym samym procesie można użyć innego modelu obrazu, porównaj kompromisy: Seedream 5.5 a GPT Image 2.6 Sunburst: który wybrać?
Źródła
- Ogłoszenie premiery Seedream 5.5 — ByteDance Seed; deklaracje dostawcy dotyczące możliwości modelu.
- Aktualny schemat punktu końcowego Seedream 5.5 — AIHubMix; pola żądania i ograniczenia właściwe dla modelu.
- Ujednolicone API generowania obrazów — AIHubMix; zadania, pobieranie i aktualne błędy.
- Przewodnik po modelu Seedream 5.5 — AIHubMix; identyfikator modelu i krótkotrwałe, uwierzytelnione linki do pobierania; w przypadku błędów dotyczących konkretnej trasy skorzystaj z dokumentacji ujednoliconego API.
- Relacja z premiery Seedream 5.5 — Sina Technology; przybliżony scenariusz kosztów edycji, a nie oficjalny cennik.



