A configurable proxy server that translates PAI voice notifications and forwards them to any TTS service. Sits on port 8888 where PAI hooks already send notifications — zero upstream PAI files modified.
PAI hooks/agents --> localhost:8888 --> Voice Proxy --> Your TTS service
(unchanged) (this repo) (external)
PAI's voice system sends notifications via HTTP to localhost:8888. The original VoiceServer uses ElevenLabs for TTS. This proxy replaces it with a translation layer that can forward to any TTS service — your own API, a webhook, Home Assistant, or anything that accepts HTTP POST.
- Drop-in replacement — occupies port 8888, no PAI code changes needed
- Three translation modes —
default(message + language + source),mapped(custom field mappings),passthrough(forward as-is) - Language support — BCP 47 codes with per-message override via payload or query param
- Hot-reload config — change settings without restarting (
POST /config/reload) - Always-200 to callers — TTS failures never break PAI's Algorithm pipeline
- Structured logging — JSONL log of every forward for debugging
- Rate limiting — 10 req/60s per IP (matches original VoiceServer)
- Server switching — toggle between proxy and original VoiceServer with one command
Requirements: Bun runtime
# 1. Clone
git clone https://github.com/YOUR_USER/voiceproxy.git
cd voiceproxy
# 2. Configure
cp proxy-config.example.json proxy-config.json
# Edit proxy-config.json with your TTS service URL
# 3. Start
bash start-proxy.sh
# 4. Test
curl http://localhost:8888/health
curl -X POST http://localhost:8888/notify \
-H 'Content-Type: application/json' \
-d '{"message": "Hello from PAI"}'Copy proxy-config.example.json to proxy-config.json and edit:
{
"target_url": "https://your-tts-service.example.com/api/webhook/TOKEN",
"target_method": "POST",
"target_headers": {},
"default_language": "en-US",
"default_source": "PAI",
"mode": "default",
"timeout_ms": 10000,
"local_logging": true,
"port": 8888
}default — Standard preset, sends { message, language, source }:
{ "message": "Entering the Observe phase", "language": "en-US", "source": "PAI" }mapped — Custom field mappings with transforms (passthrough, static values, templates). See proxy-config.example.json for syntax.
passthrough — Forwards the raw PAI payload unchanged.
Priority: query param (?language=fi-FI) > payload field > config default.
| Method | Path | Description |
|---|---|---|
| POST | /notify |
Forward notification to TTS |
| POST | /pai |
Alias for /notify |
| POST | /notify/personality |
Alias for /notify |
| GET | /health |
Server status and stats |
| GET | /config |
Current config (secrets redacted) |
| POST | /config/reload |
Hot-reload config from disk |
| Script | Description |
|---|---|
start-proxy.sh |
Start server (kills existing port 8888 process) |
stop-proxy.sh |
Stop server gracefully |
switch-server.sh proxy|original |
Toggle between proxy and original VoiceServer |
- USAGE.md — Detailed usage guide
- ARCHITECTURE.md — Technical architecture, design decisions, and diagrams
PAI hooks emit curl -s -X POST http://localhost:8888/notify at each Algorithm phase transition. The proxy receives these, translates the payload to your TTS format, and forwards. If your TTS is down, the proxy still returns 200 so the Algorithm continues uninterrupted.
MIT
