diff --git a/README.md b/README.md new file mode 100644 index 0000000..e4ab966 --- /dev/null +++ b/README.md @@ -0,0 +1,274 @@ +# Nanobot Voice Interface + +Local-first web UI for Nanobot with: + +- WebRTC voice input and streamed audio output +- text chat and agent state/log display +- live cards rendered from HTML templates +- manual tool calls from cards through the Nanobot API socket + +This repo is currently designed for a single-user, local workstation setup. + +## What This Repo Contains + +- `app.py`: FastAPI backend that serves the frontend, card HTML, and bridge endpoints +- `frontend/`: Preact + TypeScript app built with Vite +- `voice_rtc.py`: WebRTC voice session handling +- `supertonic_gateway.py`: bridge between the web app and Nanobot +- `start.sh`: local startup script that installs Python deps, builds the frontend, and launches `uvicorn` +- `examples/cards/`: checked-in snapshots of example card templates and saved card instances + +## How It Fits Together + +The app has three main pieces: + +1. Browser UI + - connects to the backend over HTTPS + - establishes a WebRTC session for audio + data channel events + - renders persisted cards and runs their inline template scripts + +2. Web backend + - serves the built frontend from `frontend/dist` + - exposes `/rtc/offer`, `/message`, `/cards`, `/tools`, `/tools/call`, and `/tools/jobs/{id}` + - materializes card templates from the Nanobot workspace card directory + +3. Nanobot runtime + - runs separately in the Nanobot repo + - exposes the Unix socket API used by this UI + - provides `message.send`, `command.execute`, `tool.list`, and `tool.call` + +Cards do not talk to Nanobot directly. They call browser helpers such as `window.__nanobotCallTool(...)`, which hit the web backend, which then forwards requests to the Nanobot API socket. + +## Current Runtime Assumptions + +This repo currently assumes: + +- single user +- local-only usage +- trusted local card templates +- a separately running Nanobot instance on the same machine + +If you expose this service beyond loopback, the trust model changes materially. + +## Prerequisites + +### Required + +- `python3` +- `uv` +- `openssl` +- `bun` or `npm` for the frontend build +- Nanobot checked out locally and runnable + +### Runtime dependencies outside this repo + +- Nanobot gateway/API from the Nanobot repo +- local Nanobot config under `~/.nanobot/config.json` +- optional voice env overrides in `.env.voice` + +## Quick Start + +### 1. Install frontend dependencies + +From `frontend/`: + +```bash +bun install +``` + +This also installs the versioned git hooks via `postinstall`. + +### 2. Make sure Nanobot is running + +This UI expects Nanobot to be running separately. In the Nanobot repo, the local combined branch setup currently uses: + +```bash +python -m nanobot gateway +``` + +The web app talks to the Nanobot Unix socket under `~/.nanobot/api.sock`. + +### 3. Start the web UI + +From this repo: + +```bash +./start.sh +``` + +What `start.sh` does: + +- creates `.venv/` if missing +- installs `requirements.txt` +- builds the frontend bundle by default +- sources `.env.voice` if present +- generates a local TLS certificate if missing +- starts `uvicorn` + +Default URL: + +```text +https://localhost:8000 +``` + +## Important Environment Variables + +### Web server + +- `UVICORN_HOST` +- `UVICORN_PORT` +- `ENABLE_HTTPS` +- `SSL_CERT_FILE` +- `SSL_KEY_FILE` +- `FRONTEND_BUILD_ON_START` + +### Nanobot bridge + +- `NANOBOT_WORKDIR` +- `NANOBOT_COMMAND` +- `NANOBOT_SUPPRESS_NOISY_UI` +- `NANOBOT_OUTPUT_DEDUP_WINDOW_S` + +### Voice pipeline + +Configured through `.env.voice` and defaults in `start.sh`, including: + +- STT provider/model/device settings +- TTS provider/model/voice settings +- push-to-talk timing +- RTC outbound buffering settings + +Read [start.sh](/home/kacper/nanobot-supertonic-wisper-web/start.sh) for the exact supported variables. + +## Frontend Commands + +Run from `frontend/`: + +```bash +bun install +bun run dev +bun run check +bun run build +bunx knip +``` + +Meaning: + +- `dev`: Vite dev server +- `check`: Biome check, warning-failing +- `build`: `tsc && vite build` +- `knip`: dead-code scan + +## Backend Checks + +Run from the repo root: + +```bash +./scripts/check_python_quality.sh +``` + +That runs: + +- Ruff format check +- Ruff lint +- Deptry +- Vulture + +## Frontend Checks + +Run from the repo root: + +```bash +./scripts/check_frontend_quality.sh +``` + +That runs: + +- `bun run check` +- `bun run build` + +## Git Hooks + +Versioned hooks live in `.githooks/`. + +They are installed by: + +```bash +bun install +``` + +or manually: + +```bash +./scripts/install_git_hooks.sh +``` + +The pre-commit hook runs: + +- backend Python quality checks for staged backend changes +- frontend checks for staged frontend changes + +## CI + +Forgejo Actions config lives at: + +- [ci.yml](/home/kacper/nanobot-supertonic-wisper-web/.forgejo/workflows/ci.yml) + +Pushes and pull requests run the same check scripts used locally. + +## Cards + +The running application loads cards from the Nanobot workspace, not from this repo: + +- templates: `~/.nanobot/cards/templates//template.html` +- template metadata: `~/.nanobot/cards/templates//manifest.json` +- instances: `~/.nanobot/cards/instances//card.json` +- per-instance state: `~/.nanobot/cards/instances//state.json` + +The backend materializes card HTML by reading the template from disk and injecting the instance `template_state` into a hidden JSON script tag. + +### Example snapshots + +Checked-in snapshots live under: + +- [examples/cards](/home/kacper/nanobot-supertonic-wisper-web/examples/cards) + +These are for reference and iteration. They are not the live source of truth used at runtime. + +## Manual Tool Calls From Cards + +Cards can call Nanobot tools through the browser helper layer: + +- `window.__nanobotListTools()` +- `window.__nanobotCallTool(name, args)` +- `window.__nanobotCallToolAsync(name, args, options)` + +Those map to: + +- `GET /tools` +- `POST /tools/call` +- `GET /tools/jobs/{job_id}` + +The backend forwards those requests to the Nanobot API socket. + +## WebRTC Notes + +The connection path is optimized for local-only operation: + +- no public STUN server by default +- short ICE gather waits on both frontend and backend +- HTTPS is enabled by default so browser media and WebRTC work consistently + +If you need external ICE servers later, you can add a frontend STUN URL with: + +- `VITE_WEBRTC_STUN_URL` + +## Repo Status + +This repo is usable for local single-user workflows, but it is still opinionated and local-environment-dependent: + +- card data lives outside the repo in `~/.nanobot/cards` +- Nanobot is a separate repo/runtime dependency +- some startup behavior still depends on local config and local MCP servers + +For now, treat this as a local application repo rather than a portable hosted product.