Tutorial
Remover o fundo da imagem com a API: edição baseada em prompt
Como substituir ou remover o fundo de imagens usando modelos de imagem para imagem no hiapi — mínimo de código, modo em lote e detalhes de schema que tornam a composição de fotos de produto precisa.
Ferramentas tradicionais de remoção de fundo oferecem apenas uma operação: recortar o sujeito, deixando uma área transparente (ou preenchimento sólido). Já a remoção de fundo baseada em prompt com modelos de imagem para imagem permite obter, em uma única chamada, tanto o recorte quanto o fundo substituído — um fundo de estúdio branco sem emendas, uma cena de estilo de vida, uma cor de marca sólida — porque o modelo regenera pixel a pixel o fundo ao redor do sujeito preservado, em vez de apenas calcular uma máscara alfa.
Este guia mostrará exatamente como fazer isso no hiapi: quais modelos de imagem para imagem realmente se destacam na remoção de fundo, a estrutura de requisição/resposta na qual você precisa codificar e os padrões de produção (callbacks, retentativas, tratamento de erros) que evitam que tarefas em lote contaminem silenciosamente seu catálogo de produtos.
Pré-requisitos:
- Obter uma chave de API hiapi no seu painel
- Python 3.9+ com
requestsinstalado (pip install requests) - Sua imagem de origem hospedada em uma URL pública — a API de tarefas do hiapi busca imagens por URL, não por upload de arquivo, portanto caminhos locais não funcionam. Qualquer armazenamento de objetos ou CDN serve.
Como a remoção de fundo funciona como tarefa de imagem para imagem
Toda geração no hiapi — imagem, vídeo ou áudio — segue o mesmo ciclo de vida assíncrono de tarefa: você envia uma tarefa, obtém um taskId e então faz polling do resultado ou o recebe via URL de callback. O contrato completo está na referência da API de tarefas assíncronas; para remoção de fundo, as partes importantes são:
POST /v1/taskscommodel+input(seu prompt, URL da imagem de origem e formato de saída) retorna{"code":200,"data":{"taskId":"tk-hiapi-..."}}. Neste momento ainda não há campostatus.GET /v1/tasks/{taskId}retornadata.status, com valor entrequeued,handling,archiving,success,fail. Apenassuccessefailsão estados terminais.- Quando o status é
success,data.outputé um array de{"url","type","expireAt"}.urlé um link assinado de curta duração (expireAté um timestamp Unix) — baixe imediatamente, não armazene esse hotlink.
Quanto ao modelo, use o endpoint de imagem para imagem e faça o prompt descrever o fundo substituído, em vez de dizer isoladamente "remover o fundo" — esses modelos respondem muito melhor a alvos concretos do que a instruções negativas:
Remova o fundo completamente e substitua-o por um fundo de estúdio
branco puro e sem emendas. Mantenha a forma, as bordas, a iluminação e as cores
do sujeito exatamente inalteradas. Não adicione sombras, reflexos ou quaisquer outros objetos
que não estavam na imagem original.
Exemplo mínimo: inserir uma imagem, substituir o fundo
seedream-5.0-lite/image-to-image é a opção mais barata e suficiente para esse uso — aceita prompt, image_urls, aspect_ratio e resolution (apenas 2K ou 4K; esse endpoint não tem faixa 1K, e campos desconhecidos como n ou seed são rejeitados diretamente com 400).
import os
import time
import requests
API = "https://api.hiapi.ai/v1"
HEADERS = {
"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}",
"Content-Type": "application/json",
}
BACKGROUND_PROMPT = (
"Remova o fundo completamente e substitua-o por um fundo de estúdio "
"branco puro e sem emendas. Mantenha a forma, as bordas, a iluminação e as "
"cores do sujeito exatamente inalteradas. Não adicione sombras, reflexos ou quaisquer outros "
"objetos que não estavam na imagem original."
)
def create_task(model: str, task_input: dict) -> str:
resp = requests.post(f"{API}/tasks", headers=HEADERS,
json={"model": model, "input": task_input}, timeout=60)
resp.raise_for_status()
return resp.json()["data"]["taskId"]
def wait_task(task_id: str, timeout_s: int = 180, poll_s: int = 3) -> dict:
deadline = time.time() + timeout_s
while time.time() < deadline:
resp = requests.get(f"{API}/tasks/{task_id}", headers=HEADERS, timeout=30)
resp.raise_for_status()
task = resp.json()["data"]
if task["status"] == "success":
return task
if task["status"] == "fail":
err = task.get("error") or {}
raise RuntimeError(f"task {task_id} failed: {err.get('code')} {err.get('message')}")
time.sleep(poll_s)
raise TimeoutError(f"task {task_id} still {task['status']} after {timeout_s}s")
task_id = create_task("seedream-5.0-lite/image-to-image", {
"prompt": BACKGROUND_PROMPT,
"image_urls": ["https://your-cdn.example.com/product-photo.jpg"],
"aspect_ratio": "1:1",
"resolution": "2K",
})
task = wait_task(task_id)
image_bytes = requests.get(task["output"][0]["url"], timeout=60).content
with open("product-no-bg.png", "wb") as f:
f.write(image_bytes)
Esse é o ciclo completo: enviar, fazer polling, baixar. Para uma verificação rápida sem código antes de integrar ao pipeline, o Laboratório de Fotos de Produto com IA executa o mesmo tipo de substituição de fundo no navegador.
Processar catálogos de produtos em lote
Catálogos reais têm dezenas ou centenas de imagens, e a API de tarefas não tem endpoint nativo de lote — você mesmo precisa expandir os envios de tarefas individuais e fazer polling delas em paralelo:
from concurrent.futures import ThreadPoolExecutor, as_completed
def remove_background(image_url: str, aspect_ratio: str = "1:1") -> str:
task_id = create_task("seedream-5.0-lite/image-to-image", {
"prompt": BACKGROUND_PROMPT,
"image_urls": [image_url],
"aspect_ratio": aspect_ratio,
"resolution": "2K",
})
task = wait_task(task_id)
return task["output"][0]["url"]
source_urls = [
"https://your-cdn.example.com/sku-1001.jpg",
"https://your-cdn.example.com/sku-1002.jpg",
# ...
]
results = {}
with ThreadPoolExecutor(max_workers=5) as pool:
futures = {pool.submit(remove_background, url): url for url in source_urls}
for future in as_completed(futures):
url = futures[future]
try:
results[url] = future.result()
except Exception as exc:
results[url] = None
print(f"failed: {url}: {exc}")
Mantenha max_workers moderado — fazer polling com muita frequência em muitas tarefas concorrentes apenas consome sua cota de requisições e não acelera a geração, pois o tempo de parede de cada tarefa é determinado principalmente pela inferência do modelo, não pela frequência do seu polling.
Reforço para produção: composição precisa, callbacks, idempotência, erros
Preserve a composição exata do produto. Para trabalho de catálogo, você geralmente não pode tolerar que o modelo recomponha ou corte levemente o sujeito — um sapato centralizado na entrada precisa permanecer centralizado na saída. seedream-5.0-pro/image-to-image suporta um valor de aspect_ratio que a faixa lite não suporta: match_input_image, que trava a tela de saída nas dimensões da própria imagem de entrada, em vez de forçar uma proporção fixa. Ele também aceita até 10 image_urls por chamada, e limita resolution a 1K/2K (conjunto de resoluções diferente do lite — não presuma que os schemas dos endpoints seedream sejam iguais, cada endpoint tem seus próprios enums). Para trabalho puro de remoção e substituição de fundo em que a composição precisa corresponder exatamente, essa é a faixa a escolher, com custo maior por imagem — consulte os preços para as tarifas atuais.
Se você precisa referenciar vários ângulos de origem em uma única chamada (por exemplo, vista frontal e vista lateral do mesmo produto), em vez de processar uma imagem por chamada, nano-banana-2 é uma alternativa razoável — ele aceita imagens de referência via image_input (não image_urls), e resolution pode ser 1K/2K/4K.
Use callbacks em vez de polling. Para qualquer tarefa em lote em escala real, webhooks são melhores que polling: adicione um objeto callback como irmão de input — não aninhado dentro dele, POST /v1/tasks rejeita essa estrutura:
task_input = {
"prompt": BACKGROUND_PROMPT,
"image_urls": [image_url],
"aspect_ratio": "1:1",
"resolution": "2K",
}
resp = requests.post(f"{API}/tasks", headers=HEADERS, json={
"model": "seedream-5.0-lite/image-to-image",
"input": task_input,
"callback": {"url": "https://your-service.example.com/hooks/hiapi", "when": "final"},
}, timeout=60)
Quando a tarefa atinge um estado terminal, o hiapi envia por POST para sua URL de callback o mesmo objeto data que GET /v1/tasks/{taskId} retornaria. Se quiser validar a autenticidade do callback no servidor, consulte o cabeçalho HMAC opcional X-HiAPI-Signature na referência de tarefas assíncronas.
Idempotência. Não há campo idempotency_key documentado em POST /v1/tasks — implemente a idempotência na camada da aplicação. Use um armazenamento pequeno (linha de banco de dados, chave Redis, ou até arquivo local para scripts únicos), com chave baseada no hash de (image_url, prompt, model), e antes de enviar uma nova tarefa verifique se essa chave já tem um taskId ou URL de saída armazenado. Se sua tarefa em lote falhar no meio e for reexecutada, você evita a cobrança duplicada de imagens já processadas, em vez de aumentar custos silenciosamente.
Tratamento de erros — três formas distintas, não trate igual:
- Validação da requisição (entrada inválida na criação) — HTTP 400, estrutura plana:
{"code":400,"error_code":"INVALID_REQUEST","message":"...","data":null}. Isso significa que seu dicionárioinputnão corresponde ao schema do modelo — verifique se há nome de campo digitado errado ou valor de enum incorreto. - Falha de autenticação — HTTP 401, aninhamento diferente:
{"error":{"code":"permission_denied","message":"...","request_id":"...","type":"hiapi_error"}}. Chave de API ausente/expirada, não erro de requisição — não faça retentativa, corrija a chave. - Falha em nível de tarefa (requisição válida, mas a geração em si falha) — manifesta-se durante o polling:
data.status == "fail",data.errordescreve o motivo. Isso é retentável; erros transitórios do upstream podem ter sucesso ao reenviar.
if task["status"] == "fail":
err = task.get("error") or {}
# registre err["code"] / err["message"], depois decida: retentar, pular ou alertar
Não agrupe os três em um único except Exception — um 401 retentado em loop só consome seu limite de taxa e nunca terá sucesso, enquanto um fail em nível de tarefa pode realmente ter sucesso na segunda tentativa.
Próximos passos
- Referência da API de tarefas assíncronas — ciclo de vida completo, assinatura de callback, todos os valores de estado
- Páginas dos modelos seedream-5.0-lite/image-to-image e seedream-5.0-pro/image-to-image — schema ao vivo e exemplos
- Construir um pipeline de tarefas assíncronas — se a remoção de fundo é uma etapa de um pipeline de geração maior
- Corrigir o callback de tarefa do hiapi que não dispara — se seu webhook silenciou, esta é uma lista de verificação de depuração
- Prompts de imagem para imagem do Flux 2 Klein 9B — padrões de prompt de outro modelo i2i, para comparação
- Laboratório de Fotos de Produto com IA — versão sem código do mesmo fluxo de trabalho
Perguntas frequentes
Isso realmente remove o fundo ou apenas o cobre? Funcionalmente, ambos — o modelo regenera toda a tela ao redor do sujeito preservado, portanto não deixa máscara residual ou bordas irregulares como ferramentas de recorte por detecção de bordas. O custo é que você precisa instruir explicitamente no prompt "mantenha todo o resto inalterado", caso contrário o modelo pode reestilizar alegremente até o sujeito.
Posso obter um PNG transparente em vez de um fundo de cor sólida? Peça diretamente no prompt (por exemplo, "substitua o fundo por transparente" ou "isole o sujeito em um fundo transparente") e solicite saída PNG onde o modelo suportar o campo output_format — o suporte varia por modelo, então verifique a página do modelo específico antes de assumir que está disponível.
Por que minha imagem volta recomposta em vez de corresponder à original? Você provavelmente está usando uma faixa cujo enum de aspect_ratio não inclui match_input_image — nas faixas lite/4.5, você escolhe uma proporção fixa, que pode cortar ou adicionar barras em relação à origem. Mude para seedream-5.0-pro/image-to-image e defina aspect_ratio como match_input_image.
Qual é o custo por imagem? O preço varia por modelo e faixa de resolução, e muda com o tempo — consulte os preços em vez de codificar números no seu código ou documentação.
E se minha URL de imagem ainda não for pública? A API de tarefas busca imagens por URL no servidor, portanto ela precisa ser acessível sem autenticação. Faça upload primeiro para qualquer bucket público ou caminho de CDN — URLs assinadas/privadas ou caminhos localhost falharão na criação da tarefa, ou (pior) falharão silenciosamente durante o processamento.
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