title: Minimal Conversation JS Static
emoji: 🎙️
colorFrom: indigo
colorTo: purple
sdk: static
pinned: false
hf_oauth: true
short_description: Static port of the minimal JS voice chat (Reachy Mini).
tags:
- reachy_mini
- reachy_mini_js_app
Minimal Conversation (JS) — static build
A sdk: static port of tfrere/minimal-conversation
(originally a sdk: docker Space). Same app, no container, no nginx, no
entrypoint script — just the Vite production build served as files.
This is an investigation Space: does the conversation app run as a pure static Space with no server-side proxy? Conclusion: yes. Three things the Docker variant used a server for turn out to be unnecessary on a static Space:
HF OAuth client ID. The Docker variant patched
__OAUTH_CLIENT_ID__intoindex.htmlfrom a container env var at start-up (docker-entrypoint.d/10-inject-hf-vars.sh). On a static Space, HF injectswindow.huggingface.variables(incl.OAUTH_CLIENT_ID) into the<head>automatically whenhf_oauth: trueis set — the SDK host shell reads it directly.OpenAI ephemeral-key minting.
src/ephemeral-key.tsPOSTs the visitor's HF token to the Pollen website (…pollen-robotics-reachy-mini.hf.space/api/openai/ephemeral) straight from the browser. That endpoint's CORS is origin-reflecting, so this origin is accepted with no allow-list change. The masterOPENAI_API_KEYstays in the website Space's secrets.OpenAI Realtime SDP call. The Docker variant routed this through an nginx
/openai/reverse-proxy because OpenAI exposes no CORS for personalsk-keys. But this app authenticates with short-livedek_…ephemeral keys, and OpenAI'sPOST /v1/realtime/callsreturnsAccess-Control-Allow-Origin: *for those — so the browser callshttps://api.openai.com/v1/realtime/callsdirectly.src/openai-realtime.tswas changed from the/openai/...same-origin path to the direct URL (overridable viaVITE_OPENAI_REALTIME_URL).
So there is no backend. The browser talks to: Reachy Mini central (robot signaling, via the SDK), the Pollen website (ephemeral key mint), and OpenAI Realtime (SDP handshake + WebRTC voice tunnel).
Must be public. A private static Space can't be loaded in the
huggingface.coSpaces iframe wrapper: itshf_jwtauth cookie is SameSite-blocked in the cross-origin iframe, so assets come back as401 text/plainand the module is refused. Public has no such cookie requirement.
How it's built
npm install
npm run build # → dist/ (this Space is the contents of dist/)
The source lives in the upstream tfrere/minimal-conversation repo
(plus the one-line openai-realtime.ts change above). This Space holds
only the built artifacts + this README. To update, rebuild and
re-upload dist/.
Architecture (unchanged from upstream)
┌────────┐ robot mic ┌────────┐ input track ┌───────────┐
│ Reachy │ ────────────► │ Browser│ ──────────► │ OpenAI │
│ Mini │ │ (this │ │ Realtime │
│ daemon │ ◄──────────── │ app) │ ◄────────── │ API │
└────────┘ robot speaker └────────┘ output track └───────────┘
License
MIT for the glue code (same as upstream). Underlying SDKs keep their own licenses.