Tutorial
Como chamar flux-2-klein-4b/text-to-image pela API HiAPI: curl, Python e uma requisição que funciona
Um tutorial prático para integrar o nível econômico de imagens ao seu pipeline
Por que flux-2-klein-4b/text-to-image é adequado para cargas de trabalho sensíveis a custo
Nem todo pipeline de imagens precisa do modelo mais pesado do catálogo. Uma parte considerável do tráfego em produção é repetitiva: imagens de produtos, prévias de variantes, miniaturas de listagens de produtos, cards sociais gerados a partir do mesmo template. Para esses cenários, flux-2-klein-4b/text-to-image foi projetado como um nível deliberadamente mais leve — você troca um pouco da mais alta fidelidade por throughput e previsibilidade, e isso costuma ser a escolha correta ao gerar milhares de assets em lote de acordo com um cronograma.
Dois tipos de carga de trabalho se beneficiam mais:
- Imagens de produtos de e-commerce. Você normalmente tem uma descrição-base limpa ("caneca de cerâmica fosca, 350ml, cinza-quente, sobre fundo branco sem emendas") e precisa gerar muitas variantes renderizadas cobrindo cores, ângulos e composição. Consistência importa mais que expressividade artística.
- Geração em lote para interfaces internas ou de cauda longa. Banners de categoria, criativos de testes A/B, imagens de placeholder para listagens em rascunho — nesses assets, o ganho marginal de qualidade não vale o custo de execução mais pesado.
Quando você está produzindo imagens principais, texturas detalhadas e quando a composição em si é o produto, escolha o nível mais pesado. Quando volume de geração, latência e custo por imagem dominam a decisão, escolha flux-2-klein-4b/text-to-image. O restante deste tutorial usa esse nível de ponta a ponta: estrutura da requisição, chamada curl, função auxiliar em Python, estratégia de proporção e ciclo de vida assíncrono.
Preparação antes de enviar a requisição
Antes da primeira chamada, é preciso definir três coisas.
1. Chave de API do HiAPI
Crie a chave no console do HiAPI. Toda requisição descrita aqui é autenticada com essa chave, e ela é a única credencial necessária — não há um processo separado de registro por modelo.
2. Manter a chave fora do controle de código-fonte
Trate a chave como qualquer outro segredo. Uma prática que funciona bem:
export HIAPI_API_KEY="your-key-here"
Depois leia-a do ambiente no shell e no Python. Nunca a faça commit, e se você usa um carregador de dotfile, adicione .env ao .gitignore. Se a chave vazar, rotacione-a no console em vez de tentar limpar o histórico.
3. Confirmar o identificador do modelo
A string do identificador é usada literalmente no corpo da requisição e, em algumas configurações, também na URL:
flux-2-klein-4b/text-to-image
Copie exatamente — tanto 4b quanto o sufixo /text-to-image fazem parte do nome. Erros de digitação aqui são a causa mais comum de 404 ou erros de "unknown model". Assim que a chave estiver no ambiente e o identificador confirmado, você pode montar o payload.
Composição de uma requisição flux-2-klein-4b/text-to-image
As requisições de texto para imagem no HiAPI são deliberadamente enxutas. Você fornece o identificador do modelo e um payload de parâmetros de geração; o retorno é o resultado ou um handle de job, dependendo de como o endpoint desse modelo está configurado.
Os campos mais importantes
model— o identificador exato,flux-2-klein-4b/text-to-image.prompt— uma string que descreve a imagem. Este é o campo que mais influencia a qualidade da saída; concentre esforço nele antes de mexer em qualquer outra coisa.- Tamanho ou proporção — como você especifica o enquadramento da saída. Prefira especificações na forma de proporção em vez de pares de pixels fixos, porque isso permanece estável mesmo que o comportamento de resolução subjacente mude.
Como o retorno se parece
O retorno assume duas formas, e seu cliente deve lidar com ambas:
- Payload síncrono — a resposta contém diretamente a localização da imagem gerada (uma URL).
- Payload de job assíncrono — a resposta contém um identificador de job e um status (
pending,processing,succeeded,failedsão os estados típicos). Você então usa esse identificador para consultar o endpoint de status até que ele atinja um estado terminal e o payload traga a localização da saída.
Não invente parâmetros que você não pode verificar. Se um campo não faça parte do conteúdo documentado de requisição do modelo, não o inclua — campos desconhecidos são a segunda causa mais comum de erros 400 confusos. Comece com model, prompt e proporção para obter uma imagem funcional e depois adicione parâmetros opcionais um a um, verificando a saída após cada alteração.
Sua primeira chamada curl funcional
Abaixo está uma requisição completa que você pode colar no terminal. Ela assume que HIAPI_API_KEY foi exportada conforme descrito acima.
curl -sS -X POST "https://api.hiapi.ai/v1/images/generations" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "flux-2-klein-4b/text-to-image",
"prompt": "Studio product photo of a matte ceramic mug, warm grey, soft diffused light, seamless white background, centered composition",
"aspect_ratio": "1:1"
}'
Passe a saída por um formatador JSON (| jq .) para ler a resposta. Você verá diretamente a URL da imagem ou um objeto de job com id e status.
Interpretando o resultado
- Se você receber uma URL de imagem, abra-a no navegador. Isso confirma que a chave, o identificador do modelo e o prompt estão funcionando.
- Se você receber um objeto de job, anote o
id— você o consultará nas seções seguintes.
Diagnosticando falhas comuns
- 401 / 403 — chave ausente, mal formatada ou não enviada no cabeçalho
Authorization: Bearer. Verifique se a variável de ambiente está realmente exportada no shell onde o curl é executado. - 404 ou "unknown model" — identificador errado. Ele deve ser exatamente
flux-2-klein-4b/text-to-image. - 400 com mensagem de validação — geralmente falta
prompt, nome de parâmetro não suportado ou proporção fora do conjunto aceito. Reduza o payload aos três campos principais e tente novamente. - 429 — você está enviando requisições mais rápido do que seu nível permite. Adicione backoff em vez de tentar novamente em loop apertado.
Quando o curl funcionar, você terá uma requisição comprovadamente funcional para comparar caso a versão em Python apresente problemas.
Portando a mesma requisição para Python
A versão em Python é um invólucro fino em torno do mesmo payload. Organize-a como funções para que o restante do pipeline possa chamá-la sem repetir a lógica HTTP.
import os
import time
import requests
API_BASE = "https://api.hiapi.ai/v1"
MODEL = "flux-2-klein-4b/text-to-image"
def generate_image(prompt: str, aspect_ratio: str = "1:1") -> dict:
"""Submit a text-to-image job and return the parsed response."""
api_key = os.environ["HIAPI_API_KEY"]
payload = {
"model": MODEL,
"prompt": prompt,
"aspect_ratio": aspect_ratio,
}
response = requests.post(
f"{API_BASE}/images/generations",
headers={
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
},
json=payload,
timeout=60,
)
if response.status_code >= 400:
# Surface the server's message rather than a bare status code.
raise RuntimeError(f"HiAPI error {response.status_code}: {response.text}")
return response.json()
Alguns hábitos que dão resultado imediato:
- Leia a chave do ambiente dentro da função, e não no momento da importação, para que o mesmo módulo funcione em notebooks, scripts e tarefas agendadas.
- Verifique explicitamente os códigos de status e inclua o corpo da resposta na exceção. As mensagens de validação do HiAPI informam qual campo está errado; um
raise_for_status()puro esconde isso. - Defina timeouts. Sem timeouts, uma conexão travada pode deixar um worker pendurado indefinidamente.
- Mantenha o payload como dict, para que você possa registrá-lo, compará-lo em diff e estender parâmetros opcionais sem reescrever a formatação de string.
Agora um driver mínimo:
result = generate_image(
"Studio product photo of a matte ceramic mug, warm grey, "
"soft diffused light, seamless white background, centered composition"
)
print(result)
Escolhendo proporções que resistem à produção
A proporção é o parâmetro com maior probabilidade de gerar retrabalho mais tarde, porque os sistemas downstream assumem enquadramentos. Decida superfície por superfície, não requisição por requisição.
Mapeamento prático
- Quadrado (1:1) — listagens de marketplace, grades de produtos, avatares e posições de miniatura. É o padrão seguro para e-commerce, porque a maioria dos tiles de produto é quadrada e o recorte funciona mal.
- Vertical (3:4 ou 4:5) — posições de feed social e imagens de produto no estilo lookbook. Dá espaço para produtos verticais como garrafas e roupas sem adicionar tarjas pretas.
- Horizontal (16:9) — banners, faixas de hero, cabeçalhos de e-mail, miniaturas de vídeo.
Por que fixar a proporção a montante
Se a proporção for escolhida no momento da renderização pelo código que por acaso chama a API, você acabará com um catálogo de produtos em que metade dos tiles é quadrada e metade é vertical, e precisará pagar por uma regeneração para corrigir. Em vez disso, codifique a proporção no seu modelo de conteúdo — um campo surface ou placement que mapeia deterministicamente para uma proporção — e gere a partir desse campo. Use 1:1 em posições que toleram recorte; use a proporção exigida pelo layout em posições com layout fixo.
A mesma disciplina se aplica aos prompts: inclua dicas de enquadramento ("composição centralizada", "produto inteiro dentro do quadro", "espaço em branco à esquerda para texto") no template de prompt, e não em strings ad hoc por chamada. Templates fazem mil imagens geradas parecerem saídas do mesmo pipeline, e é exatamente isso que um catálogo de produtos precisa.
Uma ressalva: nem todo modelo aceita toda proporção. Envie a proporção escolhida uma vez, confirme o sucesso e só então a aplique ao lote inteiro.
Consultando jobs assíncronos até a conclusão
Quando flux-2-klein-4b/text-to-image retorna um handle de job em vez de uma imagem, trate-o como uma máquina de estados. O fluxo é: enviar → receber o ID do job → consultar o status → estado terminal → ler a saída.
def wait_for_job(job_id: str, timeout_s: int = 300, interval_s: int = 2) -> dict:
api_key = os.environ["HIAPI_API_KEY"]
deadline = time.time() + timeout_s
while time.time() < deadline:
response = requests.get(
f"{API_BASE}/jobs/{job_id}",
headers={"Authorization": f"Bearer {api_key}"},
timeout=30,
)
response.raise_for_status()
job = response.json()
status = job.get("status")
if status == "succeeded":
return job
if status == "failed":
raise RuntimeError(f"Job {job_id} failed: {job.get('error')}")
time.sleep(interval_s)
raise TimeoutError(f"Job {job_id} did not finish in {timeout_s}s")
Tratando cada estado
pending/processing— continue aguardando. Comece com intervalos curtos e considere backoff suave (por exemplo, aumentando o sono até um limite) para não martelar o endpoint de status durante filas longas.succeeded— o payload agora contém a localização da saída. Pare de consultar imediatamente.failed— não tente novamente às cegas. Registre a mensagem de erro; se for um problema de prompt ou parâmetro, reenviar a mesma requisição falhará da mesma forma.
Sabendo quando parar
Sempre limite o loop com um prazo de relógio de parede. Um worker que consulta para sempre é um worker vazando. Em caso de timeout, exponha o ID do job para inspeção manual — se o job succeed depois, você ainda poderá recuperar a saída. Para lotes, execute vários jobs concurrentemente e consulte todos juntos, em vez de serializar envio e espera para cada imagem.
Baixando e armazenando a saída
A imagem gerada aparece na resposta de geração ou de job como uma localização recuperável. Busque-a no servidor e persista-a por conta própria — não faça hotlink da URL retornada em páginas de produto, pois ela é um artefato de entrega, não sua camada de armazenamento.
def download_image(url: str, path: str) -> str:
response = requests.get(url, timeout=120)
response.raise_for_status()
with open(path, "wb") as f:
f.write(response.content)
return path
Usando um esquema de nomes previsível
Caminhos como images/{surface}/{sku}/{variant}-{ratio}.png dão três coisas: os assets ficam naturalmente agrupados por produto, a superfície informa qual enquadramento foi solicitado, e a proporção no nome do arquivo torna duplicatas inesperadas óbvias. Se você regenerar variantes do mesmo SKU, inclua um hash curto do prompt no nome do arquivo — assim uma reexecução não sobrescreve silenciosamente uma tentativa anterior que você talvez quisesse comparar.
Fechando o ciclo
Registre o ID do job junto com o arquivo armazenado, em um manifesto, linha de banco de dados ou arquivo sidecar. Quando um sistema downstream reportar uma imagem ruim, o ID do job é o que permite recuperar o prompt e os parâmetros originais. Combinado com nomes de arquivo endereçados por conteúdo, isso fornece uma trilha de auditoria reproduzível do asset armazenado até a requisição exata que o produziu.
Com envio, consulta e download conectados, flux-2-klein-4b/text-to-image se torna uma etapa comum no seu pipeline: enfileirar trabalho, consultar com prazo, armazenar com nomes estáveis. A partir daí, escalar é apenas uma questão de concorrência e templates, não de novo código.
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