HiAPI
Blogue

Tutorial

Como chamar flux-1-kontext-max na HiAPI: tutorial com curl e Python

O fluxo completo de uma requisição executável: entrada, polling assíncrono e download da saída

Oct 31, 2026
hiapi.ai 博客封面图:深咖啡底色上交织的燕麦色与黄铜色宽织带,呈扁平编织图解式几何图案。

Como é uma requisição para flux-1-kontext-max

Antes de escrever qualquer código, ajuda entender o formato da interação. Na HiAPI, uma chamada de edição de imagem para flux-1-kontext-max não é uma requisição/resposta simples que devolve a imagem na mesma chamada HTTP. É uma tarefa em duas fases:

  1. Envio — você faz POST de um payload JSON descrevendo sua imagem de entrada e a edição desejada. A API aceita a tarefa e devolve um identificador de tarefa.
  2. Polling — você faz GET do status da tarefa com esse identificador até que ela reporte conclusão e então lê a URL de saída na resposta.

Esse padrão existe porque a edição de imagem é computacionalmente intensiva. Manter uma única conexão HTTP aberta durante todo o processo de renderização é frágil; um handle de tarefa permite desconectar, tentar de novo e voltar depois.

O payload em si se divide conceitualmente em três partes:

  • Seletor de modelo — um campo que indica flux-1-kontext-max como o modelo a executar.
  • Entrada — normalmente uma imagem (URL ou payload base64, conforme o schema documentado) mais uma instrução de texto descrevendo a edição.
  • Controles opcionais — parâmetros que ajustam o comportamento da geração, como proporção de aspecto ou seed, desde que estejam descritos na documentação do modelo.

Todo o resto — cabeçalho de autenticação, endpoint de envio, endpoint de status — é o mesmo pipeline que você usa em cada tarefa da HiAPI. Uma vez internalizado esse ritmo de três passos (envio → polling → download), as versões curl e Python são intercambiáveis, e você pode alternar entre elas sem reaprender o fluxo.

Pré-requisitos e autenticação

Antes de a primeira requisição ter sucesso, você precisa ter algumas coisas prontas.

O que você precisa

  • Uma conta HiAPI e uma API key criada no dashboard.
  • A URL base da API HiAPI, conforme mostrada na documentação da plataforma.
  • Uma imagem de origem acessível pela API — na maioria dos casos, uma URL HTTPS pública. Se sua imagem for privada, faça upload para um local que a API consiga acessar ou, se o schema do modelo aceitar entrada base64, passe-a inline.
  • curl para o exercício no shell, e Python 3 com a biblioteca requests para o exercício em código.

Autenticação

A HiAPI autentica requisições enviando sua API key no cabeçalho de autorização. A convenção é bearer token:

Authorization: Bearer $HIAPI_API_KEY

E toda requisição JSON deve declarar seu tipo de conteúdo:

Content-Type: application/json

Mantenha a chave fora do código-fonte

Guarde a chave em uma variável de ambiente em vez de colá-la no script:

export HIAPI_API_KEY="your_key_here"

Em Python, leia-a com os.environ["HIAPI_API_KEY"]. No curl, referencie-a como $HIAPI_API_KEY. Esse único hábito evita a causa mais comum de vazamento de credenciais — a chave ser commitada em um repositório e depois ter que ser rotacionada sob pressão.

Se a requisição retornar erro de autenticação, verifique três coisas em ordem: a chave existe e é válida, o cabeçalho está escrito exatamente como na documentação, e não há espaços ou quebras de linha extras na variável de ambiente.

Enviando a requisição com curl

Abaixo está a chamada de envio. Substitua pela sua própria URL de imagem e instrução de edição.

curl -X POST "$HIAPI_BASE_URL/jobs" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "flux-1-kontext-max",
    "input": {
      "image": "https://example.com/input.jpg",
      "prompt": "Replace the sky with a dramatic sunset, keep the buildings unchanged"
    }
  }'

O que cada parte faz

  • -X POST — o envio é uma operação de criação, então use POST.
  • Endpoint — o endpoint de jobs aceita novas tarefas. A URL base vem do seu ambiente, então o comando é portável entre ambientes.
  • Authorization — seu bearer token, lido da variável de ambiente em vez de inline.
  • Content-Type: application/json — obrigatório; sem ele, o servidor pode recusar ou interpretar mal o corpo da requisição.
  • -d — o payload JSON. model seleciona flux-1-kontext-max, input.image aponta para sua imagem de origem, input.prompt descreve a edição.

Lendo a resposta

Um envio bem-sucedido devolve um corpo JSON contendo o identificador da tarefa — normalmente um campo como id ou job_id — e um status indicando que a tarefa foi enfileirada ou está em processamento. Guarde esse identificador; o polling depende dele.

curl -s -X POST "$HIAPI_BASE_URL/jobs" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d @payload.json | python -m json.tool

Passar a saída por python -m json.tool formata a resposta de forma legível, facilitando encontrar o ID da tarefa. Colocar o corpo da requisição em payload.json mantém o comando legível mesmo quando o prompt fica mais longo.

Neste ponto você enviou a tarefa, mas ainda não recebeu a imagem. A imagem só vem depois do polling.

A mesma requisição em Python

A versão em Python carrega a mesma lógica, com uma ergonomia mais confortável para qualquer coisa que você pretenda manter a longo prazo.

import os
import requests

BASE_URL = os.environ["HIAPI_BASE_URL"]
API_KEY = os.environ["HIAPI_API_KEY"]

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}

payload = {
    "model": "flux-1-kontext-max",
    "input": {
        "image": "https://example.com/input.jpg",
        "prompt": "Replace the sky with a dramatic sunset, keep the buildings unchanged",
    },
}

response = requests.post(
    f"{BASE_URL}/jobs",
    headers=headers,
    json=payload,
    timeout=30,
)
response.raise_for_status()
job = response.json()
print("job id:", job["id"])

Por que isso espelha a chamada curl

O parâmetro json=payload serializa o dicionário e define o tipo de conteúdo para você — os bytes enviados são os mesmos que no curl. timeout=30 limita a requisição de envio, fazendo conexões penduradas falharem ruidosamente em vez de travar seu processo. raise_for_status() transforma 4xx ou 5xx em uma exceção que você pode capturar, em vez de devolver silenciosamente um documento de erro.

Pequenas diferenças que importam

  • Dicionário em vez de string — você constrói o payload como objeto Python, o que facilita montar prompts dinâmicos ou injetar variáveis.
  • Tratamento de exceções — envolva a chamada em try/except requests.HTTPError para registrar o corpo da resposta; payloads de erro geralmente explicam o que havia de errado na entrada.
  • Sem escape de shell — prompts longos com aspas não precisam mais de escape, o que elimina toda uma classe de erros.

O ID de tarefa retornado aqui vai direto para a etapa de polling abaixo. A tarefa não muda em nada por ter sido enviada de Python em vez de curl.

Tratando tarefas assíncronas e fazendo polling do resultado

O envio retorna rápido; a renderização, não. Você espera fazendo polling do endpoint de status do ID da tarefa.

Loop de polling

import time

def wait_for_job(job_id, headers, interval=3, max_attempts=100):
    url = f"{BASE_URL}/jobs/{job_id}"
    for attempt in range(max_attempts):
        r = requests.get(url, headers=headers, timeout=30)
        r.raise_for_status()
        data = r.json()
        status = data.get("status")
        if status == "succeeded" or status == "completed":
            return data
        if status == "failed" or status == "error":
            raise RuntimeError(f"Job failed: {data}")
        time.sleep(interval)
    raise TimeoutError(f"Job {job_id} did not finish in time")

Interpretando os status da tarefa

Espere um vocabulário pequeno: um status queued/pending antes de o trabalho começar, um status processing/running durante a renderização do modelo, e um status terminal — sucesso ou falha. Algumas APIs usam grafias ligeiramente diferentes; examine a resposta que você realmente recebe e mapeie essas strings, sem presumir. Regra fundamental: só considere a tarefa concluída quando o status for terminal de sucesso e houver uma URL de saída. O endpoint de status retornar 200 não significa que a imagem está pronta.

Etiqueta de polling

  • Espaçe suas requisições. Para tarefas de imagem, alguns segundos entre cada polling são suficientes. Consultar a cada 100 ms desperdiça limite de taxa sem nenhum ganho.
  • Limite o tempo de espera. max_attempts limita o loop, fazendo uma tarefa travada derrubar seu código em vez de pendurar para sempre.
  • Faça backoff em 429. Se atingir o limite de taxa, espere mais antes de tentar de novo, em vez de insistir.
  • Prefira webhook, se disponível. Se a documentação da plataforma descrever um mecanismo de callback, ele elimina completamente o polling e escala melhor.

Para um teste rápido no shell, um loop simples funciona do mesmo jeito:

JOB_ID="your_job_id"
while true; do
  BODY=$(curl -s "$HIAPI_BASE_URL/jobs/$JOB_ID" -H "Authorization: Bearer $HIAPI_API_KEY")
  echo "$BODY"
  echo "$BODY" | grep -q '"succeeded"' && break
  sleep 3
done

Assim que você sair do loop, a resposta terminal contém a referência de saída. Esse é o próximo passo.

Baixando e salvando a saída

A resposta da tarefa concluída aponta para a imagem renderizada, normalmente uma URL (às vezes uma lista). Faça uma segunda requisição para obtê-la e grave os bytes em disco.

import pathlib

def download_output(job_data, path="edit.png"):
    out = job_data.get("output")
    if isinstance(out, list):
        out = out[0]
    url = out["url"] if isinstance(out, dict) else out

    r = requests.get(url, timeout=60)
    r.raise_for_status()
    pathlib.Path(path).write_bytes(r.content)
    return path

Pontos de atenção

  • Não hardcode o formato. O campo de saída varia conforme o modelo — às vezes é uma URL em string, às vezes um objeto com chave url, às vezes uma lista. Examine a resposta real e normalize antes de baixar.
  • A URL de saída pode expirar. Trate a URL como de vida curta: baixe imediatamente ou copie logo para o seu próprio armazenamento. Não guarde a URL como registro permanente da imagem.
  • Valide os bytes. Verifique se o Content-Type começa com image/ e se o tamanho do arquivo é razoável; uma página de erro salva como .png é uma falha silenciosa.
  • Tente de novo em erros transitórios de download. Envolva o GET em tentativas com backoff curto — URLs assinadas às vezes retornam 403 por desvio de relógio, e a rede também oscila.

Para uma verificação manual rápida, curl basta:

curl -L -o edit.png "$OUTPUT_URL"

A flag -L segue redirecionamentos, comuns em saídas hospedadas em CDN. Depois que o arquivo estiver em disco, abra-o e confirme que a edição corresponde ao prompt — essa é sua verificação de ponta a ponta, e em pipelines em que a imagem precisa ser regenerada em caso de falha, vale automatizar uma checagem visual ou de hash.

Falhas comuns e correções

A maioria das falhas de primeira integração acontece de algumas poucas maneiras.

Autenticação e cabeçalhos

  • 401/403 — chave errada, expirada ou com espaços extras. Reexporte a variável de ambiente e confirme que o formato do cabeçalho confere com a documentação.
  • Content-Type ausente — enviar JSON sem esse cabeçalho pode gerar erros 4xx confusos. Inclua-o ou use json= em Python.

Problemas de entrada

  • Imagem inacessível — a API busca sua imagem no servidor. URLs de localhost ou links que exigem autenticação vão falhar. Use uma URL HTTPS pública ou base64 inline quando houver suporte.
  • Prompt ignorado ou rejeitado — instruções vagas geram resultados vagos. Descreva o que deve mudar e o que deve ser mantido, como no exemplo do pôr do sol. Prompts muito longos podem ser truncados.
  • Parâmetros não suportados — passar campos que o modelo não aceita pode causar erro de validação. Comece com o payload mínimo e depois adicione os controles documentados um a um.

Erros de processamento assíncrono

  • Ler a imagem na resposta de envio — a chamada de envio retorna um handle de tarefa, não pixels. Faça polling primeiro.
  • Tratar qualquer 200 como conclusão — o endpoint de status também retorna 200 para tarefas ainda em execução. Verifique o campo de status e a existência da URL de saída.
  • Polling rápido demais ou eterno — adicione intervalo e um limite superior, ou você esgotará o limite de taxa e pendurará seu worker.

Problemas de download

  • Salvar HTML como imagem — sempre verifique o tipo de conteúdo e o tamanho.
  • URL de saída expirada — baixe logo após a conclusão; não deixe a URL na fila para depois.

Erros estruturais

  • IDs de tarefa trocados — se você enviar várias tarefas, marque cada ID com seu próprio request ID, para que os resultados de polling não se misturem.
  • Sem timeout — toda requisição deve ter um. Sem isso, uma chamada pendurada pode travar um lote inteiro.

Transformando o exercício em uma função auxiliar reutilizável

Os três passos — envio, polling, download — pertencem a uma única função, para que quem chama não precise repetir a orquestração.

def edit_image(image_url, prompt, model="flux-1-kontext-max",
               headers=None, poll_interval=3, max_attempts=100):
    payload = {"model": model,
               "input": {"image": image_url, "prompt": prompt}}
    r = requests.post(f"{BASE_URL}/jobs", headers=headers,
                      json=payload, timeout=30)
    r.raise_for_status()
    job_id = r.json()["id"]

    data = wait_for_job(job_id, headers,
                        interval=poll_interval,
                        max_attempts=max_attempts)
    return download_output(data, path=f"{job_id}.png")

O que a torna pronta para produção

  • Ponto de entrada único. Quem chama passa a imagem e o prompt e recebe um caminho de arquivo ou uma exceção. Os detalhes do fluxo ficam ocultos.
  • Falha explícita. Toda requisição lança exceção em erro HTTP, e o poller lança em falha de tarefa ou timeout, para que sua fila ou quem chama possa tentar de novo.
  • Temporização configurável. poll_interval e max_attempts são parâmetros, então você pode afrouxá-los para edições mais pesadas sem tocar na lógica.
  • Nomeação previsível da saída. Usar o ID da tarefa como nome de arquivo facilita correlacionar arquivos com logs.

Para onde ir em seguida

Envolva a chamada com preocupações de camada de aplicação: registre o ID da tarefa e a latência, tente de novo envios que falharam com jitter, e envie os bytes baixados direto para o armazenamento de objetos em vez de para o disco local. Se você processa muitas edições, envie um lote de tarefas primeiro e faça polling de todas juntas — o envio é barato, e a concorrência está na espera, não no upload.

A página de flux-1-kontext-max na documentação da HiAPI é a referência para os campos aceitos e os parâmetros atuais. Mantenha a função auxiliar enxuta e deixe a documentação conduzir o schema; assim a mesma função cobre tanto scripts exploratórios quanto pipelines reais.

Artigos relacionados

Ver todos os artigos →

Comece a criar com artefactos de IA persistentes

Obtenha a sua chave de API e chame modelos de imagem, vídeo e áudio através de uma única API baseada em tasks.

Ler a documentação da API