robopark 3.3.44 → 3.3.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/robopark/audio-select.js +11 -3
- package/dist/robopark/audio-select.js.map +1 -1
- package/dist/robopark/start.js +114 -9
- package/dist/robopark/start.js.map +1 -1
- package/dist/robopark/video-select.js +123 -0
- package/dist/robopark/video-select.js.map +1 -0
- package/dist/robopark-cli.js +1 -0
- package/dist/robopark-cli.js.map +1 -1
- package/package.json +1 -1
- package/scheduler/static/voice-join.html +98 -7
- package/ui/standalone/.next/BUILD_ID +1 -1
- package/ui/standalone/.next/app-build-manifest.json +69 -69
- package/ui/standalone/.next/app-path-routes-manifest.json +19 -19
- package/ui/standalone/.next/build-manifest.json +2 -2
- package/ui/standalone/.next/server/app-paths-manifest.json +19 -19
- package/ui/standalone/.next/server/pages/500.html +1 -1
- package/ui/standalone/public/voice-join.html +98 -7
- /package/ui/standalone/.next/static/{VHNdBIGajqd6Wv28naVNO → GwsTXhcc2wWhmMKp14ZmG}/_buildManifest.js +0 -0
- /package/ui/standalone/.next/static/{VHNdBIGajqd6Wv28naVNO → GwsTXhcc2wWhmMKp14ZmG}/_ssgManifest.js +0 -0
|
@@ -2,57 +2,57 @@
|
|
|
2
2
|
"/_not-found/page": "app/_not-found/page.js",
|
|
3
3
|
"/api/device-character/route": "app/api/device-character/route.js",
|
|
4
4
|
"/api/download-piper-model/route": "app/api/download-piper-model/route.js",
|
|
5
|
-
"/api/prompt/route": "app/api/prompt/route.js",
|
|
6
|
-
"/api/reload-tools/route": "app/api/reload-tools/route.js",
|
|
7
5
|
"/api/models/route": "app/api/models/route.js",
|
|
6
|
+
"/api/prompt/route": "app/api/prompt/route.js",
|
|
8
7
|
"/api/prewarm/route": "app/api/prewarm/route.js",
|
|
9
8
|
"/api/robopark/devices/[deviceId]/control/route": "app/api/robopark/devices/[deviceId]/control/route.js",
|
|
10
9
|
"/api/robopark/robots/[robotId]/operations/route": "app/api/robopark/robots/[robotId]/operations/route.js",
|
|
10
|
+
"/api/reload-tools/route": "app/api/reload-tools/route.js",
|
|
11
11
|
"/api/robopark/sessions/[sessionId]/end/route": "app/api/robopark/sessions/[sessionId]/end/route.js",
|
|
12
12
|
"/api/robopark/transcripts/[sessionId]/route": "app/api/robopark/transcripts/[sessionId]/route.js",
|
|
13
|
-
"/api/setup/status/route": "app/api/setup/status/route.js",
|
|
14
13
|
"/api/setup/complete/route": "app/api/setup/complete/route.js",
|
|
15
14
|
"/api/setup/test-groq/route": "app/api/setup/test-groq/route.js",
|
|
16
15
|
"/api/setup/test-hass/route": "app/api/setup/test-hass/route.js",
|
|
17
|
-
"/api/setup/
|
|
16
|
+
"/api/setup/status/route": "app/api/setup/status/route.js",
|
|
18
17
|
"/api/setup/test-n8n/route": "app/api/setup/test-n8n/route.js",
|
|
18
|
+
"/api/setup/test-ollama/route": "app/api/setup/test-ollama/route.js",
|
|
19
19
|
"/api/test-tts/route": "app/api/test-tts/route.js",
|
|
20
20
|
"/api/voices/route": "app/api/voices/route.js",
|
|
21
21
|
"/api/wake-word/models/route": "app/api/wake-word/models/route.js",
|
|
22
22
|
"/api/wake-word/status/route": "app/api/wake-word/status/route.js",
|
|
23
23
|
"/api/wake-word/upload/route": "app/api/wake-word/upload/route.js",
|
|
24
24
|
"/favicon.ico/route": "app/favicon.ico/route.js",
|
|
25
|
-
"/api/model-status/route": "app/api/model-status/route.js",
|
|
26
25
|
"/api/kiosk-hardware/route": "app/api/kiosk-hardware/route.js",
|
|
27
|
-
"/api/robopark/character-ai/route": "app/api/robopark/character-ai/route.js",
|
|
28
26
|
"/api/connection-details/route": "app/api/connection-details/route.js",
|
|
27
|
+
"/api/model-status/route": "app/api/model-status/route.js",
|
|
28
|
+
"/api/robopark/device-access/route": "app/api/robopark/device-access/route.js",
|
|
29
29
|
"/api/robopark/camera-token/route": "app/api/robopark/camera-token/route.js",
|
|
30
|
-
"/api/robopark/robots/route": "app/api/robopark/robots/route.js",
|
|
31
30
|
"/api/robopark/live-rooms/route": "app/api/robopark/live-rooms/route.js",
|
|
32
|
-
"/api/robopark/device-access/route": "app/api/robopark/device-access/route.js",
|
|
33
31
|
"/api/robopark/monitor-token/route": "app/api/robopark/monitor-token/route.js",
|
|
32
|
+
"/api/robopark/character-ai/route": "app/api/robopark/character-ai/route.js",
|
|
33
|
+
"/api/robopark/robots/route": "app/api/robopark/robots/route.js",
|
|
34
34
|
"/api/robopark/servers/[serverId]/metrics/route": "app/api/robopark/servers/[serverId]/metrics/route.js",
|
|
35
|
+
"/api/robopark/servers/[serverId]/route": "app/api/robopark/servers/[serverId]/route.js",
|
|
35
36
|
"/api/robopark/servers/route": "app/api/robopark/servers/route.js",
|
|
36
37
|
"/api/robopark/sessions/route": "app/api/robopark/sessions/route.js",
|
|
37
|
-
"/api/robopark/servers/[serverId]/route": "app/api/robopark/servers/[serverId]/route.js",
|
|
38
|
-
"/api/robopark/vision-caption/route": "app/api/robopark/vision-caption/route.js",
|
|
39
|
-
"/api/robopark/robots/[robotId]/voice-engine/route": "app/api/robopark/robots/[robotId]/voice-engine/route.js",
|
|
40
38
|
"/api/robovoice/robots/[robotId]/media-health/route": "app/api/robovoice/robots/[robotId]/media-health/route.js",
|
|
39
|
+
"/api/robopark/vision-caption/route": "app/api/robopark/vision-caption/route.js",
|
|
41
40
|
"/api/settings/route": "app/api/settings/route.js",
|
|
42
|
-
"/api/robopark/
|
|
41
|
+
"/api/robopark/robots/[robotId]/voice-engine/route": "app/api/robopark/robots/[robotId]/voice-engine/route.js",
|
|
43
42
|
"/api/turn-credentials/route": "app/api/turn-credentials/route.js",
|
|
44
|
-
"/api/
|
|
43
|
+
"/api/robopark/transcripts/route": "app/api/robopark/transcripts/route.js",
|
|
45
44
|
"/camera-grid/route": "app/camera-grid/route.js",
|
|
46
|
-
"/
|
|
45
|
+
"/api/wake/route": "app/api/wake/route.js",
|
|
47
46
|
"/fed/media/robots/[robotId]/video_feed/route": "app/fed/media/robots/[robotId]/video_feed/route.js",
|
|
48
|
-
"/robopark/
|
|
49
|
-
"/fed/[...path]/route": "app/fed/[...path]/route.js",
|
|
50
|
-
"/tailnet/route": "app/tailnet/route.js",
|
|
47
|
+
"/robopark/[...path]/route": "app/robopark/[...path]/route.js",
|
|
51
48
|
"/vendor/livekit-client.umd.js/route": "app/vendor/livekit-client.umd.js/route.js",
|
|
49
|
+
"/fed/[...path]/route": "app/fed/[...path]/route.js",
|
|
50
|
+
"/robopark/api/robots/[robotId]/stream/route": "app/robopark/api/robots/[robotId]/stream/route.js",
|
|
52
51
|
"/(app)/opengraph-image-xg4ifa/route": "app/(app)/opengraph-image-xg4ifa/route.js",
|
|
52
|
+
"/tailnet/route": "app/tailnet/route.js",
|
|
53
53
|
"/robopark/api/[...path]/route": "app/robopark/api/[...path]/route.js",
|
|
54
54
|
"/robopark/page": "app/robopark/page.js",
|
|
55
55
|
"/voice-tester/page": "app/voice-tester/page.js",
|
|
56
|
-
"/(app)/
|
|
57
|
-
"/(app)/page": "app/(app)/page.js"
|
|
56
|
+
"/(app)/page": "app/(app)/page.js",
|
|
57
|
+
"/(app)/voice/page": "app/(app)/voice/page.js"
|
|
58
58
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html><head><meta charSet="utf-8" data-next-head=""/><meta name="viewport" content="width=device-width" data-next-head=""/><title data-next-head="">500: Internal Server Error</title><noscript data-n-css=""></noscript><script defer="" noModule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-5252e5254da079b5.js" defer=""></script><script src="/_next/static/chunks/framework-e60c938074ff7136.js" defer=""></script><script src="/_next/static/chunks/main-9e24e8708ff075fc.js" defer=""></script><script src="/_next/static/chunks/pages/_app-131c90850aef965b.js" defer=""></script><script src="/_next/static/chunks/pages/_error-e4ba546eb376bdf4.js" defer=""></script><script src="/_next/static/
|
|
1
|
+
<!DOCTYPE html><html><head><meta charSet="utf-8" data-next-head=""/><meta name="viewport" content="width=device-width" data-next-head=""/><title data-next-head="">500: Internal Server Error</title><noscript data-n-css=""></noscript><script defer="" noModule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-5252e5254da079b5.js" defer=""></script><script src="/_next/static/chunks/framework-e60c938074ff7136.js" defer=""></script><script src="/_next/static/chunks/main-9e24e8708ff075fc.js" defer=""></script><script src="/_next/static/chunks/pages/_app-131c90850aef965b.js" defer=""></script><script src="/_next/static/chunks/pages/_error-e4ba546eb376bdf4.js" defer=""></script><script src="/_next/static/GwsTXhcc2wWhmMKp14ZmG/_buildManifest.js" defer=""></script><script src="/_next/static/GwsTXhcc2wWhmMKp14ZmG/_ssgManifest.js" defer=""></script></head><body><div id="__next"><div style="font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div style="line-height:48px"><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding-right:23px;font-size:24px;font-weight:500;vertical-align:top">500</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:28px">Internal Server Error<!-- -->.</h2></div></div></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"statusCode":500}},"page":"/_error","query":{},"buildId":"GwsTXhcc2wWhmMKp14ZmG","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html>
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
callPanel.insertAdjacentHTML('beforeend','<div class=call-row hidden><label for=call-mode>Call mode</label><select id=call-mode><option value=test>Test call · browser only</option><option value=production>Production on-site · robot video and tools</option></select></div>');
|
|
35
35
|
callPanel.insertAdjacentHTML('beforeend','<div class=call-row id=robot-row hidden><label for=call-robot>Production robot</label><select id=call-robot><option value=none>Select a registered robot...</option></select></div>');
|
|
36
36
|
callPanel.insertAdjacentHTML('beforeend','<div class=call-row><label for=call-microphone>Microphone</label><select id=call-microphone><option value=default>System default microphone</option></select></div>');
|
|
37
|
-
callPanel.insertAdjacentHTML('beforeend','<div class=call-row hidden><label for=call-camera>Camera</label><select id=call-camera><option value=default>System default camera</option></select></div>');
|
|
37
|
+
callPanel.insertAdjacentHTML('beforeend','<div class=call-row id=camera-row hidden><label for=call-camera id=camera-label>Camera</label><select id=call-camera><option value=default>System default camera</option></select></div>');
|
|
38
38
|
callPanel.insertAdjacentHTML('beforeend','<div class=call-row><label for=call-speaker>Speaker output</label><select id=call-speaker><option value=default>System default speaker</option></select></div>');
|
|
39
39
|
callPanel.insertAdjacentHTML('beforeend','<div class=call-actions hidden><button class=primary id=request-hardware type=button>Request all media</button><button id=refresh-hardware type=button>Refresh devices</button></div>');
|
|
40
40
|
callPanel.insertAdjacentHTML('beforeend','<p class="call-note call-status" id=hardware-status>Grant browser media access to reveal device names.</p><span class=mode-badge id=mode-badge hidden>TEST ? BROWSER ONLY</span>');
|
|
@@ -52,6 +52,96 @@
|
|
|
52
52
|
: 'Microphone and camera are blocked because this page is not on a secure origin ('+location.protocol+'//'+location.host+'). Open it over https:// or from localhost.';
|
|
53
53
|
}
|
|
54
54
|
function refreshHardware(requestPermission){if(!navigator.mediaDevices||!navigator.mediaDevices.enumerateDevices){setHardwareStatus(mediaBlockedReason(),'bad');return Promise.reject(new Error('media devices unavailable'))}var permission=Promise.resolve();if(requestPermission){permission=navigator.mediaDevices.getUserMedia({audio:true,video:true}).catch(function(){return navigator.mediaDevices.getUserMedia({audio:true})}).then(function(stream){stream.getTracks().forEach(function(track){track.stop()})})}setHardwareStatus(requestPermission?'Requesting browser media access...':'Scanning browser hardware...','');return permission.then(function(){return navigator.mediaDevices.enumerateDevices()}).then(function(devices){fillHardwareSelect('call-microphone',devices,'audioinput','microphone');fillHardwareSelect('call-camera',devices,'videoinput','camera');fillHardwareSelect('call-speaker',devices,'audiooutput','speaker');var mic=devices.filter(function(device){return device.kind==='audioinput'}).length,cam=devices.filter(function(device){return device.kind==='videoinput'}).length,out=devices.filter(function(device){return device.kind==='audiooutput'}).length;setHardwareStatus('Ready: '+mic+' microphone(s), '+cam+' camera(s), '+out+' speaker output(s).','ok');return devices}).catch(function(error){setHardwareStatus(error&&error.message||String(error),'bad');throw error})}
|
|
55
|
+
// ---- Persistent device selection ---------------------------------------
|
|
56
|
+
// Two consumers read this page's pick and they speak different identifiers,
|
|
57
|
+
// so both are written on every change:
|
|
58
|
+
// * PUT '/robopark'/api/kiosk-hardware stores browser MediaDeviceInfo.deviceIds,
|
|
59
|
+
// which is what lets this page and the control-centre panel restore
|
|
60
|
+
// themselves after a reload.
|
|
61
|
+
// * PATCH '/robopark'/api/devices/<robot> stores the option LABEL, because the
|
|
62
|
+
// OpenCV/sounddevice side can only act on a human-readable name; a
|
|
63
|
+
// browser deviceId is origin-scoped and rotates, so it is useless to
|
|
64
|
+
// Python. That row is exactly what `robopark start` replays.
|
|
65
|
+
// Writing only the first is why the CLI was left scanning for a camera while
|
|
66
|
+
// this page worked every time.
|
|
67
|
+
var HW_SELECTS={audioinput:'call-microphone',videoinput:'call-camera',audiooutput:'call-speaker'};
|
|
68
|
+
var HW_KEYS={audioinput:'robopark:media-device:audioinput',videoinput:'robopark:media-device:videoinput',audiooutput:'robopark:media-device:audiooutput'};
|
|
69
|
+
var HW_DEVICE_FIELD={audioinput:'audio_device',videoinput:'video_device',audiooutput:'audio_output_device'};
|
|
70
|
+
var HW_NOUN={audioinput:'microphone',videoinput:'camera',audiooutput:'speaker'};
|
|
71
|
+
var hardwareRevision=0;
|
|
72
|
+
function hardwareValue(kind){var select=el(HW_SELECTS[kind]);return select&&select.value&&select.value!=='default'?select.value:''}
|
|
73
|
+
// Chrome suffixes device labels with the USB vendor:product pair
|
|
74
|
+
// ("HD Webcam C270 (046d:0825)"), which the OS name never carries — and the
|
|
75
|
+
// resolver on the other side matches by substring of the OS name, so the
|
|
76
|
+
// suffix turns a good label into no match at all.
|
|
77
|
+
function hardwareLabel(kind){var select=el(HW_SELECTS[kind]);if(!select||select.value==='default'||select.selectedIndex<0)return '';return String((select.options[select.selectedIndex]||{}).textContent||'').replace(/\s*\([0-9a-f]{4}:[0-9a-f]{4}\)\s*$/i,'').trim()}
|
|
78
|
+
function hardwareSelection(){return {audioinput:hardwareValue('audioinput'),videoinput:hardwareValue('videoinput'),audiooutput:hardwareValue('audiooutput')}}
|
|
79
|
+
function storeHardwareLocal(kind){try{var value=hardwareValue(kind);if(value)localStorage.setItem(HW_KEYS[kind],value);else localStorage.removeItem(HW_KEYS[kind])}catch(_){}}
|
|
80
|
+
function pushHardwareSelection(kind){
|
|
81
|
+
storeHardwareLocal(kind);
|
|
82
|
+
if(!robot)return Promise.resolve();
|
|
83
|
+
var selection=hardwareSelection(),label=hardwareLabel(kind),body={};
|
|
84
|
+
// An empty pick means "you decide": for the camera that is the literal
|
|
85
|
+
// device value 'auto' (scan every index), for audio it is the empty string
|
|
86
|
+
// the vision server already reads as the system default.
|
|
87
|
+
body[HW_DEVICE_FIELD[kind]]=label||(kind==='videoinput'?'auto':'');
|
|
88
|
+
var writes=[fetch('/robopark'+'/api/devices/'+encodeURIComponent(robot),{method:'PATCH',headers:{'content-type':'application/json'},body:JSON.stringify(body)}).catch(function(){})];
|
|
89
|
+
// PUT /api/kiosk-hardware answers 400 when the microphone is empty, so the
|
|
90
|
+
// browser half of the write waits until one is actually chosen.
|
|
91
|
+
if(selection.audioinput)writes.push(fetch('/robopark'+'/api/kiosk-hardware',{method:'PUT',headers:{'content-type':'application/json'},body:JSON.stringify({device_id:robot,selection:selection})}).then(function(response){return response.ok?response.json():null}).then(function(data){if(data&&data.hardware)hardwareRevision=Number(data.hardware.revision||0)}).catch(function(){}));
|
|
92
|
+
// Under ?camera=off the vision server owns the capture device, so the pick
|
|
93
|
+
// is also handed to it directly and takes effect now rather than at the
|
|
94
|
+
// next `robopark start`. Best-effort: this is a cross-origin call to
|
|
95
|
+
// 127.0.0.1 and a page served over https cannot make it.
|
|
96
|
+
if(kind==='videoinput'&&cameraOff&&visionBase)writes.push(fetch(visionBase+'/api/media/config',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({video_device:label||'auto'})}).catch(function(){}));
|
|
97
|
+
return Promise.all(writes).then(function(){setHardwareStatus('Saved '+HW_NOUN[kind]+': '+(label||'system default')+' - kept for this kiosk and replayed by `robopark start`.','ok')})
|
|
98
|
+
}
|
|
99
|
+
// Echo the enumerated devices back. The revision/applied_revision handshake
|
|
100
|
+
// is what the control-centre hardware panel reads; a page that PUT a
|
|
101
|
+
// selection but never reported would leave that panel permanently showing a
|
|
102
|
+
// pending change.
|
|
103
|
+
function reportHardwareObserved(devices){
|
|
104
|
+
if(!robot||!devices)return Promise.resolve(devices);
|
|
105
|
+
return fetch('/robopark'+'/api/kiosk-hardware',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({
|
|
106
|
+
device_id:robot,
|
|
107
|
+
devices:Array.prototype.slice.call(devices).filter(function(device){return device.deviceId}).map(function(device){return {deviceId:device.deviceId,kind:device.kind,label:device.label}}),
|
|
108
|
+
selected:hardwareSelection(),
|
|
109
|
+
secure:Boolean(window.isSecureContext),
|
|
110
|
+
applied_revision:hardwareRevision
|
|
111
|
+
})}).catch(function(){}).then(function(){return devices})
|
|
112
|
+
}
|
|
113
|
+
function scanHardware(requestPermission){return refreshHardware(requestPermission).then(reportHardwareObserved)}
|
|
114
|
+
function applyHardwareValue(kind){var value=hardwareValue(kind);if(kind==='audioinput')inputDeviceId=value;else if(kind==='videoinput')cameraDeviceId=value;else outputDeviceId=value}
|
|
115
|
+
// Seed precedence matches the Next hardware gate: the scheduler's desired
|
|
116
|
+
// pick wins, then whatever the kiosk last reported, then this browser's own
|
|
117
|
+
// localStorage. `dataset.dirty` is what stops a seed that lands late from
|
|
118
|
+
// clobbering a pick the operator has already made.
|
|
119
|
+
function seedHardwareFromScheduler(){
|
|
120
|
+
if(!robot)return Promise.resolve();
|
|
121
|
+
return fetch('/robopark'+'/api/kiosk-hardware?device_id='+encodeURIComponent(robot),{cache:'no-store'}).then(function(response){return response.ok?response.json():null}).then(function(data){
|
|
122
|
+
var hardware=(data&&data.hardware)||{},desired=hardware.desired||{},observed=hardware.observed||{},reported=observed.selected||{};
|
|
123
|
+
hardwareRevision=Number(hardware.revision||0);
|
|
124
|
+
Object.keys(HW_SELECTS).forEach(function(kind){
|
|
125
|
+
var select=el(HW_SELECTS[kind]);if(!select||select.dataset.dirty==='1')return;
|
|
126
|
+
var wanted=desired[kind]||reported[kind]||'';
|
|
127
|
+
if(!wanted){try{wanted=localStorage.getItem(HW_KEYS[kind])||''}catch(_){}}
|
|
128
|
+
if(wanted&&Array.prototype.some.call(select.options,function(option){return option.value===wanted}))select.value=wanted;
|
|
129
|
+
applyHardwareValue(kind)
|
|
130
|
+
})
|
|
131
|
+
}).catch(function(){})
|
|
132
|
+
}
|
|
133
|
+
// ?camera=off means this page never calls getUserMedia({video}) — but the
|
|
134
|
+
// operator still has to be able to say WHICH camera the vision server should
|
|
135
|
+
// open, which is the choice `robopark start` was previously making by
|
|
136
|
+
// scanning indices. So on a kiosk the picker is revealed and relabelled
|
|
137
|
+
// rather than left hidden.
|
|
138
|
+
function revealVisionCameraPicker(){
|
|
139
|
+
if(!(q.get('kiosk')==='1'||q.get('kiosk')==='on')&&!cameraOff)return;
|
|
140
|
+
var row=el('camera-row'),label=el('camera-label');
|
|
141
|
+
if(row)row.hidden=false;
|
|
142
|
+
if(label)label.textContent=cameraOff?'Vision server camera':'Camera';
|
|
143
|
+
if(cameraOff)callPanel.insertAdjacentHTML('beforeend','<p class="call-note">This picks the camera the on-site vision server opens for the robot feed. The browser does not open a local preview here.</p>')
|
|
144
|
+
}
|
|
55
145
|
function ensureCameraSdk(){if(window.LivekitClient)return Promise.resolve(window.LivekitClient);if(cameraSdkPromise)return cameraSdkPromise;cameraSdkPromise=new Promise(function(resolve,reject){var script=document.createElement('script');script.src='/vendor/livekit-client.umd.js';script.onload=function(){window.LivekitClient?resolve(window.LivekitClient):reject(new Error('LiveKit camera SDK unavailable'))};script.onerror=function(){reject(new Error('LiveKit camera SDK failed to load'))};document.head.appendChild(script)});return cameraSdkPromise}
|
|
56
146
|
function scheduleCameraPublishRetry(){if(cameraPublishRetry||ending||!localVideoStream)return;if(cameraRetryCount>=8){event('camera_published','failed','Giving up after 8 attempts - the media server is not reachable.',{attempts:cameraRetryCount});return}var delay=Math.min(30000,3000*Math.pow(1.6,cameraRetryCount));cameraRetryCount++;cameraPublishRetry=setTimeout(function(){cameraPublishRetry=null;publishLocalVideo().catch(function(){})},delay)}
|
|
57
147
|
function publishLocalVideo(){var pendingCameraRoom=null;if(!localVideoStream||!localVideoStream.getVideoTracks().length)return Promise.resolve();if(cameraRoom)return Promise.resolve();return Promise.all([ensureCameraSdk(),fetch('/api/robopark/camera-token',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({character_id:character,robot_id:robot||null})}).then(function(response){if(!response.ok)throw new Error('camera token '+response.status);return response.json()})]).then(function(parts){var LK=parts[0],info=parts[1],room=new LK.Room();pendingCameraRoom=room;cameraRoom=room;room.on(LK.RoomEvent.Disconnected,function(){if(cameraRoom===room){cameraRoom=null;scheduleCameraPublishRetry()}});return room.connect(info.url,info.token).then(function(){return room.localParticipant.publishTrack(localVideoStream.getVideoTracks()[0],{name:'camera',source:LK.Track.Source.Camera})}).then(function(){cameraRetryCount=0;if(cameraPublishRetry){clearTimeout(cameraPublishRetry);cameraPublishRetry=null}event('camera_published','ok','Camera relay live',{})})}).catch(function(error){try{if(pendingCameraRoom&&pendingCameraRoom.disconnect)pendingCameraRoom.disconnect(true)}catch(_){}pendingCameraRoom=null;cameraRoom=null;event('camera_published','failed',error.message,{});scheduleCameraPublishRetry();throw error})}
|
|
@@ -336,12 +426,13 @@
|
|
|
336
426
|
el('call-mode').value=mode;el('call-robot').value=robot||'none';
|
|
337
427
|
el('call-mode').onchange=function(){if(desired||conversation||connecting)end('mode_changed');applyCallMode()};
|
|
338
428
|
el('call-robot').onchange=function(){robot=this.value==='none'?'':this.value;showRobotVideo();text('f-robot',robot||'missing robot')};
|
|
339
|
-
el('call-microphone').onchange=function(){inputDeviceId=this.value==='default'?'':this.value};
|
|
340
|
-
el('call-camera').onchange=function(){cameraDeviceId=this.value==='default'?'':this.value;startLocalVideo().catch(function(){})};
|
|
341
|
-
el('call-speaker').onchange=function(){outputDeviceId=this.value==='default'?'':this.value};
|
|
342
|
-
el('request-hardware').onclick=function(){
|
|
343
|
-
el('refresh-hardware').onclick=function(){
|
|
344
|
-
|
|
429
|
+
el('call-microphone').onchange=function(){this.dataset.dirty='1';inputDeviceId=this.value==='default'?'':this.value;pushHardwareSelection('audioinput')};
|
|
430
|
+
el('call-camera').onchange=function(){this.dataset.dirty='1';cameraDeviceId=this.value==='default'?'':this.value;pushHardwareSelection('videoinput');startLocalVideo().catch(function(){})};
|
|
431
|
+
el('call-speaker').onchange=function(){this.dataset.dirty='1';outputDeviceId=this.value==='default'?'':this.value;pushHardwareSelection('audiooutput')};
|
|
432
|
+
el('request-hardware').onclick=function(){scanHardware(true).catch(function(){})};
|
|
433
|
+
el('refresh-hardware').onclick=function(){scanHardware(false).catch(function(){})};
|
|
434
|
+
revealVisionCameraPicker();
|
|
435
|
+
applyCallMode();loadProductionRobots();scanHardware(false).then(seedHardwareFromScheduler).catch(function(){});
|
|
345
436
|
function installElevenLabsHardwareRouting(){var sdk=window.ElevenLabsClient;if(!sdk||!sdk.Conversation)return false;if(sdk.Conversation.__roboparkHardware)return true;var nativeStart=sdk.Conversation.startSession.bind(sdk.Conversation);sdk.Conversation.startSession=function(options){return nativeStart(Object.assign({},options||{},{inputDeviceId:inputDeviceId||undefined,outputDeviceId:outputDeviceId||undefined}))};sdk.Conversation.__roboparkHardware=true;return true}
|
|
346
437
|
installElevenLabsHardwareRouting();
|
|
347
438
|
var hardwarePatchTimer=setInterval(function(){if(installElevenLabsHardwareRouting())clearInterval(hardwarePatchTimer)},500);
|
|
File without changes
|
/package/ui/standalone/.next/static/{VHNdBIGajqd6Wv28naVNO → GwsTXhcc2wWhmMKp14ZmG}/_ssgManifest.js
RENAMED
|
File without changes
|