Download README.md from amir-tfrere/minimal-conversation-app-s2s-backend: direct link, hf CLI and curl.
- Browser
- Download file 3.79 kB
-
https://huggingface.co/spaces/amir-tfrere/minimal-conversation-app-s2s-backend/resolve/main/README.md
- Command line
-
hf download hf://spaces/amir-tfrere/minimal-conversation-app-s2s-backend/README.md
-
curl -L -o README.md https://huggingface.co/spaces/amir-tfrere/minimal-conversation-app-s2s-backend/resolve/main/README.md
title: Minimal Conversation (S2S backend)
emoji: 🎙️
colorFrom: indigo
colorTo: purple
sdk: static
pinned: false
short_description: Voice chat over WebRTC against a HF speech-to-speech
Minimal Conversation App (S2S backend)
Tiny browser app that opens a WebRTC voice session with a self-hosted Hugging Face speech-to-speech backend. No OpenAI key, no robot, no OAuth, no proxy. The browser talks directly to the backend.
How it works
- App POSTs
<lb_url>/session(empty JSON body). - The load balancer picks a ready compute (round-robin) and returns:
{ "session_id": "...", "websocket_url": "wss://<compute>/v1/realtime", "connect_url": "wss://<compute>/v1/realtime?session_token=<JWT>", "session_token": "<JWT>", "pending_timeout_s": 60 } - App rewrites
connect_urlfromwss://tohttps://and POSTs an SDP offer to it (Content-Type: application/sdp). The compute, running aiortc, answers201 application/sdpwith the SDP answer. - WebRTC peer connection opens. Audio streams over the media tracks (the browser
sends Opus 48 kHz, the backend resamples to 16 kHz for STT and back for TTS).
Events flow over a data channel labelled
oai-eventsusing the OpenAI Realtime JSON protocol (session.update,response.audio_transcript.delta,conversation.item.input_audio_transcription.delta, ...).
The backend exposes one concurrent session per compute; the LB pins a session to
a specific compute via a signed session_token.
Backend requirement
This app talks to the WebRTC route POST /v1/realtime defined in
websocket_router.py.
That route lives on the feat/webrtc-transport branch. If the compute is
deployed from main it will reply 404 on the SDP POST. Verify with:
LB="https://<your-lb>.endpoints.huggingface.cloud"
curl -X POST "$LB/session" -H "Content-Type: application/json" -d '{}'
# -> { "connect_url": "wss://<compute>/v1/realtime?session_token=..." }
# Rewrite wss -> https, POST a SDP offer:
curl -X POST "https://<compute>/v1/realtime?session_token=..." \
-H "Content-Type: application/sdp" --data-binary @offer.sdp
# expect 201 application/sdp; if 404, the compute is on the wrong branch.
Run locally
This is a pure static app. No build step, no node_modules. Any HTTP server works:
cd minimal-conversation-app-s2s-backend
python3 -m http.server 5173
# or: npx --yes http-server -p 5173 -c-1
Then open http://localhost:5173/, click the orb, allow the mic, talk.
Browsers require HTTPS or
localhostforgetUserMedia().127.0.0.1works, as doeslocalhost. Plainhttp://192.168.x.y:5173does NOT (mic blocked).
Settings (stored in localStorage)
| Key | What |
|---|---|
| Load balancer URL | Base URL of your S2S deployment. App POSTs <lb>/session. |
| Voice | Qwen3-TTS speaker name (Aiden, Ryan, Dylan, Eric, Ono_Anna, Serena, Sohee, Uncle_Fu, Vivian) |
| Instructions | System prompt sent in session.update once the data channel opens |
Files
| File | Role |
|---|---|
index.html |
Single page, orb + settings modal |
main.js |
State machine, settings, mic capture, output audio piping |
s2s-client.js |
WebRTC handshake against the LB + compute |
style.css |
Orb animations, layout, dark theme |
Credits
- Backend: huggingface/speech-to-speech on
feat/webrtc-transport - UI forked from
reachy_mini_minimal_conversation(Pollen Robotics × Hugging Face), stripped of all robot-specific bits