Avatar
O Gustavo ou a Helena fala um texto (voz e boca) ou dubla um áudio seu (só a boca). Uma conexão, várias falas, uma de cada vez. Escopo avatar; R$ 0,20 por minuto de fala, voz incluída.
wss://api.int8labs.com/v1/avatar/streamAutenticação
No servidor, Authorization: Bearer int8_live_… no handshake. No navegador, ?token=int8_tmp_… na URL (um token de POST /v1/tokens). O SDK web faz tudo isto por você.
Parâmetros
avatar(opcional):gustavo(o padrão) ouhelena. Escolhe quem fala: o rosto que o seu renderizador desenha, a voz e a boca. Outro valor recebeinvalid_requeste o fechamento 4400, antes de qualquer cobrança.token: só no navegador, o token temporário (veja acima).
Mensagens
"speak"Modo texto: até 1.000 caracteres, com a voz do avatar da conexão.
{"type":"speak","text":"Olá! Como posso ajudar?"}"audio.start"Modo áudio próprio: a taxa do seu áudio (8000, 16000, 22050, 24000, 44100 ou 48000).
{"type":"audio.start","sample_rate":16000}áudiobinárioNo modo áudio próprio: o som que a boca vai dublar, até 5 minutos por fala.
PCM16 LE mono, até 1 s por mensagem
"audio.end"Fim do áudio da fala.
{"type":"audio.end"}"start"A fala começou. mode é text ou audio; no modo texto o áudio sai a 44100 Hz.
{"type":"start","utterance_id":"utt_01JAA5B3N9P2Q4R6S8T0V1W3XY","sample_rate":44100,"mode":"text"}0x01 áudiobinárioSó no modo texto: a voz do avatar, em pedaços.
0x01 · índice do pedaço (uint16 LE) · PCM16 LE mono
0x02 rostobinárioA boca e a expressão, para o renderizador do avatar. O SDK web lê esses pacotes por você.
0x02 · pacote de rosto (25 quadros por segundo, 103 valores fp16 por quadro)
"done"Fim da fala: duração, custo e saldo.
{"type":"done","utterance_id":"utt_01JAA5B3N9P2Q4R6S8T0V1W3XY","audio_ms":2140,"cost_brl":0.00713333,"balance_brl":87.39286667}"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
- O parâmetro
avatarda URL escolhe quem fala:gustavo(o padrão) ouhelena. Cada um tem a sua voz e a sua boca. Outro valor recebeinvalid_requeste o fechamento 4400, antes de qualquer cobrança. - No modo texto, erros de uma fala (
invalid_request,payload_too_large,server_busy,concurrency_limited) chegam sem fechar a conexão. No modo áudio próprio, todo erro fecha. - Áudio próprio parado por 10 s sem
audio.endfecha com 4400. Fala acima de 5 minutos fecha com 4413. - Sem mensagem por 5 minutos, ou depois de 4 horas de sessão, a conexão fecha com 1000.
- A credencial é conferida antes de cada fala: chave revogada ou token vencido fecha com 4401.
- O SDK web (
createAvatar) cuida de tudo isto e da sincronia da boca com o som.
Fechamentos
| Fechamento | Quando |
|---|---|
1000 | Fim normal: depois do done da transcrição ao vivo, por ociosidade ou ao passar de 4 h de sessão. |
4400 | invalid_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. |
4401 | invalid_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. |
4402 | insufficient_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. |
4403 | ip_not_allowed ou scope_denied. |
4413 | payload_too_large no modo áudio do avatar (fala acima de 5 min). |
4429 | rate_limited (áudio mais rápido que o tempo real) ou concurrency_limited (WebSockets demais na organização). |
4500 | internal_error. |
4503 | server_busy ou model_unavailable. |
Exemplo
import asyncioimport jsonimport osimport websockets # pip install "websockets>=14"async def main() -> None:# avatar=gustavo (o padrão) ou helena: o rosto, a voz e a boca.async with websockets.connect("wss://api.int8labs.com/v1/avatar/stream?avatar=helena",additional_headers={"Authorization": f"Bearer {os.environ['INT8_API_KEY']}"},) as ws:await ws.send(json.dumps({"type": "speak", "text": "Olá! Como posso ajudar?"}))audio, pacotes = bytearray(), 0async for mensagem in ws:if isinstance(mensagem, bytes):if mensagem[0] == 0x01:audio += mensagem[3:] # PCM16 LE mono, 44100 Hzelif mensagem[0] == 0x02:pacotes += 1 # pacote de rosto, para o renderizadorcontinueevento = json.loads(mensagem)if evento["type"] == "done":print(evento["audio_ms"], "ms;", pacotes, "pacotes de rosto; R$", evento["cost_brl"])breakasyncio.run(main())