Tutorial
Gerar imagens de produtos de e-commerce com o FLUX.1 [schnell] via API hiapi
Um guia prático de curl + Python para imagens de catálogo em fundo branco, imagens de cena e imagens de variantes, a $0.005 por imagem.
A fotografia de catálogo é a parte mais lenta de publicar um SKU online. Reservar estúdio, contratar modelo, montar softbox, contratar retocador — para uma caneca de $24, isso simplesmente não faz sentido. O flux-schnell/text-to-image na hiapi gera imagens de produto utilizáveis em fundo branco, imagens principais de cena e imagens de variantes de cor/material, a $0.005 por imagem, com cerca de 30 segundos de ponta a ponta — nessa escala, você para de se preocupar com o custo por captura e começa a pensar em prompts e lotes de prompts.
Este guia percorre o fluxo de trabalho exato: os quatro tipos de imagem que uma página de detalhes de produto realmente precisa; a estrutura de prompt que mantém o modelo sobre um fundo branco contínuo limpo, em vez de inventar uma mesa de madeira do nada; como gerar 100 variantes em lote via /v1/tasks sem derrubar seu terminal; e as poucas coisas que o schnell não faz bem, que você precisa planejar com antecedência.
Por que o trabalho de catálogo é especialmente adequado ao flux-schnell
A hiapi também tem modelos de maior fidelidade (flux-2, flux-1.1-pro, nano-banana-pro>), e para a imagem principal de uma campanha de marca, você deveria usá-los. Mas para catálogo, a conta é diferente:
- Uma renovação de 200 SKUs, com cerca de 4 imagens por SKU (fundo branco, cena, referência de escala, vista superior) = 800 imagens. A $0.005, isso dá $4. A $0.05, dá $40. A $0.17, dá $136.
- O
schnellconclui a geração em 1–4 passos de amostragem, então de ponta a ponta (fila + geração + download) levou cerca de 30 segundos nas nossas execuções. Oflux-2e onano-banana-prosão várias vezes mais lentos. - Imagens de catálogo são exibidas a 600px de largura na página de detalhes do produto e a 200px na grade. Nesses tamanhos, a margem de fidelidade dos modelos avançados é simplesmente invisível; a aderência ao prompt e a sanidade da proporção importam mais.
O trade-off é real: o schnell é fraco em textos pequenos e legíveis em rótulos, fraco em produtos segurados por pessoas (para isso, use o nano-banana-pro) e visivelmente fraco em logos de marca complexos. Para "me mostre o produto sobre um fundo limpo, em três cores, em vista superior e em três quartos" — o trabalho real dele — ele é excelente.
A lista de imagens que você realmente vai gerar
Antes de escrever qualquer prompt, defina o que o template da sua página de detalhes de produto precisa. Um conjunto inicial útil:
| Tipo de imagem | Proporção | Usada para |
|---|---|---|
| Imagem de produto em fundo branco | 1:1 |
Imagem principal da página de detalhes, miniaturas da grade |
| Foto de estúdio em três quartos | 4:3 |
2ª imagem da galeria da página de detalhes |
| Imagem de cena / contextual | 3:2 |
Galeria da página de detalhes, anúncios sociais |
| Imagem plana vista de cima | 1:1 |
Galeria da página de detalhes, referência de escala |
| Grade de variantes de cor/material | 1:1 por variante |
Miniaturas do seletor de cor |
O flux-schnell na hiapi aceita 1:1, 3:2, 2:3, 4:3, 3:4, 5:4, 4:5, 16:9, 9:16, 21:9, auto. Qualquer outra proporção é rejeitada na criação da tarefa.
Execução única: gerar uma única imagem de produto com curl
O mínimo necessário para confirmar que o token funciona. Minha última execução de ponta a ponta levou 31 segundos:
TOKEN="$HIAPI_API_KEY"
# 1. Criar a tarefa
TASK=$(curl -s -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model": "flux-schnell/text-to-image",
"input": {
"prompt": "Product packshot: matte ceramic coffee mug, soft beige glaze, centered on seamless white cyclorama, soft diffused studio lighting, subtle contact shadow, 50mm photography, no props, ecommerce hero, clean negative space top and bottom",
"aspect_ratio": "1:1"
}
}' | jq -r '.data.taskId')
echo "task: $TASK"
# 2. Poll até concluir (success | fail)
while true; do
STATE=$(curl -s "https://api.hiapi.ai/v1/tasks/$TASK" \
-H "Authorization: Bearer $TOKEN")
STATUS=$(echo "$STATE" | jq -r '.data.status')
echo " status=$STATUS"
[ "$STATUS" = "success" ] && break
[ "$STATUS" = "fail" ] && { echo "$STATE" | jq '.data.error'; exit 1; }
sleep 4
done
# 3. Baixar (a URL de saída expira; capture imediatamente)
URL=$(echo "$STATE" | jq -r '.data.output[0].url')
curl -s -o packshot.jpg "$URL"
echo "saved packshot.jpg"
Uma peculiaridade específica do flux-schnell: o schema de entrada do modelo aceita aspect_ratio, mas rejeita resolution. Outros modelos de imagem na hiapi (por exemplo, flux-2, nano-banana-pro) aceitam ambos. Se você enviar {"aspect_ratio": "1:1", "resolution": "1K"} para o flux-schnell, recebe:
{
"code": 400,
"message": "additional properties not allowed: resolution"
}
Remova o resolution. Você não precisa dele — o schnell gera na proporção que você escolher, no tamanho padrão do modelo.
Produção: geração em lote com Python
O trabalho real de catálogo envia muitas tarefas, baixa as saídas conforme ficam prontas e repete as falhas. Este é o script que usamos ao prototipar uma família de SKUs:
"""Gerador em lote de packshots para flux-schnell na hiapi.
Lê um CSV de (sku, prompt, aspect_ratio), envia todos os jobs, faz poll em paralelo,
baixa as saídas prontas para ./out/{sku}.jpg. Custo total = $0.005 * len(csv).
"""
import csv
import json
import os
import subprocess
import time
from concurrent.futures import ThreadPoolExecutor, as_completed
from pathlib import Path
API = "https://api.hiapi.ai/v1/tasks"
TOKEN = os.environ["HIAPI_API_KEY"]
OUT = Path("./out"); OUT.mkdir(exist_ok=True)
def _post(path, body):
r = subprocess.run(
["curl", "-s", "-X", "POST", path,
"-H", f"Authorization: Bearer {TOKEN}",
"-H", "Content-Type: application/json",
"-d", json.dumps(body)],
capture_output=True, text=True, timeout=60,
)
return json.loads(r.stdout)
def _get(path):
r = subprocess.run(
["curl", "-s", path, "-H", f"Authorization: Bearer {TOKEN}"],
capture_output=True, text=True, timeout=30,
)
return json.loads(r.stdout)
def render(sku: str, prompt: str, ratio: str) -> tuple[str, str]:
"""Enviar → poll → baixar. Retorna (sku, status). status='ok' ou 'fail:<reason>'."""
body = {"model": "flux-schnell/text-to-image",
"input": {"prompt": prompt, "aspect_ratio": ratio}}
resp = _post(API, body)
task_id = (resp.get("data") or {}).get("taskId")
if not task_id:
return sku, f"fail:submit:{resp.get('message')}"
deadline = time.time() + 180
while time.time() < deadline:
state = _get(f"{API}/{task_id}")
data = state.get("data") or {}
status = data.get("status")
if status == "success":
url = (data.get("output") or [{}])[0].get("url")
if not url:
return sku, "fail:no-output-url"
subprocess.run(["curl", "-s", "-o", str(OUT / f"{sku}.jpg"), url],
timeout=60, check=True)
return sku, "ok"
if status == "fail":
return sku, f"fail:model:{data.get('error', {}).get('code')}"
time.sleep(4)
return sku, "fail:timeout"
def main():
rows = list(csv.DictReader(open("skus.csv")))
print(f"submitting {len(rows)} renders (cost ${0.005 * len(rows):.3f})")
with ThreadPoolExecutor(max_workers=8) as ex:
futures = {ex.submit(render, r["sku"], r["prompt"], r["aspect_ratio"]): r
for r in rows}
for f in as_completed(futures):
sku, status = f.result()
print(f" {sku}: {status}")
if __name__ == "__main__":
main()
Uma linha de skus.csv se parece com isto:
sku,prompt,aspect_ratio
mug-beige-01,"Product packshot: matte ceramic mug, beige glaze, seamless white cyclorama, soft studio lighting, subtle contact shadow, 50mm photography, ecommerce hero, clean negative space",1:1
mug-charcoal-01,"Product packshot: matte ceramic mug, charcoal glaze, seamless white cyclorama, soft studio lighting, subtle contact shadow, 50mm photography, ecommerce hero, clean negative space",1:1
Notas sobre o código de produção:
ThreadPoolExecutor(max_workers=8)é um nível de paralelismo seguro para oschnell. Mais do que isso só aprofunda a fila, não conclui mais rápido.- O timeout de 180 segundos por tarefa é conservador; na prática, toda tarefa bem-sucedida conclui em 30–60 segundos. Disparar o timeout significa que a tarefa travou — veja as quatro causas no guia de diagnose de travamento/timeout de tarefas da hiapi.
- Baixamos imediatamente após
success.output[].urlé um link temporário com um carimboexpireAt; não o armazene no seu CMS.
O template de prompt que produz suas imagens de produto entediantes mas úteis
Prompt de catálogo não é prompt criativo. Você quer a mesma iluminação, o mesmo fundo, a mesma câmera em todas, mudando só o produto. Um template:
Product packshot: {MATERIAL} {PRODUCT}, {COLOR} {FINISH},
{COMPOSITION},
{BACKGROUND},
{LIGHTING},
{LENS_NOTE},
ecommerce hero, no props, clean negative space {AREA}
Preenchido:
Product packshot: matte ceramic coffee mug, soft beige glaze,
centered single subject filling about 60% of frame,
seamless white cyclorama background,
soft diffused studio lighting from the upper left, subtle contact shadow underneath,
shot on 50mm with shallow depth of field,
ecommerce hero, no props, clean negative space top and bottom
A ordem importa menos que a estrutura. Estes elementos melhoram consistentemente a saída:
- "seamless white cyclorama" é melhor que "white background" — o primeiro implica a iluminação de fundo infinito de estúdio, o segundo às vezes produz uma toalha de mesa.
- "subtle contact shadow underneath" evita que o produto pareça flutuar.
- "filling about 60% of frame" ancora a composição; sem isso, o
schnellàs vezes afasta demais ou empurra o produto para um canto. - "no props" evita pratos, folhas ou papelaria extras ao lado da caneca.
Para a variante de cena, substitua os blocos de fundo + iluminação:
... matte ceramic coffee mug, soft beige glaze, single subject filling about 40% of frame,
on a light oak countertop with morning sunlight from a kitchen window,
soft golden-hour rim lighting, gentle defocused background showing a blurred linen curtain,
shot on 35mm at f/2.8, lifestyle photography, no people, no other props
Para a imagem plana vista de cima:
... single subject centered, top-down 90-degree angle, ceramic coffee mug, soft beige glaze,
on a light grey paper surface, soft even overhead lighting, soft shadow directly under the rim,
shot on 50mm, flatlay product photography, no props, clean negative space all sides, 1:1
Rodando esses três prompts para o mesmo SKU, você obtém uma galeria de página de detalhes utilizável por $0.015.
Variantes de cor/material sem nova sessão de fotos
O schnell brilha no e-commerce é na geração de variantes. Uma vez que um prompt funciona para uma cor, você pode produzir as demais em lote por substituição de string no descritor de cor:
COLORS = [
("beige", "soft beige glaze"),
("charcoal", "deep charcoal matte glaze"),
("sage", "muted sage green glaze"),
("terracotta", "warm terracotta clay glaze"),
("cream", "off-white cream glaze with subtle speckle"),
]
TEMPLATE = (
"Product packshot: matte ceramic coffee mug, {color_desc}, "
"centered single subject filling about 60% of frame, "
"seamless white cyclorama background, soft diffused studio lighting from the upper left, "
"subtle contact shadow underneath, shot on 50mm, ecommerce hero, no props, "
"clean negative space top and bottom"
)
rows = [{"sku": f"mug-{c}-01", "prompt": TEMPLATE.format(color_desc=desc),
"aspect_ratio": "1:1"} for c, desc in COLORS]
Cinco variantes a $0.005 = $0.025 pelo seletor de cor inteiro. A ressalva: o schnell não mantém a forma perfeitamente idêntica entre renderizações. A espessura da alça, a curva da borda e as proporções variam levemente entre as cores. Para uma página de produto estilizada, isso é aceitável. Para variantes idênticas em nível de pixel, você precisa de condicionamento por imagem de referência, o que significa usar flux-1.1-pro com imagem de referência ou nano-banana-pro, não o schnell.
Integração ao front-end da sua loja
A saída é um arquivo JPG baixado. Dali até uma página de detalhes de produto publicada, o caminho depende da sua plataforma:
- Shopify:
POST /admin/api/2025-01/products/{id}/images.jsoncom o corpo{"image": {"attachment": "<base64>"}}. Ele retorna uma URL de CDN hospedada no Shopify. - WooCommerce: faça upload pela biblioteca de mídia do WP (
POST /wp-json/wp/v2/media) e depois faça PATCH no produto com o ID de mídia retornado comoimages: [{id: ...}]. - Headless / CMS próprio: faça upload para seu próprio armazenamento de objetos (S3, R2, Cloudflare Images) e referencie a URL gerada no registro do produto.
Em qualquer caso, faça o upload do lado do servidor, não no cliente, para que sua chave da hiapi nunca chegue ao navegador.
Cálculo de custo para planejamento
A $0.005 por imagem, o orçamento raramente é a restrição — mas pensar em lotes ajuda:
| Lote | Nº de imagens | Custo |
|---|---|---|
| Um SKU, 4 imagens | 4 | $0.02 |
| Lançamento de 50 SKUs, 4 imagens cada | 200 | $1.00 |
| Atualização de catálogo de 200 SKUs | 800 | $4.00 |
| Teste diário de variantes, 100 imagens/dia, por 30 dias | 3,000 | $15.00 |
Na hiapi, o custo do lado dos tokens (prompt) dos endpoints de imagem é grátis — você paga apenas pelas imagens de saída.
O que o flux-schnell não faz bem
Coisas a planejar antes de se comprometer:
- Texto de rótulo legível. Se sua imagem de produto precisa mostrar um wordmark de marca legível, gere a base com o
schnelle depois componha um PNG de rótulo real em um editor de imagem. Pedir aoschnellpara renderizar "a palavra 'OAK ROAST' na caneca" produz rabisco cerca de 80% das vezes. - Produtos segurados na mão. Anatomia humana é um ponto fraco do
schnell. Para imagens de cena com pessoas, use onano-banana-proou oflux-1.1-pro. - Produto idêntico em nível de pixel entre variantes. Para isso, use um modelo que aceite imagem de referência.
- Detalhes sub-milimétricos (joias, relógios com ponteiros visíveis, metal gravado). Isso é território de modelos avançados.
Para todo o resto na página de detalhes de produto — fundos, iluminação, variantes de cor, imagens contextuais, atmosfera — o flux-schnell é a ferramenta certa, na faixa de preço certa, com o tempo de resposta certo. O ciclo inteiro cabe em um script while true: poll; download e um CSV de SKUs, e o custo é baixo o bastante para você iterar prompts sem reunião de orçamento.
Perguntas frequentes
P: Posso enviar uma imagem de referência para o flux-schnell?
R: Não. O flux-schnell/text-to-image é apenas texto-para-imagem — o campo input aceita apenas prompt e aspect_ratio, e nada mais. Para variantes condicionadas por referência, use flux-1.1-pro ou nano-banana-pro, que aceitam entrada de imagem na hiapi.
P: Quais proporções são suportadas?
R: 1:1, 3:2, 2:3, 4:3, 3:4, 5:4, 4:5, 16:9, 9:16, 21:9 e auto. Qualquer outra proporção (por exemplo, 5:7, 2:1) é rejeitada na criação da tarefa com um erro apontando o conjunto suportado.
P: Por que a criação da tarefa retorna 400 quando incluo resolution?
R: O input do flux-schnell aceita apenas aspect_ratio. Outros modelos de imagem na hiapi (por exemplo, flux-2, nano-banana-pro) aceitam resolution (1K/2K/4K). Para o schnell, remova-a.
P: Quanto tempo dura a URL de saída?
R: Cada output[].url carrega um carimbo expireAt (geralmente algumas dezenas de minutos). Assim que o status virar success, baixe imediatamente os bytes da imagem e guarde no seu próprio bucket — não faça hotlink da URL temporária no seu banco de dados de produtos.
P: Posso rodar mais de 8 tarefas concorrentes?
R: Pode, mas na prática não concluirá mais rápido — o schnell já é rápido de ponta a ponta, e passar de cerca de 8 paralelas só acumula a fila. Para lotes realmente grandes (milhares), paralelize em várias máquinas de trabalho em vez de usar threads em um processo.
P: Como obtenho variantes idênticas em nível de pixel do mesmo produto?
R: Com o schnell sozinho, não dá. Gere a imagem principal uma vez e depois use um modelo com suporte a imagem de referência (flux-1.1-pro ou nano-banana-pro) para gerar as variantes usando a principal como referência. O custo sobe, mas a consistência de forma melhora significativamente.
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