Tutorial
Como chamar o gemini-3.1-flash-tts na HiAPI: curl, Python e uma requisição executável
O que o gemini-3.1-flash-tts pode fazer por você na HiAPI
gemini-3.1-flash-tts é um modelo de texto para fala disponibilizado pela API unificada da HiAPI. Você envia o texto e a configuração de voz, e a plataforma retorna o áudio gerado. Como ele é exposto por meio de uma interface única e consistente, você não precisa de integrações separadas para cada modelo — os mesmos cabeçalhos de autenticação, a mesma URL base e o mesmo padrão de tarefa assíncrona se aplicam a todos os modelos de TTS da plataforma.
Escolha este modelo quando precisar de:
- Narração com múltiplos locutores. Roteiros, diálogos ou conteúdo no estilo podcast, em que trechos diferentes devem soar como vozes diferentes.
- Resposta rápida. A linha
flashé voltada para geração de baixa latência, o que é especialmente importante para aplicações interativas ou tarefas em lote com SLA apertado. - Interface de integração previsível. Uma única forma de requisição cobre desde uma linha de texto até cenários com múltiplos locutores.
Se a aplicação que você está construindo já chama outros modelos da HiAPI, adicionar funcionalidade de voz exige apenas trocar o identificador do modelo e ajustar o corpo da requisição — sem novo SDK e sem novo fluxo de credenciais.
Pré-requisitos e configuração de autenticação
Antes da primeira chamada, garanta que você tem:
- Uma conta HiAPI e uma chave de API. Gere a chave no console. Trate-a como confidencial — não a envie para o controle de versão.
- A URL base da HiAPI. Todas as requisições vão para o mesmo host; apenas o caminho de cada endpoint varia.
- Uma ferramenta para fazer requisições HTTP.
curlpara testes rápidos e Python 3.9+ com a bibliotecarequestspara scripts.
A autenticação é feita com um token bearer no cabeçalho Authorization:
Authorization: Bearer $HIAPI_API_KEY
Armazene a chave em uma variável de ambiente, em vez de codificá-la diretamente:
export HIAPI_API_KEY="your_key_here"
Todos os endpoints descritos abaixo — envio de tarefa, verificação de status e obtenção de arquivo — usam o mesmo cabeçalho. Se você receber 401, o cabeçalho está ausente, malformado ou a chave foi revogada. Faça a rotação da chave no console em vez de compartilhar uma mesma chave entre ambientes.
Montando o corpo da requisição para voz com múltiplos locutores
O corpo da requisição é JSON. No mínimo, ele precisa conter o identificador do modelo e o conteúdo de entrada. Para saída com múltiplos locutores, você adiciona uma configuração de locutores que mapeia locutores nomeados para vozes e marca o texto de entrada com etiquetas de locutor.
Um corpo de requisição típico é assim:
{
"model": "gemini-3.1-flash-tts",
"input": {
"text": "[Host] Welcome back to the show. [Guest] Thanks for having me.",
"multi_speaker": true,
"speakers": [
{ "name": "Host", "voice": "voice_a" },
{ "name": "Guest", "voice": "voice_b" }
]
}
}
Pontos-chave que costumam causar problemas:
- Os nomes dos locutores precisam corresponder exatamente. O
nameno arrayspeakersdeve ser idêntico à etiqueta usada no texto (entre colchetes neste exemplo). Diferenças de maiúsculas e minúsculas são a causa mais comum de falha na renderização com múltiplos locutores. - Cada etiqueta precisa ser declarada. Se o texto referencia
[Narrator], mas não há um locutor definido comname: "Narrator", a requisição será rejeitada. - Os identificadores de voz vêm do catálogo de vozes da plataforma. Use os identificadores fornecidos pela HiAPI, em vez de adivinhar. Para tarefas com locutor único, omita
multi_speakerespeakerse, em vez disso, defina um único campovoice. - O texto é enviado como uma única string. Roteiros longos não são problema, mas fique atento aos limites por requisição documentados na plataforma.
Depois que o corpo da requisição passa na validação, a tarefa é aceita e retorna um identificador de tarefa, que você usará para consultar o status.
Executando com curl
Salve o corpo da requisição acima como payload.json e envie:
curl -X POST "$HIAPI_BASE_URL/v1/audio/speech/jobs" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d @payload.json
A resposta contém um objeto de tarefa com os campos id e status (normalmente queued ou processing):
{ "id": "job_abc123", "status": "queued" }
Para verificar o progresso, obtenha a tarefa pelo ID:
curl "$HIAPI_BASE_URL/v1/audio/speech/jobs/job_abc123" \
-H "Authorization: Bearer $HIAPI_API_KEY"
Quando status passar a succeeded, a resposta incluirá uma referência ao arquivo de áudio (URL ou ID de arquivo), que você pode baixar por meio de uma requisição subsequente — veja a seção de polling abaixo. Se a tarefa falhar, status será failed e haverá um campo error explicando o motivo.
Para experimentação rápida, você pode pular o arquivo e enviar o JSON inline:
curl -X POST "$HIAPI_BASE_URL/v1/audio/speech/jobs" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"gemini-3.1-flash-tts","input":{"text":"Hello from HiAPI.","voice":"voice_a"}}'
Executando com Python
A versão em Python usa requests e uma pequena função auxiliar para manter o loop de polling legível. O corpo da requisição é idêntico ao exemplo com curl.
import os
import time
import requests
API_KEY = os.environ["HIAPI_API_KEY"]
BASE_URL = os.environ["HIAPI_BASE_URL"]
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
payload = {
"model": "gemini-3.1-flash-tts",
"input": {
"text": "[Host] Welcome back to the show. [Guest] Thanks for having me.",
"multi_speaker": True,
"speakers": [
{"name": "Host", "voice": "voice_a"},
{"name": "Guest", "voice": "voice_b"},
],
},
}
resp = requests.post(
f"{BASE_URL}/v1/audio/speech/jobs",
headers={**HEADERS, "Content-Type": "application/json"},
json=payload,
timeout=30,
)
resp.raise_for_status()
job = resp.json()
job_id = job["id"]
print("submitted", job_id)
while True:
r = requests.get(f"{BASE_URL}/v1/audio/speech/jobs/{job_id}", headers=HEADERS, timeout=30)
r.raise_for_status()
status = r.json()
if status["status"] in ("succeeded", "failed"):
break
time.sleep(2)
if status["status"] == "failed":
raise RuntimeError(status.get("error"))
print("audio ready:", status["output"])
Observações:
- Timeouts são importantes. Defina timeouts explícitos em cada requisição; um loop de polling travado é pior do que um loop que falha.
- Não consulte com frequência excessiva. Um intervalo de dois segundos é razoável para roteiros curtos; para roteiros longos, use backoff.
- Coloque o corpo da requisição em uma função. No código real, parametrize texto, locutores e vozes para poder reutilizar a mesma lógica de envio em tarefas com locutor único.
Consultando tarefas assíncronas e baixando o áudio
A geração de voz é assíncrona: você envia a tarefa e depois verifica o status até que ela atinja um estado terminal. Existem dois estados terminais — succeeded e failed. Todos os outros estados devem ser tratados como "continue aguardando".
Um programa de polling robusto deve:
- Limitar o tempo total de espera. Mesmo modelos rápidos podem ficar na fila atrás de outro trabalho. Pare após um limite razoável e exponha o ID da tarefa para que o chamador possa tentar novamente.
- Backoff exponencial. Comece com um ou dois segundos e dobre a cada tentativa até um teto. Isso evita sobrecarregar a API em tarefas longas.
- Tratar falhas explicitamente. Quando
status == "failed", leia o campoerrore registre-o — ele normalmente aponta para um problema no corpo da requisição (locutor não declarado, texto vazio, voz não suportada).
Quando a tarefa é bem-sucedida, a resposta de status inclui uma referência de saída. Baixe-a com os mesmos cabeçalhos de autenticação:
out = status["output"]
audio = requests.get(out["url"], headers=HEADERS, timeout=60)
audio.raise_for_status()
with open("narration.wav", "wb") as f:
f.write(audio.content)
Se a resposta retornar um ID de arquivo em vez de uma URL, obtenha-o pelo endpoint de arquivos correspondente na HiAPI. Armazene o ID da tarefa original junto com o arquivo salvo — é a única maneira confiável de rastrear uma renderização ruim até sua requisição posteriormente.
Entendendo a cobrança por caractere
O gemini-3.1-flash-tts na HiAPI é cobrado pelo número de caracteres do texto de entrada. Não há componente de cobrança por requisição ou por minuto a modelar — o custo da tarefa escala com o volume de texto enviado, o que simplifica a estimativa: o total de caracteres de todos os roteiros multiplicado pela taxa atual por caractere.
Implicações práticas:
- Estime antes de lançar. Some o volume mensal de texto esperado e confira com a taxa atual exibida no painel de preços. Não codifique a taxa diretamente no código; leia-a da plataforma no momento da construção ou mantenha-a em configuração.
- Conteúdo longo domina o custo. Dez minutos de narração são principalmente custo de texto. Se você for gerar audiolivros ou material de curso, modele o volume primeiro.
- Novas tentativas geram custo. Tarefas que falham após a geração podem ainda ser cobradas, dependendo do modo de falha. Faça validação no cliente antes de enviar — verifique se cada etiqueta de locutor está declarada e se o texto não está vazio.
- Faça cache ativamente. Se o mesmo roteiro for renderizado repetidamente (por exemplo, demonstrações ou fixtures de teste), salve o áudio gerado e reutilize-o, em vez de cobrar novamente pelos mesmos caracteres.
Para taxas atuais e eventuais faixas por volume, consulte o painel de preços no site — essa é a única fonte de verdade.
Pontos comuns de falha e como corrigi-los
A maioria dos problemas de integração se enquadra em algumas poucas categorias. Verifique-as em ordem.
401 Não autorizado
Seu cabeçalho Authorization está ausente ou malformado. Confirme que a chave está definida no ambiente e que o conteúdo do cabeçalho é exatamente Bearer <key>. Se a chave foi rotacionada, atualize seu ambiente.
400 Requisição inválida — locutor desconhecido
O texto contém uma etiqueta [Name] que não foi declarada em speakers, ou há diferença de maiúsculas e minúsculas. Faça a etiqueta e o campo name serem idênticos byte a byte.
400 Requisição inválida — entrada vazia ou grande demais
Texto vazio falha imediatamente na validação. Roteiros muito longos podem exceder o limite por requisição; divida-os em várias tarefas em vez de truncar.
400 Requisição inválida — identificador de voz inválido
Os nomes de voz devem vir do catálogo da plataforma. Copie o identificador exatamente; não invente nomes amigáveis.
Tarefa presa em processing
Isso geralmente é fila, não um bug. Aplique backoff e timeout total. Se persistir muito além do tempo normal, registre o ID da tarefa e tente novamente uma vez com um corpo de requisição menor, para determinar se o tamanho é o problema.
Tarefa failed com erro de geração
Leia o campo error. Ele geralmente aponta para um problema de conteúdo ou configuração, não para uma falha transitória. Corrija o corpo da requisição, reenvie e evite loops de nova tentativa cegos — cada tentativa pode ser cobrada por caractere.
O áudio pode ser baixado, mas não reproduz
Antes de assumir que o arquivo está corrompido, verifique o tipo de conteúdo do arquivo baixado. Salve com a extensão correta correspondente ao formato retornado e confirme que o tamanho em bytes é diferente de zero. Um arquivo truncado normalmente significa que a requisição de download foi interrompida — tente novamente o download, em vez de regenerar.
Com essas verificações, a maioria dos problemas de integração do primeiro dia pode ser resolvida em minutos, não em horas.
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