README: document Plan 3 Pi client surface

This commit is contained in:
2026-06-11 22:56:34 +00:00
parent 8662dbe8a7
commit 82ea164695
+70 -3
View File
@@ -137,10 +137,77 @@ PY
Don't send `wake` from the smoke — it would open a real OpenAI session and Don't send `wake` from the smoke — it would open a real OpenAI session and
burn budget. Plan 3 exercises that end-to-end. burn budget. Plan 3 exercises that end-to-end.
## Plan 3: Pi client
The Python client lives in `client/`. It is shipped to the Pi inside
`client.tar.gz` (built into the backend Docker image) and installed by
`install.sh`. Modules:
- `main.py` — entry point. Sets `PA_ALSA_PLUGHW=1` before importing
sounddevice. Wires audio, state, wakeword, session, and playback.
- `state.py` — `IDLE → WAKE_PENDING → LISTENING ↔ ASSISTANT_SPEAKING →
IDLE_PENDING → IDLE`. `wakeword_enabled` is true only in `IDLE`;
`uplink_enabled` is true only in `LISTENING`.
- `audio.py` — USB device discovery, persistent 24 kHz/mono/int16 InputStream
and OutputStream, and the 24 → 16 kHz resample for the wakeword feed.
- `wakeword.py` — openwakeword `alexa` model, threshold + cooldown.
- `playback.py` — single worker thread that owns the OutputStream and
implements `set_volume` as a software gain (the USB Speaker Phone has no
hardware playback volume control; only a `PCM Playback Switch`).
- `session.py` — backend WS client, dispatch, tool round-trip,
exponential-backoff reconnect.
- `config.py` — `~/assistant/state/config.json` (mode 0600).
- `pair.py` — `python -m client.pair --backend <url> [--code <code>]`.
### Updating the Pi
For a fast iteration loop:
```sh
sshpass -p 'assistant' rsync -az --delete --exclude __pycache__ --exclude tests \
client/ pi@192.168.50.115:assistant/code/client/
sshpass -p 'assistant' ssh pi@192.168.50.115 'systemctl --user restart assistant'
sshpass -p 'assistant' ssh pi@192.168.50.115 \
'journalctl --user -u assistant -n 50 --no-pager'
```
For a production update (after a backend deploy):
```sh
sshpass -p 'assistant' ssh pi@192.168.50.115 \
'curl -fsSL https://assistant.volcanic.tes.gd/install.sh | bash'
```
### Local tests
```sh
python3 -m venv .venv
.venv/bin/pip install -r requirements-dev.txt requests websockets numpy scipy
.venv/bin/python -m pytest client/tests
```
Hardware-touching modules (`audio.py` streams, `wakeword.py`, `playback.py`,
`session.run_forever`) are smoke-tested via the live deploy. Deterministic
modules (`state.py`, `config.py`, `pair.py`, the resample helper, the session
dispatcher) are covered by the pytest suite.
### End-to-end smoke
With the unit running on the Pi:
```sh
sshpass -p 'assistant' ssh pi@192.168.50.115 'journalctl --user -u assistant -f'
```
…then say `alexa` near the Speaker Phone. Expected log sequence: `wakeword
fired`, `state IDLE -> WAKE_PENDING`, `session_started conversation_id=…`,
`state WAKE_PENDING -> LISTENING`. Speak a question; the assistant replies
through the speaker (`state LISTENING -> ASSISTANT_SPEAKING`, then
`assistant_done`). Say "bye" → `session_ended reason=tool`, then `state
LISTENING -> IDLE_PENDING -> IDLE`. The conversation row + turns are visible
via the deployed backend's DB (admin UI in Plan 4).
## What's next ## What's next
- **Plan 3** — full Python client on the Pi (wakeword, VAD, audio plumbing,
state machine, install + pair CLIs). This is the production caller of
`/device` and the integration test for everything above.
- **Plan 4** — React management UI for the admin dashboard, per-device - **Plan 4** — React management UI for the admin dashboard, per-device
config editor, and conversation history viewer. config editor, and conversation history viewer.