Snapshot: full project state

This commit is contained in:
2026-10-06 23:43:30 -07:00
commit 9991a836fe
15 changed files with 1642 additions and 0 deletions

66
README.md Normal file
View File

@@ -0,0 +1,66 @@
# The Collector
A smooth-operator conversational voice AI running on drjones' homelab. Lives on
Proxmox LXC **CT 771** @ `10.30.20.172:8766`.
## What it is
A latency-optimized voice assistant. It listens, responds naturally through a
local LLM, speaks with a natural voice, and can make outbound phone calls on
request.
## Pipeline (latency budget)
| Stage | Engine | Latency |
|-------|--------|---------|
| STT | faster-whisper `small.en` (GPU, nightmare `.29:8770`) | ~0.35s / utterance |
| LLM | `ornith-1.5:9b-64k` @ nightmare `.29:11434` (fallback `.222`) | ~600ms first token, streamed |
| TTS | Piper `lessac-high` (CPU, 22.05k → 16k) | ~400ms / sentence, overlapped w/ LLM |
Sentence-level TTS/LLM overlap: audio starts flowing after the first sentence
completes while the model keeps generating. Server-side energy VAD with barge-in.
## Interfaces
- **Browser voice** — `GET /` (WebSocket `/ws`, PCM16 16 kHz full-duplex)
- **Phone** — SignalWire (outbound via `POST /api/call {to, task}`; inbound stays
on JONES's number for now). Media stream `/signalwire/stream` (mulaw 8 kHz).
- **Text** — `POST /api/text {text}`
- **Health** — `GET /api/health`
## Public URL
Cloudflare quick tunnel (ephemeral): `https://placed-ivory-unto-effective.trycloudflare.com`
Self-registers via `POST /api/config {public_base_url}` (systemd `collector-tunnel.service`).
## Key decisions
- **LLM lane = nightmare `.29`, not `.222`**: `.222` holds ornith resident but is
saturated by ~92 cron jobs + Kalshi bots and hangs on `/api/chat`; `.29` answers
in ~1s. `keep_alive:30m` keeps ornith warm there.
- **STT on GPU (nightmare), not the CT CPU**: whisper on the CT's 2 cores was 7-8s
(the real latency killer); `faster-whisper` on nightmare's 4080S
(`collector-stt.service` @ `:8770`, CUDA) is ~0.35s — 20×. TTS stays on CPU (Piper
~400ms, not the bottleneck).
- **Phone** reuses the SignalWire account + number (`+1 254 513 9895`) JONES uses;
outbound TwiML points at this app's tunnel.
## Files
```
/opt/collector/
app.py self-contained FastAPI app (STT/TTS/LLM/phone)
config.yaml model lane, TTS voice, SignalWire creds, persona
selftest.py Piper→whisper round-trip self-test
static/index.html browser voice UI (AudioWorklet)
tunnel.sh cloudflared quick tunnel + self-registration
collector.service systemd unit (app)
collector-tunnel.service systemd unit (tunnel)
```
## Ops
```bash
# restart
ssh root@10.30.20.85 "pct exec 771 -- systemctl restart collector"
# logs
ssh root@10.30.20.85 "pct exec 771 -- journalctl -u collector -n 30"
# self-test the audio pipeline
ssh root@10.30.20.85 "pct exec 771 -- python3 /opt/collector/selftest.py"
# make a phone call
curl -s -X POST http://10.30.20.172:8766/api/call \
-H 'Content-Type: application/json' -d '{"to":"+1XXXXXXXXXX","task":"..."}'
```