first commit
This commit is contained in:
253
README.md
Normal file
253
README.md
Normal file
@@ -0,0 +1,253 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user