Tutorial da API do Seedream 5.5: geração, edição e migração

Gere e edite imagens com a API do Seedream 5.5: ID do modelo, status da tarefa, downloads autenticados, consultas assíncronas e armadilhas de migração.

AIHubMix10 min de leitura
Tutorial da API do Seedream 5.5: geração, edição e migração

A migração útil do Seedream 5.5 envolve um fluxo de arquivos, não apenas substituir o nome do modelo: gere uma imagem, inspecione a tarefa retornada, salve a imagem e, em seguida, envie esses bytes salvos como referência para uma edição.

Seedream 5.5 no AIHubMix usa atualmente doubao-seedream-5-5 e POST /ai/v1/images/generations. Este tutorial cria uma imagem de produto de uma caneca de cerâmica e, em seguida, solicita uma edição apenas de cor.

Escopo: documentação verificada em 12 de novembro de 2026. O código passou apenas por verificações locais de sintaxe e auxiliares offline; nenhuma solicitação de geração foi executada. Isso não comprova a qualidade do resultado, a fidelidade da edição, a latência nem uma cobrança real.

1. Prepare uma solicitação simples e explícita

Use Python 3.10+ com requests. No Bash, instale a dependência e informe a chave sem incluir seu valor no histórico do shell:

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

Em código implantado, injete a variável de ambiente por meio do seu gerenciador de segredos. Mantenha a chave fora dos arquivos-fonte, exemplos de solicitação, logs, notebooks e código executado no navegador. Antes de qualquer um dos POSTs, ative o recurso de tarefas da conta, conforme exigido pelo guia de tarefas assíncronas. Esse pré-requisito se aplica aos endpoints de tarefas de mídia nativos /ai/v1, inclusive ao aguardar de forma síncrona; ele é independente da escolha de execução em segundo plano.

Consulte o esquema atual do endpoint do modelo, selecionando a entrada por path, não pela posição no array. As restrições específicas do modelo prevalecem sobre uma lista compartilhada de parâmetros.

Configuração Valor usado aqui
Modelo doubao-seedream-5-5
Rota POST /ai/v1/images/generations
Corpo JSON simples
Tamanho 2048x2048
Quantidade de imagens n = 1
Formato do arquivo png
Formato da resposta url

O esquema exige model e um prompt não vazio, limita n a 1 e lista as saídas png e jpeg. Aceita um URL em image, entrada Base64 ou um objeto {url}; images aceita um array com um máximo publicado de 14 referências. Esse limite não foi testado em tempo de execução aqui. Este exemplo usa uma referência e especifica o tamanho padrão, sem objeto externo input nem extensões extra.

2. Gere, inspecione a tarefa e salve o PNG

A documentação da API unificada de imagens define uma resposta de tarefa com id, object: image, model, status, output e error. Não a interprete como o formato legado data[0].url.

Leia primeiro o fluxo resumido; a configuração completa e o auxiliar de download estão no Apêndice recolhido abaixo. Antes de executar estes exemplos, carregue uma vez o bloco do apêndice na mesma sessão do Python. Ele define settings, api_json e collect sem enviar uma solicitação de imagem. Em seguida, execute os blocos resumidos na ordem. Cada POST é uma ação paga separada; não o execute novamente para corrigir uma resposta ausente ou um download com falha.

Envie a solicitação de imagem uma vez

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)

Inspecione a tarefa e salve o PNG

A omissão de async implica espera síncrona. Uma resposta HTTP 200 ainda pode conter status: failed. O auxiliar salva o ID da tarefa antes de inspecionar o status: somente completed segue para o download; failed, cancelled e estados desconhecidos interrompem o processo. pending e in_progress exigem a inspeção de uma tarefa existente, não outra geração.

collect(task, "mug-blue")

Esta única chamada usa a chave que criou a tarefa para recuperar o resultado concluído, verifica os bytes do PNG e salva mug-blue.png. Ela não tenta criar novamente de forma automática e rejeita hosts de download ou redirecionamentos inesperados antes de encaminhar a chave. A implementação completa está no apêndice; este é o comportamento descrito na documentação, não um resultado de geração verificado.

O guia do modelo informa que os URLs de saída duram cerca de 30 minutos. Baixe o arquivo prontamente usando o mesmo cabeçalho Bearer e armazene os bytes por conta própria. expires_at: null não é uma promessa de retenção permanente. Se b64_json estiver preenchido, decodifique-o em vez de baixar um URL.

3. Edite o arquivo local, não o URL de download protegido

Inspecione você mesmo a imagem salva antes de pagar por uma edição. Um content_url que seu cliente autenticado consegue baixar não é necessariamente um URL público que o provedor de imagens possa acessar. Reenvie o PNG local como 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")

Isso solicita a preservação; não demonstra que ela ocorreu. Analise o resultado antes de outra rodada paga. A solicitação JSON inteira, incluindo a codificação embutida, deve caber em 32 MiB; também se aplicam os limites de mídia específicos do modelo. Um URL de imagem realmente público e acessível ao provedor é outra opção de entrada aceita.

4. Opcional: espera assíncrona e recuperação após interrupções

O pré-requisito da conta mencionado na seção 1 é independente do modo de execução. 403 async_not_enabled significa que o recurso de tarefas precisa ser ativado no console. Apenas a execução em segundo plano é opcional.

Se preferir a geração em segundo plano, crie o mesmo dicionário generation e use as duas linhas abaixo no lugar da linha síncrona task = api_json(...) e da chamada separada collect(...). Escolha o modo antes de enviar; não execute as duas versões:

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

O auxiliar consulta GET /ai/v1/images/{id} aproximadamente a cada 15 segundos, até chegar a um estado terminal. Essa é a recomendação de consulta documentada, não um intervalo imposto pelo servidor. Webhooks exigem async: true; a configuração de um receptor está fora do escopo deste tutorial.

Se a coleta for interrompida, se necessário, carregue novamente apenas o bloco compartilhado de configuração/auxiliares do apêndice em uma sessão nova, não um bloco de criação. Se um ID foi salvo, retome sem fazer nenhum 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)

Use o radical correspondente mug-green para recuperar a edição. Se a resposta de criação desapareceu antes de um ID ser salvo, inspecione as tarefas recentes:

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"))

Confira o modelo e o horário de criação; não selecione cegamente a tarefa mais recente. Se necessário, use next_after como cursor after da próxima solicitação. Se não for possível identificar a tarefa com segurança, contate o suporte em vez de enviar outra solicitação. Uma lista é um instantâneo; use os detalhes da tarefa para fazer consultas. output_error em uma linha significa que não foi possível ler o resultado, não que a geração não produziu nada ou que as cobranças foram alteradas.

Continue usando a chave que criou a tarefa. Em particular, o acesso à lista unificada de tarefas, aos detalhes e ao conteúdo é isolado por token: outra chave da mesma conta não pode ler essas tarefas. Uma interrupção local não comprova que houve falha ou que não houve cobrança.

5. Erros atuais e armadilhas de migração

A documentação do adaptador legado do Doubao lista IDs mais antigos em /v1/models/doubao/<id>/predictions, com um envelope input. A lista não inclui a versão 5.5. Use aqui a rota 5.5 disponível para descoberta e o corpo simples; nenhuma falha de geração pelo endpoint legado foi testada. Copie exatamente o ID atual com hífens, sem presumir que uma grafia com pontos seja um alias.

Não reutilize os campos de nível superior quality, background, aspect_ratio ou seed: eles não constam do esquema atual deste modelo. O anúncio de lançamento da ByteDance descreve uma saída RGBA transparente nativa, mas o esquema do gateway não expõe background nem layer_decomposition. Selecionar apenas PNG não é uma receita de transparência verificada.

Estes são erros documentados da API unificada de imagens, não respostas observadas do 5.5. Verifique separadamente o status HTTP e o status da tarefa, e use code para determinar a ação, não a mensagem completa.

Onde Código Próxima ação
HTTP 400 schema_violation Corrija os campos do esquema
HTTP 400 capability_not_supported Remova as opções não compatíveis
HTTP 504 sync_timeout Recupere; contate o suporte
HTTP 502 task_status_unavailable Não envie novamente
HTTP 422 output_blocked Revise o conteúdo
HTTP 403 async_not_enabled Ative o recurso de tarefas
Tarefa com falha result_delivery_failed Investigue o resultado existente

Para HTTP 502 task_status_unavailable, o guia informa:

Não foi possível confirmar o status da tarefa no provedor do modelo. Não a envie novamente. Entre em contato com o suporte e informe o ID da tarefa ou o ID da solicitação.

Para result_delivery_failed no nível da tarefa, o guia informa:

Não foi possível entregar o resultado gerado. Não envie novamente de forma automática. Entre em contato com o suporte e informe o ID da tarefa.

Um sync_timeout não comprova que a execução nunca ocorreu. Guarde error.tid, use um ID de tarefa somente se ele tiver sido realmente retornado e peça ao suporte que resolva resultados incertos. Se um download recuperável falhar, tente recuperar o arquivo novamente, em vez de gerar outra imagem. 410 artifact_expired é diferente: esse artefato não pode mais ser recuperado. Primeiro, verifique os arquivos salvos; se ainda precisar de uma substituição, autorize deliberadamente uma nova geração paga. Para 429 too_many_downloads, verifique as cópias salvas ou contate o suporte; aguardar não garante que o acesso será restabelecido.

O guia isenta explicitamente a taxa de geração para output_blocked, inclusive quando informado em uma tarefa com falha. Não estenda essa exceção a toda solicitação com falha ou moderada; output_policy_violation segue as regras de cobrança de moderação vigentes.

6. Planeje o orçamento para o fluxo de trabalho, não apenas para uma saída

A reportagem de lançamento da Sina Technology informa aproximadamente CNY 0.28 para uma edição quadrada em 2K, incluindo entrada e saída de imagem, com tokens de texto gratuitos. Trata-se de uma reportagem, não de uma tabela oficial de tarifas verificada nem de uma cotação do AIHubMix.

Um exemplo: duas rodadas pagas de edição de uma imagem existente, cada uma correspondendo a esse cenário arredondado, custam aproximadamente 2 × CNY 0.28 = CNY 0.56. Isso exclui a geração inicial de texto para imagem, imagens de referência adicionais, candidatos extras e novas tentativas. Não se trata de uma cobrança medida.

Para este exemplo de geração seguida de edição, use total = cobrança da geração inicial + cobrança da edição com referência. Não foi possível estabelecer uma tarifa oficial completa do 5.5 com base nas páginas examinadas; por isso, este tutorial não apresenta nem um total fixo nem uma proporção precisa de economia entre a versão antiga e a nova.

Antes de enviar:

  • Confirme o ID atual, a rota, o corpo simples e o esquema do modelo.
  • Mantenha a chave no ambiente e guarde os IDs das tarefas para recuperação.
  • Trate cada POST como uma ação paga separada, nunca como uma nova tentativa de download.
  • Confira o status da tarefa e a imagem salva antes de editar.
  • Envie novamente os bytes locais com o tipo MIME correto.
  • Recupere tarefas cujo resultado é incerto antes de considerar uma nova geração.

Comece com uma imagem e uma edição deliberada; só adicione mais etapas depois de revisar os arquivos.

Apêndice: configuração compartilhada e função auxiliar de download

Ignore este apêndice ao acompanhar o fluxo de trabalho. Antes de executar os exemplos curtos, expanda e carregue este bloco uma vez na mesma sessão do Python. Ele configura a sessão e define funções, sem gerar uma imagem. Para recuperar uma tarefa interrompida em uma sessão nova, recarregue apenas este bloco — não um bloco de criação ou edição.

Expandir a função auxiliar completa — carregue uma vez antes dos exemplos curtos; nenhuma solicitação de imagem
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

O tempo limite de leitura de 600 segundos é uma escolha do cliente, não uma promessa de latência do serviço. A verificação de PNG corresponde ao formato de saída explícito deste tutorial; adapte-a se escolher JPEG.

Perguntas frequentes

Qual ID do modelo e endpoint o Seedream 5.5 deve usar?
Use doubao-seedream-5-5 com POST /ai/v1/images/generations e JSON simples. Não presuma que outra grafia ou um adaptador legado seja equivalente.

Este tutorial inclui resultados de geração testados?
Não. O código se baseia na documentação, com apenas verificações locais de sintaxe e auxiliares offline. Não foi executada nenhuma solicitação de inferência, medição da qualidade da imagem, medição de latência ou teste de cobrança.

O modo assíncrono é obrigatório?
Não; a espera síncrona é o padrão. A execução em segundo plano usa o valor booleano async: true. A ativação do recurso de tarefas no nível da conta é um pré-requisito para os endpoints nativos de tarefas de mídia, mesmo ao aguardar de forma síncrona.

HTTP 200 significa que a imagem foi gerada com sucesso?
Não. Confira o status da tarefa e o erro, se houver. Uma tarefa pode falhar mesmo quando a solicitação HTTP é bem-sucedida; faça o download somente após a conclusão.

Uma URL de download do resultado pode ser usada como referência para a próxima edição?
Não presuma que sim. Faça o download com a chave usada na criação e, em seguida, codifique a imagem local como um Data URI ou forneça uma URL de imagem realmente pública.

O que fazer após um tempo limite ou a perda da resposta?
Não repita a geração automaticamente. Verifique o ID da tarefa salvo ou recupere-o da lista de imagens com a chave usada na criação. Guarde os IDs das solicitações e entre em contato com o suporte quando o resultado for incerto.

Escolher PNG garante saída transparente ou uma cobrança de CNY 0.28?
Nenhuma das duas coisas. O esquema não fornece um controle de transparência verificado. CNY 0.28 é um valor aproximado, divulgado pela imprensa, para um exemplo de edição em 2K — não é uma cotação da AIHubMix nem um preço fixo para texto para imagem mais edição.

Continue lendo: a série Seedream 5.5

Fontes

  1. Anúncio de lançamento do Seedream 5.5 — ByteDance Seed; declarações do fornecedor sobre os recursos.
  2. Esquema atual do endpoint do Seedream 5.5 — AIHubMix; campos da solicitação e restrições específicas do modelo.
  3. API unificada de geração de imagens — AIHubMix; tarefas, downloads e erros atuais.
  4. Guia do modelo Seedream 5.5 — AIHubMix; ID do modelo e downloads autenticados de curta duração; consulte o documento da API unificada para erros específicos da rota.
  5. Cobertura do lançamento do Seedream 5.5 — Sina Technology; cenário de custo aproximado de edição, não uma tarifa oficial.

Um só gateway para vários provedores de IA. Feito para produção.

Acessar AIHubMix