HiAPI
Blogue

Tutorial

Como chamar muse-image-1.0/image-to-image na HiAPI API: curl, Python e um exemplo de requisição que funciona

Oct 31, 2026
奶油色底上的多层薄纸叠层插画,一块陶红色纸层作点缀,构图克制均衡,为教程文章封面图。

O que uma requisição image-to-image realmente envia

Antes de escrever a primeira linha de código, é útil entender o que uma chamada image-to-image espera. Diferentemente de uma requisição puramente text-to-image, em que o prompt é a única entrada criativa, muse-image-1.0/image-to-image requer uma imagem de origem, além de instruções sobre como transformá-la.

No mínimo, seu payload de requisição inclui:

  • model: o identificador muse-image-1.0/image-to-image.
  • image: a imagem de origem que você quer editar. Normalmente isso é enviado como uma string codificada em base64 ou como uma URL publicamente acessível, dependendo do formato que o endpoint aceita. Consulte o schema de entrada do modelo para confirmar o nome exato do campo e o formato.
  • prompt: a descrição textual da edição que você deseja fazer. Seja específico sobre o que mudar e o que manter.
  • Parâmetros opcionais como strength ou guidance (caso o modelo os exponha) permitem controlar o quanto a saída se afasta da imagem de origem. O conjunto exato de parâmetros varia conforme o modelo, então confirme sempre na referência da API em vez de presumir.

A mudança de mentalidade fundamental é: você não está gerando do zero, está fornecendo um ponto de partida e uma direção. Prompts vagos como "make it better" produzem resultados imprevisíveis porque o modelo tem liberdade demais. Já um prompt como "replace the sky with a sunset and keep the buildings unchanged" dá ao modelo uma restrição clara.

Além disso, confirme com antecedência as restrições da imagem — formatos suportados, dimensões máximas e tamanho de arquivo. Se sua imagem de origem for um PNG de 12 MB, talvez seja necessário reduzi-la ou convertê-la para JPEG antes que a requisição seja aceita. Processar a imagem corretamente antes de enviar economiza uma ida e volta e uma mensagem de erro confusa.

Assim que você tiver a imagem de origem e um prompt de edição claro, é hora da primeira chamada.

Enviar a primeira requisição com curl

A forma mais rápida de validar a integração é enviar a requisição diretamente do terminal. O caminho exato do endpoint e o schema do payload estão definidos na referência da API do modelo; o exemplo abaixo mostra a forma geral para que você possa ajustá-lo conforme a especificação atual.

curl -X POST https://api.hiapi.ai/v1/images/edits \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "muse-image-1.0/image-to-image",
    "image": "https://your-bucket.example.com/source.jpg",
    "prompt": "replace the sky with a warm sunset, keep the buildings unchanged",
    "strength": 0.6
  }'

Substitua $HIAPI_API_KEY por uma variável de ambiente em vez de colar a chave diretamente. Se sua ferramenta permitir, exporte a chave na sessão do shell para que ela não fique no histórico de comandos.

A resposta retornada conterá um identificador de job. Como a edição de imagens é computacionalmente intensiva, a API normalmente não devolve a imagem finalizada na mesma resposta. Em vez disso, você recebe um ID de job e um status. Guarde esse ID — você o usará na próxima etapa para consultar o resultado.

Se a chamada falhar, leia com atenção o corpo da resposta de erro. Um 400 geralmente indica payload malformado ou formato de imagem não suportado. Um 401 indica chave ausente ou incorreta. Um 429 indica que você enviou requisições rápido demais. Corrigir esses problemas na fase de terminal é muito mais fácil do que depurar dentro de uma aplicação completa.

A mesma requisição em Python

Depois que a chamada curl funcionar, converta-a em uma pequena função Python. Usar requests mantém o exemplo com poucas dependências e fácil de portar.

import os
import requests

HIAPI_API_KEY = os.environ["HIAPI_API_KEY"]
BASE_URL = "https://api.hiapi.ai/v1/images/edits"

def submit_edit(image_url: str, prompt: str, strength: float = 0.6) -> str:
    payload = {
        "model": "muse-image-1.0/image-to-image",
        "image": image_url,
        "prompt": prompt,
        "strength": strength,
    }
    headers = {
        "Authorization": f"Bearer {HIAPI_API_KEY}",
        "Content-Type": "application/json",
    }
    response = requests.post(BASE_URL, json=payload, headers=headers, timeout=30)
    response.raise_for_status()
    data = response.json()
    return data["id"]

Algumas observações sobre essa função:

  • O parâmetro timeout evita que o script fique pendurado indefinidamente se a rede travar. Para uma chamada de submissão, 30 segundos é folgado, mas ajuste conforme necessário.
  • raise_for_status() converte erros HTTP em exceções, para que você possa capturá-los em um único lugar.
  • Retornar apenas o ID do job mantém a função focada. A lógica de polling deve ficar em uma função separada.

Se você preferir enviar a imagem de origem em bytes em vez de uma URL, leia o arquivo, codifique em base64 e coloque o resultado no campo image. Antes de mudar, confirme o formato esperado na documentação, porque essas duas codificações nem sempre são intercambiáveis.

Esta função é intencionalmente minimalista. Em um serviço real, você adicionaria logging, tratamento de retentativas e validação de tipos, mas o padrão central da requisição é exatamente o que você vê aqui.

Lidar com jobs assíncronos e consultar o resultado

A edição de imagens leva tempo — normalmente de alguns segundos a dezenas de segundos, dependendo do prompt e da resolução. A API trata isso aceitando sua requisição, retornando um ID de job e processando o trabalho em segundo plano. Sua tarefa é verificar repetidamente até que o status atinja um estado terminal.

Polling parece simples, mas um loop ingênuo disparado a cada 100 ms desperdiça cota e pode acionar limites de taxa. Use um intervalo razoável e um limite de tentativas:

import time
import requests

def poll_job(job_id: str, interval: float = 2.0, max_attempts: int = 30) -> dict:
    url = f"https://api.hiapi.ai/v1/jobs/{job_id}"
    headers = {"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}"}
    for attempt in range(max_attempts):
        response = requests.get(url, headers=headers, timeout=15)
        response.raise_for_status()
        data = response.json()
        status = data["status"]
        if status == "succeeded":
            return data
        if status == "failed":
            raise RuntimeError(data.get("error", "job failed"))
        time.sleep(interval)
    raise TimeoutError(f"job {job_id} did not finish after {max_attempts} attempts")

Um intervalo de dois segundos é um bom ponto de partida. Se seus jobs costumam terminar em cinco segundos, você pode consultar com mais frequência no início e depois aumentar gradualmente o intervalo. Se costumam demorar mais, reduza a frequência de polling para evitar chamadas desnecessárias.

O limite de tentativas é sua rede de segurança. Sem ele, um job travado pode entrar em loop infinito. Ao atingir o limite, lance um erro claro para que o chamador saiba que a operação expirou, em vez de ficar pendurado silenciosamente.

Em produção, considere mover o polling para um worker em segundo plano ou para uma fila, para que a thread que processa sua requisição não fique bloqueada esperando a renderização da imagem terminar.

Baixar e armazenar a imagem de saída

Quando o job atinge o status succeeded, a resposta contém uma ou mais imagens de saída, normalmente fornecidas como URLs. Seu próximo passo é baixar a imagem e armazená-la de forma persistente.

def download_image(result: dict, dest_path: str) -> None:
    image_url = result["output"][0]["url"]
    response = requests.get(image_url, timeout=30)
    response.raise_for_status()
    with open(dest_path, "wb") as f:
        f.write(response.content)

Algumas considerações práticas:

  • As URLs de saída podem ser temporárias. Trate-as como recursos de vida curta e baixe-as rapidamente, em vez de armazenar a URL como referência única.
  • Escreva o arquivo em modo binário. Respostas de imagem não são texto; abrir com "w" corromperá os dados.
  • Antes de declarar sucesso, verifique se o arquivo não está vazio. Um download de zero bytes geralmente significa que a URL expirou ou que a requisição foi bloqueada.

Para qualquer cenário além de um script local, faça o download diretamente em streaming para seu provedor de armazenamento, em vez de salvar em disco primeiro. A maioria dos SDKs de object storage aceita objetos semelhantes a arquivos ou fluxos de bytes, então você pode canalizar response.raw ou response.content direto para a chamada de upload, sem arquivo intermediário.

Por fim, registre o ID do job junto com o objeto armazenado. Se a saída for corrompida posteriormente, ou se você precisar reproduzir uma edição específica, o ID do job mais a entrada original permitem rastrear o que foi enviado.

Pontos comuns de falha e como corrigi-los

A maioria dos problemas de integração se enquadra em poucas categorias. Veja como diagnosticar cada um.

A requisição é rejeitada antes de criar o job

Um erro 400 no momento da submissão geralmente indica payload incorreto. Verifique se o model é exatamente muse-image-1.0/image-to-image, se a image está acessível ou corretamente codificada em base64, e se o prompt é uma string não vazia. Se a imagem for uma URL, confirme que ela é publicamente acessível — buckets privados ou URLs assinadas expiradas não passarão na validação.

O job falha durante o processamento

Se o polling retornar o status failed, leia a mensagem de erro no corpo da resposta. Causas comuns incluem imagem grande demais, prompt que viola a política de conteúdo, ou valores de parâmetros fora do intervalo permitido. Reduza o tamanho da imagem e simplifique o prompt para isolar a causa.

Timeout no polling

Se você atingir o limite de tentativas sem um estado terminal, o job pode realmente precisar de mais tempo, ou pode estar travado. Primeiro, aumente max_attempts e confirme o tempo típico de processamento na referência da API. Se o job continuar dando timeout, verifique se a imagem de origem está excepcionalmente grande. Não simplesmente remova o limite de tentativas — retentativas limitadas evitam loops infinitos silenciosos.

Limite de taxa

Uma resposta 429 significa que você enviou requisições rápido demais. Faça backoff, respeite qualquer cabeçalho retry-after e escalone as submissões concorrentes. Se você estiver processando um lote de imagens, processe em sequência ou use um limite de concorrência menor, em vez de disparar tudo de uma vez.

Saída ausente ou truncada

Se o job for bem-sucedido mas o arquivo baixado estiver vazio, a URL de saída pode ter expirado entre o polling e o download. Baixe imediatamente após o sucesso. Se a imagem estiver corrompida, confirme que você escreveu em modo binário e que não aplicou nenhuma codificação de texto ao fluxo.

Depurar fica mais fácil quando você registra o payload da requisição, o ID do job e as transições de status. Com essas três informações, quase qualquer falha pode ser rastreada até a origem.

Com a forma da requisição, os padrões curl e Python, a lógica de polling e a etapa de download, você tem um pipeline funcional para usar muse-image-1.0/image-to-image na HiAPI API. Comece pelo exemplo de terminal, leve-o para um script e, depois que o caminho normal estiver estável, adicione retentativas e logging.

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