Você chamou createTask e recebeu uma taskId em vez de uma imagem. Agora precisa obter o resultado sem manter uma conexão aberta por minutos, pagar duas vezes após um timeout ou perder a tarefa quando seu processo reiniciar.
A versão resumida:
- Modelos de imagem rápidos em um script: adicione
?wait=30acreateTaske, muitas vezes, você poderá dispensar a sondagem. - Scripts, desenvolvimento local, sem servidor público: consulte a tarefa com um loop limitado como o exemplo abaixo.
- Qualquer trabalho que deixe o usuário esperando, vídeo ou grande volume: use
callBackUrl, verifique a assinatura, confirme o recebimento rapidamente e processe os eventos por uma fila. - Produção: combine os dois. O callback é o caminho rápido; uma varredura periódica dos estados recupera os callbacks que nunca chegam.
Na API direta, ?wait=<seconds> (até 60) mantém createTask aberto até a tarefa terminar. Isso serve para modelos de imagem que concluem em segundos, mas não para vídeo. callBackUrl (com B maiúsculo) é o endereço HTTPS público que recebe o resultado, e recordInfo é a chamada de estado encapsulada por get_task no SDK. A referência de tarefas explica os três.
Experimente primeiro no Playground
Abra o Playground de seedream-5-0-pro. Digite um Prompt curto, defina Resolution como 1k, pressione Run model e veja o resultado em Output; History lista as execuções anteriores. A sondagem e os Webhooks automatizam para sua aplicação a espera que você vê; eles não criam uma segunda imagem.
Escolha como receber o resultado
| Sua aplicação | Comece com | Por quê |
|---|---|---|
| Script local ou lote ocasional | Sondagem pelo SDK | Não há receptor público para implantar |
| Aplicação interativa de imagem ou vídeo | Webhook verificado | Reage ao fim da geração sem manter um processo em espera para cada tarefa |
| Serviço em produção | Webhook e varredura de reconciliação | Um callback perdido não deixa uma tarefa aceita sem acompanhamento |
Escolha sondagem quando houver poucas tarefas ou sua máquina não puder receber chamadas HTTPS públicas. Escolha Webhooks quando usuários estiverem esperando em uma aplicação interativa ou tarefas longas de vídeo forem ocupar os processos de trabalho.
Para tarefas com imagem de entrada, o fluxo de upload do SDK executa /files/{fileId}/commit e retorna uma URI spicy://; veja a documentação de mídia.
Execute uma tarefa com o SDK
Instale spicyapi, defina SPICY_API_KEY e execute o exemplo. Guarde map-image.json para retomar a mesma tarefa após uma interrupção. Para uma imagem intencionalmente diferente, use um novo nome de execução. O Python SDK fornece os métodos da API; a referência de tarefas cobre o ciclo de vida completo.
import json
import os
import time
import uuid
from pathlib import Path
from spicyapi import SpicyClient, output_assets
client = SpicyClient()
def run(model, inputs, name):
path = Path(name + ".json")
request = {"model": model, "input": inputs}
saved = json.loads(path.read_text()) if path.exists() else {"request": request, "key": str(uuid.uuid4())}
if saved["request"] != request:
raise ValueError("Changed input needs a new run name; preserve the old attempt.")
def save():
temporary = path.with_suffix(".tmp")
temporary.write_text(json.dumps(saved))
temporary.chmod(0o600)
temporary.replace(path)
if not saved.get("taskId"):
if time.time() - saved.get("sentAt", time.time()) >= 23 * 3600:
raise RuntimeError("Reconcile the saved attempt before submitting again.")
if "quote" not in saved:
saved["quote"] = client.quote_task(model=model, input_data=inputs)
if input(f"Maximum ${saved['quote']['maxCharge']}. Create? [y/N] ") != "y":
raise SystemExit("Stopped without creating this task.")
saved.setdefault("sentAt", time.time())
save()
quote = saved["quote"]
task = client.create_task(model=model, input_data=inputs,
idempotency_key=saved["key"], quote_id=quote["quoteId"], expected_cost=quote["estimatedCost"])
saved["taskId"] = task["taskId"]
save()
print("Task:", saved["taskId"])
for _ in range(360):
task = client.get_task(saved["taskId"])
if task["state"] not in {"queued", "running"} and task["state"] != "succeeded":
raise RuntimeError(str(task.get("errorMessage", task["state"])))
if task["state"] == "succeeded":
assets = output_assets(task)
if assets and assets[0].get("unavailable"):
raise RuntimeError("Output unavailable; keep the task ID for reconciliation.")
if assets and assets[0].get("url") and not assets[0].get("pending"):
return assets[0]
time.sleep(5)
raise TimeoutError("Rerun the same saved attempt to resume; no new task is needed.")
asset = run("bytedance/seedream-5.0-pro/text-to-image", {
"prompt": "a folded paper map on a wooden table, overhead", "resolution": "1k", "output_format": "png"
}, "map-image")
print(asset["url"])Leia a resposta corretamente
Uma tarefa sempre está em um destes estados: queued, running, succeeded, failed ou expired. Só os dois primeiros indicam que ela continua em andamento. Portanto, encerre o loop quando o estado não for queued nem running, em vez de esperar apenas por succeeded; caso contrário, você consultará indefinidamente uma tarefa que falhou (registros antigos também podem mostrar o estado somente de leitura canceled). O link do resultado fica em output.assets[0].url. Ao chamar a API direta, leia a tarefa no objeto data do envelope, não na raiz da resposta. Uma tarefa aceita não pode ser cancelada, e só succeeded é cobrado; failed e expired normalmente liberam o valor reservado.
O que um timeout significa para sua aplicação
HTTP 202 significa que uma tarefa foi aceita, não que a geração terminou. Um timeout local interrompe a espera; não cancela a tarefa aceita. Guarde o ID e retome essa tarefa em vez de comprar outra geração. O prazo retornado pela tarefa delimita a recuperação, não prevê o tempo de renderização.
- Resposta de envio perdida: preserve a solicitação e sua chave para que a recuperação encontre a tarefa original.
- Geração falhou: mostre o erro do modelo e deixe o usuário escolher conscientemente outra tentativa.
- Geração concluída, arquivo pendente: continue esperando nessa tarefa; a imagem ou o vídeo ainda está sendo preparado para entrega.
Uma nova solicitação recebe uma nova chave de idempotência. Ao recuperar a mesma solicitação, mantenha a chave e a entrada inalteradas. A referência de idempotência descreve a janela de 24 horas para repetir uma solicitação.
Use Webhooks para o caminho rápido
Envie os eventos de conclusão ao backend da sua aplicação e depois atualize a interface pelo seu canal habitual de notificações. Um callback não é uma mensagem direta ao navegador do usuário.
O receptor deve fazer quatro coisas:
- Verificar o evento com o SDK oficial e o corpo bruto da solicitação.
- Confirmar que a tarefa pertence a um trabalho da sua aplicação.
- Persistir o evento e eliminar duplicatas antes de confirmar seu recebimento.
- Enfileirar a cópia do resultado e a atualização da aplicação separadamente da resposta HTTP.
Escolha quando: você já tiver um backend e quiser avisos rápidos de conclusão. Procure outra opção quando: for um script local curto sem receptor público; a sondagem é mais simples.
Verifique separadamente a conclusão da tarefa e a entrega de mídia. Um evento bem formado pode descrever uma tarefa que falhou, enquanto uma tarefa bem-sucedida pode exigir o tratamento dos arquivos antes de sua aplicação indicar que está pronta. A documentação de Webhooks contém as regras de verificação e entrega.
Mantenha uma varredura de reconciliação
Salve o ID de cada tarefa aceita. Revise periodicamente as tarefas que sua aplicação ainda não resolveu, especialmente após uma implantação, falha de rede ou rotação do segredo de assinatura. Passe um resultado recuperado pelo mesmo manipulador de conclusão idempotente usado por um Webhook, para que a galeria não receba o mesmo arquivo duas vezes.
Mantenha as cobranças não resolvidas no registro até a liquidação terminar. Se os registros locais se perderem, o histórico de tarefas da chave atual permite recuperar os IDs; a integração em produção explica esse caminho.
Copie os resultados antes que expirem
Os links de resultados prontos são temporários. Copie os arquivos para um armazenamento que você controle, com um cabeçalho de solicitação User-Agent e um nome de arquivo correspondente ao formato retornado. Uma falha no download é motivo para recuperar o resultado existente, não para gerá-lo novamente.
Consulte os prazos em retenção e entrega de mídia e o fluxo de cópia em armazenamento durável.
A decisão
Comece com sondagem pelo SDK para um script pequeno. Adicione Webhooks verificados quando tiver um serviço interativo e mantenha a varredura para recuperação. O ID salvo conecta os três caminhos: eles recuperam uma única geração em vez de enviar tarefas substitutas.
Para mais trabalhos simultâneos, adicione um despacho de lotes com limites. Para seu primeiro par de imagem e vídeo, use o guia inicial.
Deixe um Agent cuidar da chamada
Use um Agent quando quiser que ele prepare as entradas e retorne o resultado enquanto você aprova o preço e as escolhas criativas.
- CLI: salve
{"prompt": "a folded paper map on a wooden table, overhead", "resolution": "1k", "output_format": "png"}comoinput.jsone usenpx @spicyapi/cli tasks create --model bytedance/seedream-5.0-pro/text-to-image --input-file input.json --wait. A CLI pede a confirmação do preço; guarde o ID retornado para recuperação. - MCP: peça ao assistente para usar
spicyapi_task_createparabytedance/seedream-5.0-pro/text-to-imagee depoisspicyapi_task_wait. O MCP server solicita a confirmação do preço antes da criação. - Skill: instale com
npx skills add spicyapi-ai/spicy-skill, depois peça a$spicyapipara executar o mesmo fluxo e parar para sua aprovação. O Skill usa uma conexão CLI ou MCP configurada.







