HiAPI
Blogue

Tutorial

Como usar o omnihuman-1.5 através da API hiapi: curl, Python e requisições prontas para executar

Oct 14, 2026
Como usar o omnihuman-1.5 através da API hiapi: curl, Python e requisições prontas para executar

omnihuman-1.5 combina uma foto de retrato com um trecho de áudio para gerar um vídeo de fala com sincronização labial. Na hiapi, assim como todos os outros modelos de mídia, ele opera sobre o mesmo protocolo de tarefas assíncronas: primeiro chame uma vez POST /v1/tasks para criar a tarefa, depois faça polling (ou receba webhook) até que a URL do vídeo esteja pronta. Este guia usa o schema real de requisição — verificado campo a campo com a API em produção — portanto os códigos curl e Python abaixo podem ser copiados e executados diretamente, e não são apenas exemplos.

O que você vai construir

Um script que envia uma imagem de rosto e uma faixa de voz para o omnihuman-1.5 e retorna um arquivo MP4 no qual o rosto fala de acordo com o áudio, com sincronização labial. A duração do vídeo acompanha o áudio — não há campo duration para configurar.

Pré-requisitos

  1. Uma chave de API hiapi. Crie uma no dashboard; ela será enviada como Bearer token em cada requisição. Consulte a documentação de autenticação para o formato do cabeçalho.
  2. Uma URL de imagem e uma URL de áudio publicamente acessíveis. O omnihuman-1.5 baixa ambas no servidor, portanto basta que sejam URLs http(s) que sua máquina consiga abrir anonimamente; caminhos localhost e URLs assinadas que expiram no meio da tarefa não funcionam.

É só isso — não é necessário SDK, nem conta além da chave.

Schema de entrada

O omnihuman-1.5 aceita um objeto input estrito. Campos desconhecidos são rejeitados, então estes são todos os campos disponíveis:

Campo Tipo Obrigatório Descrição
image_url string Sim URL de um retrato. Um rosto único, nítido e frontal funciona melhor.
audio_url string Sim Faixa de voz usada para a sincronização labial. Determina a duração da saída.
prompt string Não Direcionamento opcional de movimento/expressão.
resolution string Não "720p" ou "1080p".

Não existe modo somente texto: audio_url é obrigatório. Se você só tem o roteiro, gere primeiro a voz (com um modelo TTS, ou com um avatar digital guiado por texto como o heygen-avatar-v) e depois passe a URL do áudio gerado aqui.

Exemplo mínimo executável (curl)

Criar a tarefa:

curl -s -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer sk-YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "omnihuman-1.5",
    "input": {
      "image_url": "https://example.com/portrait.jpg",
      "audio_url": "https://example.com/voiceover.mp3",
      "resolution": "720p"
    }
  }'

A resposta traz o id da tarefa:

{ "code": 200, "data": { "taskId": "b3f1c2e8-...", "status": "pending" } }

Faça polling da tarefa até ela atingir um estado terminal:

curl -s https://api.hiapi.ai/v1/tasks/b3f1c2e8-... \
  -H "Authorization: Bearer sk-YOUR_KEY"

Quando concluída, data.status é "success" e o vídeo está em data.output[0].url:

{
  "code": 200,
  "data": {
    "taskId": "b3f1c2e8-...",
    "status": "success",
    "output": [
      { "url": "https://temp.hiapi.ai/.../omnihuman.mp4", "expireAt": 1760000000 }
    ]
  }
}

A URL em output é temporária (acompanha expireAt). Baixe o MP4 imediatamente após a tarefa ter sucesso — não faça hotlink desse endereço em produção.

A mesma chamada em Python

import time
import requests  # pip install requests

API = "https://api.hiapi.ai/v1/tasks"
KEY = "sk-YOUR_KEY"
HEADERS = {"Authorization": f"Bearer {KEY}", "Content-Type": "application/json"}


def create_task() -> str:
    payload = {
        "model": "omnihuman-1.5",
        "input": {
            "image_url": "https://example.com/portrait.jpg",
            "audio_url": "https://example.com/voiceover.mp3",
            "resolution": "720p",
        },
    }
    r = requests.post(API, headers=HEADERS, json=payload, timeout=60)
    r.raise_for_status()
    return r.json()["data"]["taskId"]


def wait_for_video(task_id: str, timeout: int = 600, interval: int = 5) -> str:
    deadline = time.time() + timeout
    while time.time() < deadline:
        r = requests.get(f"{API}/{task_id}", headers=HEADERS, timeout=30)
        data = r.json()["data"]
        status = data["status"]
        if status == "success":
            return data["output"][0]["url"]
        if status == "fail":
            raise RuntimeError(f"omnihuman-1.5 task failed: {data.get('error')}")
        time.sleep(interval)
    raise TimeoutError(f"task {task_id} did not finish in {timeout}s")


if __name__ == "__main__":
    tid = create_task()
    print("task:", tid)
    video_url = wait_for_video(tid)
    # URLs expire — persist the bytes immediately.
    mp4 = requests.get(video_url, timeout=120).content
    with open("talking_head.mp4", "wb") as f:
        f.write(mp4)
    print("saved talking_head.mp4")

Colocando em produção

Prefira callbacks em vez de polling intenso. Adicione um objeto callback no nível superior e a hiapi enviará a tarefa concluída via POST ao seu endpoint, em vez de você fazer polling:

{
  "model": "omnihuman-1.5",
  "input": {
    "image_url": "https://example.com/portrait.jpg",
    "audio_url": "https://example.com/voiceover.mp3",
    "resolution": "1080p"
  },
  "callback": { "url": "https://your.app/webhooks/hiapi", "when": "final" }
}

when aceita apenas "final" e dispara tanto em sucesso quanto em falha — portanto seu webhook precisa ramificar com base em data.status. O corpo entregue é o mesmo objeto obtido via GET /v1/tasks/{id}. A entrega tem semântica de pelo menos uma vez, então deduplique por taskId.

Nunca reenvie em erros temporários. Se uma requisição de polling expirar ou a conexão cair, faça polling do mesmo taskId novamente — não chame POST /v1/tasks outra vez. Reenviar inicia uma segunda tarefa cobrada. Salve o taskId imediatamente após obtê-lo.

Trate as três formas de falha separadamente:

  • Falha de autenticação → HTTP 401, corpo {"error": {"code": "permission_denied", "type": "hiapi_error", ...}}. Corrija a chave; não repita a requisição.
  • Requisição inválida (campo ausente/inválido) → HTTP 400, corpo {"code": 400, "error_code": "INVALID_REQUEST", "message": "..."}. A message indica o campo problemático — corrija e reenvie.
  • Tarefa iniciada que falhou → HTTP 200, com data.status == "fail" e data.error. A causa mais comum é o servidor não conseguir baixar image_url/audio_url. Verifique se ambos estão publicamente acessíveis e ainda válidos. Sempre ramifique com base em data.status, não apenas no código de status HTTP.

O preço é cobrado por segundos de saída, listado na página de preços; como a duração do vídeo acompanha seu áudio, o custo varia com a duração do áudio.

Guias relacionados

Perguntas frequentes

Posso usar texto em vez de arquivo de áudio para acionar o omnihuman-1.5? Não. audio_url é obrigatório e o modelo faz a sincronização labial com esse áudio. Para um fluxo de roteiro para vídeo, sintetize a voz primeiro (qualquer TTS), ou use um avatar digital guiado por texto como o heygen-avatar-v, e depois passe a URL do áudio aqui.

Qual é a duração do vídeo de saída? Acompanha o trecho de áudio — não há parâmetro duration. Uma faixa de voz de 12 segundos gera aproximadamente 12 segundos de vídeo.

Que tipo de imagem funciona melhor? Um retrato único de uma pessoa, com iluminação nítida e frontal, em uma URL pública. Fotos em grupo ou com o rosto muito obstruído resultam em sincronização labial pior.

720p ou 1080p? Ambos são aceitos em resolution. Comece com 720p durante a iteração; mude para 1080p na renderização final. Resolução maior custa mais por segundo — consulte preços.

Minha tarefa retorna status: "fail" imediatamente. Por quê? Quase sempre é o servidor não conseguindo acessar alguma URL de entrada. Confirme que image_url e audio_url estão publicamente acessíveis (abra-as em uma janela anônima) e não expiraram. A mensagem em data.error ajuda a identificar o problema.

Preciso fazer polling ou posso usar webhook? Ambos funcionam. Scripts simples podem usar polling com GET /v1/tasks/{id}; em produção, registre callback.url e defina when como "final", assim você não precisa manter um loop de polling.

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