@flowingspring/dsh-voco 0.3.6 → 0.3.8
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/README.md +6 -0
- package/README.zh.md +7 -1
- package/lib/client.js +546 -58
- package/lib/client.js.map +1 -1
- package/lib/plugins/voice-local.js +59 -20
- package/lib/plugins/voice-web.js +2 -1
- package/lib/plugins/voice.js +4 -0
- package/package.json +13 -3
package/lib/client.js
CHANGED
|
@@ -4,35 +4,63 @@ window.__ModuleLoader__.load({
|
|
|
4
4
|
var module = { exports: {} };
|
|
5
5
|
var exports = module.exports;
|
|
6
6
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
|
-
let react_jsx_runtime = require("react/jsx-runtime");
|
|
8
7
|
let react = require("react");
|
|
8
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
9
9
|
let react_dom_client = require("react-dom/client");
|
|
10
10
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
11
11
|
let _deepseek_ai_dsh_client_runtime_client = require("@deepseek-ai/dsh-client-runtime/client");
|
|
12
12
|
//#region \0dsh-css:D:\QUAN\DevCode\Python\Project\dsh\dsh-voco\packages\ui-voice\src\client\VoiceControl.module.css.mjs
|
|
13
|
-
const css$
|
|
14
|
-
const tagId$
|
|
15
|
-
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$
|
|
13
|
+
const css$4 = ".TFZsua_controls{align-items:center;gap:2px;display:inline-flex}.TFZsua_button{touch-action:manipulation;width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:8px;justify-content:center;align-items:center;padding:0;display:inline-flex}.TFZsua_button:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.TFZsua_active{color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-interactive-bg-hover-solid)}.TFZsua_button[data-muted=true]{color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb, currentColor 12%, transparent)}.TFZsua_button[data-push-to-talk=true]{color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-interactive-bg-hover-solid);transform:scale(.94)}.TFZsua_interruptButton,.TFZsua_interruptButton:hover{color:var(--dsw-alias-state-error-primary)}.TFZsua_button[data-muted=true]:hover{background:color-mix(in srgb, currentColor 18%, transparent)}.TFZsua_button[data-state=speaking][data-muted=false]{animation:1.2s ease-in-out infinite TFZsua_voice-pulse}@keyframes TFZsua_voice-pulse{50%{opacity:.55;transform:scale(.94)}}@media (prefers-reduced-motion:reduce){.TFZsua_button[data-state=speaking][data-muted=false]{animation:none}}";
|
|
14
|
+
const tagId$4 = "@flowingspring/dsh-voco/VoiceControl.module.css";
|
|
15
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$4) + "]") === null) {
|
|
16
16
|
const tag = document.createElement("style");
|
|
17
17
|
tag.dataset.plugin = "@flowingspring/dsh-voco";
|
|
18
|
-
tag.dataset.pluginCss = tagId$
|
|
19
|
-
tag.textContent = css$
|
|
18
|
+
tag.dataset.pluginCss = tagId$4;
|
|
19
|
+
tag.textContent = css$4;
|
|
20
20
|
document.head.appendChild(tag);
|
|
21
21
|
}
|
|
22
22
|
var VoiceControl_module_css_default = {
|
|
23
|
-
"interruptButton": "TFZsua_interruptButton",
|
|
24
|
-
"voice-pulse": "TFZsua_voice-pulse",
|
|
25
23
|
"controls": "TFZsua_controls",
|
|
26
24
|
"button": "TFZsua_button",
|
|
27
|
-
"active": "TFZsua_active"
|
|
25
|
+
"active": "TFZsua_active",
|
|
26
|
+
"interruptButton": "TFZsua_interruptButton",
|
|
27
|
+
"voice-pulse": "TFZsua_voice-pulse"
|
|
28
28
|
};
|
|
29
29
|
//#endregion
|
|
30
30
|
//#region ../ui-voice/src/client/VoiceControl.tsx
|
|
31
31
|
/** Start a fresh Voice Session from this Session's location or control the active connection. */
|
|
32
|
-
function VoiceControl({ sessionId, useVoice, startVoice, retryVoice, setVoiceMuted, t, interruptResponse }) {
|
|
32
|
+
function VoiceControl({ sessionId, useVoice, startVoice, retryVoice, beginPushToTalk, endPushToTalk, setVoiceMuted, t, interruptResponse }) {
|
|
33
33
|
const state = useVoice((snapshot) => snapshot.state);
|
|
34
34
|
const activeSessionId = useVoice((snapshot) => snapshot.sessionId);
|
|
35
35
|
const inputMuted = useVoice((snapshot) => snapshot.inputMuted);
|
|
36
|
+
const pushToTalkActive = useVoice((snapshot) => snapshot.pushToTalkActive);
|
|
37
|
+
const timer = (0, react.useRef)(void 0);
|
|
38
|
+
const pointerDown = (0, react.useRef)(false);
|
|
39
|
+
const longPress = (0, react.useRef)(false);
|
|
40
|
+
const suppressClick = (0, react.useRef)(false);
|
|
41
|
+
const clearTimer = () => {
|
|
42
|
+
if (timer.current !== void 0) {
|
|
43
|
+
window.clearTimeout(timer.current);
|
|
44
|
+
timer.current = void 0;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
const releasePushToTalk = () => {
|
|
48
|
+
clearTimer();
|
|
49
|
+
pointerDown.current = false;
|
|
50
|
+
if (longPress.current) {
|
|
51
|
+
longPress.current = false;
|
|
52
|
+
endPushToTalk();
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
(0, react.useEffect)(() => {
|
|
56
|
+
window.addEventListener("blur", releasePushToTalk);
|
|
57
|
+
document.addEventListener("visibilitychange", releasePushToTalk);
|
|
58
|
+
return () => {
|
|
59
|
+
window.removeEventListener("blur", releasePushToTalk);
|
|
60
|
+
document.removeEventListener("visibilitychange", releasePushToTalk);
|
|
61
|
+
releasePushToTalk();
|
|
62
|
+
};
|
|
63
|
+
}, []);
|
|
36
64
|
const toggle = async () => {
|
|
37
65
|
if (state === "error" && activeSessionId !== void 0) {
|
|
38
66
|
try {
|
|
@@ -55,6 +83,35 @@ window.__ModuleLoader__.load({
|
|
|
55
83
|
interruptResponse();
|
|
56
84
|
} catch {}
|
|
57
85
|
};
|
|
86
|
+
const onPointerDown = (event) => {
|
|
87
|
+
if (event.pointerType === "mouse" && event.button !== 0) return;
|
|
88
|
+
pointerDown.current = true;
|
|
89
|
+
longPress.current = false;
|
|
90
|
+
suppressClick.current = false;
|
|
91
|
+
if (typeof event.currentTarget.setPointerCapture === "function") event.currentTarget.setPointerCapture(event.pointerId);
|
|
92
|
+
clearTimer();
|
|
93
|
+
timer.current = window.setTimeout(() => {
|
|
94
|
+
timer.current = void 0;
|
|
95
|
+
if (!pointerDown.current) return;
|
|
96
|
+
longPress.current = true;
|
|
97
|
+
suppressClick.current = true;
|
|
98
|
+
beginPushToTalk(sessionId);
|
|
99
|
+
}, 400);
|
|
100
|
+
};
|
|
101
|
+
const onPointerUp = (event) => {
|
|
102
|
+
releasePushToTalk();
|
|
103
|
+
if (event.currentTarget.hasPointerCapture?.(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
|
|
104
|
+
};
|
|
105
|
+
const onPointerCancel = () => {
|
|
106
|
+
releasePushToTalk();
|
|
107
|
+
};
|
|
108
|
+
const onClick = () => {
|
|
109
|
+
if (suppressClick.current) {
|
|
110
|
+
suppressClick.current = false;
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
toggle();
|
|
114
|
+
};
|
|
58
115
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
59
116
|
className: VoiceControl_module_css_default.controls,
|
|
60
117
|
children: [state === "speaking" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
@@ -88,14 +145,17 @@ window.__ModuleLoader__.load({
|
|
|
88
145
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
89
146
|
type: "button",
|
|
90
147
|
className: `${VoiceControl_module_css_default.button} ${active ? VoiceControl_module_css_default.active : ""}`,
|
|
91
|
-
"aria-label": label,
|
|
148
|
+
"aria-label": pushToTalkActive ? t("control.pushToTalk") : label,
|
|
92
149
|
"aria-pressed": active ? inputMuted : void 0,
|
|
93
150
|
title: label,
|
|
94
151
|
"data-state": state,
|
|
95
152
|
"data-muted": inputMuted,
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
153
|
+
"data-push-to-talk": pushToTalkActive,
|
|
154
|
+
onPointerDown,
|
|
155
|
+
onPointerUp,
|
|
156
|
+
onPointerCancel,
|
|
157
|
+
onLostPointerCapture: onPointerCancel,
|
|
158
|
+
onClick,
|
|
99
159
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
100
160
|
viewBox: "0 0 16 16",
|
|
101
161
|
width: "16",
|
|
@@ -153,33 +213,33 @@ window.__ModuleLoader__.load({
|
|
|
153
213
|
}
|
|
154
214
|
//#endregion
|
|
155
215
|
//#region \0dsh-css:D:\QUAN\DevCode\Python\Project\dsh\dsh-voco\packages\ui-voice\src\client\VoiceNodeViews.module.css.mjs
|
|
156
|
-
const css$
|
|
157
|
-
const tagId$
|
|
158
|
-
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$
|
|
216
|
+
const css$3 = ".Kt2smW_utterance{flex-direction:column;align-items:flex-start;gap:6px;min-width:0;display:flex}.Kt2smW_utterance[data-role=user]{align-items:flex-end}.Kt2smW_bubble{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);max-width:min(525px,82%);color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;white-space:pre-wrap;border-radius:18px;padding:10px 16px;font-size:16px;line-height:24px}.Kt2smW_utterance[data-role=user] .Kt2smW_bubble{background:var(--dsw-specific-bubble);border-color:#0000}.Kt2smW_utterance[data-state=streaming] .Kt2smW_bubble{color:var(--dsw-alias-label-secondary)}.Kt2smW_meta,.Kt2smW_voiceBadge{align-items:center;display:inline-flex}.Kt2smW_meta{color:var(--dsw-alias-label-tertiary);gap:8px;padding:0 5px;font-size:10px;line-height:14px}.Kt2smW_voiceBadge{color:var(--dsw-alias-state-business-primary);letter-spacing:.04em;gap:4px;font-weight:600}.Kt2smW_miniWave{align-items:center;gap:1px;height:10px;display:inline-flex}.Kt2smW_miniWave i{background:currentColor;border-radius:1px;width:1.5px;height:4px}.Kt2smW_miniWave i:nth-child(2){height:8px}.Kt2smW_miniWave i:nth-child(3){height:6px}.Kt2smW_taskCard{box-sizing:border-box;width:fit-content;min-width:0;max-width:min(525px,100%)}.Kt2smW_taskSummary{min-width:0;max-width:100%;color:inherit;cursor:pointer;font:inherit;background:0 0;border:0;border-radius:6px;align-items:center;gap:7px;margin:-3px -5px;padding:3px 5px;display:inline-flex}.Kt2smW_taskSummary:hover{background:var(--dsw-alias-bg-layer-1)}.Kt2smW_taskDot{background:var(--dsw-alias-state-business-primary);border-radius:50%;flex:none;width:7px;height:7px}.Kt2smW_taskCard[data-status=completed] .Kt2smW_taskDot{background:var(--dsw-alias-state-success-primary)}.Kt2smW_taskCard[data-status=failed] .Kt2smW_taskDot{background:var(--dsw-alias-state-error-primary)}.Kt2smW_taskCard[data-status=cancelled] .Kt2smW_taskDot,.Kt2smW_taskCard[data-status=interrupted] .Kt2smW_taskDot{background:var(--dsw-alias-state-warn-primary)}.Kt2smW_taskTitle{min-width:0;color:var(--dsw-alias-label-secondary);text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:600;line-height:20px;overflow:hidden}.Kt2smW_taskStatus{color:var(--dsw-alias-label-tertiary);flex:none;font-size:11px;line-height:16px}.Kt2smW_taskStatus:before{content:\"·\";margin-right:7px}.Kt2smW_taskChevron{border-right:1px solid var(--dsw-alias-label-tertiary);border-bottom:1px solid var(--dsw-alias-label-tertiary);width:6px;height:6px;margin:0 2px 0 1px;transition:transform .12s;transform:rotate(-45deg)}.Kt2smW_taskCard[data-expanded=true] .Kt2smW_taskChevron{transform:rotate(45deg)}.Kt2smW_taskInput,.Kt2smW_taskUpdate{overflow-wrap:anywhere;margin:0;font-size:13px;line-height:20px}.Kt2smW_taskInput{color:var(--dsw-alias-label-primary)}.Kt2smW_taskUpdate{color:var(--dsw-alias-label-secondary);margin-top:4px}.Kt2smW_taskDetails{border-left:1px solid var(--dsw-alias-border-l2);margin:9px 0 0 3px;padding:2px 0 2px 16px}.Kt2smW_taskActions{align-items:center;gap:14px;margin-top:7px;display:flex}.Kt2smW_taskLink{color:var(--dsw-alias-state-business-primary);cursor:pointer;font:inherit;background:0 0;border:0;padding:0;font-size:12px;line-height:18px}.Kt2smW_taskLink:hover:not(:disabled){text-underline-position:from-font;text-decoration:underline}.Kt2smW_taskLink:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.Kt2smW_taskCancel{color:var(--dsw-alias-state-error-primary)}";
|
|
217
|
+
const tagId$3 = "@flowingspring/dsh-voco/VoiceNodeViews.module.css";
|
|
218
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
|
|
159
219
|
const tag = document.createElement("style");
|
|
160
220
|
tag.dataset.plugin = "@flowingspring/dsh-voco";
|
|
161
|
-
tag.dataset.pluginCss = tagId$
|
|
162
|
-
tag.textContent = css$
|
|
221
|
+
tag.dataset.pluginCss = tagId$3;
|
|
222
|
+
tag.textContent = css$3;
|
|
163
223
|
document.head.appendChild(tag);
|
|
164
224
|
}
|
|
165
225
|
var VoiceNodeViews_module_css_default = {
|
|
226
|
+
"taskSummary": "Kt2smW_taskSummary",
|
|
227
|
+
"taskTitle": "Kt2smW_taskTitle",
|
|
166
228
|
"bubble": "Kt2smW_bubble",
|
|
167
|
-
"taskDetails": "Kt2smW_taskDetails",
|
|
168
|
-
"taskUpdate": "Kt2smW_taskUpdate",
|
|
169
|
-
"voiceBadge": "Kt2smW_voiceBadge",
|
|
170
229
|
"meta": "Kt2smW_meta",
|
|
230
|
+
"taskCancel": "Kt2smW_taskCancel",
|
|
231
|
+
"taskStatus": "Kt2smW_taskStatus",
|
|
232
|
+
"taskUpdate": "Kt2smW_taskUpdate",
|
|
171
233
|
"utterance": "Kt2smW_utterance",
|
|
172
|
-
"taskCard": "Kt2smW_taskCard",
|
|
173
234
|
"taskInput": "Kt2smW_taskInput",
|
|
174
|
-
"taskDot": "Kt2smW_taskDot",
|
|
175
|
-
"taskChevron": "Kt2smW_taskChevron",
|
|
176
235
|
"taskLink": "Kt2smW_taskLink",
|
|
177
|
-
"
|
|
178
|
-
"taskActions": "Kt2smW_taskActions",
|
|
236
|
+
"taskChevron": "Kt2smW_taskChevron",
|
|
179
237
|
"miniWave": "Kt2smW_miniWave",
|
|
180
|
-
"
|
|
181
|
-
"
|
|
182
|
-
"
|
|
238
|
+
"taskCard": "Kt2smW_taskCard",
|
|
239
|
+
"taskDot": "Kt2smW_taskDot",
|
|
240
|
+
"taskActions": "Kt2smW_taskActions",
|
|
241
|
+
"taskDetails": "Kt2smW_taskDetails",
|
|
242
|
+
"voiceBadge": "Kt2smW_voiceBadge"
|
|
183
243
|
};
|
|
184
244
|
//#endregion
|
|
185
245
|
//#region ../ui-voice/src/client/VoiceNodeViews.tsx
|
|
@@ -307,21 +367,21 @@ window.__ModuleLoader__.load({
|
|
|
307
367
|
}
|
|
308
368
|
//#endregion
|
|
309
369
|
//#region \0dsh-css:D:\QUAN\DevCode\Python\Project\dsh\dsh-voco\packages\ui-voice\src\client\VoiceOverlay.module.css.mjs
|
|
310
|
-
const css$
|
|
311
|
-
const tagId$
|
|
312
|
-
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$
|
|
370
|
+
const css$2 = ".GPPB2G_root{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-overlay);max-width:min(260px,100vw - 36px);min-height:36px;box-shadow:var(--dsw-shadow-lv2);color:var(--dsw-alias-label-primary);pointer-events:auto;border-radius:12px;align-items:center;gap:8px;padding:4px 6px 4px 12px;font-size:12px;line-height:18px;display:flex;position:absolute;bottom:18px;right:18px}.GPPB2G_wave{width:18px;height:18px;color:var(--dsw-alias-state-business-primary);flex:none;justify-content:center;align-items:center;gap:2px;display:inline-flex}.GPPB2G_wave i{background:currentColor;border-radius:1px;width:2px;height:5px;animation:.9s ease-in-out infinite alternate GPPB2G_voice-wave}.GPPB2G_wave i:nth-child(2){height:11px;animation-delay:-300ms}.GPPB2G_wave i:nth-child(3){height:8px;animation-delay:-600ms}.GPPB2G_wave i:nth-child(4){height:4px;animation-delay:-150ms}.GPPB2G_root[data-state=connecting] .GPPB2G_wave,.GPPB2G_root[data-state=error] .GPPB2G_wave{opacity:.55}.GPPB2G_root[data-state=error] .GPPB2G_wave{color:var(--dsw-alias-state-error-primary)}.GPPB2G_status{text-overflow:ellipsis;white-space:nowrap;flex:0 auto;min-width:0;overflow:hidden}.GPPB2G_root[data-muted=true] .GPPB2G_wave{color:var(--dsw-alias-state-error-primary);opacity:.65}.GPPB2G_root[data-muted=true] .GPPB2G_status{color:var(--dsw-alias-state-error-primary);font-weight:600}.GPPB2G_root[data-muted=true] .GPPB2G_wave i{animation:none}.GPPB2G_stop{min-height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;font:inherit;background:0 0;border:0;border-radius:7px;flex:none;padding:0 8px}.GPPB2G_stop:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.GPPB2G_stop{color:var(--dsw-alias-state-error-primary)}@keyframes GPPB2G_voice-wave{to{transform:scaleY(.55)}}@media (prefers-reduced-motion:reduce){.GPPB2G_wave i{animation:none}}";
|
|
371
|
+
const tagId$2 = "@flowingspring/dsh-voco/VoiceOverlay.module.css";
|
|
372
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
|
|
313
373
|
const tag = document.createElement("style");
|
|
314
374
|
tag.dataset.plugin = "@flowingspring/dsh-voco";
|
|
315
|
-
tag.dataset.pluginCss = tagId$
|
|
316
|
-
tag.textContent = css$
|
|
375
|
+
tag.dataset.pluginCss = tagId$2;
|
|
376
|
+
tag.textContent = css$2;
|
|
317
377
|
document.head.appendChild(tag);
|
|
318
378
|
}
|
|
319
379
|
var VoiceOverlay_module_css_default = {
|
|
320
|
-
"
|
|
380
|
+
"root": "GPPB2G_root",
|
|
321
381
|
"wave": "GPPB2G_wave",
|
|
322
382
|
"status": "GPPB2G_status",
|
|
323
|
-
"
|
|
324
|
-
"
|
|
383
|
+
"stop": "GPPB2G_stop",
|
|
384
|
+
"voice-wave": "GPPB2G_voice-wave"
|
|
325
385
|
};
|
|
326
386
|
//#endregion
|
|
327
387
|
//#region ../ui-voice/src/client/VoiceOverlay.tsx
|
|
@@ -370,30 +430,30 @@ window.__ModuleLoader__.load({
|
|
|
370
430
|
}
|
|
371
431
|
//#endregion
|
|
372
432
|
//#region \0dsh-css:D:\QUAN\DevCode\Python\Project\dsh\dsh-voco\packages\ui-voice\src\client\VoiceSessionMarkers.module.css.mjs
|
|
373
|
-
const css = "._0brRca_slot{flex:none;justify-content:center;align-items:center;width:16px;height:20px;display:inline-flex}._0brRca_marker{width:16px;height:16px;color:var(--dsw-alias-state-business-primary);pointer-events:none;justify-content:center;align-items:center;display:inline-flex}._0brRca_marker svg{width:14px;height:14px;display:block}._0brRca_toggle{width:18px;height:18px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:4px;flex:none;justify-content:center;align-items:center;margin-left:1px;padding:0;font-size:16px;line-height:16px;display:inline-flex}._0brRca_toggle:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}._0brRca_children{flex-direction:column;gap:2px;margin:2px 0 2px 20px;display:flex}._0brRca_child{min-width:0;height:30px;color:var(--dsw-alias-label-secondary);cursor:pointer;text-align:left;font:inherit;background:0 0;border:0;border-radius:8px;align-items:center;gap:8px;padding:0 10px 0 12px;display:flex;position:relative}._0brRca_childMain{min-width:0;height:30px;color:inherit;cursor:pointer;text-align:left;font:inherit;background:0 0;border:0;flex:1;align-items:center;gap:8px;padding:0;display:flex}._0brRca_child:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}._0brRca_childMain:disabled{color:var(--dsw-alias-label-tertiary);cursor:not-allowed;opacity:.72}._0brRca_child[aria-current=page]{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-selected)}._0brRca_childDot{background:var(--dsw-alias-label-tertiary);border-radius:50%;flex:none;width:6px;height:6px}._0brRca_childDot[data-activity=running]{background:var(--dsw-alias-state-success-primary)}._0brRca_childLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}._0brRca_childTime{color:var(--dsw-alias-label-tertiary);flex:none;margin-left:auto;font-size:12px;line-height:20px}._0brRca_child[data-menu-open=true] ._0brRca_childTime,._0brRca_child:hover ._0brRca_childTime{display:none}._0brRca_childActions{flex:none;align-items:center;display:none;position:absolute;right:10px}._0brRca_child:hover ._0brRca_childActions,._0brRca_child[data-menu-open=true] ._0brRca_childActions{display:inline-flex}._0brRca_childMenuButton{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:4px;justify-content:center;align-items:center;padding:0;display:inline-flex}._0brRca_childMenuButton:hover{color:var(--dsw-alias-label-primary)}._0brRca_deleteAction:not(:disabled){color:var(--dsw-alias-state-error-primary)}._0brRca_deleteStatus{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}._0brRca_deleteError{color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}";
|
|
374
|
-
const tagId = "@flowingspring/dsh-voco/VoiceSessionMarkers.module.css";
|
|
375
|
-
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
433
|
+
const css$1 = "._0brRca_slot{flex:none;justify-content:center;align-items:center;width:16px;height:20px;display:inline-flex}._0brRca_marker{width:16px;height:16px;color:var(--dsw-alias-state-business-primary);pointer-events:none;justify-content:center;align-items:center;display:inline-flex}._0brRca_marker svg{width:14px;height:14px;display:block}._0brRca_toggle{width:18px;height:18px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:4px;flex:none;justify-content:center;align-items:center;margin-left:1px;padding:0;font-size:16px;line-height:16px;display:inline-flex}._0brRca_toggle:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}._0brRca_children{flex-direction:column;gap:2px;margin:2px 0 2px 20px;display:flex}._0brRca_child{min-width:0;height:30px;color:var(--dsw-alias-label-secondary);cursor:pointer;text-align:left;font:inherit;background:0 0;border:0;border-radius:8px;align-items:center;gap:8px;padding:0 10px 0 12px;display:flex;position:relative}._0brRca_childMain{min-width:0;height:30px;color:inherit;cursor:pointer;text-align:left;font:inherit;background:0 0;border:0;flex:1;align-items:center;gap:8px;padding:0;display:flex}._0brRca_child:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}._0brRca_childMain:disabled{color:var(--dsw-alias-label-tertiary);cursor:not-allowed;opacity:.72}._0brRca_child[aria-current=page]{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-selected)}._0brRca_childDot{background:var(--dsw-alias-label-tertiary);border-radius:50%;flex:none;width:6px;height:6px}._0brRca_childDot[data-activity=running]{background:var(--dsw-alias-state-success-primary)}._0brRca_childLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}._0brRca_childTime{color:var(--dsw-alias-label-tertiary);flex:none;margin-left:auto;font-size:12px;line-height:20px}._0brRca_child[data-menu-open=true] ._0brRca_childTime,._0brRca_child:hover ._0brRca_childTime{display:none}._0brRca_childActions{flex:none;align-items:center;display:none;position:absolute;right:10px}._0brRca_child:hover ._0brRca_childActions,._0brRca_child[data-menu-open=true] ._0brRca_childActions{display:inline-flex}._0brRca_childMenuButton{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:4px;justify-content:center;align-items:center;padding:0;display:inline-flex}._0brRca_childMenuButton:hover{color:var(--dsw-alias-label-primary)}._0brRca_deleteAction:not(:disabled){color:var(--dsw-alias-state-error-primary)}._0brRca_deleteStatus{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}._0brRca_deleteError{color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}";
|
|
434
|
+
const tagId$1 = "@flowingspring/dsh-voco/VoiceSessionMarkers.module.css";
|
|
435
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
376
436
|
const tag = document.createElement("style");
|
|
377
437
|
tag.dataset.plugin = "@flowingspring/dsh-voco";
|
|
378
|
-
tag.dataset.pluginCss = tagId;
|
|
379
|
-
tag.textContent = css;
|
|
438
|
+
tag.dataset.pluginCss = tagId$1;
|
|
439
|
+
tag.textContent = css$1;
|
|
380
440
|
document.head.appendChild(tag);
|
|
381
441
|
}
|
|
382
442
|
var VoiceSessionMarkers_module_css_default = {
|
|
383
|
-
"
|
|
384
|
-
"deleteAction": "_0brRca_deleteAction",
|
|
385
|
-
"child": "_0brRca_child",
|
|
386
|
-
"childMain": "_0brRca_childMain",
|
|
443
|
+
"toggle": "_0brRca_toggle",
|
|
387
444
|
"children": "_0brRca_children",
|
|
445
|
+
"marker": "_0brRca_marker",
|
|
446
|
+
"child": "_0brRca_child",
|
|
388
447
|
"childLabel": "_0brRca_childLabel",
|
|
389
|
-
"childTime": "_0brRca_childTime",
|
|
390
448
|
"childActions": "_0brRca_childActions",
|
|
449
|
+
"childMenuButton": "_0brRca_childMenuButton",
|
|
391
450
|
"deleteStatus": "_0brRca_deleteStatus",
|
|
451
|
+
"deleteAction": "_0brRca_deleteAction",
|
|
452
|
+
"childDot": "_0brRca_childDot",
|
|
453
|
+
"childTime": "_0brRca_childTime",
|
|
392
454
|
"deleteError": "_0brRca_deleteError",
|
|
393
|
-
"
|
|
394
|
-
"
|
|
395
|
-
"toggle": "_0brRca_toggle",
|
|
396
|
-
"childDot": "_0brRca_childDot"
|
|
455
|
+
"childMain": "_0brRca_childMain",
|
|
456
|
+
"slot": "_0brRca_slot"
|
|
397
457
|
};
|
|
398
458
|
//#endregion
|
|
399
459
|
//#region ../ui-voice/src/client/VoiceSessionMarkers.tsx
|
|
@@ -857,10 +917,162 @@ window.__ModuleLoader__.load({
|
|
|
857
917
|
return marker;
|
|
858
918
|
}
|
|
859
919
|
//#endregion
|
|
920
|
+
//#region \0dsh-css:D:\QUAN\DevCode\Python\Project\dsh\dsh-voco\packages\ui-voice\src\client\VocoSettingsCard.module.css.mjs
|
|
921
|
+
const css = ".G5LlXq_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}.G5LlXq_card:hover{border-color:var(--dsw-alias-label-dimmed)}.G5LlXq_cardOpen{border-color:var(--dsw-alias-label-dimmed);background:var(--dsw-alias-bg-layer-2)}.G5LlXq_header{appearance:none;width:100%;color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.G5LlXq_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.G5LlXq_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.G5LlXq_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.G5LlXq_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.G5LlXq_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.G5LlXq_chevronOpen{transform:rotate(180deg)}.G5LlXq_body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}.G5LlXq_readOnly{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}.G5LlXq_pending,.G5LlXq_badge{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);white-space:nowrap;border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.G5LlXq_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.G5LlXq_fieldHead{align-items:center;gap:8px;display:flex}.G5LlXq_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.G5LlXq_badgeMuted{color:var(--dsw-alias-label-tertiary);white-space:nowrap;border-radius:999px;padding:1px 8px;font-size:11px;line-height:17px}.G5LlXq_input{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);height:34px;color:var(--dsw-alias-label-primary);font:inherit;border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.G5LlXq_input:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.G5LlXq_input:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.G5LlXq_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}.G5LlXq_providerDetails{flex-direction:column;gap:4px;margin:6px 0 0;display:flex}.G5LlXq_providerDetail{grid-template-columns:88px minmax(0,1fr);gap:8px;font-size:12px;line-height:1.5;display:grid}.G5LlXq_providerDetail dt{color:var(--dsw-alias-label-tertiary)}.G5LlXq_providerDetail dd{overflow-wrap:anywhere;min-width:0;color:var(--dsw-alias-label-secondary);margin:0}.G5LlXq_footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}.G5LlXq_failed{min-width:0;color:var(--dsw-alias-label-error);flex:1;margin:0;font-size:12px;line-height:1.5}.G5LlXq_discard,.G5LlXq_save{appearance:none;font:inherit;cursor:pointer;border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.G5LlXq_discard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}.G5LlXq_discard:hover:not(:disabled){border-color:var(--dsw-alias-label-dimmed);color:var(--dsw-alias-label-primary)}.G5LlXq_save{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.G5LlXq_discard:disabled,.G5LlXq_save:disabled{opacity:.4;cursor:default}.G5LlXq_discard:focus-visible,.G5LlXq_save:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}";
|
|
922
|
+
const tagId = "@flowingspring/dsh-voco/VocoSettingsCard.module.css";
|
|
923
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
924
|
+
const tag = document.createElement("style");
|
|
925
|
+
tag.dataset.plugin = "@flowingspring/dsh-voco";
|
|
926
|
+
tag.dataset.pluginCss = tagId;
|
|
927
|
+
tag.textContent = css;
|
|
928
|
+
document.head.appendChild(tag);
|
|
929
|
+
}
|
|
930
|
+
var VocoSettingsCard_module_css_default = {
|
|
931
|
+
"save": "G5LlXq_save",
|
|
932
|
+
"chevron": "G5LlXq_chevron",
|
|
933
|
+
"hint": "G5LlXq_hint",
|
|
934
|
+
"header": "G5LlXq_header",
|
|
935
|
+
"body": "G5LlXq_body",
|
|
936
|
+
"pending": "G5LlXq_pending",
|
|
937
|
+
"headText": "G5LlXq_headText",
|
|
938
|
+
"chevronOpen": "G5LlXq_chevronOpen",
|
|
939
|
+
"description": "G5LlXq_description",
|
|
940
|
+
"readOnly": "G5LlXq_readOnly",
|
|
941
|
+
"label": "G5LlXq_label",
|
|
942
|
+
"providerDetails": "G5LlXq_providerDetails",
|
|
943
|
+
"failed": "G5LlXq_failed",
|
|
944
|
+
"badgeMuted": "G5LlXq_badgeMuted",
|
|
945
|
+
"fieldHead": "G5LlXq_fieldHead",
|
|
946
|
+
"providerDetail": "G5LlXq_providerDetail",
|
|
947
|
+
"cardOpen": "G5LlXq_cardOpen",
|
|
948
|
+
"footer": "G5LlXq_footer",
|
|
949
|
+
"field": "G5LlXq_field",
|
|
950
|
+
"input": "G5LlXq_input",
|
|
951
|
+
"badge": "G5LlXq_badge",
|
|
952
|
+
"name": "G5LlXq_name",
|
|
953
|
+
"discard": "G5LlXq_discard",
|
|
954
|
+
"card": "G5LlXq_card"
|
|
955
|
+
};
|
|
956
|
+
//#endregion
|
|
957
|
+
//#region ../ui-voice/src/client/VocoSettingsCard.tsx
|
|
958
|
+
/** Official plugin-settings slot contribution for the Voco credential. */
|
|
959
|
+
function VocoSettingsCard({ useVocoSettings, editApiKey, save, discard, t }) {
|
|
960
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
961
|
+
const state = useVocoSettings((value) => value);
|
|
962
|
+
if (!state.available) return null;
|
|
963
|
+
const title = t("settings.title");
|
|
964
|
+
const disabled = !state.writable || !state.apiKeyWritable || state.saving;
|
|
965
|
+
const saveDisabled = !state.dirty || disabled;
|
|
966
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
967
|
+
className: `${VocoSettingsCard_module_css_default.card} ${open ? VocoSettingsCard_module_css_default.cardOpen : ""}`,
|
|
968
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
969
|
+
type: "button",
|
|
970
|
+
className: VocoSettingsCard_module_css_default.header,
|
|
971
|
+
"aria-expanded": open,
|
|
972
|
+
"aria-label": `${t(open ? "settings.collapse" : "settings.expand")}: ${title}`,
|
|
973
|
+
onClick: () => {
|
|
974
|
+
setOpen(!open);
|
|
975
|
+
},
|
|
976
|
+
children: [
|
|
977
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
978
|
+
className: VocoSettingsCard_module_css_default.headText,
|
|
979
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
980
|
+
className: VocoSettingsCard_module_css_default.name,
|
|
981
|
+
children: title
|
|
982
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
983
|
+
className: VocoSettingsCard_module_css_default.description,
|
|
984
|
+
children: t("settings.description")
|
|
985
|
+
})]
|
|
986
|
+
}),
|
|
987
|
+
state.dirty && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
988
|
+
className: VocoSettingsCard_module_css_default.pending,
|
|
989
|
+
children: t("settings.unsaved")
|
|
990
|
+
}),
|
|
991
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { className: `${VocoSettingsCard_module_css_default.chevron} ${open ? VocoSettingsCard_module_css_default.chevronOpen : ""}` })
|
|
992
|
+
]
|
|
993
|
+
}), open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
994
|
+
className: VocoSettingsCard_module_css_default.body,
|
|
995
|
+
children: [
|
|
996
|
+
!state.writable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
997
|
+
className: VocoSettingsCard_module_css_default.readOnly,
|
|
998
|
+
role: "status",
|
|
999
|
+
children: t("settings.readOnly")
|
|
1000
|
+
}),
|
|
1001
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1002
|
+
className: VocoSettingsCard_module_css_default.field,
|
|
1003
|
+
children: [
|
|
1004
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1005
|
+
className: VocoSettingsCard_module_css_default.fieldHead,
|
|
1006
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
1007
|
+
className: VocoSettingsCard_module_css_default.label,
|
|
1008
|
+
htmlFor: "voco-siliconflow-api-key",
|
|
1009
|
+
children: t("settings.apiKey")
|
|
1010
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1011
|
+
className: state.apiKeyConfigured ? VocoSettingsCard_module_css_default.badge : VocoSettingsCard_module_css_default.badgeMuted,
|
|
1012
|
+
children: t(state.apiKeyConfigured ? "settings.apiKeySet" : "settings.apiKeyUnset")
|
|
1013
|
+
})]
|
|
1014
|
+
}),
|
|
1015
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1016
|
+
id: "voco-siliconflow-api-key",
|
|
1017
|
+
className: VocoSettingsCard_module_css_default.input,
|
|
1018
|
+
type: "password",
|
|
1019
|
+
autoComplete: "off",
|
|
1020
|
+
value: state.apiKey,
|
|
1021
|
+
disabled,
|
|
1022
|
+
onChange: (event) => {
|
|
1023
|
+
editApiKey(event.target.value);
|
|
1024
|
+
}
|
|
1025
|
+
}),
|
|
1026
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1027
|
+
className: VocoSettingsCard_module_css_default.hint,
|
|
1028
|
+
children: t("settings.apiKeyHint")
|
|
1029
|
+
}),
|
|
1030
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("dl", {
|
|
1031
|
+
className: VocoSettingsCard_module_css_default.providerDetails,
|
|
1032
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1033
|
+
className: VocoSettingsCard_module_css_default.providerDetail,
|
|
1034
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("settings.platform") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: t("settings.platformValue") })]
|
|
1035
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1036
|
+
className: VocoSettingsCard_module_css_default.providerDetail,
|
|
1037
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("settings.model") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: t("settings.modelValue") })]
|
|
1038
|
+
})]
|
|
1039
|
+
})
|
|
1040
|
+
]
|
|
1041
|
+
}),
|
|
1042
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1043
|
+
className: VocoSettingsCard_module_css_default.footer,
|
|
1044
|
+
children: [
|
|
1045
|
+
state.failed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1046
|
+
className: VocoSettingsCard_module_css_default.failed,
|
|
1047
|
+
role: "status",
|
|
1048
|
+
children: t("settings.saveFailed")
|
|
1049
|
+
}),
|
|
1050
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1051
|
+
type: "button",
|
|
1052
|
+
className: VocoSettingsCard_module_css_default.discard,
|
|
1053
|
+
disabled: !state.dirty || state.saving,
|
|
1054
|
+
onClick: discard,
|
|
1055
|
+
children: t("settings.discard")
|
|
1056
|
+
}),
|
|
1057
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1058
|
+
type: "button",
|
|
1059
|
+
className: VocoSettingsCard_module_css_default.save,
|
|
1060
|
+
disabled: saveDisabled,
|
|
1061
|
+
onClick: save,
|
|
1062
|
+
children: t(state.saving ? "settings.saving" : "settings.save")
|
|
1063
|
+
})
|
|
1064
|
+
]
|
|
1065
|
+
})
|
|
1066
|
+
]
|
|
1067
|
+
})]
|
|
1068
|
+
});
|
|
1069
|
+
}
|
|
1070
|
+
//#endregion
|
|
860
1071
|
//#region ../ui-voice/src/client/voice-controller.ts
|
|
861
1072
|
const INITIAL_SNAPSHOT = {
|
|
862
1073
|
state: "off",
|
|
863
1074
|
inputMuted: false,
|
|
1075
|
+
pushToTalkActive: false,
|
|
864
1076
|
textById: {}
|
|
865
1077
|
};
|
|
866
1078
|
/** Own the single browser microphone, provider WebSocket, playback queue, and live transcript feed. */
|
|
@@ -875,6 +1087,9 @@ window.__ModuleLoader__.load({
|
|
|
875
1087
|
pendingText = [];
|
|
876
1088
|
onConversationStarted;
|
|
877
1089
|
conversationStarted = false;
|
|
1090
|
+
pushToTalkOrigin;
|
|
1091
|
+
pushToTalkPending = false;
|
|
1092
|
+
pushToTalkActive = false;
|
|
878
1093
|
constructor(options = {}) {
|
|
879
1094
|
this.onConversationStarted = options.onConversationStarted;
|
|
880
1095
|
}
|
|
@@ -894,6 +1109,101 @@ window.__ModuleLoader__.load({
|
|
|
894
1109
|
async start(sessionId) {
|
|
895
1110
|
await this.open(sessionId, false);
|
|
896
1111
|
}
|
|
1112
|
+
/** Begin a temporary manually committed utterance after a long press. */
|
|
1113
|
+
beginPushToTalk(sessionId) {
|
|
1114
|
+
if (this.pushToTalkPending || this.pushToTalkActive) return;
|
|
1115
|
+
const state = this.snapshot.state;
|
|
1116
|
+
if (state === "off") {
|
|
1117
|
+
this.pushToTalkOrigin = "off";
|
|
1118
|
+
this.pushToTalkPending = true;
|
|
1119
|
+
this.open(sessionId, true).catch(() => {});
|
|
1120
|
+
return;
|
|
1121
|
+
}
|
|
1122
|
+
if (state === "error") {
|
|
1123
|
+
const activeSessionId = this.snapshot.sessionId;
|
|
1124
|
+
if (activeSessionId === void 0) return;
|
|
1125
|
+
this.pushToTalkOrigin = this.snapshot.inputMuted ? "muted" : "hands-free";
|
|
1126
|
+
this.pushToTalkPending = true;
|
|
1127
|
+
this.open(activeSessionId, true).catch(() => {});
|
|
1128
|
+
return;
|
|
1129
|
+
}
|
|
1130
|
+
this.pushToTalkOrigin = this.snapshot.inputMuted ? "muted" : "hands-free";
|
|
1131
|
+
this.pushToTalkPending = true;
|
|
1132
|
+
if (state === "connecting") this.setInputMutedWithoutCommit(true);
|
|
1133
|
+
this.activatePushToTalk();
|
|
1134
|
+
}
|
|
1135
|
+
/** Finish or cancel the temporary manually committed utterance. */
|
|
1136
|
+
endPushToTalk() {
|
|
1137
|
+
if (!this.pushToTalkPending && !this.pushToTalkActive) return;
|
|
1138
|
+
if (!this.pushToTalkActive) {
|
|
1139
|
+
this.pushToTalkPending = false;
|
|
1140
|
+
this.restorePendingInputState();
|
|
1141
|
+
return;
|
|
1142
|
+
}
|
|
1143
|
+
const transport = this.transport;
|
|
1144
|
+
if (transport === void 0) {
|
|
1145
|
+
this.pushToTalkActive = false;
|
|
1146
|
+
this.pushToTalkPending = false;
|
|
1147
|
+
this.publish({
|
|
1148
|
+
...this.snapshot,
|
|
1149
|
+
pushToTalkActive: false
|
|
1150
|
+
});
|
|
1151
|
+
return;
|
|
1152
|
+
}
|
|
1153
|
+
const origin = this.pushToTalkOrigin;
|
|
1154
|
+
const restoreMuted = origin === "off" || origin === "muted";
|
|
1155
|
+
try {
|
|
1156
|
+
transport.commitAudio();
|
|
1157
|
+
transport.setInputMuted(restoreMuted, false);
|
|
1158
|
+
} catch {
|
|
1159
|
+
this.handleUnexpectedClose();
|
|
1160
|
+
return;
|
|
1161
|
+
}
|
|
1162
|
+
this.pushToTalkActive = false;
|
|
1163
|
+
this.pushToTalkPending = false;
|
|
1164
|
+
this.pushToTalkOrigin = void 0;
|
|
1165
|
+
this.publish({
|
|
1166
|
+
...this.snapshot,
|
|
1167
|
+
inputMuted: restoreMuted,
|
|
1168
|
+
pushToTalkActive: false
|
|
1169
|
+
});
|
|
1170
|
+
}
|
|
1171
|
+
activatePushToTalk() {
|
|
1172
|
+
if (!this.pushToTalkPending || this.pushToTalkActive || this.transport === void 0) return;
|
|
1173
|
+
try {
|
|
1174
|
+
this.transport.setInputMuted(false, false);
|
|
1175
|
+
this.transport.beginManualUtterance();
|
|
1176
|
+
} catch {
|
|
1177
|
+
this.handleUnexpectedClose();
|
|
1178
|
+
return;
|
|
1179
|
+
}
|
|
1180
|
+
this.pushToTalkActive = true;
|
|
1181
|
+
this.publish({
|
|
1182
|
+
...this.snapshot,
|
|
1183
|
+
inputMuted: false,
|
|
1184
|
+
pushToTalkActive: true
|
|
1185
|
+
});
|
|
1186
|
+
}
|
|
1187
|
+
restorePendingInputState() {
|
|
1188
|
+
const origin = this.pushToTalkOrigin;
|
|
1189
|
+
if (origin === void 0) return;
|
|
1190
|
+
const restoreMuted = origin === "off" || origin === "muted";
|
|
1191
|
+
(this.transport ?? this.openingTransport)?.setInputMuted(restoreMuted, false);
|
|
1192
|
+
this.pushToTalkOrigin = void 0;
|
|
1193
|
+
this.publish({
|
|
1194
|
+
...this.snapshot,
|
|
1195
|
+
inputMuted: restoreMuted,
|
|
1196
|
+
pushToTalkActive: false
|
|
1197
|
+
});
|
|
1198
|
+
}
|
|
1199
|
+
setInputMutedWithoutCommit(muted) {
|
|
1200
|
+
this.openingTransport?.setInputMuted(muted, false);
|
|
1201
|
+
this.transport?.setInputMuted(muted, false);
|
|
1202
|
+
if (this.snapshot.inputMuted !== muted) this.publish({
|
|
1203
|
+
...this.snapshot,
|
|
1204
|
+
inputMuted: muted
|
|
1205
|
+
});
|
|
1206
|
+
}
|
|
897
1207
|
async open(sessionId, inputMuted) {
|
|
898
1208
|
const generation = ++this.generation;
|
|
899
1209
|
this.pendingText.splice(0);
|
|
@@ -909,6 +1219,7 @@ window.__ModuleLoader__.load({
|
|
|
909
1219
|
this.publish({
|
|
910
1220
|
state: "connecting",
|
|
911
1221
|
inputMuted,
|
|
1222
|
+
pushToTalkActive: false,
|
|
912
1223
|
sessionId,
|
|
913
1224
|
textById: {}
|
|
914
1225
|
});
|
|
@@ -939,7 +1250,8 @@ window.__ModuleLoader__.load({
|
|
|
939
1250
|
this.openingTransport = void 0;
|
|
940
1251
|
this.transport = transport;
|
|
941
1252
|
for (const text of this.pendingText.splice(0)) transport.submitText(text);
|
|
942
|
-
this.
|
|
1253
|
+
if (this.pushToTalkPending) this.activatePushToTalk();
|
|
1254
|
+
if (this.snapshot.state !== "error") this.setState("listening");
|
|
943
1255
|
} catch (cause) {
|
|
944
1256
|
if (generation !== this.generation) return;
|
|
945
1257
|
this.setState("error");
|
|
@@ -995,6 +1307,9 @@ window.__ModuleLoader__.load({
|
|
|
995
1307
|
this.openingAbort = void 0;
|
|
996
1308
|
this.publish(INITIAL_SNAPSHOT);
|
|
997
1309
|
this.pendingText.splice(0);
|
|
1310
|
+
this.pushToTalkPending = false;
|
|
1311
|
+
this.pushToTalkActive = false;
|
|
1312
|
+
this.pushToTalkOrigin = void 0;
|
|
998
1313
|
await this.closeTransport();
|
|
999
1314
|
}
|
|
1000
1315
|
async closeTransport() {
|
|
@@ -1014,6 +1329,13 @@ window.__ModuleLoader__.load({
|
|
|
1014
1329
|
}
|
|
1015
1330
|
handleUnexpectedClose() {
|
|
1016
1331
|
this.openingAbort?.abort();
|
|
1332
|
+
this.pushToTalkPending = false;
|
|
1333
|
+
this.pushToTalkActive = false;
|
|
1334
|
+
this.pushToTalkOrigin = void 0;
|
|
1335
|
+
if (this.snapshot.pushToTalkActive) this.publish({
|
|
1336
|
+
...this.snapshot,
|
|
1337
|
+
pushToTalkActive: false
|
|
1338
|
+
});
|
|
1017
1339
|
this.setState("error");
|
|
1018
1340
|
this.closeTransport().catch((cause) => {
|
|
1019
1341
|
console.error("voice transport cleanup failed:", cause);
|
|
@@ -1144,6 +1466,14 @@ window.__ModuleLoader__.load({
|
|
|
1144
1466
|
const chunks = [];
|
|
1145
1467
|
const playing = /* @__PURE__ */ new Set();
|
|
1146
1468
|
const transport = {
|
|
1469
|
+
beginManualUtterance: () => {
|
|
1470
|
+
if (socket.readyState !== WebSocket.OPEN) throw new Error("voice transport is not open");
|
|
1471
|
+
socket.send(JSON.stringify({ type: "audio.push-to-talk.start" }));
|
|
1472
|
+
},
|
|
1473
|
+
commitAudio: () => {
|
|
1474
|
+
if (socket.readyState !== WebSocket.OPEN) throw new Error("voice transport is not open");
|
|
1475
|
+
socket.send(JSON.stringify({ type: "audio.commit" }));
|
|
1476
|
+
},
|
|
1147
1477
|
cancelTask: (taskId) => {
|
|
1148
1478
|
if (socket.readyState !== WebSocket.OPEN) throw new Error("voice transport is not open");
|
|
1149
1479
|
socket.send(JSON.stringify({
|
|
@@ -1156,12 +1486,12 @@ window.__ModuleLoader__.load({
|
|
|
1156
1486
|
socket.send(JSON.stringify({ type: "response.interrupt" }));
|
|
1157
1487
|
stopPlayback();
|
|
1158
1488
|
},
|
|
1159
|
-
setInputMuted: (muted) => {
|
|
1489
|
+
setInputMuted: (muted, commit = true) => {
|
|
1160
1490
|
if (inputMuted === muted) return;
|
|
1161
1491
|
inputMuted = muted;
|
|
1162
1492
|
chunks.splice(0);
|
|
1163
1493
|
for (const track of stream?.getTracks() ?? []) track.enabled = !muted;
|
|
1164
|
-
if (muted && !stopped && socket.readyState === WebSocket.OPEN) socket.send(JSON.stringify({ type: "audio.commit" }));
|
|
1494
|
+
if (muted && commit && !stopped && socket.readyState === WebSocket.OPEN) socket.send(JSON.stringify({ type: "audio.commit" }));
|
|
1165
1495
|
},
|
|
1166
1496
|
submitText: (text) => {
|
|
1167
1497
|
if (socket.readyState !== WebSocket.OPEN) throw new Error("voice transport is not open");
|
|
@@ -1841,6 +2171,7 @@ registerProcessor('dsh-pcm-capture', DshPcmCaptureProcessor)
|
|
|
1841
2171
|
"control.interrupt": "打断播放",
|
|
1842
2172
|
"control.mute": "静音麦克风",
|
|
1843
2173
|
"control.unmute": "解除静音",
|
|
2174
|
+
"control.pushToTalk": "按住说话中,松开发送",
|
|
1844
2175
|
"overlay.connecting": "正在连接语音",
|
|
1845
2176
|
"overlay.listening": "正在聆听",
|
|
1846
2177
|
"overlay.speaking": "正在回复",
|
|
@@ -1862,7 +2193,25 @@ registerProcessor('dsh-pcm-capture', DshPcmCaptureProcessor)
|
|
|
1862
2193
|
"task.expand": "展开后台处理详情",
|
|
1863
2194
|
"task.collapse": "收起后台处理详情",
|
|
1864
2195
|
"task.cancel": "取消任务",
|
|
1865
|
-
"task.open": "查看后台详情"
|
|
2196
|
+
"task.open": "查看后台详情",
|
|
2197
|
+
"settings.title": "语音助手(Voco)",
|
|
2198
|
+
"settings.description": "语音识别供应商配置。",
|
|
2199
|
+
"settings.expand": "展开设置",
|
|
2200
|
+
"settings.collapse": "收起设置",
|
|
2201
|
+
"settings.unsaved": "未保存",
|
|
2202
|
+
"settings.readOnly": "本部署的设置为只读。",
|
|
2203
|
+
"settings.apiKey": "API Key",
|
|
2204
|
+
"settings.apiKeyHint": "安全保存到 DSH 凭据库。留空表示保持当前密钥。",
|
|
2205
|
+
"settings.platform": "API 平台",
|
|
2206
|
+
"settings.platformValue": "硅基流动",
|
|
2207
|
+
"settings.model": "语音识别模型",
|
|
2208
|
+
"settings.modelValue": "XingChenAGI/XingChenASR-V3.2-Ultra(免费)",
|
|
2209
|
+
"settings.apiKeySet": "已配置密钥。",
|
|
2210
|
+
"settings.apiKeyUnset": "未配置密钥。",
|
|
2211
|
+
"settings.save": "保存",
|
|
2212
|
+
"settings.saving": "保存中…",
|
|
2213
|
+
"settings.discard": "放弃修改",
|
|
2214
|
+
"settings.saveFailed": "密钥保存失败,已保留供你重试。"
|
|
1866
2215
|
};
|
|
1867
2216
|
/** English dictionary, checked complete against the zh key set. */
|
|
1868
2217
|
const en = {
|
|
@@ -1872,6 +2221,7 @@ registerProcessor('dsh-pcm-capture', DshPcmCaptureProcessor)
|
|
|
1872
2221
|
"control.interrupt": "Stop playback",
|
|
1873
2222
|
"control.mute": "Mute microphone",
|
|
1874
2223
|
"control.unmute": "Unmute microphone",
|
|
2224
|
+
"control.pushToTalk": "Push to talk, release to send",
|
|
1875
2225
|
"overlay.connecting": "Connecting voice",
|
|
1876
2226
|
"overlay.listening": "Listening",
|
|
1877
2227
|
"overlay.speaking": "Playing response",
|
|
@@ -1893,7 +2243,127 @@ registerProcessor('dsh-pcm-capture', DshPcmCaptureProcessor)
|
|
|
1893
2243
|
"task.expand": "Show background task details",
|
|
1894
2244
|
"task.collapse": "Hide background task details",
|
|
1895
2245
|
"task.cancel": "Cancel task",
|
|
1896
|
-
"task.open": "View background details"
|
|
2246
|
+
"task.open": "View background details",
|
|
2247
|
+
"settings.title": "Voice Assistant (Voco)",
|
|
2248
|
+
"settings.description": "Speech recognition provider configuration.",
|
|
2249
|
+
"settings.expand": "Show settings",
|
|
2250
|
+
"settings.collapse": "Hide settings",
|
|
2251
|
+
"settings.unsaved": "Unsaved",
|
|
2252
|
+
"settings.readOnly": "This deployment stores settings read-only.",
|
|
2253
|
+
"settings.apiKey": "API key",
|
|
2254
|
+
"settings.apiKeyHint": "Stored securely in DSH credentials. Leave blank to keep the current key.",
|
|
2255
|
+
"settings.platform": "API platform",
|
|
2256
|
+
"settings.platformValue": "SiliconFlow",
|
|
2257
|
+
"settings.model": "Speech model",
|
|
2258
|
+
"settings.modelValue": "XingChenAGI/XingChenASR-V3.2-Ultra (free)",
|
|
2259
|
+
"settings.apiKeySet": "A key is configured.",
|
|
2260
|
+
"settings.apiKeyUnset": "No key is configured.",
|
|
2261
|
+
"settings.save": "Save",
|
|
2262
|
+
"settings.saving": "Saving…",
|
|
2263
|
+
"settings.discard": "Discard",
|
|
2264
|
+
"settings.saveFailed": "The key could not be saved and was kept for you to retry."
|
|
2265
|
+
};
|
|
2266
|
+
//#endregion
|
|
2267
|
+
//#region ../ui-voice/src/client/voco-settings-controller.ts
|
|
2268
|
+
const VOCO_SETTINGS_NAMESPACE = "voice-local";
|
|
2269
|
+
const SILICONFLOW_API_KEY_REF = "SILICONFLOW_API_KEY";
|
|
2270
|
+
/** Bridges the voice-local namespace and the write-only DSH credentials API. */
|
|
2271
|
+
var VocoSettingsController = class {
|
|
2272
|
+
scope;
|
|
2273
|
+
api;
|
|
2274
|
+
store;
|
|
2275
|
+
draft = "";
|
|
2276
|
+
saving = false;
|
|
2277
|
+
failed = false;
|
|
2278
|
+
credential = {
|
|
2279
|
+
configured: false,
|
|
2280
|
+
writable: true
|
|
2281
|
+
};
|
|
2282
|
+
constructor(scope, api) {
|
|
2283
|
+
this.scope = scope;
|
|
2284
|
+
this.api = api;
|
|
2285
|
+
this.store = (0, _deepseek_ai_dsh_client_runtime_client.createSnapshotStore)(this.projection());
|
|
2286
|
+
scope.subscribe(() => {
|
|
2287
|
+
this.publish();
|
|
2288
|
+
});
|
|
2289
|
+
this.readCredential();
|
|
2290
|
+
}
|
|
2291
|
+
refreshCredential(ref) {
|
|
2292
|
+
if (ref === "SILICONFLOW_API_KEY") this.readCredential();
|
|
2293
|
+
}
|
|
2294
|
+
inject() {
|
|
2295
|
+
return {
|
|
2296
|
+
hooks: { vocoSettings: this.store },
|
|
2297
|
+
editApiKey: (value) => {
|
|
2298
|
+
this.draft = value;
|
|
2299
|
+
this.failed = false;
|
|
2300
|
+
this.publish();
|
|
2301
|
+
},
|
|
2302
|
+
save: () => {
|
|
2303
|
+
this.save();
|
|
2304
|
+
},
|
|
2305
|
+
discard: () => {
|
|
2306
|
+
this.draft = "";
|
|
2307
|
+
this.failed = false;
|
|
2308
|
+
this.publish();
|
|
2309
|
+
}
|
|
2310
|
+
};
|
|
2311
|
+
}
|
|
2312
|
+
projection() {
|
|
2313
|
+
const snapshot = this.scope.getSnapshot();
|
|
2314
|
+
return {
|
|
2315
|
+
available: snapshot.status === "ready",
|
|
2316
|
+
writable: snapshot.writable,
|
|
2317
|
+
dirty: this.draft.trim() !== "",
|
|
2318
|
+
saving: this.saving,
|
|
2319
|
+
failed: this.failed,
|
|
2320
|
+
apiKey: this.draft,
|
|
2321
|
+
apiKeyConfigured: this.credential.configured,
|
|
2322
|
+
apiKeyWritable: this.credential.writable
|
|
2323
|
+
};
|
|
2324
|
+
}
|
|
2325
|
+
publish() {
|
|
2326
|
+
this.store.set(this.projection());
|
|
2327
|
+
}
|
|
2328
|
+
async readCredential() {
|
|
2329
|
+
let response;
|
|
2330
|
+
try {
|
|
2331
|
+
response = await this.api.credentials.describe({ refs: [SILICONFLOW_API_KEY_REF] });
|
|
2332
|
+
} catch {
|
|
2333
|
+
return;
|
|
2334
|
+
}
|
|
2335
|
+
if (!response.result.ok) return;
|
|
2336
|
+
const view = response.result.value.credentials[SILICONFLOW_API_KEY_REF];
|
|
2337
|
+
this.credential = {
|
|
2338
|
+
configured: view?.configured ?? false,
|
|
2339
|
+
writable: view?.writable ?? true
|
|
2340
|
+
};
|
|
2341
|
+
this.publish();
|
|
2342
|
+
}
|
|
2343
|
+
async save() {
|
|
2344
|
+
const value = this.draft.trim();
|
|
2345
|
+
if (value === "" || this.saving || !this.scope.getSnapshot().writable || !this.credential.writable) return;
|
|
2346
|
+
this.saving = true;
|
|
2347
|
+
this.failed = false;
|
|
2348
|
+
this.publish();
|
|
2349
|
+
try {
|
|
2350
|
+
if (!(await this.api.credentials.set({
|
|
2351
|
+
ref: "SILICONFLOW_API_KEY",
|
|
2352
|
+
value
|
|
2353
|
+
})).result.ok) {
|
|
2354
|
+
this.failed = true;
|
|
2355
|
+
return;
|
|
2356
|
+
}
|
|
2357
|
+
await this.readCredential();
|
|
2358
|
+
if (this.credential.configured) this.draft = "";
|
|
2359
|
+
else this.failed = true;
|
|
2360
|
+
} catch {
|
|
2361
|
+
this.failed = true;
|
|
2362
|
+
} finally {
|
|
2363
|
+
this.saving = false;
|
|
2364
|
+
this.publish();
|
|
2365
|
+
}
|
|
2366
|
+
}
|
|
1897
2367
|
};
|
|
1898
2368
|
//#endregion
|
|
1899
2369
|
//#region ../ui-voice/src/client/index.ts
|
|
@@ -1904,7 +2374,9 @@ registerProcessor('dsh-pcm-capture', DshPcmCaptureProcessor)
|
|
|
1904
2374
|
"sessions",
|
|
1905
2375
|
"workspaces",
|
|
1906
2376
|
"locale",
|
|
1907
|
-
"remote"
|
|
2377
|
+
"remote",
|
|
2378
|
+
"connection",
|
|
2379
|
+
"settingsScope"
|
|
1908
2380
|
];
|
|
1909
2381
|
/**
|
|
1910
2382
|
* The Harness model-selection UI intentionally hides addressed children. Voice
|
|
@@ -1949,6 +2421,7 @@ registerProcessor('dsh-pcm-capture', DshPcmCaptureProcessor)
|
|
|
1949
2421
|
}
|
|
1950
2422
|
/** Mount root transport controls and durable Voice conversation renderers. @param ctx - browser context. */
|
|
1951
2423
|
function apply(ctx) {
|
|
2424
|
+
const vocoSettings = new VocoSettingsController(ctx.settingsScope.bind({ namespace: VOCO_SETTINGS_NAMESPACE }), ctx.get("connection").api);
|
|
1952
2425
|
const controller = new VoiceController({ onConversationStarted: () => {
|
|
1953
2426
|
refreshSessions(ctx);
|
|
1954
2427
|
} });
|
|
@@ -1973,6 +2446,12 @@ registerProcessor('dsh-pcm-capture', DshPcmCaptureProcessor)
|
|
|
1973
2446
|
const sessionId = controller.getSnapshot().sessionId;
|
|
1974
2447
|
if (sessionId !== void 0) history.record(sessionId);
|
|
1975
2448
|
},
|
|
2449
|
+
beginPushToTalk: (sessionId) => {
|
|
2450
|
+
controller.beginPushToTalk(sessionId);
|
|
2451
|
+
},
|
|
2452
|
+
endPushToTalk: () => {
|
|
2453
|
+
controller.endPushToTalk();
|
|
2454
|
+
},
|
|
1976
2455
|
interruptResponse: () => {
|
|
1977
2456
|
controller.interruptResponse();
|
|
1978
2457
|
},
|
|
@@ -2053,6 +2532,9 @@ registerProcessor('dsh-pcm-capture', DshPcmCaptureProcessor)
|
|
|
2053
2532
|
zh,
|
|
2054
2533
|
en
|
|
2055
2534
|
}), "ui-voice: dictionaries");
|
|
2535
|
+
ctx.effect(() => ctx.remote.$on("credentials/reference-updated", (ref) => {
|
|
2536
|
+
vocoSettings.refreshCredential(ref);
|
|
2537
|
+
}), "ui-voice: credential invalidations");
|
|
2056
2538
|
ctx.effect(() => async () => {
|
|
2057
2539
|
await controller.stop();
|
|
2058
2540
|
}, "ui-voice: transport teardown");
|
|
@@ -2098,6 +2580,12 @@ registerProcessor('dsh-pcm-capture', DshPcmCaptureProcessor)
|
|
|
2098
2580
|
locale: NS,
|
|
2099
2581
|
inject: delegationInjected
|
|
2100
2582
|
}, VoiceDelegationView));
|
|
2583
|
+
ctx.slots.inject("settings.plugin.item", () => ctx.slots.register({
|
|
2584
|
+
name: "settings.plugin.item",
|
|
2585
|
+
key: VOCO_SETTINGS_NAMESPACE,
|
|
2586
|
+
locale: NS,
|
|
2587
|
+
inject: () => vocoSettings.inject()
|
|
2588
|
+
}, VocoSettingsCard));
|
|
2101
2589
|
}
|
|
2102
2590
|
/** Archive-manager archives one requested ID; Voice treats that state as
|
|
2103
2591
|
* inherited by every descendant without mutating the third-party archive set. */
|