Tutorial
Como chamar seedream-4.5/image-to-image pela API da HiAPI: curl e Python
Uma demonstração completa de uma requisição executável, abrangendo entrada com múltiplas imagens de referência, polling assíncrono e tratamento da saída
O que este endpoint faz e quando escolhê-lo
seedream-4.5/image-to-image transforma uma ou mais imagens de referência, junto com um prompt de texto, em uma nova imagem. Ele pertence à família de image-to-image da HiAPI: você fornece o contexto visual e o modelo o reinterpreta conforme suas instruções. Esta é a diferença crucial em relação ao text-to-image — no text-to-image, o prompt é a única entrada e o modelo cria tudo do zero.
Escolha image-to-image quando quiser que o resultado visual permaneça ancorado em material já existente: redesenhar o estilo de um ativo existente, alterar iluminação ou fundo mantendo a forma e o layout do produto, iterar a composição sem perder o sujeito, ou reutilizar as mesmas imagens de referência para garantir consistência visual em um lote de resultados.
Escolha text-to-image quando não tiver material de referência e quiser apenas descrever uma cena com texto.
Este endpoint é assíncrono. Você envia a tarefa, recebe um identificador e então faz polling até que a tarefa atinja um estado terminal e possa obter a saída. Planeje esse ciclo de vida desde o início; o restante deste guia constrói uma requisição executável e depois a reforça.
Construindo uma requisição curl executável
Toda requisição enviada a este endpoint tem a mesma estrutura básica. Trate campo por campo.
Endpoint e método
A requisição é enviada via POST para a rota de image-to-image sob a URL base da HiAPI, usando o identificador de modelo seedream-4.5/image-to-image. O nome do modelo é um valor no payload da requisição, não parte do caminho.
Autenticação
Passe sua chave de API da HiAPI como bearer token no cabeçalho Authorization. Mantenha-a em uma variável de ambiente para que não entre no histórico do shell nem no controle de código-fonte:
export HIAPI_API_KEY="your-key-here"
Payload mínimo da requisição
curl -sS -X POST "$HIAPI_BASE_URL/v1/images/generations" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "seedream-4.5/image-to-image",
"prompt": "restyle this photo as a warm studio portrait",
"image": "https://example.com/reference.jpg"
}'
Campo por campo:
model— o identificador literalseedream-4.5/image-to-image.prompt— o que fazer com a imagem de referência. Descreva a transformação, não apenas o sujeito.image— a entrada de referência. Para uma única imagem, é um valor; a próxima seção aborda múltiplas imagens de referência.
Lendo a primeira resposta
A chamada retorna uma tarefa aceita, não uma imagem concluída. Capture o identificador da tarefa do corpo da resposta e guarde-o; você precisará dele durante o polling. Não trate um status do tipo 200 como “imagem pronta”.
Antes de escrever qualquer código de cliente, execute esta requisição uma vez, exatamente como está. Um payload que falha no curl também falhará no Python pelos mesmos motivos, e depurar no shell é mais rápido.
Portando a requisição para Python
A versão em Python mantém o payload byte a byte idêntico, substituindo apenas a camada de transporte e o tratamento de autenticação. Essa separação é o ponto central: se o curl funciona, o Python deve funcionar na primeira tentativa.
import os
import requests
BASE_URL = os.environ["HIAPI_BASE_URL"]
API_KEY = os.environ["HIAPI_API_KEY"]
payload = {
"model": "seedream-4.5/image-to-image",
"prompt": "restyle this photo as a warm studio portrait",
"image": "https://example.com/reference.jpg",
}
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
}
resp = requests.post(
f"{BASE_URL}/v1/images/generations",
json=payload,
headers=headers,
timeout=30,
)
resp.raise_for_status()
job = resp.json()
print(job["id"])
As observações a seguir economizam tempo mais adiante:
- Construa o payload como um dict Python e deixe
json=cuidar da serialização. Strings JSON escritas à mão são a origem típica de erros de aspas. - Mantenha a construção da autenticação em uma função auxiliar. Se o formato do cabeçalho mudar, você altera em um único lugar.
- Passe sempre um
timeoutexplícito também na chamada de envio. Um socket travado na etapa de envio é indistinguível de um modelo lento. - Armazene o identificador de tarefa retornado imediatamente, em vez de derivá-lo novamente a partir de logs.
O código de polling nas seções seguintes usa o mesmo BASE_URL, API_KEY e headers, então mantenha-os no escopo do módulo ou em uma pequena classe de cliente.
Passando múltiplas imagens de referência
A entrada com múltiplas imagens de referência é o ponto mais propenso a erros em requisições image-to-image, geralmente porque o modelo recebe três imagens e o prompt descreve apenas uma delas.
Organize as entradas explicitamente
Coloque as imagens de referência como uma lista no mesmo campo image, na ordem desejada, e faça o prompt indicar o papel de cada posição:
payload = {
"model": "seedream-4.5/image-to-image",
"prompt": (
"Use the first reference for the subject's pose, "
"the second for the background setting, "
"and the third for color grading. Keep the subject sharp."
),
"image": [
"https://example.com/pose.jpg",
"https://example.com/background.jpg",
"https://example.com/grading.jpg",
],
}
Por que rotular é melhor que posicionar
A ordem da lista é uma convenção, mas o prompt é o que diz ao modelo como interpretar essa ordem. Um array vago com um prompt ambíguo força o modelo a adivinhar qual referência tem prioridade quando elas entram em conflito. Indicar o papel de cada imagem no prompt transforma suposições implícitas de posição em instruções explícitas.
Regras práticas:
- Mantenha o número de imagens de referência pequeno e cada uma com um propósito claro. Referências em excesso diluem o resultado em vez de enriquecê-lo.
- Explique como resolver conflitos: se a referência de pose e a de fundo discordam no enquadramento, diga qual delas tem prioridade.
- Use URLs estáveis e acessíveis publicamente, ou um mecanismo de upload equivalente. Uma referência que retorna 404 no meio da tarefa faz a requisição inteira falhar.
Se a saída ignorar alguma imagem de referência, a solução habitual não é reenviar ao modelo, mas sim indicar o papel daquela imagem com uma frase mais clara no prompt.
Tratando o ciclo de vida de tarefas assíncronas
A geração de imagens leva tempo, então este endpoint é baseado em tarefas. Trate o ciclo de vida como quatro etapas separadas e escreva código para cada uma.
1. Envio
Envie o POST mostrado anteriormente. Antes de fazer qualquer outra coisa, persista o identificador de tarefa da resposta.
2. Polling
Usando os mesmos cabeçalhos de autenticação, faça requisições GET para a rota da tarefa até que o status atinja um estado terminal:
import time
def poll_job(job_id, interval=2.0, max_interval=30.0, deadline=300.0):
start = time.monotonic()
while True:
r = requests.get(
f"{BASE_URL}/v1/images/generations/{job_id}",
headers=headers,
timeout=30,
)
r.raise_for_status()
data = r.json()
status = data["status"]
if status in ("succeeded", "failed"):
return data
if time.monotonic() - start > deadline:
raise TimeoutError(f"job {job_id} not finished within {deadline}s")
time.sleep(interval)
interval = min(interval * 2, max_interval)
3. Detectando o estado terminal
Apenas dois resultados encerram o loop: sucesso ou falha. Qualquer outro caso significa continuar aguardando. Nunca presuma que a saída é imediata e nunca faça um número fixo de tentativas de polling sem um limite de tempo real.
4. Obtendo o resultado
Tratado na próxima seção.
O backoff é importante. Um loop apertado de sleep(0.1) gasta seu orçamento de requisições em verificações de status. Começar com cerca de dois segundos e dobrar até um limite mantém a latência baixa sem sobrecarregar a API.
Recuperando e armazenando a saída
Quando o polling retorna um status de sucesso, a resposta traz uma referência à saída. O que é retornado é um ponteiro para a imagem gerada, não necessariamente os bytes em si.
Baixando de forma intencional
data = poll_job(job_id)
url = data["output"][0]["url"] if isinstance(data["output"], list) else data["output"]
with requests.get(url, stream=True, timeout=60) as r:
r.raise_for_status()
with open(f"{job_id}.png", "wb") as f:
for chunk in r.iter_content(chunk_size=8192):
f.write(chunk)
Ajuste o caminho conforme a estrutura real da resposta observada na sua primeira tarefa real, em vez de presumir um formato fixo.
Regras de armazenamento que evitam retrabalho
- Nomeie o arquivo pelo identificador da tarefa. Ele é único, rastreável e associa o artefato à requisição que o produziu.
- Baixe prontamente. Os links de saída podem ter validade limitada, então persista imediatamente após o polling bem-sucedido, em vez de guardar a URL para depois.
- Use streaming para arquivos grandes, em vez de carregá-los inteiros na memória.
- Registre o prompt e a lista de imagens de referência junto com o arquivo. Quando a saída for inesperada, as entradas são o registro de depuração.
Se você precisar de novas tentativas determinísticas, armazenar o identificador da tarefa significa que pode refazer o polling ou o download sem pagar por uma segunda geração.
Erros, novas tentativas e controle de custos
A maioria das falhas se enquadra em três categorias, e cada uma exige um tratamento diferente.
Erros de cliente
Payload malformado, model ausente, URL de imagem de referência inacessível ou chave incorreta. Esses erros retornam imediatamente e continuarão retornando em novas tentativas. Corrija a requisição; não repita em loop. Valide que as URLs das imagens de referência resolvem antes do envio.
Erros temporários de servidor e rede
Timeouts, resets de conexão, respostas de rate limit. Vale a pena tentar novamente com backoff exponencial e jitter, limitado a um número pequeno de tentativas máximas. Repita a etapa específica — envio, polling ou download —, não o pipeline inteiro. Reenviar após um envio bem-sucedido é exatamente como se paga a mais sem querer.
Falhas no nível da tarefa
A tarefa atinge o estado terminal de falha. Tentar novamente com o mesmo identificador de tarefa não ajudará. Decida explicitamente se deve reenviar com um prompt ou conjunto de referências modificado, e registre a causa da falha para distinguir erro de entrada de falha temporária.
def with_retries(fn, attempts=4, base=1.0):
for i in range(attempts):
try:
return fn()
except requests.RequestException:
if i == attempts - 1:
raise
time.sleep(base * (2 ** i))
Controle de custos
A cobrança está vinculada à geração, então o erro caro é o envio duplicado. Imponha um limite de tempo real ao polling, mantenha o envio idempotente armazenando o identificador da tarefa antes do polling e limite a concorrência para que uma tempestade de novas tentativas não inflacione para dezenas de tarefas cobradas. Registre cada envio com seu identificador de tarefa; esse log é sua trilha de auditoria de gastos.
Conecte esses três pontos ao cliente de uma vez e o mesmo código tratará requisições com uma ou várias imagens de referência sem alterações.
Artigos relacionados
Ver todos os artigos →-
Tutorial
Como chamar hailuo-2.3-fast/image-to-video pela API HiAPI: curl e Python na prática
A primeira requisição executável do nível rápido e econômico de geração de vídeo a partir de imagem — do ID do modelo ao download do MP4
-
Tutorial
Como chamar hailuo-2.3/text-to-video pela API HiAPI: curl, Python e exemplos de requisição executáveis
-
Tutorial
Usar Kandinsky 6.0 Pro text-to-video na HiAPI: tutorial de curl e Python
Demonstração prática com foco na requisição: montar a chamada de prompt para clipe de vídeo, enviar a requisição, consultar o status de conclusão e baixar o resultado