BREAKING CHANGE: NODE_RED reasoning is no longer supported. Unsupported mode values fall back to PROXY. PROXY and OPENAI remain available.
162 lines
8.6 KiB
Markdown
162 lines
8.6 KiB
Markdown
# Vocero React frontend
|
|
|
|
React 19, TypeScript, Tailwind CSS 4, and Vite 8 client for the existing
|
|
`s2s-client` FastAPI backend. This is a client-side application with React-owned
|
|
rendering and state, including the realtime WebSocket and audio integration.
|
|
|
|
## Run during development
|
|
|
|
From the repository root, run `./start_ui.sh`. Open `http://localhost:8420`.
|
|
Add `?debug=true` to access settings, tools, and custom RAG context. Existing
|
|
`phoneNumber` and `episode_id` query parameters are supported.
|
|
|
|
The launcher requires Python 3 with venv support, Node.js 22.18 or later on the
|
|
22.x line or Node.js 24+, npm, Bash 4.4+, `setsid` (util-linux), and `curl`.
|
|
It creates `.venv` and installs missing Python dependencies. It runs
|
|
`npm ci --include=dev` on first start and when either frontend package manifest
|
|
changes. Subsequent restarts reuse the installed dependencies.
|
|
|
|
| Server | Default address | Purpose |
|
|
| ------- | ---------------- | ---------------------------------------------- |
|
|
| Vite | `0.0.0.0:8420` | Public React UI, backend proxy, and hot reload |
|
|
| FastAPI | `127.0.0.1:8421` | Internal HTTP APIs and speech WebSocket relay |
|
|
|
|
`UI_PORT` preserves the existing public port override. `UI_HOST` defaults to
|
|
`0.0.0.0`; `S2S_BACKEND_PORT` changes the loopback backend port. The two ports
|
|
must differ. Occupied ports fail startup rather than silently selecting a new
|
|
endpoint. The launcher waits for FastAPI before starting Vite, stops both
|
|
process groups on Ctrl+C/SIGTERM, and exits with a failure if either server exits.
|
|
Uvicorn watches only `s2s-client`, avoiding frontend and dependency directories.
|
|
The Vite child explicitly uses `NODE_ENV=development`, including when a process
|
|
manager sets `NODE_ENV=production`, so React Fast Refresh remains enabled.
|
|
|
|
Vite serves React and Tailwind with hot updates. It proxies `/api`,
|
|
`/v1/realtime` (including WebSockets), and backend documentation routes
|
|
to FastAPI. The browser uses one origin on port `8420`, so there is no separate
|
|
API origin or development CORS setup. The proxy preserves the incoming Host
|
|
header because FastAPI uses it to construct the speech WebSocket URL.
|
|
|
|
Runtime UI flags, voices, reasoning mode, prompts, and the speech URL still come from FastAPI's
|
|
`/api/config`. A backend explicitly configured with `SPEECH_TO_SPEECH_URL`
|
|
continues to return that direct speech endpoint.
|
|
|
|
The launcher sources the root `.env`, retaining its precedence over shell
|
|
variables. The Vite configuration reads this project's environment files and
|
|
the inherited `S2S_*` settings. Do not copy the repository's backend secrets
|
|
into this directory or into `VITE_*`
|
|
variables, which are exposed to browser code.
|
|
|
|
## Staging with hot reload
|
|
|
|
PM2 can continue running the root `start_ui.sh` as its existing `s2s_ui` process.
|
|
Ensure the Node/npm versions above are on PM2's PATH and deploy `s2s-frontend`
|
|
alongside `s2s-client` and `docs`. The reverse proxy still targets port `8420`.
|
|
|
|
Set the exact public hostname in the root `.env`, without scheme or port:
|
|
|
|
```dotenv
|
|
S2S_DEV_ALLOWED_HOSTS=voice-staging.example.com
|
|
```
|
|
|
|
Replace the example with the existing staging hostname; use commas for multiple
|
|
hosts. IP addresses and localhost are accepted without this setting.
|
|
The HTTPS reverse proxy must preserve `Host`, `X-Forwarded-Host` and
|
|
`X-Forwarded-Proto`, and forward WebSocket upgrades for `/v1/realtime` and
|
|
`/__vite_hmr`. HMR uses the browser's public origin, including HTTPS/WSS, so no
|
|
second public port is needed. The browser needs HTTPS for microphone access
|
|
outside localhost. Restart `s2s_ui` after changing launcher or environment
|
|
settings; source edits use the reloaders. The speech service remains separately
|
|
managed.
|
|
|
|
## Run the servers separately
|
|
|
|
Start FastAPI on `127.0.0.1:8421` as described in the
|
|
[client usage guide](../docs/client/usage.md), then run:
|
|
|
|
```sh
|
|
cd s2s-frontend
|
|
npm ci
|
|
npm run dev
|
|
```
|
|
|
|
Standalone Vite binds `127.0.0.1:8420`; add `-- --host 0.0.0.0` for remote
|
|
access. For a different backend, copy `.env.example` to `.env.local` and set
|
|
`S2S_BACKEND_URL`. The combined launcher overrides that setting to point at the
|
|
backend it starts. Do not start standalone Vite while the combined launcher
|
|
already owns the public port.
|
|
|
|
Component and CSS changes use Fast Refresh. Editing the session controller or
|
|
audio modules can require restarting a conversation or a page reload. Teardown
|
|
closes microphone tracks, worklets, sockets, queue tickets, timers, and pending
|
|
requests on session stop or page exit.
|
|
|
|
## Checks and commands
|
|
|
|
The scripts and code style follow `frontend-admin` conventions, with Vite and
|
|
React plugins replacing Next.js-specific tooling. Executable configuration
|
|
files use TypeScript; TypeScript's own project settings use JSON.
|
|
|
|
| Command | Purpose |
|
|
| ----------------------- | ----------------------------------------------------------- |
|
|
| `npm run dev` | Vite development server on port 8420, with a fixed port |
|
|
| `npm run check` | Formatting, strict typed ESLint, type checking, and tests |
|
|
| `npm run lint:fix` | Apply ESLint fixes |
|
|
| `npm run format` | Format source and sort Tailwind classes |
|
|
| `npm run typecheck` | Check application, tests, audio worklets, and configuration |
|
|
| `npm test` | Run Vitest and React Testing Library regression tests |
|
|
| `npm run test:watch` | Watch tests while editing |
|
|
| `npm run test:launcher` | Test launcher supervision and signal handling on Linux |
|
|
| `npm run build` | Typecheck and compile the app and worklets into `dist/` |
|
|
| `npm run preview` | Inspect the compiled output locally |
|
|
|
|
No build step is needed before `npm run dev`. `dist/` is generated and ignored
|
|
by Git. The launcher serves source through Vite; it does not use `dist/` or
|
|
`vite preview`.
|
|
|
|
Tests cover session initialization, response sequencing, cumulative transcripts,
|
|
interruptions, queue polling, admission deadlines, cancellation, microphone-permission cancellation, tool
|
|
results, external reasoning, late-response cleanup, the idle
|
|
timeout, settings, RAG, profiles, and sanitized Markdown/export behavior.
|
|
Launcher tests start temporary local children to check readiness, environment
|
|
forwarding, failures, and shutdown of complete process groups.
|
|
Vitest handles Node 26's experimental web storage behavior internally.
|
|
|
|
## Source layout
|
|
|
|
- `src/components/`: voice controls, chat, dialogs, and caller profile views.
|
|
- `src/realtime/`: session lifecycle, observable application state, queue
|
|
handling, WebSocket protocol, tools, and external reasoning.
|
|
- `src/audio/`: TypeScript capture/playback worklets, audio graph, PCM codec,
|
|
and visualizer. Vite emits the worklets as separate JavaScript assets.
|
|
- `src/lib/`: validated backend contracts, settings, prompt context, profile
|
|
and report presentation, Markdown sanitization, and conversation exports.
|
|
- `config/backend-proxy.ts`: the shared HTTP/WebSocket development proxy.
|
|
- `src/styles.css`: Tailwind integration and React-specific layout adjustments.
|
|
- `src/styles/legacy-theme.css`: the existing visual styles, retained for
|
|
fidelity to both the white microphone and dark orb themes. The UI is ported
|
|
to React; the full design has not been rewritten as Tailwind utilities.
|
|
|
|
The current Spanish interface, local preference keys, session-only RAG,
|
|
Markdown replies, JSON/TXT exports, optional browser wake word, TALK/TALKFIRST
|
|
startup modes, and optional backend features are retained. Camera controls and
|
|
quick actions remain absent, matching their disabled state in the old UI.
|
|
|
|
Native speech stays at the current project's 16 kHz PCM rate. The backend
|
|
continues to own VAD, transcription, model inference, synthesis, upstream
|
|
credentials, and ApiPilot execution. Browser `SpeechSynthesis` is used only
|
|
when the configured external reasoning service returns an answer.
|
|
|
|
Session startup waits for audio initialization and `session.created`, then sends
|
|
`session.update` before microphone audio or the initial greeting. The speech
|
|
server processes those frames in order and does not emit `session.updated` on
|
|
success. That acknowledgment is therefore optional; receiving it later does not
|
|
restart the greeting or reset an active response. The startup timeout still
|
|
closes the microphone and socket if the server never creates a session.
|
|
|
|
## References
|
|
|
|
- [Vite getting started](https://vite.dev/guide/)
|
|
- [Vite server and proxy options](https://vite.dev/config/server-options)
|
|
- [Vite features and asset handling](https://vite.dev/guide/features)
|
|
- [Tailwind's Vite integration](https://tailwindcss.com/docs/installation/using-vite)
|