refactor(ui): delete legacy static website and refresh documentation
This commit is contained in:
@@ -42,17 +42,15 @@ audio. It is not an unconditional byte-for-byte tunnel.
|
||||
|
||||
| Source | Responsibility |
|
||||
|---|---|
|
||||
| [server.py](../../s2s-client/server.py) | Configuration, static serving, WebSocket relay, context loading, ApiPilot, reasoning, search, queue and usage routes |
|
||||
| [server.py](../../s2s-client/server.py) | Configuration, documentation serving, WebSocket relay, context loading, ApiPilot, reasoning, search and queue routes |
|
||||
| [start_ui.sh](../../start_ui.sh) | Dependency setup, ports, readiness, reload processes, and shutdown |
|
||||
| [vite.config.ts](../../s2s-frontend/vite.config.ts) | Public development endpoint, HMR, allowed hosts, and backend routing |
|
||||
| [App.tsx](../../s2s-frontend/src/App.tsx) | React layout, voice controls, dialogs, profile and reports sidebar |
|
||||
| [controller.ts](../../s2s-frontend/src/realtime/controller.ts) | Application state, settings, context, queue, tools and external reasoning |
|
||||
| [client.ts](../../s2s-frontend/src/realtime/client.ts) | Realtime protocol, session lifecycle, audio and transcript events |
|
||||
| [components](../../s2s-frontend/src/components) | Chat, account, settings and voice components |
|
||||
| [components](../../s2s-frontend/src/components) | Chat, caller profile, settings and voice components |
|
||||
| [audio](../../s2s-frontend/src/audio) | TypeScript capture/playback worklets, PCM codec, and visualizer |
|
||||
| [legacy-theme.css](../../s2s-frontend/src/styles/legacy-theme.css) | Retained themes and responsive visual styles alongside Tailwind |
|
||||
| [auth.py](../../s2s-client/auth.py) | Hugging Face OAuth and caller identity/tier |
|
||||
| [limiter.py](../../s2s-client/limiter.py) | SQLite daily talk-time reservations and reconciliation |
|
||||
| [flows.json](../../s2s-reasoning-engine/flows.json) | Node-RED reasoning and assistant-response logging |
|
||||
|
||||
## Server routes
|
||||
@@ -68,15 +66,14 @@ audio. It is not an unconditional byte-for-byte tunnel.
|
||||
| `POST /api/apipilot/execute` | Validated tool execution returning a `success/data/error` envelope |
|
||||
| `POST /api/search` | Serper web search proxy |
|
||||
| `/api/session`, `/api/queue/*` | Load-balancer session and waiting-queue proxies |
|
||||
| `/api/me`, `/api/session/heartbeat`, `/api/session/end` | Identity, reservation extension and usage reconciliation |
|
||||
|
||||
The public root serves the React UI. `/__vite_hmr` carries Vite hot updates;
|
||||
`/v1/realtime` remains the speech connection. `/docs` remains the FastAPI API
|
||||
explorer, while project documentation files are served in the `/docs/`
|
||||
subdirectories. Markdown remains
|
||||
source text, and directories without `index.html` are not browsable pages.
|
||||
The existing static client remains in `s2s-client` for direct FastAPI and Docker
|
||||
usage; its static responses retain the existing no-cache headers.
|
||||
FastAPI serves backend and documentation routes only. The frontend source and
|
||||
assets live in `s2s-frontend` and are served by Vite.
|
||||
|
||||
## Audio path
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
Context reaches the assistant through browser-built instructions, server-patched
|
||||
realtime session instructions, and HTTP reasoning context. The implementation is
|
||||
in [server.py](../../s2s-client/server.py),
|
||||
[main.js](../../s2s-client/main.js), and the
|
||||
[WebSocket client](../../s2s-client/ws/s2s-ws-client.js).
|
||||
[context.ts](../../s2s-frontend/src/lib/context.ts), and the
|
||||
[WebSocket client](../../s2s-frontend/src/realtime/client.ts).
|
||||
|
||||
## Independent controls
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Design language
|
||||
|
||||
This guide describes the current browser UI. Use
|
||||
[style.css](../../s2s-client/style.css) as the token/selector reference and
|
||||
[index.html](../../s2s-client/index.html) for the theme-specific structure.
|
||||
[legacy-theme.css](../../s2s-frontend/src/styles/legacy-theme.css) as the token/selector
|
||||
reference and [App.tsx](../../s2s-frontend/src/App.tsx) for the theme-specific structure.
|
||||
Earlier documentation described a monochrome-only dark UI; the current design
|
||||
also uses aurora gradients, glass surfaces, and a separate light theme.
|
||||
|
||||
@@ -36,7 +36,7 @@ selector overrides rather than a second stylesheet.
|
||||
| Listening/user speaking | Cyan (`--listening`) |
|
||||
| Assistant speaking | Violet (`--speaking`) |
|
||||
| Processing | Amber (`--processing`) |
|
||||
| Ready/authenticated | Green (`--success`) |
|
||||
| Ready/success | Green (`--success`) |
|
||||
| Error | Red (`--error`) |
|
||||
|
||||
`--voice-user`, `--voice-assistant` and `--voice-tool` connect transcript roles
|
||||
|
||||
@@ -34,7 +34,7 @@ names shown in a deployment are configuration examples, not definitions.
|
||||
| Queue | Users waiting for an available compute slot; waiting is not yet an active conversation |
|
||||
| Ticket | A held queue position returned by the load balancer |
|
||||
| Position | The displayed place in the queue; distinct from a time estimate |
|
||||
| Claim | The transition from a waiting ticket to an allocated realtime session and usage reservation |
|
||||
| Claim | The transition from a waiting ticket to an allocated realtime session |
|
||||
| At capacity | A full waiting queue that cannot accept another ticket |
|
||||
| Barge-in | User speech interrupts an active assistant response, coordinating playback clearing and backend cancellation |
|
||||
| Log-only reasoning | External transcript processing that observes/logs the turn without replacing native speech output |
|
||||
|
||||
+10
-11
@@ -15,15 +15,15 @@ The mode is normalized case-insensitively. `NODERED` and `NODE-RED` resolve to
|
||||
|
||||
## Shared instruction assembly
|
||||
|
||||
In [main.js](../../s2s-client/main.js), `effectiveReasoningInstructions()` starts
|
||||
with `pinnedPrompt || settings.instructions`. `/api/config` pins
|
||||
In [context.ts](../../s2s-frontend/src/lib/context.ts), `buildInstructions()` starts
|
||||
with `config.primaryPrompt || settings.instructions`. `/api/config` pins
|
||||
`S2S_PRIMARY_PROMPT` when non-empty; otherwise the settings prompt or
|
||||
`DEFAULT_INSTRUCTIONS` is used. The current server does not fetch a remote agent
|
||||
profile to choose this base prompt.
|
||||
|
||||
The browser adds caller context when `injectProfile` is enabled, custom RAG text
|
||||
when the operator has applied it, and an available ApiPilot catalog block.
|
||||
`effectiveInstructions()` adds `OPENAI_RENDER_HINT` only in `OPENAI` mode.
|
||||
`speechInstructions()` adds the speech-rendering hint only in `OPENAI` mode.
|
||||
The WebSocket client packages these instructions in `session.update.session`;
|
||||
the local proxy may then add server-resolved context. Details belong in
|
||||
[context injection](context-injection.md).
|
||||
@@ -49,8 +49,8 @@ S2S_REASONING_TYPE=NODE_RED
|
||||
S2S_REASONING_NODE_RED_URL=http://localhost:1881
|
||||
```
|
||||
|
||||
`maybeRunOpenAiReasoning()` handles both external modes despite its historical
|
||||
function name. It runs after a complete user transcript and posts a body with
|
||||
`VoiceController.reason()` in [controller.ts](../../s2s-frontend/src/realtime/controller.ts)
|
||||
handles both external modes. It runs after a complete user transcript and posts a body with
|
||||
`transcript`, `instructions`, `language`, `user_context`, `phoneNumber`, and
|
||||
`episode_id`. The server builds context and forwards the reasoning fields to
|
||||
Node-RED with a 30-second timeout.
|
||||
@@ -84,10 +84,9 @@ browser's native `session.tools` catalog as OpenAI Chat Completions `tools`.
|
||||
|
||||
For a non-log-only answer, the browser cancels/suppresses the active native
|
||||
response and appends the external assistant text. It uses browser
|
||||
`SpeechSynthesis` when available. Its compatibility fallback sends
|
||||
`[VOCERO_RENDER_REPLY]` plus the answer to the realtime backend and requests a
|
||||
response. The render hint asks the model to read only the answer after that
|
||||
marker. This instruction is model behavior, not a guarantee of exact playback.
|
||||
`SpeechSynthesis` when available. The React client adds the answer to the realtime
|
||||
conversation as an assistant item; without browser speech synthesis it remains
|
||||
visible as text.
|
||||
|
||||
External reasoning adds an HTTP operation to each completed transcript and has
|
||||
separate provider token usage. It is not the speech pipeline's `responses-api`
|
||||
@@ -99,8 +98,8 @@ realtime backend instead.
|
||||
| Goal | Source |
|
||||
|---|---|
|
||||
| Change the base agent prompt | `S2S_PRIMARY_PROMPT` or browser settings when unpinned |
|
||||
| Change browser context assembly | `effectiveReasoningInstructions()` in `main.js` |
|
||||
| Change browser context assembly | `buildInstructions()` in `s2s-frontend/src/lib/context.ts` |
|
||||
| Change HTTP provider messages | `reasoning()` in `server.py` |
|
||||
| Change external-answer rendering | `maybeRunOpenAiReasoning()` in `main.js` |
|
||||
| Change external-answer rendering | `VoiceController.reason()` and `RealtimeClient.renderExternalAnswer()` |
|
||||
| Change Node-RED processing | `s2s-reasoning-engine/flows.json` |
|
||||
| Change native model/tool generation | `speech_to_speech/LLM` and realtime handlers |
|
||||
|
||||
@@ -48,8 +48,9 @@ For a native call, the backend emits:
|
||||
```
|
||||
|
||||
`arguments` is a JSON-encoded string. The
|
||||
[WebSocket client](../../s2s-client/ws/s2s-ws-client.js) parses it and dispatches
|
||||
`toolcall`; [main.js](../../s2s-client/main.js) runs the supported executor.
|
||||
[WebSocket client](../../s2s-frontend/src/realtime/client.ts) validates the event and
|
||||
dispatches `tool`; [controller.ts](../../s2s-frontend/src/realtime/controller.ts)
|
||||
parses the arguments and runs the supported executor.
|
||||
Web search uses `POST /api/search`, keeping the deployment's Serper key on the
|
||||
server. Tool output returns to the model as:
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ code before claiming a root cause is resolved.
|
||||
`S2S_DEBUG_PROMPT=true` enables complete prompt logs, including caller information
|
||||
and conversation text. Use summaries when full payloads are unnecessary. The
|
||||
browser's application functions are module-scoped; do not assume names such as
|
||||
`effectiveInstructions()` are available directly on `window` in DevTools.
|
||||
`buildInstructions()` are available directly on `window` in DevTools.
|
||||
|
||||
## Short gaps or clipped words around tool results
|
||||
|
||||
@@ -119,15 +119,17 @@ microphone/audio permissions. If automatic startup fails, use the unlocker
|
||||
gesture and inspect the permission error rather than increasing the timer
|
||||
without evidence.
|
||||
|
||||
## Read-only source checks
|
||||
## Local validation
|
||||
|
||||
From the repository root, useful syntax checks are:
|
||||
From the repository root, run the frontend checks and local backend fixtures:
|
||||
|
||||
```bash
|
||||
node --check s2s-client/main.js
|
||||
node --check s2s-client/ws/s2s-ws-client.js
|
||||
python -m py_compile s2s-client/server.py
|
||||
npm --prefix s2s-frontend run check
|
||||
npm --prefix s2s-frontend run build
|
||||
.venv/bin/python -m unittest discover -s s2s-client/tests -v
|
||||
```
|
||||
|
||||
Syntax checks do not validate microphone access, network services, model output,
|
||||
or audio quality. Collect a fresh browser/backend reproduction for those paths.
|
||||
These checks cover frontend contracts and local session/queue/WebSocket
|
||||
fixtures. They do not validate deployed services, real microphone hardware,
|
||||
model output, or audio quality. Use a local browser/backend reproduction for
|
||||
those paths before deployment.
|
||||
|
||||
+17
-18
@@ -70,7 +70,7 @@ See [LLM](../speech/llm.md), [STT](../speech/stt.md), and [TTS](../speech/tts.md
|
||||
|---|---|---|---|
|
||||
| `SPEECH_TO_SPEECH_URL` set | Direct to pinned URL | Locked | Disabled |
|
||||
| `S2S_PROXY_TARGET` set, no direct URL | Same-origin `/v1/realtime` proxy | Locked | Disabled |
|
||||
| `LOAD_BALANCER_URL` set, neither above set | Per-session compute URL from `/api/session` | Hidden | Queue enabled; metering requires `SPACE_ID` too |
|
||||
| `LOAD_BALANCER_URL` set, neither above set | Per-session compute URL from `/api/session` | Hidden | Allocation, queue polling and cancellation |
|
||||
| None set | User-provided realtime URL | Editable | Disabled |
|
||||
|
||||
Direct URLs may be full `ws(s)://.../v1/realtime` addresses or host values that
|
||||
@@ -84,8 +84,9 @@ server; it is not a universally available local service.
|
||||
|
||||
## Docker
|
||||
|
||||
This existing image serves the retained static client. It does not run the
|
||||
React/Vite development launcher.
|
||||
This image serves FastAPI backend routes and shared documentation. Run the
|
||||
React frontend separately with Vite and point `S2S_BACKEND_URL` at the exposed
|
||||
backend address. The image does not run the development launcher or serve a UI.
|
||||
|
||||
Use the project root as the build context:
|
||||
|
||||
@@ -144,24 +145,22 @@ The warmup is a timer, not proof that all upstream context requests have
|
||||
finished. Browser permission and audio policies can still require a gesture.
|
||||
The greeting uses the same `hola vocero` input as wake-word handling.
|
||||
|
||||
## Queue and daily usage
|
||||
## Queue and session lifecycle
|
||||
|
||||
Load-balancer mode proxies session acquisition and queue polling. Waiting does
|
||||
not reserve conversation time; a daily budget is reserved when a compute slot
|
||||
is granted. The server enables metering only with both `LOAD_BALANCER_URL` and
|
||||
`SPACE_ID` and with neither pinned direct/proxy mode active.
|
||||
Load-balancer mode proxies `POST /api/session`. A free compute slot returns a
|
||||
grant containing `session_id`, `connect_url`, and `pending_timeout_s`. Otherwise
|
||||
the browser receives a queue ticket and polls `GET /api/queue/{queue_id}` until
|
||||
a slot is granted. The browser offers a timed join action after waiting.
|
||||
|
||||
| Environment setting | Default | Purpose |
|
||||
|---|---|---|
|
||||
| `LIMIT_ANON_SEC` | 300 | Anonymous seconds per UTC day |
|
||||
| `LIMIT_FREE_SEC` | 600 | Signed-in non-PRO seconds per UTC day |
|
||||
| `UNLIMITED_ORGS` | Adds to built-in organizations | Additional unlimited organization members |
|
||||
| `USAGE_HASH_SECRET` | Random if unset | Identity-key hashing and anonymous cookie signing |
|
||||
`DELETE /api/queue/{queue_id}` cancels a waiting ticket. On session stop or page
|
||||
exit, the browser uses `POST /api/queue/end` through `sendBeacon`, falling back
|
||||
to a keepalive fetch. Expired tickets and missed join deadlines require a new
|
||||
attempt. Full queues return `503` with `state: "at_capacity"`.
|
||||
|
||||
PRO members are unlimited. Built-in unlimited organizations are `cerebras`,
|
||||
`HuggingFaceM4`, `smolagents`, and `pollen-robotics`; organization matching is
|
||||
case-insensitive. See [auth.py](../../s2s-client/auth.py) and
|
||||
[limiter.py](../../s2s-client/limiter.py) for the current enforcement behavior.
|
||||
Once connected, session teardown closes the microphone, audio graph and
|
||||
WebSocket. The 30-second inactivity timeout remains active when the assistant
|
||||
is not speaking. Caller-profile lookup and upstream authorization operate
|
||||
independently of allocation and use their existing configured endpoints.
|
||||
|
||||
For external transcript processing, configure the selected
|
||||
[reasoning mode](reasoning.md). For connection, context and audio diagnostics,
|
||||
|
||||
Reference in New Issue
Block a user