Tutorial
Como usar qwen-audio-3.0-tts-plus via API hiapi: conversão de texto em fala com curl e Python
qwen-audio-3.0-tts-plus é um modelo de conversão de texto em fala, acessado por meio da fila unificada de tarefas assíncronas da plataforma hiapi — o mesmo endpoint POST /v1/tasks usado para geração de imagens e vídeos, e não uma API de áudio separada. Você envia o texto, recebe imediatamente um taskId e então faz polling ou aguarda um callback para obter a URL do arquivo de áudio para download. Este tutorial vai te levar por uma requisição funcional em curl e Python (validada de ponta a ponta com a API em tempo real) e, em seguida, apresenta os padrões de produção que você realmente precisa: callback vs. polling, retentativas idempotentes e as formas exatas de erro que precisam ser tratadas.
O que você vai construir
Um script que envia texto para qwen-audio-3.0-tts-plus, aguarda a conclusão da tarefa e baixa o áudio gerado — além da referência de parâmetros e de padrões de tratamento de erros, para transformar esse script em uma integração de verdade.
Pré-requisitos: uma chave de API hiapi. Obtenha-a no painel da hiapi — cada requisição abaixo é autenticada com Authorization: Bearer sk-<your-key>.
Exemplo mínimo funcional
curl
Crie a tarefa:
curl -s -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer $HIAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "qwen-audio-3.0-tts-plus",
"input": {
"text": "Welcome to hiapi, the unified API for AI models.",
"voice": "longanlingxin"
}
}'
{"code": 200, "data": {"taskId": "tk-hiapi-01KZ59B7ZJ7012PXB5J9GE1QE7"}, "message": "success"}
Em seguida, faça polling de GET /v1/tasks/<taskId> com o mesmo token bearer até que data.status saia de "processing". Para este modelo, os testes levaram cerca de 5 segundos:
curl -s https://api.hiapi.ai/v1/tasks/tk-hiapi-01KZ59B7ZJ7012PXB5J9GE1QE7 \
-H "Authorization: Bearer $HIAPI_KEY"
{
"code": 200,
"data": {
"taskId": "tk-hiapi-01KZ59B7ZJ7012PXB5J9GE1QE7",
"status": "success",
"model": "qwen-audio-3.0-tts-plus",
"storage": "temp",
"created": 1785810231,
"completed": 1785810236,
"output": [{"type": "audio", "url": "https://temp.hiapi.ai/.../01KZ59B7ZJ7012PXB5J9GE1QE7-0.mp3", "artifactId": "66654", "expireAt": 1786415036}]
},
"message": "success"
}
output[0].url é um MP3 real e baixável (content-type: audio/mpeg — confirmado com uma requisição direta). Trata-se de um link temporário: quando storage mantém o valor padrão "temp", expireAt fica quase exatamente 7 dias após created, então, se você precisar reter o áudio por mais tempo, baixe os bytes e armazene por conta própria.
Python
import os
import time
import requests
API_BASE = "https://api.hiapi.ai/v1/tasks"
headers = {"Authorization": f"Bearer {os.environ['HIAPI_KEY']}"}
resp = requests.post(
API_BASE,
headers={**headers, "Content-Type": "application/json"},
json={
"model": "qwen-audio-3.0-tts-plus",
"input": {
"text": "Welcome to hiapi, the unified API for AI models.",
"voice": "longanlingxin",
},
},
timeout=30,
)
resp.raise_for_status()
task_id = resp.json()["data"]["taskId"]
while True:
task = requests.get(f"{API_BASE}/{task_id}", headers=headers, timeout=30).json()["data"]
if task["status"] == "success":
audio_url = task["output"][0]["url"]
break
if task["status"] == "fail":
raise RuntimeError(task["error"])
time.sleep(2)
audio_bytes = requests.get(audio_url, timeout=60).content
with open("output.mp3", "wb") as f:
f.write(audio_bytes)
Padrões de uso em produção
Esquema completo de entrada
O objeto input aceita apenas os campos abaixo — a API rejeita qualquer outro campo com 400, então não reaproveite nomes de parâmetros de outros provedores de TTS:
| Campo | Obrigatório | Tipo / valor |
|---|---|---|
text |
Sim | String |
voice |
Sim | Um de "longanlingxin", "longanlufeng" (este modelo atualmente só tem dois timbres disponíveis) |
format |
Não | Um de "pcm", "wav", "mp3", "opus" — o padrão quando omitido é mp3 |
sample_rate |
Não | Um de 8000, 16000, 22050, 24000, 44100, 48000 |
pitch |
Não | Número, 0.5–2 |
volume |
Não | Número, 0–100 |
Cada limite e valor de enumeração acima vem dos próprios erros de validação da API — se você enviar um voice inválido ou um pitch fora do intervalo, a hiapi informa exatamente os valores permitidos:
{"code": 400, "data": null, "error_code": "INVALID_REQUEST", "message": "invalid input: voice: value must be one of 'longanlingxin', 'longanlufeng'"}
Este modelo não tem campos de controle como emotion, speed ou estilo SSML — requisições que os incluam falham com "additional properties '...' not allowed".
Callback vs. polling
Para qualquer caso que vá além de scripts rápidos, dispense o polling e deixe a hiapi enviar o resultado. Adicione um objeto callback à requisição de criação de tarefa:
{
"model": "qwen-audio-3.0-tts-plus",
"callback": {"url": "https://example.com/hiapi/callback", "when": "final"},
"input": {"text": "Welcome to hiapi.", "voice": "longanlingxin"}
}
"final" é atualmente o único valor suportado para when — seja a tarefa concluída com sucesso ou com falha, a hiapi fará um POST em callback.url, e você lê desse payload o mesmo formato de detalhes da tarefa que obteria via polling de GET /v1/tasks/<taskId>. Se preferir, omita totalmente o callback e faça polling por conta própria, como nos exemplos acima.
Também vale saber: a saída da tarefa usa storage: "temp" por padrão (os arquivos duram cerca de uma semana, como mostra o valor de expireAt acima). Se você precisa que o áudio permaneça recuperável por mais tempo, defina "storage": "persistent" na tarefa — o armazenamento persistente é cobrado por tamanho, então, para gerações pontuais, geralmente sai mais barato baixar e armazenar por conta própria.
Idempotência e retentativas
POST /v1/tasks aceita o cabeçalho Idempotency-Key (até 255 bytes). Repetir a mesma requisição com a mesma chave na mesma conta cria a tarefa apenas uma vez — o reenvio retorna o taskId original, em vez de uma segunda geração cobrada. Use isso para retentar após timeouts ou 5xx, quando você não sabe ao certo se a primeira requisição chegou:
curl -s -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer $HIAPI_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: tts-job-42" \
-d '{"model": "qwen-audio-3.0-tts-plus", "input": {"text": "...", "voice": "longanlingxin"}}'
Tratamento de erros
Uma chave inválida ou não autorizada retorna HTTP 401, com o envelope de erro padrão da hiapi (validado diretamente neste modelo):
{"error": {"code": "permission_denied", "message": "This API key cannot use the selected model...", "request_id": "...", "type": "hiapi_error"}}
Um payload input incorreto retorna HTTP 400, com error_code: "INVALID_REQUEST" e uma message que indica o campo infrator, como mostrado na seção de esquema acima — faça o branching com base em error_code / error.code, e não no texto legível da mensagem. Se a tarefa atingir o estado terminal "fail" em vez de falhar na criação, a resposta de detalhes da tarefa carrega o mesmo formato em data.error (code + message), em vez da chave error no nível superior.
Leituras relacionadas
- Painel da hiapi — crie e gerencie chaves de API.
- Documentação de criação de tarefas — o contrato completo de
POST /v1/tasks, incluindo cabeçalhos, callback e idempotência. - Documentação de detalhes da tarefa — o endpoint de polling usado acima.
- Documentação de autenticação da hiapi — como o cabeçalho
Authorizatione o escopo de chaves funcionam em toda a plataforma. - Documentação de limites de taxa da hiapi — comportamento de
429eRetry-After. - Modelos de áudio na hiapi — explore outros modelos de voz e áudio na plataforma.
- Consulte o preço atual deste modelo na página de preços em tempo real; ele não é repetido aqui.
Perguntas frequentes
A geração de áudio é diferente da API de tarefas de imagem/vídeo da hiapi?
Não — é a mesma fila POST /v1/tasks, o mesmo fluxo de polling ou callback após a criação e o mesmo formato output[0].url. Apenas output[0].type (aqui, "audio") e o esquema de input variam por modelo.
O que acontece se eu não definir format?
Você recebe um MP3 — confirmado nos testes ao omiti-lo. Se precisar de wav, pcm ou opus, defina format explicitamente.
Posso transmitir o áudio em streaming em vez de esperar a tarefa concluir? Não. Este modelo só expõe o fluxo padrão de tarefas criar/polling/callback — não há parâmetro de streaming no esquema de entrada, e a geração é rápida o suficiente (alguns segundos para textos curtos), então fazer polling a cada 1–2 segundos normalmente basta.
Por quanto tempo a URL de saída permanece válida?
Cerca de 7 dias por padrão (storage: "temp"), com base no intervalo entre os timestamps created e expireAt da tarefa. Baixe o áudio logo, ou defina "storage": "persistent" na tarefa se precisar de recuperação por mais tempo.
Por que minha requisição falha com "additional properties ... not allowed"?
O esquema é estrito — este modelo aceita apenas text, voice, format, sample_rate, pitch e volume. Parâmetros vindos de outras APIs de TTS (como emotion ou speed) não são reconhecidos aqui e retornam 400.
Onde encontro o preço atual? Na página de preços — este tutorial deliberadamente não fixa custos por caractere ou por requisição, já que os preços podem mudar.
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