cduss's picture
Upload folder using huggingface_hub
3389a05 verified
|
Raw
History Blame Contribute Delete
3.7 kB
metadata
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:

  1. HF OAuth client ID. The Docker variant patched __OAUTH_CLIENT_ID__ into index.html from a container env var at start-up (docker-entrypoint.d/10-inject-hf-vars.sh). On a static Space, HF injects window.huggingface.variables (incl. OAUTH_CLIENT_ID) into the <head> automatically when hf_oauth: true is set — the SDK host shell reads it directly.

  2. OpenAI ephemeral-key minting. src/ephemeral-key.ts POSTs 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 master OPENAI_API_KEY stays in the website Space's secrets.

  3. OpenAI Realtime SDP call. The Docker variant routed this through an nginx /openai/ reverse-proxy because OpenAI exposes no CORS for personal sk- keys. But this app authenticates with short-lived ek_… ephemeral keys, and OpenAI's POST /v1/realtime/calls returns Access-Control-Allow-Origin: * for those — so the browser calls https://api.openai.com/v1/realtime/calls directly. src/openai-realtime.ts was changed from the /openai/... same-origin path to the direct URL (overridable via VITE_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.co Spaces iframe wrapper: its hf_jwt auth cookie is SameSite-blocked in the cross-origin iframe, so assets come back as 401 text/plain and 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.