Pular para o conteúdo
int8labs

Voz em streaming

Texto entra, áudio sai em pedaços assim que cada um fica pronto. Várias falas por conexão, uma de cada vez. Escopo tts; R$ 20 por 1 milhão de caracteres.

1 min de leitura · atualizado em 13/10/2026
WSwss://api.int8labs.com/v1/tts/stream

Autenticação

No servidor, Authorization: Bearer int8_live_… no handshake. No navegador, ?token=int8_tmp_… na URL (um token de POST /v1/tokens). Credencial errada recebe a mensagem de erro e o fechamento 4401.

Mensagens

VOCÊ →"speak"

Uma fala: text (1 a 5.000 caracteres), voice e, opcionais, speed (0.8 a 1.3) e sample_rate (8000, 16000, 22050, 24000 ou 44100; padrão 44100).

{"type":"speak","text":"Sua consulta está confirmada.","voice":"helena","speed":1.0,"sample_rate":24000}
← SERVIDOR"start"

A fala começou: o id da fala, a taxa do áudio e em quantos pedaços ela vem.

{"type":"start","utterance_id":"utt_01JAA4K2W8M5R1T7Y3Q9C6V0BN","sample_rate":24000,"chunks":2}
← SERVIDOR0x01 áudiobinário

Um pedaço de áudio. O primeiro byte é 0x01, os dois seguintes são o índice do pedaço, o resto é o som.

0x01 · índice do pedaço (uint16 LE) · PCM16 LE mono
← SERVIDOR"chunk"

Depois de cada pedaço binário: o índice e a duração dele.

{"type":"chunk","index":0,"audio_ms":1840}
← SERVIDOR"done"

Fim da fala: caracteres cobrados, duração, tempo até o primeiro som, custo e saldo depois do débito.

{"type":"done","utterance_id":"utt_01JAA4K2W8M5R1T7Y3Q9C6V0BN","characters":29,"audio_ms":2310,"first_audio_ms":412,"cost_brl":0.00058,"balance_brl":87.3994}
← SERVIDOR"error"

Erro, com o mesmo code do REST. Os que fecham a conexão vêm seguidos do fechamento 4000 + o status HTTP.

{"type":"error","code":"insufficient_balance","message":"Saldo insuficiente. Recarregue em console › Faturamento.","request_id":"req_01JAA4M7Q2W8E5R3T6Y9U1I0PZ"}

Regras

  • Mande o próximo speak só depois do done da fala anterior.
  • Erros de uma fala (invalid_request, payload_too_large, server_busy, concurrency_limited) chegam sem fechar a conexão; mande outra fala.
  • A credencial é conferida de novo antes de cada fala: chave revogada ou token vencido fecha com 4401.
  • Sem mensagem por 5 minutos, ou depois de 4 horas de sessão, a conexão fecha com 1000.

Fechamentos

FechamentoQuando
1000Fim normal: depois do done da transcrição ao vivo, por ociosidade ou ao passar de 4 h de sessão.
4400invalid_request na transcrição ao vivo ou no modo áudio do avatar. Na voz e no modo texto do avatar, o erro de uma fala chega sem fechar a conexão.
4401invalid_api_key, api_key_expired ou api_key_revoked, no começo ou no meio da sessão. Na transcrição ao vivo, os final do áudio já recebido chegam antes do erro.
4402insufficient_balance: o saldo acabou. O que já foi falado ou ouvido é cobrado; na transcrição ao vivo, os final desse áudio chegam antes do erro.
4403ip_not_allowed ou scope_denied.
4413payload_too_large no modo áudio do avatar (fala acima de 5 min).
4429rate_limited (áudio mais rápido que o tempo real) ou concurrency_limited (WebSockets demais na organização).
4500internal_error.
4503server_busy ou model_unavailable.

Exemplo

import asyncio
import json
import os
​
import websockets # pip install "websockets>=14"
​
​
async def falar(texto: str) -> bytes:
audio = bytearray()
async with websockets.connect(
"wss://api.int8labs.com/v1/tts/stream",
additional_headers={"Authorization": f"Bearer {os.environ['INT8_API_KEY']}"},
) as ws:
await ws.send(json.dumps({"type": "speak", "text": texto, "voice": "helena", "sample_rate": 24000}))
async for mensagem in ws:
if isinstance(mensagem, bytes):
if mensagem[0] == 0x01: # 0x01 + índice (uint16 LE) + PCM16 LE mono
audio += mensagem[3:]
continue
evento = json.loads(mensagem)
if evento["type"] == "done":
print("1º som em", evento["first_audio_ms"], "ms; custo R$", evento["cost_brl"])
break
if evento["type"] == "error":
raise RuntimeError(evento["message"])
return bytes(audio)
​
​
pcm = asyncio.run(falar("Sua consulta ficou para terça, às 14h30."))