11 KiB
TIA Voice API
Este repositorio contem a stack de voz-to-voz do projeto TIA.
Estrutura
src/app: gateway WebSocket, runtime LiveKit, providers e utilitariossrc/agent: pipeline e estagios do agentetests: testes automatizadosdocs: documentacao viva do projetok8s/livekit: imagem e manifest do pod dedicado do LiveKitk8s/tia: imagem e manifest do pod da aplicacao combridgeeagentrequirements.txt: dependencias Python da aplicacaolivekit.yaml: configuracao local do servidor LiveKit
Setup local
make setup
O alvo make setup faz o bootstrap do ambiente local:
- cria
.venvpriorizandopython3.13,python3.12,python3.11,python3.10,python3.9,python3epython - instala as dependencias de
requirements.txt - cria
.env.deva partir de.env.examplese o arquivo ainda nao existir
O projeto hoje exige Python 3.9 ate 3.13. Python 3.14 nao e aceito pelas dependencias atuais de livekit-agents==1.3.10.
Se voce tiver mais de um Python instalado e quiser forcar uma versao especifica no bootstrap:
make BOOTSTRAP_PY=python3.12 setup
Se voce preferir fazer manualmente ou quiser depurar o bootstrap, use:
python3.12 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -r requirements.txt
cp .env.example .env.dev
Se make test, make agent ou make bridge falharem com erro de virtualenv ausente, rode make setup primeiro.
Teste local
make test
O makefile executa os testes com .venv/bin/python e injeta PYTHONPATH=src, entao o comando deve ser chamado a partir da raiz do repositorio.
Execucao local
O .env.dev de desenvolvimento pode ser configurado em dois modos:
- smoke test local:
AGENT_BACKEND=remote_ws_fake,STT_PROVIDER=fakeeTTS_PROVIDER=fake - integracao real: ajuste
AGENT_BACKEND,STT_PROVIDER,TTS_PROVIDERe as credenciais externas necessarias
No modo fake, o agent nao depende de STT HTTP, ElevenLabs ou backend LLM externo. O STT fake consome uma sequencia configurada em FAKE_STT_TRANSCRIPTS e o TTS fake gera um tom PCM local para validar o pipeline de audio.
Importante: LIVEKIT_API_KEY e LIVEKIT_API_SECRET do .env.dev precisam ser identicos ao bloco keys de livekit.yaml. Se esses valores divergirem, o bridge falha ao conectar/publicar no LiveKit e o dispatch do agent retorna erro de autenticacao.
Para usar o STT HTTP real, configure no .env.dev:
STT_PROVIDER=internal_httpSTT_URL=http://10.152.95.27:8100STT_KEY=...se o servico exigir o headerx-api-keySTT_LANG=portuguese
Observacao: o provider faz POST exatamente na URL configurada em STT_URL. Se o seu servico expuser uma rota especifica, use a URL completa, por exemplo http://10.152.95.27:8100/transcribe.
Para usar Azure Speech TTS com o plugin oficial do LiveKit, configure no .env.dev:
TTS_PROVIDER=azureAZURE_SPEECH_KEY=...AZURE_SPEECH_REGION=...ouAZURE_SPEECH_ENDPOINT=https://...cognitiveservices.azure.com/AZURE_SPEECH_VOICE=pt-BR-FranciscaNeuralAZURE_SPEECH_LANGUAGE=pt-BRAZURE_SPEECH_DEPLOYMENT_ID=...apenas para Custom Voice
Para usar xAI TTS, configure no .env.dev:
TTS_PROVIDER=xaiXAI_API_KEY=...XAI_WEBSOCKET_URL=https://cloud9.api.x.ai/v1/ttsXAI_TTS_READINESS_MODE=connectopcional para validar apenas o handshake do WebSocket; defaultsynthesizeXAI_TTS_VOICE=araopcionalXAI_TTS_LANGUAGE=pt-BRopcionalTTS_FRAME_GAP_TIMEOUT_S=2limite entre deltas de audio do xAI; quando estoura, o runtime registraFalha TTS, toca o audio de conforto e reenvia o texto
Para enviar logs estruturados ao Google Pub/Sub, configure:
GCP_PROJECT_ID=...AGENT_PUBSUB_TOPIC=agent-logsouprojects/.../topics/agent-logs
Se uma dessas variaveis nao existir, os eventos estruturados continuam indo apenas para o log local. O ambiente tambem precisa ter credenciais Google disponiveis via Application Default Credentials ou service account com permissao de publicacao no topico.
Para subir o fluxo local de voz:
make local-up
Depois abra http://127.0.0.1:8000/voice-client. O cliente web agora vem com remote_ws_fake, fake STT e fake TTS por padrao para smoke test local.
Para rodar o teste operacional com STT Sofya, TTS xAI, Bridge e LiveKit reais:
make local-stresstest
O alvo sobe o ambiente local se necessario, executa python -m app.tools.local_stresstest e gera os artefatos em .run/local-stresstest/:
report.md: resumo em Markdown com tabelas e diagramas Mermaidsummary.json: resultado estruturado completostt_results.csv,tts_results.csv,e2e_results.csv: planilhas dos cenariostimeline_excerpt.jsonl: eventos relevantes da timeline da chamada E2Ediagrams/*.svg: imagens estaticas dos fluxos, boas para preview no VSCodediagrams/*.mmd: fontes Mermaid dos fluxosstt_dumps/*.wavestt_dumps/*.pcm: audio efetivamente enviado ao STT- WAVs gerados para baseline, variacoes, TTS e audio recebido do Bridge
Por padrao, o alvo habilita dumps de audio do STT e logs de VAD do agent
(FLOW_LOG_VAD_DECISIONS=1, FLOW_LOG_VAD_ACTIVITY=1). O agent local e reiniciado
antes do teste para garantir que esses flags entrem no processo.
Se STRESS_AUDIO nao for informado, o runner gera um baseline sintetico com xAI TTS usando STRESS_SYNTH_TEXT, ou STRESS_EXPECTED_TEXT quando STRESS_SYNTH_TEXT nao for definido. Quando houver uma gravacao humana, rode:
STRESS_AUDIO=/caminho/audio_16k_mono.wav make local-stresstest
Variaveis uteis:
STRESS_EXPECTED_TEXT: frase esperada para calculo de WERSTRESS_SYNTH_TEXT: frase usada na sintese do baseline xAI TTS, default igual aSTRESS_EXPECTED_TEXTSTRESS_CRITICAL_TERMS: termos obrigatorios separados por virgulaSTRESS_WER_THRESHOLD: limite de WER, default0.20STRESS_REPEAT: repeticoes dos cenarios STT, default1; com os 25 cenarios atuais, gera 25 chamadas ao STT. UseSTRESS_REPEAT=2para 50 chamadasSTRESS_CONCURRENCY: concorrencia dos cenarios STT, default2STRESS_PREFIX_TEXT: prefixo que precisa aparecer no inicio da transcricao, default primeiras palavras deSTRESS_EXPECTED_TEXTSTRESS_PREFIX_WORDS: quantidade de palavras usadas no prefixo automatico, default2STRESS_VAD_PROXY_DBFS: limiar RMS usado na analise local de VAD proxy, default-45STRESS_VAD_PREFIX_PADDING_MS: padding usado na analise local de VAD proxy, default vem deVAD_PREFIX_PADDING_DURATIONSTRESS_VAD_MIN_SPEECH_MS: fala minima usada na analise local de VAD proxy, default100VAD_PREFIX_PADDING_DURATION: pre-roll do LiveKit VAD, default2.0segundosVAD_PREFIX_PADDING_MIN_DURATION: piso aplicado tambem sobre override decall_config, default2.0segundosSTT_INPUT_PREFIX_PADDING_MS: silencio curto adicionado antes do WAV enviado ao STT HTTP, default250STT_DUMP_DIR: diretorio dos WAV/PCM enviados ao STT, default.run/local-stresstest/stt_dumpsFLOW_LOG_VAD_DECISIONS: habilita logsvad_speech_start/vad_speech_end, default1no alvoFLOW_LOG_VAD_ACTIVITY: habilita logsvad_activity, default1no alvoSTRESS_RESTART_AGENT_FOR_DIAGNOSTICS: reinicia o agent antes do teste, default1STRESS_STARTUP_WAIT_S: tempo maximo para aguardar Bridge e agent runtime, default180STRESS_STARTUP_POLL_S: intervalo entre probes de prontidao, default3STRESS_SKIP_LOCAL_WAIT: use1para pular a espera inicialSTRESS_BRIDGE_HEALTH_URL: URL de health do Bridge, derivada deSTRESS_BRIDGE_URLpor padraoSTRESS_AGENT_HEALTH_URL: URL de health do agent runtime, defaulthttp://127.0.0.1:18081/STRESS_REPORT_DIR: diretorio de saida, default.run/local-stresstest
Comandos auxiliares do modo local:
make local-status
make local-logs
make bridge-logs
make agent-logs
make local-down
Se o agent falhar com worker process is not responding.. worker crashed? e o log mostrar erro de bind na porta 18081, existe um worker antigo preso nessa porta. Nesse caso, rode make agent-down e depois make agent-up ou make local-up novamente.
Kubernetes
A pasta k8s agora esta organizada em dois blocos:
k8s/livekit/Dockerfile: usa a imagem oficiallivekit/livekit-servercomo base para publicacao no registro privado da empresak8s/livekit/deployment.yaml: deployment e service do pod exclusivo do LiveKitk8s/tia/Dockerfile: mesma imagem da aplicacao Python da raiz do repo, mantida ao lado do manifest para facilitar pipeline de build/publicacaok8s/tia/deployment.yaml: deployment e service do podtia-app, com dois containers na mesma imagem:tia-bridgeetia-agent
Os dois Dockerfiles devem ser buildados a partir da raiz do repositorio, porque dependem do contexto raiz para copiar requirements.txt, src/ e livekit.yaml.
Exemplos:
docker build -f k8s/livekit/Dockerfile -t registry.example.com/tia/livekit:TAG .
docker build -f k8s/tia/Dockerfile -t registry.example.com/tia/app:TAG .
Depois do push para o registry privado, ajuste as imagens em k8s/livekit/deployment.yaml e k8s/tia/deployment.yaml ou substitua os placeholders via pipeline:
LIVEKIT_IMAGE_REPOSITORY:LIVEKIT_IMAGE_TAGTIA_IMAGE_REPOSITORY:TIA_IMAGE_TAG
Aplicacao dos manifests:
kubectl apply -f k8s/livekit/deployment.yaml
kubectl apply -f k8s/tia/deployment.yaml
Observacoes:
k8s/livekit/Dockerfileembute o arquivolivekit.yamldentro da imagem; se a configuracao do LiveKit mudar, a imagem precisa ser rebuildadak8s/tia/deployment.yamlainda usa envs inline de placeholder paraLIVEKIT_API_KEYeLIVEKIT_API_SECRET; o passo seguinte natural e migrar isso paraSecrete demais configs paraConfigMap- o
bridgeatende na porta8000e oagentexpõe a porta interna18081
Comandos uteis
make test
make agent
make bridge
make livekit
Todos os comandos assumem o codigo em src, portanto a raiz do projeto deve ser usada como diretorio de execucao.
Documentacao
docs/README.md: indice das docs do projetodocs/refactor-plan.md: plano do refactor incrementaldocs/refactor-log.md: registro das mudancas por etapadocs/api-overview.md: documentacao viva da API e do comportamento atual
Regional xAI TTS pool (Kubernetes)
Esta versão inclui uma arquitetura opcional para alta disponibilidade do TTS xAI com Pods TIA regionais, pool WebSocket pré-aquecido por Pod, readiness orientada a capacidade e failover via Service/Load Balancer.
Documentação:
docs/regional/ARQUITETURA_TIA_XAI_REGIONAL.mddocs/regional/DEPLOYMENT_TIA_XAI_REGIONAL.mddocs/regional/TESTES_TIA_XAI_REGIONAL.md
Código principal:
src/app/livekit/adapters/xai_pool_proxy.py
Manifests e scripts:
k8s/regional/scripts/render-regional-k8s.shscripts/validate-regional-k8s.shscripts/deploy-regional-k8s.sh
O modo antigo de conexão direta com xAI foi preservado. O deployment regional é opt-in.