Tutorial
Como usar o nano-banana-pro pela API do HiAPI: exemplos com curl e Python
O que o nano-banana-pro no HiAPI oferece
O nano-banana-pro é um modelo de geração de imagens que pode ser chamado por meio da API unificada do HiAPI. Em vez de integrar diretamente com o provedor do modelo, basta enviar ao HiAPI uma requisição no formato unificado para obter as imagens geradas — usando a mesma autenticação, as mesmas convenções de endpoint e o mesmo envelope de resposta que os demais modelos da plataforma.
O nano-banana-pro foi projetado para geração de imagens orientada por prompt e permite anexar imagens de referência além do prompt de texto. As imagens de referência permitem guiar a saída com contexto visual (sujeito, estilo, composição), sem precisar descrever tudo em palavras. A saída é entregue em resolução 2K, o que torna o modelo mais adequado para ativos de produção do que para rascunhos rápidos.
Ao concluir este tutorial, você terá uma integração completa e funcional que pode:
- enviar um prompt ao nano-banana-pro pelo HiAPI com uma requisição
curlvalidada; - reproduzir a mesma chamada em Python sem alterar o payload da requisição;
- anexar imagens de referência à requisição;
- submeter tarefas assíncronas, fazer polling até a conclusão e tratar tentativas de repetição de forma sensata;
- baixar a imagem 2K concluída e armazená-la na sua própria infraestrutura.
Cada seção se apoia na anterior, então o caminho mais seguro é seguir em ordem: primeiro confirmar a requisição manualmente, depois movê-la para o código.
Antes de enviar a primeira requisição
Você precisa de três coisas antes da primeira chamada.
Uma chave de API
Crie uma chave de API na sua conta HiAPI e garanta que ela não seja incluída no controle de versão. Trate-a como qualquer outro segredo: carregue-a de uma variável de ambiente (HIAPI_API_KEY) ou de um gerenciador de segredos, e nunca a codifique diretamente em arquivos que você possa commitar. Se a chave vazar, rotacione-a no painel em vez de tentar removê-la do histórico.
Um cliente HTTP
Qualquer ferramenta capaz de enviar requisições HTTPS serve. Para a primeira requisição, o curl na linha de comando é ideal, porque não há framework entre você e a rede — cada cabeçalho e cada byte do corpo da resposta ficam visíveis. Para a parte em Python, a biblioteca padrão urllib.request é suficiente; se você já usa requests ou httpx, o mapeamento é o mesmo. Este tutorial limita o Python à biblioteca padrão, então não é necessário instalar nada extra.
Um local para armazenar a saída
Como as tarefas do nano-banana-pro são assíncronas, planeje desde o início o diretório ou bucket em que as imagens concluídas serão salvas. Durante o desenvolvimento, uma pasta local output/ basta; em produção, mire em armazenamento de objetos.
Você não precisa instalar SDK de fornecedor. O HiAPI é chamado por HTTPS comum, então a requisição que você monta no curl é exatamente a mesma que seu cliente Python enviará depois.
Uma requisição curl funcional, explicada passo a passo
A forma mais rápida de confirmar que a chave, o endpoint e o payload estão corretos é enviar uma requisição manualmente. Antes de digitá-la, decomponha-a em partes.
Endpoint e método
Todas as chamadas de modelo vão para a mesma URL base do HiAPI, e o modelo é identificado no corpo da requisição, não no caminho. Requisições de geração usam POST.
Cabeçalhos
Três cabeçalhos importam em cada chamada:
Authorization: Bearer $HIAPI_API_KEY— sua chave, passada como token bearer.Content-Type: application/json— para requisições contendo apenas prompt.Accept: application/json— para receber uma resposta estruturada em vez de uma página de erro HTML.
Corpo da requisição
O corpo JSON carrega o nome do modelo e os parâmetros de geração. No mínimo, envie o identificador do modelo e seu prompt:
curl -sS -X POST "$HIAPI_BASE_URL" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"model": "nano-banana-pro",
"input": {
"prompt": "a glass terrarium on a sunlit windowsill, soft morning light, shallow depth of field"
}
}'
Antes de executar este comando, defina HIAPI_BASE_URL e HIAPI_API_KEY no shell. Guardar a URL em uma variável significa que depois você pode apontar o mesmo script para uma URL de staging ou sandbox sem alterar o comando.
Ler a resposta
Uma submissão bem-sucedida retorna um objeto JSON que identifica a tarefa. O campo importante é o identificador da tarefa — você o usará na etapa de polling. Como a geração leva tempo, não espere receber a imagem em si na primeira resposta; o nano-banana-pro opera de forma assíncrona, e esta chamada é apenas a parte de submissão da interação.
Se o comando retornar erro, pare aqui e corrija antes de escrever qualquer código. A requisição curl validada é sua implementação de referência: cada etapa seguinte deve produzir a mesma requisição HTTP.
Portar a requisição para Python
O porte é mecânico: URL, método, cabeçalhos e corpo JSON permanecem iguais. Apenas o cliente muda.
A mesma requisição com urllib
import json
import os
import urllib.request
api_key = os.environ["HIAPI_API_KEY"]
base_url = os.environ["HIAPI_BASE_URL"]
payload = {
"model": "nano-banana-pro",
"input": {
"prompt": "a glass terrarium on a sunlit windowsill, soft morning light, shallow depth of field"
},
}
request = urllib.request.Request(
base_url,
data=json.dumps(payload).encode("utf-8"),
method="POST",
headers={
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
"Accept": "application/json",
},
)
with urllib.request.urlopen(request, timeout=60) as response:
body = json.loads(response.read().decode("utf-8"))
print(body)
Regras de mapeamento
Ao converter do curl, três detalhes costumam causar erros:
- O corpo deve ser bytes.
json.dumpsgera uma string; ela precisa ser codificada antes de ser passada ao objeto de requisição. - Cabeçalhos são um dicionário, não flags. Cada linha
-Hvira um par chave/valor. Preserve o prefixoBearere o espaço depois dele. - O método deve ser especificado explicitamente. Quando há dados,
urllib.requestusaPOSTpor padrão, mas definirmethod="POST"torna a intenção mais clara e evita surpresas se você remover o corpo depois.
Se você usa requests, o equivalente é requests.post(base_url, headers=headers, json=payload, timeout=60) — json= cuida da serialização e do tipo de conteúdo para você. Se você usa httpx, a forma da chamada é a mesma.
Uma pequena função auxiliar que vale a pena ter
Coloque a chamada de submissão em uma função que recebe um prompt e retorna o identificador da tarefa. Cada seção seguinte — imagens de referência, polling, download — se apoia nessa função, e mantê-la em um só lugar significa que mudanças na forma da requisição acontecem apenas uma vez.
Enviar imagens de referência junto com o prompt
Imagens de referência mudam a forma da requisição, então decida cedo qual modo de entrada sua aplicação vai usar.
Duas opções práticas
Entrada baseada em URL. Se a imagem de referência já estiver acessível via HTTPS, você pode incluir a URL dela junto com o prompt no corpo da requisição. Isso mantém a requisição como application/json, que é a forma mais fácil de repetir e registrar.
Upload de arquivo. Se a imagem estiver no cliente ou em armazenamento privado, você pode enviá-la como parte de arquivo em uma requisição multipart/form-data. Nesse caso, o cabeçalho Content-Type: application/json é substituído pelo tipo de conteúdo multipart — deixe seu cliente HTTP gerá-lo para garantir que o boundary esteja correto — e os campos JSON passam a ser campos de formulário na mesma requisição.
Para a maioria das integrações no lado do servidor, a entrada baseada em URL é mais simples: suas imagens já estão no armazenamento de objetos, a requisição permanece JSON e você evita enviar corpos grandes duas vezes ao repetir tentativas.
Mantenha o prompt e a imagem de referência em sincronia
O prompt deve descrever o propósito da imagem de referência, não apenas o conteúdo dela. “Combine a iluminação e a paleta da imagem de referência; troque o sujeito por um vaso de cerâmica” dá ao modelo uma tarefa clara. Um prompt que ignora a imagem de referência desperdiça a entrada.
Valide antes de enviar
Imagens de referência são a fonte mais comum de erros de requisição. Verifique se a URL é acessível publicamente (ou se ambos os lados do seu sistema concordam com o prazo de expiração de URLs assinadas), se o tipo de arquivo é aceito pelo modelo e se a imagem não é grande a ponto de causar timeout de upload. Faça essas verificações no seu próprio código primeiro — depurar uma validação que falha no cliente custa muito menos do que depurar uma requisição rejeitada.
Tratar tarefas assíncronas e fazer polling de resultados
A geração do nano-banana-pro é assíncrona. Estruture seu cliente em torno de três etapas independentes: submeter, fazer polling e baixar. Misturá-las em uma única função torna difícil raciocinar sobre tentativas de repetição e timeouts.
Etapa 1: submeter
Envie a requisição acima e armazene o identificador de tarefa retornado. Persista esse identificador em algum lugar durável — uma linha de banco de dados ou uma mensagem de fila — porque seu processo pode reiniciar entre a submissão e a conclusão.
Etapa 2: polling
Use a mesma URL base e o mesmo cabeçalho Authorization, incluindo o identificador da tarefa na requisição, para consultar o status da tarefa. Faça polling em intervalos em vez de um loop apertado; alguns segundos entre verificações é o típico, e se várias verificações consecutivas retornarem estado pendente, aplique backoff.
import time
TERMINAL = {"succeeded", "failed"}
def wait_for_job(job_id, timeout=300, interval=3):
deadline = time.monotonic() + timeout
while time.monotonic() < deadline:
status = get_job_status(job_id) # same headers as submit
if status in TERMINAL:
return status
time.sleep(interval)
raise TimeoutError(f"job {job_id} did not finish in time")
Etapa 3: respeitar os estados
Trate o campo de status como um enum. A tarefa ou ainda está em execução, ou foi concluída com sucesso, ou falhou. Trate explicitamente os três casos: em caso de sucesso, siga para o download; em caso de falha, leia a mensagem de erro e determine se o problema está na entrada ou no prompt; em caso de timeout, pare o polling e exponha o identificador da tarefa para investigação posterior.
Tentativas de repetição pertencem a dois níveis
Tentativas de repetição em nível de rede devem ser aplicadas à chamada de submissão e a cada requisição de polling, com um número limitado de tentativas. Tentativas no nível da tarefa são diferentes: se a tarefa falhou por causa de um prompt ruim ou de uma imagem de referência ruim, reenviar o mesmo payload falhará da mesma forma. Só repita a tarefa em si depois de alterar a entrada.
Um padrão comum em produção é ter um worker responsável pelo loop de polling, para que as requisições web nunca fiquem bloqueadas pela geração. Submeta a partir do seu handler de API, entregue o identificador da tarefa ao worker e notifique o cliente quando o worker terminar.
Baixar e armazenar a saída 2K
A resposta final da tarefa aponta para a imagem gerada em vez de embuti-la, o que significa que o download é uma etapa sob sua responsabilidade.
Obter a imagem
Quando a tarefa reporta sucesso, a resposta contém a localização da saída. Recupere-a com uma requisição GET comum e grave os bytes em um arquivo ou faça streaming para o armazenamento. Durante o desenvolvimento, salve em um diretório local com um nome previsível construído a partir do identificador da tarefa, para associar o arquivo ao registro da tarefa.
import pathlib
import urllib.request
def save_image(url, job_id, out_dir="output"):
pathlib.Path(out_dir).mkdir(exist_ok=True)
target = pathlib.Path(out_dir) / f"nano-banana-pro-{job_id}.png"
with urllib.request.urlopen(url, timeout=60) as response:
target.write_bytes(response.read())
return target
Armazenar corretamente
Em produção, faça streaming da resposta diretamente para o armazenamento de objetos em vez de gravar em disco local, para que o comportamento seja consistente independentemente do worker que processa a tarefa. Registre no banco de dados a chave do objeto e o identificador da tarefa, e verifique se o tipo de conteúdo e a extensão do arquivo correspondem ao que o modelo gera. Se a imagem for servida em páginas web, gere miniaturas no mesmo pipeline, para que páginas públicas nunca carreguem o arquivo completo em resolução 2K.
Planeje uma política de retenção
As saídas geradas são seus dados. Decida por quanto tempo retê-las, se precisam de versionamento e se o local final é algo que sua aplicação consegue regenerar se for perdido. Se a resposta for não, armazene também o payload da requisição junto com a imagem, para que um bug futuro ou uma mudança de modelo nunca impeça a reprodução do resultado.
Pontos comuns de falha e como depurar
A maioria das primeiras integrações falha por alguns poucos motivos. Antes de assumir que há um problema no modelo, percorra esta lista.
- Erros de autorização. Falta o prefixo
Bearer, a chave tem uma quebra de linha final por ter sido copiada de um arquivo de ambiente, ou você está usando uma chave de um ambiente diferente daquele da URL base configurada. - Incompatibilidade de tipo de conteúdo. Enviar campos JSON com cabeçalho de requisição multipart, ou enviar um arquivo com
application/json, é a causa mais comum de rejeição de requisições com imagem de referência. Para corpos multipart, deixe o cliente definir o cabeçalho. - Método ou forma de corpo errados. Usar GET em vez de POST, ou usar um
promptno nível superior em vez do objeto aninhadoinput, produz erros de validação que parecem completamente sem relação. Compare sua requisição byte a byte com a chamadacurlvalidada —curl -vmostra os cabeçalhos realmente enviados. - Polling rápido demais ou inexistente. Requisitar o endpoint de status com muita frequência causa limitação de taxa; nunca fazer polling não traz resultado nenhum. Use um intervalo fixo com backoff e um timeout rígido.
- URL de saída expirada. Se você esperar demais entre a conclusão da tarefa e o download, a URL de saída assinada pode expirar. Baixe imediatamente após o sucesso, ou tenha um caminho de reaquisição para obter uma nova localização.
- Falhas silenciosas no código. Registre sempre o status HTTP e o corpo da resposta em caso de erro. Mensagens de exceção genéricas lançadas pelo cliente HTTP escondem a parte útil da resposta.
Quando algo não estiver claro, volte para a requisição curl validada da primeira seção. Se ela funciona e sua chamada em Python não, a diferença entre as duas é o bug.
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