Spaces:
Running
Running
Auto-auth via HF login, fallback to token input
Browse files- First try connecting without token (HF proxy auth)
- Show token input only if auto-auth fails
- Cleaner UX for logged-in users
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- README.md +15 -5
- index.html +28 -16
README.md
CHANGED
|
@@ -1,10 +1,20 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
|
|
|
|
|
|
| 8 |
---
|
| 9 |
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: Reachy Mini WebRTC Demo
|
| 3 |
+
emoji: 🤖
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: indigo
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
| 8 |
+
hf_oauth: true
|
| 9 |
+
hf_oauth_expiration_minutes: 480
|
| 10 |
---
|
| 11 |
|
| 12 |
+
# Reachy Mini WebRTC Demo
|
| 13 |
+
|
| 14 |
+
WebRTC dashboard to connect to your Reachy Mini robot via the central signaling server.
|
| 15 |
+
|
| 16 |
+
## Features
|
| 17 |
+
|
| 18 |
+
- Video streaming from robot camera
|
| 19 |
+
- Head control via data channel
|
| 20 |
+
- HuggingFace OAuth authentication
|
index.html
CHANGED
|
@@ -119,10 +119,8 @@
|
|
| 119 |
<div class="grid">
|
| 120 |
<!-- Connection Panel -->
|
| 121 |
<div class="card">
|
| 122 |
-
<h2>1.
|
| 123 |
-
<
|
| 124 |
-
<input type="password" id="hfToken" placeholder="hf_...">
|
| 125 |
-
<p class="token-info">Get your token from <a href="https://huggingface.co/settings/tokens" target="_blank">huggingface.co/settings/tokens</a></p>
|
| 126 |
|
| 127 |
<div class="controls">
|
| 128 |
<button id="connectBtn" onclick="connectSignaling()">Connect</button>
|
|
@@ -134,6 +132,14 @@
|
|
| 134 |
<span id="signalingStatus" class="status disconnected">Disconnected</span>
|
| 135 |
</div>
|
| 136 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 137 |
<h3 style="margin-top: 20px; font-size: 1em;">Available Robots:</h3>
|
| 138 |
<div id="producerList" class="producer-list">
|
| 139 |
<em style="color: #666;">Connect to signaling server first</em>
|
|
@@ -194,12 +200,6 @@
|
|
| 194 |
let selectedProducerId = null;
|
| 195 |
let myPeerId = null;
|
| 196 |
|
| 197 |
-
// Try to load token from localStorage
|
| 198 |
-
const savedToken = localStorage.getItem('hf_token');
|
| 199 |
-
if (savedToken) {
|
| 200 |
-
document.getElementById('hfToken').value = savedToken;
|
| 201 |
-
}
|
| 202 |
-
|
| 203 |
// Logging
|
| 204 |
function log(message, type = 'info') {
|
| 205 |
const logArea = document.getElementById('logArea');
|
|
@@ -215,19 +215,24 @@
|
|
| 215 |
document.getElementById('logArea').innerHTML = '';
|
| 216 |
}
|
| 217 |
|
| 218 |
-
// Signaling
|
| 219 |
function connectSignaling() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 220 |
const token = document.getElementById('hfToken').value.trim();
|
| 221 |
if (!token) {
|
| 222 |
log('Please enter your HuggingFace token', 'error');
|
| 223 |
return;
|
| 224 |
}
|
| 225 |
-
|
| 226 |
-
// Save token for convenience
|
| 227 |
localStorage.setItem('hf_token', token);
|
|
|
|
|
|
|
| 228 |
|
| 229 |
-
|
| 230 |
-
log(`Connecting to
|
| 231 |
updateSignalingStatus('connecting');
|
| 232 |
|
| 233 |
try {
|
|
@@ -238,6 +243,7 @@
|
|
| 238 |
updateSignalingStatus('connected');
|
| 239 |
document.getElementById('connectBtn').disabled = true;
|
| 240 |
document.getElementById('disconnectBtn').disabled = false;
|
|
|
|
| 241 |
};
|
| 242 |
|
| 243 |
signalingWs.onmessage = (event) => {
|
|
@@ -253,7 +259,13 @@
|
|
| 253 |
signalingWs.onclose = (event) => {
|
| 254 |
log(`Disconnected: code=${event.code}`);
|
| 255 |
if (event.code === 4001) {
|
| 256 |
-
log('
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 257 |
}
|
| 258 |
updateSignalingStatus('disconnected');
|
| 259 |
document.getElementById('connectBtn').disabled = false;
|
|
|
|
| 119 |
<div class="grid">
|
| 120 |
<!-- Connection Panel -->
|
| 121 |
<div class="card">
|
| 122 |
+
<h2>1. Connection</h2>
|
| 123 |
+
<p style="color: #888; font-size: 0.9em;">You should be automatically authenticated via your HuggingFace login.</p>
|
|
|
|
|
|
|
| 124 |
|
| 125 |
<div class="controls">
|
| 126 |
<button id="connectBtn" onclick="connectSignaling()">Connect</button>
|
|
|
|
| 132 |
<span id="signalingStatus" class="status disconnected">Disconnected</span>
|
| 133 |
</div>
|
| 134 |
|
| 135 |
+
<!-- Fallback token input (hidden by default, shown if auto-auth fails) -->
|
| 136 |
+
<div id="tokenSection" style="display: none; margin-top: 15px; padding-top: 15px; border-top: 1px solid #0f3460;">
|
| 137 |
+
<label>HuggingFace Token (fallback):</label>
|
| 138 |
+
<input type="password" id="hfToken" placeholder="hf_...">
|
| 139 |
+
<p class="token-info">Get your token from <a href="https://huggingface.co/settings/tokens" target="_blank">huggingface.co/settings/tokens</a></p>
|
| 140 |
+
<button onclick="connectWithToken()" style="width: 100%;">Connect with Token</button>
|
| 141 |
+
</div>
|
| 142 |
+
|
| 143 |
<h3 style="margin-top: 20px; font-size: 1em;">Available Robots:</h3>
|
| 144 |
<div id="producerList" class="producer-list">
|
| 145 |
<em style="color: #666;">Connect to signaling server first</em>
|
|
|
|
| 200 |
let selectedProducerId = null;
|
| 201 |
let myPeerId = null;
|
| 202 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 203 |
// Logging
|
| 204 |
function log(message, type = 'info') {
|
| 205 |
const logArea = document.getElementById('logArea');
|
|
|
|
| 215 |
document.getElementById('logArea').innerHTML = '';
|
| 216 |
}
|
| 217 |
|
| 218 |
+
// Signaling - try without token first (HF proxy auth)
|
| 219 |
function connectSignaling() {
|
| 220 |
+
doConnect(SIGNALING_SERVER);
|
| 221 |
+
}
|
| 222 |
+
|
| 223 |
+
// Fallback: connect with explicit token
|
| 224 |
+
function connectWithToken() {
|
| 225 |
const token = document.getElementById('hfToken').value.trim();
|
| 226 |
if (!token) {
|
| 227 |
log('Please enter your HuggingFace token', 'error');
|
| 228 |
return;
|
| 229 |
}
|
|
|
|
|
|
|
| 230 |
localStorage.setItem('hf_token', token);
|
| 231 |
+
doConnect(`${SIGNALING_SERVER}?token=${encodeURIComponent(token)}`);
|
| 232 |
+
}
|
| 233 |
|
| 234 |
+
function doConnect(url) {
|
| 235 |
+
log(`Connecting to signaling server...`);
|
| 236 |
updateSignalingStatus('connecting');
|
| 237 |
|
| 238 |
try {
|
|
|
|
| 243 |
updateSignalingStatus('connected');
|
| 244 |
document.getElementById('connectBtn').disabled = true;
|
| 245 |
document.getElementById('disconnectBtn').disabled = false;
|
| 246 |
+
document.getElementById('tokenSection').style.display = 'none';
|
| 247 |
};
|
| 248 |
|
| 249 |
signalingWs.onmessage = (event) => {
|
|
|
|
| 259 |
signalingWs.onclose = (event) => {
|
| 260 |
log(`Disconnected: code=${event.code}`);
|
| 261 |
if (event.code === 4001) {
|
| 262 |
+
log('Auto-auth failed. Please enter your HF token below.', 'error');
|
| 263 |
+
document.getElementById('tokenSection').style.display = 'block';
|
| 264 |
+
// Try loading saved token
|
| 265 |
+
const savedToken = localStorage.getItem('hf_token');
|
| 266 |
+
if (savedToken) {
|
| 267 |
+
document.getElementById('hfToken').value = savedToken;
|
| 268 |
+
}
|
| 269 |
}
|
| 270 |
updateSignalingStatus('disconnected');
|
| 271 |
document.getElementById('connectBtn').disabled = false;
|