# TIA Voice API Este repositorio contem a stack de voz-to-voz do projeto TIA. ## Estrutura - `src/app`: gateway WebSocket, runtime LiveKit, providers e utilitarios - `src/agent`: pipeline e estagios do agente - `tests`: testes automatizados - `docs`: documentacao viva do projeto - `k8s/livekit`: imagem e manifest do pod dedicado do LiveKit - `k8s/tia`: imagem e manifest do pod da aplicacao com `bridge` e `agent` - `requirements.txt`: dependencias Python da aplicacao - `livekit.yaml`: configuracao local do servidor LiveKit ## Setup local ```bash make setup ``` O alvo `make setup` faz o bootstrap do ambiente local: - cria `.venv` priorizando `python3.13`, `python3.12`, `python3.11`, `python3.10`, `python3.9`, `python3` e `python` - instala as dependencias de `requirements.txt` - cria `.env.dev` a partir de `.env.example` se 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: ```bash make BOOTSTRAP_PY=python3.12 setup ``` Se voce preferir fazer manualmente ou quiser depurar o bootstrap, use: ```bash 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 ```bash 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=fake` e `TTS_PROVIDER=fake` - integracao real: ajuste `AGENT_BACKEND`, `STT_PROVIDER`, `TTS_PROVIDER` e 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_http` - `STT_URL=http://10.152.95.27:8100` - `STT_KEY=...` se o servico exigir o header `x-api-key` - `STT_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=azure` - `AZURE_SPEECH_KEY=...` - `AZURE_SPEECH_REGION=...` ou `AZURE_SPEECH_ENDPOINT=https://...cognitiveservices.azure.com/` - `AZURE_SPEECH_VOICE=pt-BR-FranciscaNeural` - `AZURE_SPEECH_LANGUAGE=pt-BR` - `AZURE_SPEECH_DEPLOYMENT_ID=...` apenas para Custom Voice Para usar xAI TTS, configure no `.env.dev`: - `TTS_PROVIDER=xai` - `XAI_API_KEY=...` - `XAI_WEBSOCKET_URL=https://cloud9.api.x.ai/v1/tts` - `XAI_TTS_READINESS_MODE=connect` opcional para validar apenas o handshake do WebSocket; default `synthesize` - `XAI_TTS_VOICE=ara` opcional - `XAI_TTS_LANGUAGE=pt-BR` opcional - `TTS_FRAME_GAP_TIMEOUT_S=2` limite entre deltas de audio do xAI; quando estoura, o runtime registra `Falha 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-logs` ou `projects/.../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: ```bash 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: ```bash 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 Mermaid - `summary.json`: resultado estruturado completo - `stt_results.csv`, `tts_results.csv`, `e2e_results.csv`: planilhas dos cenarios - `timeline_excerpt.jsonl`: eventos relevantes da timeline da chamada E2E - `diagrams/*.svg`: imagens estaticas dos fluxos, boas para preview no VSCode - `diagrams/*.mmd`: fontes Mermaid dos fluxos - `stt_dumps/*.wav` e `stt_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: ```bash STRESS_AUDIO=/caminho/audio_16k_mono.wav make local-stresstest ``` Variaveis uteis: - `STRESS_EXPECTED_TEXT`: frase esperada para calculo de WER - `STRESS_SYNTH_TEXT`: frase usada na sintese do baseline xAI TTS, default igual a `STRESS_EXPECTED_TEXT` - `STRESS_CRITICAL_TERMS`: termos obrigatorios separados por virgula - `STRESS_WER_THRESHOLD`: limite de WER, default `0.20` - `STRESS_REPEAT`: repeticoes dos cenarios STT, default `1`; com os 25 cenarios atuais, gera 25 chamadas ao STT. Use `STRESS_REPEAT=2` para 50 chamadas - `STRESS_CONCURRENCY`: concorrencia dos cenarios STT, default `2` - `STRESS_PREFIX_TEXT`: prefixo que precisa aparecer no inicio da transcricao, default primeiras palavras de `STRESS_EXPECTED_TEXT` - `STRESS_PREFIX_WORDS`: quantidade de palavras usadas no prefixo automatico, default `2` - `STRESS_VAD_PROXY_DBFS`: limiar RMS usado na analise local de VAD proxy, default `-45` - `STRESS_VAD_PREFIX_PADDING_MS`: padding usado na analise local de VAD proxy, default vem de `VAD_PREFIX_PADDING_DURATION` - `STRESS_VAD_MIN_SPEECH_MS`: fala minima usada na analise local de VAD proxy, default `100` - `VAD_PREFIX_PADDING_DURATION`: pre-roll do LiveKit VAD, default `2.0` segundos - `VAD_PREFIX_PADDING_MIN_DURATION`: piso aplicado tambem sobre override de `call_config`, default `2.0` segundos - `STT_INPUT_PREFIX_PADDING_MS`: silencio curto adicionado antes do WAV enviado ao STT HTTP, default `250` - `STT_DUMP_DIR`: diretorio dos WAV/PCM enviados ao STT, default `.run/local-stresstest/stt_dumps` - `FLOW_LOG_VAD_DECISIONS`: habilita logs `vad_speech_start`/`vad_speech_end`, default `1` no alvo - `FLOW_LOG_VAD_ACTIVITY`: habilita logs `vad_activity`, default `1` no alvo - `STRESS_RESTART_AGENT_FOR_DIAGNOSTICS`: reinicia o agent antes do teste, default `1` - `STRESS_STARTUP_WAIT_S`: tempo maximo para aguardar Bridge e agent runtime, default `180` - `STRESS_STARTUP_POLL_S`: intervalo entre probes de prontidao, default `3` - `STRESS_SKIP_LOCAL_WAIT`: use `1` para pular a espera inicial - `STRESS_BRIDGE_HEALTH_URL`: URL de health do Bridge, derivada de `STRESS_BRIDGE_URL` por padrao - `STRESS_AGENT_HEALTH_URL`: URL de health do agent runtime, default `http://127.0.0.1:18081/` - `STRESS_REPORT_DIR`: diretorio de saida, default `.run/local-stresstest` Comandos auxiliares do modo local: ```bash 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 oficial `livekit/livekit-server` como base para publicacao no registro privado da empresa - `k8s/livekit/deployment.yaml`: deployment e service do pod exclusivo do LiveKit - `k8s/tia/Dockerfile`: mesma imagem da aplicacao Python da raiz do repo, mantida ao lado do manifest para facilitar pipeline de build/publicacao - `k8s/tia/deployment.yaml`: deployment e service do pod `tia-app`, com dois containers na mesma imagem: `tia-bridge` e `tia-agent` Os dois `Dockerfile`s devem ser buildados a partir da raiz do repositorio, porque dependem do contexto raiz para copiar `requirements.txt`, `src/` e `livekit.yaml`. Exemplos: ```bash 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_TAG` - `TIA_IMAGE_REPOSITORY:TIA_IMAGE_TAG` Aplicacao dos manifests: ```bash kubectl apply -f k8s/livekit/deployment.yaml kubectl apply -f k8s/tia/deployment.yaml ``` Observacoes: - `k8s/livekit/Dockerfile` embute o arquivo `livekit.yaml` dentro da imagem; se a configuracao do LiveKit mudar, a imagem precisa ser rebuildada - `k8s/tia/deployment.yaml` ainda usa envs inline de placeholder para `LIVEKIT_API_KEY` e `LIVEKIT_API_SECRET`; o passo seguinte natural e migrar isso para `Secret` e demais configs para `ConfigMap` - o `bridge` atende na porta `8000` e o `agent` expõe a porta interna `18081` ## Comandos uteis ```bash 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 projeto - `docs/refactor-plan.md`: plano do refactor incremental - `docs/refactor-log.md`: registro das mudancas por etapa - `docs/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.md` - `docs/regional/DEPLOYMENT_TIA_XAI_REGIONAL.md` - `docs/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.sh` - `scripts/validate-regional-k8s.sh` - `scripts/deploy-regional-k8s.sh` O modo antigo de conexão direta com xAI foi preservado. O deployment regional é opt-in.