@flowingspring/dsh-voco 0.2.6 → 0.2.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/LICENSE +21 -21
- package/README.md +56 -56
- package/README.zh.md +56 -56
- package/cordis.patch.yml +13 -13
- package/lib/client.js +260 -102
- package/lib/client.js.map +1 -1
- package/lib/plugins/voice-assistant.js +69 -2
- package/package.json +114 -114
package/lib/client.js
CHANGED
|
@@ -7,25 +7,27 @@ window.__ModuleLoader__.load({
|
|
|
7
7
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
8
8
|
let react = require("react");
|
|
9
9
|
let _deepseek_ai_dsh_client_runtime_client = require("@deepseek-ai/dsh-client-runtime/client");
|
|
10
|
-
//#region \0dsh-css:
|
|
11
|
-
const css$
|
|
12
|
-
const tagId$
|
|
13
|
-
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$
|
|
10
|
+
//#region \0dsh-css:D:\QUAN\DevCode\Python\Project\dsh\dsh-voco\packages\ui-voice\src\client\VoiceControl.module.css.mjs
|
|
11
|
+
const css$4 = ".TFZsua_controls{align-items:center;gap:2px;display:inline-flex}.TFZsua_button{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_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}}";
|
|
12
|
+
const tagId$4 = "@flowingspring/dsh-voco/VoiceControl.module.css";
|
|
13
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$4) + "]") === null) {
|
|
14
14
|
const tag = document.createElement("style");
|
|
15
15
|
tag.dataset.plugin = "@flowingspring/dsh-voco";
|
|
16
|
-
tag.dataset.pluginCss = tagId$
|
|
17
|
-
tag.textContent = css$
|
|
16
|
+
tag.dataset.pluginCss = tagId$4;
|
|
17
|
+
tag.textContent = css$4;
|
|
18
18
|
document.head.appendChild(tag);
|
|
19
19
|
}
|
|
20
20
|
var VoiceControl_module_css_default = {
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
21
|
+
"interruptButton": "TFZsua_interruptButton",
|
|
22
|
+
"button": "TFZsua_button",
|
|
23
|
+
"controls": "TFZsua_controls",
|
|
24
|
+
"active": "TFZsua_active",
|
|
25
|
+
"voice-pulse": "TFZsua_voice-pulse"
|
|
24
26
|
};
|
|
25
27
|
//#endregion
|
|
26
28
|
//#region ../ui-voice/src/client/VoiceControl.tsx
|
|
27
29
|
/** Start a fresh Voice Session from this Session's location or control the active connection. */
|
|
28
|
-
function VoiceControl({ sessionId, useVoice, startVoice, retryVoice, setVoiceMuted, t }) {
|
|
30
|
+
function VoiceControl({ sessionId, useVoice, startVoice, retryVoice, setVoiceMuted, t, interruptResponse }) {
|
|
29
31
|
const state = useVoice((snapshot) => snapshot.state);
|
|
30
32
|
const activeSessionId = useVoice((snapshot) => snapshot.sessionId);
|
|
31
33
|
const inputMuted = useVoice((snapshot) => snapshot.inputMuted);
|
|
@@ -46,74 +48,110 @@ window.__ModuleLoader__.load({
|
|
|
46
48
|
};
|
|
47
49
|
const label = state === "off" ? t("control.start") : state === "error" ? t("control.retry") : inputMuted ? t("control.unmute") : t("control.mute");
|
|
48
50
|
const active = state !== "off" && state !== "error";
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
"
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
51
|
+
const interrupt = () => {
|
|
52
|
+
try {
|
|
53
|
+
interruptResponse();
|
|
54
|
+
} catch {}
|
|
55
|
+
};
|
|
56
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
57
|
+
className: VoiceControl_module_css_default.controls,
|
|
58
|
+
children: [state === "speaking" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
59
|
+
type: "button",
|
|
60
|
+
className: `${VoiceControl_module_css_default.button} ${VoiceControl_module_css_default.interruptButton}`,
|
|
61
|
+
"aria-label": t("control.interrupt"),
|
|
62
|
+
title: t("control.interrupt"),
|
|
63
|
+
"data-state": state,
|
|
64
|
+
onClick: interrupt,
|
|
65
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
66
|
+
viewBox: "0 0 16 16",
|
|
67
|
+
width: "16",
|
|
68
|
+
height: "16",
|
|
69
|
+
"aria-hidden": true,
|
|
70
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
71
|
+
cx: "8",
|
|
72
|
+
cy: "8",
|
|
73
|
+
r: "6.25",
|
|
72
74
|
fill: "none",
|
|
73
75
|
stroke: "currentColor",
|
|
74
76
|
strokeWidth: "1.4"
|
|
75
|
-
}),
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
77
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
|
|
78
|
+
x: "5.25",
|
|
79
|
+
y: "5.25",
|
|
80
|
+
width: "5.5",
|
|
81
|
+
height: "5.5",
|
|
82
|
+
rx: "1",
|
|
83
|
+
fill: "currentColor"
|
|
84
|
+
})]
|
|
85
|
+
})
|
|
86
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
87
|
+
type: "button",
|
|
88
|
+
className: `${VoiceControl_module_css_default.button} ${active ? VoiceControl_module_css_default.active : ""}`,
|
|
89
|
+
"aria-label": label,
|
|
90
|
+
"aria-pressed": active ? inputMuted : void 0,
|
|
91
|
+
title: label,
|
|
92
|
+
"data-state": state,
|
|
93
|
+
"data-muted": inputMuted,
|
|
94
|
+
onClick: () => {
|
|
95
|
+
toggle();
|
|
96
|
+
},
|
|
97
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
98
|
+
viewBox: "0 0 16 16",
|
|
99
|
+
width: "16",
|
|
100
|
+
height: "16",
|
|
101
|
+
"aria-hidden": true,
|
|
102
|
+
children: [
|
|
103
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
|
|
104
|
+
x: "5",
|
|
105
|
+
y: "2",
|
|
106
|
+
width: "6",
|
|
107
|
+
height: "8",
|
|
108
|
+
rx: "3",
|
|
109
|
+
fill: "none",
|
|
110
|
+
stroke: "currentColor",
|
|
111
|
+
strokeWidth: "1.4"
|
|
112
|
+
}),
|
|
113
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
114
|
+
d: "M3.5 7.5a4.5 4.5 0 0 0 9 0M8 12v2M5.5 14h5",
|
|
115
|
+
fill: "none",
|
|
116
|
+
stroke: "currentColor",
|
|
117
|
+
strokeWidth: "1.4",
|
|
118
|
+
strokeLinecap: "round"
|
|
119
|
+
}),
|
|
120
|
+
inputMuted && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
121
|
+
d: "M2.5 2.5l11 11",
|
|
122
|
+
fill: "none",
|
|
123
|
+
stroke: "currentColor",
|
|
124
|
+
strokeWidth: "1.8",
|
|
125
|
+
strokeLinecap: "round"
|
|
126
|
+
})
|
|
127
|
+
]
|
|
128
|
+
})
|
|
129
|
+
})]
|
|
92
130
|
});
|
|
93
131
|
}
|
|
94
132
|
//#endregion
|
|
95
|
-
//#region \0dsh-css:
|
|
96
|
-
const css$
|
|
97
|
-
const tagId$
|
|
98
|
-
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$
|
|
133
|
+
//#region \0dsh-css:D:\QUAN\DevCode\Python\Project\dsh\dsh-voco\packages\ui-voice\src\client\VoiceHistoryAction.module.css.mjs
|
|
134
|
+
const css$3 = "._3t8AFq_trigger{width:100%;min-height:36px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:8px;justify-content:center;align-items:center;gap:9px;display:flex}._3t8AFq_trigger:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}._3t8AFq_panel{z-index:60;border:1px solid var(--dsw-alias-border-l2);width:min(320px,100vw - 32px);max-height:min(480px,100vh - 96px);color:var(--dsw-alias-label-primary);background:var(--dsw-specific-menu);box-shadow:var(--dsw-shadow-lv3);border-radius:14px;flex-direction:column;display:flex;position:fixed;bottom:64px;left:16px;overflow:hidden}._3t8AFq_header{border-bottom:1px solid var(--dsw-alias-border-l2);justify-content:space-between;align-items:center;min-height:48px;padding:0 12px 0 16px;display:flex}._3t8AFq_close{width:28px;height:28px;color:inherit;cursor:pointer;background:0 0;border:0;border-radius:7px;font-size:20px;line-height:1}._3t8AFq_close:hover{background:var(--dsw-alias-interactive-bg-hover)}._3t8AFq_list{padding:8px;overflow:auto}._3t8AFq_empty{color:var(--dsw-alias-label-tertiary);text-align:center;margin:0;padding:24px 12px;font-size:13px}._3t8AFq_row{width:100%;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:9px;align-items:center;gap:10px;padding:10px;display:flex}._3t8AFq_row:hover,._3t8AFq_row[data-active=true]{background:var(--dsw-alias-interactive-bg-hover)}._3t8AFq_wave{width:24px;height:24px;color:var(--dsw-alias-state-business-primary);background:color-mix(in srgb, currentColor 10%, transparent);border-radius:50%;flex:none;justify-content:center;align-items:center;gap:2px;display:flex}._3t8AFq_wave i{background:currentColor;border-radius:2px;width:2px}._3t8AFq_wave i:first-child{height:6px}._3t8AFq_wave i:nth-child(2){height:11px}._3t8AFq_wave i:nth-child(3){height:8px}._3t8AFq_rowText{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}._3t8AFq_title{text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:500;overflow:hidden}._3t8AFq_meta{color:var(--dsw-alias-label-tertiary);font-size:11px}";
|
|
135
|
+
const tagId$3 = "@flowingspring/dsh-voco/VoiceHistoryAction.module.css";
|
|
136
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
|
|
99
137
|
const tag = document.createElement("style");
|
|
100
138
|
tag.dataset.plugin = "@flowingspring/dsh-voco";
|
|
101
|
-
tag.dataset.pluginCss = tagId$
|
|
102
|
-
tag.textContent = css$
|
|
139
|
+
tag.dataset.pluginCss = tagId$3;
|
|
140
|
+
tag.textContent = css$3;
|
|
103
141
|
document.head.appendChild(tag);
|
|
104
142
|
}
|
|
105
143
|
var VoiceHistoryAction_module_css_default = {
|
|
106
|
-
"
|
|
107
|
-
"
|
|
108
|
-
"
|
|
109
|
-
"
|
|
110
|
-
"
|
|
111
|
-
"
|
|
112
|
-
"
|
|
113
|
-
"
|
|
114
|
-
"
|
|
115
|
-
"
|
|
116
|
-
"
|
|
144
|
+
"trigger": "_3t8AFq_trigger",
|
|
145
|
+
"panel": "_3t8AFq_panel",
|
|
146
|
+
"title": "_3t8AFq_title",
|
|
147
|
+
"meta": "_3t8AFq_meta",
|
|
148
|
+
"wave": "_3t8AFq_wave",
|
|
149
|
+
"rowText": "_3t8AFq_rowText",
|
|
150
|
+
"row": "_3t8AFq_row",
|
|
151
|
+
"header": "_3t8AFq_header",
|
|
152
|
+
"list": "_3t8AFq_list",
|
|
153
|
+
"empty": "_3t8AFq_empty",
|
|
154
|
+
"close": "_3t8AFq_close"
|
|
117
155
|
};
|
|
118
156
|
//#endregion
|
|
119
157
|
//#region ../ui-voice/src/client/VoiceHistoryAction.tsx
|
|
@@ -214,34 +252,34 @@ window.__ModuleLoader__.load({
|
|
|
214
252
|
})] });
|
|
215
253
|
}
|
|
216
254
|
//#endregion
|
|
217
|
-
//#region \0dsh-css:
|
|
218
|
-
const css$
|
|
219
|
-
const tagId$
|
|
220
|
-
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$
|
|
255
|
+
//#region \0dsh-css:D:\QUAN\DevCode\Python\Project\dsh\dsh-voco\packages\ui-voice\src\client\VoiceNodeViews.module.css.mjs
|
|
256
|
+
const css$2 = ".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)}";
|
|
257
|
+
const tagId$2 = "@flowingspring/dsh-voco/VoiceNodeViews.module.css";
|
|
258
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
|
|
221
259
|
const tag = document.createElement("style");
|
|
222
260
|
tag.dataset.plugin = "@flowingspring/dsh-voco";
|
|
223
|
-
tag.dataset.pluginCss = tagId$
|
|
224
|
-
tag.textContent = css$
|
|
261
|
+
tag.dataset.pluginCss = tagId$2;
|
|
262
|
+
tag.textContent = css$2;
|
|
225
263
|
document.head.appendChild(tag);
|
|
226
264
|
}
|
|
227
265
|
var VoiceNodeViews_module_css_default = {
|
|
228
|
-
"
|
|
229
|
-
"
|
|
230
|
-
"
|
|
231
|
-
"
|
|
232
|
-
"
|
|
233
|
-
"
|
|
234
|
-
"
|
|
235
|
-
"
|
|
236
|
-
"
|
|
237
|
-
"
|
|
238
|
-
"
|
|
239
|
-
"
|
|
240
|
-
"
|
|
241
|
-
"
|
|
242
|
-
"
|
|
243
|
-
"
|
|
244
|
-
"
|
|
266
|
+
"taskDetails": "Kt2smW_taskDetails",
|
|
267
|
+
"taskTitle": "Kt2smW_taskTitle",
|
|
268
|
+
"miniWave": "Kt2smW_miniWave",
|
|
269
|
+
"meta": "Kt2smW_meta",
|
|
270
|
+
"taskSummary": "Kt2smW_taskSummary",
|
|
271
|
+
"taskLink": "Kt2smW_taskLink",
|
|
272
|
+
"taskDot": "Kt2smW_taskDot",
|
|
273
|
+
"bubble": "Kt2smW_bubble",
|
|
274
|
+
"taskCard": "Kt2smW_taskCard",
|
|
275
|
+
"taskStatus": "Kt2smW_taskStatus",
|
|
276
|
+
"voiceBadge": "Kt2smW_voiceBadge",
|
|
277
|
+
"taskCancel": "Kt2smW_taskCancel",
|
|
278
|
+
"taskChevron": "Kt2smW_taskChevron",
|
|
279
|
+
"taskInput": "Kt2smW_taskInput",
|
|
280
|
+
"taskActions": "Kt2smW_taskActions",
|
|
281
|
+
"taskUpdate": "Kt2smW_taskUpdate",
|
|
282
|
+
"utterance": "Kt2smW_utterance"
|
|
245
283
|
};
|
|
246
284
|
//#endregion
|
|
247
285
|
//#region ../ui-voice/src/client/VoiceNodeViews.tsx
|
|
@@ -358,23 +396,23 @@ window.__ModuleLoader__.load({
|
|
|
358
396
|
return status === "completed" || status === "failed" || status === "cancelled" || status === "interrupted";
|
|
359
397
|
}
|
|
360
398
|
//#endregion
|
|
361
|
-
//#region \0dsh-css:
|
|
362
|
-
const css = ".
|
|
363
|
-
const tagId = "@flowingspring/dsh-voco/VoiceOverlay.module.css";
|
|
364
|
-
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
399
|
+
//#region \0dsh-css:D:\QUAN\DevCode\Python\Project\dsh\dsh-voco\packages\ui-voice\src\client\VoiceOverlay.module.css.mjs
|
|
400
|
+
const css$1 = ".GPPB2G_root{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-overlay);max-width:min(520px,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:10px;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 0 4em;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_link,.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_link:hover:not(:disabled),.GPPB2G_stop:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.GPPB2G_link:disabled{cursor:default;opacity:.45}.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}}";
|
|
401
|
+
const tagId$1 = "@flowingspring/dsh-voco/VoiceOverlay.module.css";
|
|
402
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
365
403
|
const tag = document.createElement("style");
|
|
366
404
|
tag.dataset.plugin = "@flowingspring/dsh-voco";
|
|
367
|
-
tag.dataset.pluginCss = tagId;
|
|
368
|
-
tag.textContent = css;
|
|
405
|
+
tag.dataset.pluginCss = tagId$1;
|
|
406
|
+
tag.textContent = css$1;
|
|
369
407
|
document.head.appendChild(tag);
|
|
370
408
|
}
|
|
371
409
|
var VoiceOverlay_module_css_default = {
|
|
372
|
-
"
|
|
373
|
-
"
|
|
374
|
-
"voice-wave": "
|
|
375
|
-
"
|
|
376
|
-
"wave": "
|
|
377
|
-
"
|
|
410
|
+
"stop": "GPPB2G_stop",
|
|
411
|
+
"root": "GPPB2G_root",
|
|
412
|
+
"voice-wave": "GPPB2G_voice-wave",
|
|
413
|
+
"link": "GPPB2G_link",
|
|
414
|
+
"wave": "GPPB2G_wave",
|
|
415
|
+
"status": "GPPB2G_status"
|
|
378
416
|
};
|
|
379
417
|
//#endregion
|
|
380
418
|
//#region ../ui-voice/src/client/VoiceOverlay.tsx
|
|
@@ -432,6 +470,100 @@ window.__ModuleLoader__.load({
|
|
|
432
470
|
});
|
|
433
471
|
}
|
|
434
472
|
//#endregion
|
|
473
|
+
//#region \0dsh-css:D:\QUAN\DevCode\Python\Project\dsh\dsh-voco\packages\ui-voice\src\client\VoiceSessionMarkers.module.css.mjs
|
|
474
|
+
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}";
|
|
475
|
+
const tagId = "@flowingspring/dsh-voco/VoiceSessionMarkers.module.css";
|
|
476
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
477
|
+
const tag = document.createElement("style");
|
|
478
|
+
tag.dataset.plugin = "@flowingspring/dsh-voco";
|
|
479
|
+
tag.dataset.pluginCss = tagId;
|
|
480
|
+
tag.textContent = css;
|
|
481
|
+
document.head.appendChild(tag);
|
|
482
|
+
}
|
|
483
|
+
var VoiceSessionMarkers_module_css_default = {
|
|
484
|
+
"slot": "_0brRca_slot",
|
|
485
|
+
"marker": "_0brRca_marker"
|
|
486
|
+
};
|
|
487
|
+
//#endregion
|
|
488
|
+
//#region ../ui-voice/src/client/VoiceSessionMarkers.tsx
|
|
489
|
+
/**
|
|
490
|
+
* The workspace package currently owns the session-row renderer and does not
|
|
491
|
+
* expose a row-level slot. This small, read-only decorator keeps the marker in
|
|
492
|
+
* sync with that renderer while leaving row interactions and layout intact.
|
|
493
|
+
*/
|
|
494
|
+
function VoiceSessionMarkers({ useSessions, useVoiceHistory }) {
|
|
495
|
+
const sessions = useSessions((state) => state.byId);
|
|
496
|
+
const history = useVoiceHistory((state) => state.entries);
|
|
497
|
+
(0, react.useEffect)(() => {
|
|
498
|
+
const voiceTitles = new Set(history.map((entry) => entry.sessionId));
|
|
499
|
+
const sessionIds = new Set(Object.keys(sessions));
|
|
500
|
+
let frame = 0;
|
|
501
|
+
const decorate = () => {
|
|
502
|
+
frame = 0;
|
|
503
|
+
const rows = document.querySelectorAll("[role=\"treeitem\"].sessionRow, [role=\"treeitem\"][class*=\"sessionRow\"]");
|
|
504
|
+
for (const row of rows) {
|
|
505
|
+
const slot = row.querySelector("[class*=\"slot\"]");
|
|
506
|
+
const marker = row.querySelector("[data-voice-session-marker]");
|
|
507
|
+
const sessionId = findSessionKey(row, sessionIds);
|
|
508
|
+
if (!(sessionId !== void 0 && voiceTitles.has(sessionId))) {
|
|
509
|
+
marker?.remove();
|
|
510
|
+
continue;
|
|
511
|
+
}
|
|
512
|
+
if (marker !== null) continue;
|
|
513
|
+
(slot ?? createMarkerSlot(row)).append(createMarker());
|
|
514
|
+
}
|
|
515
|
+
};
|
|
516
|
+
const schedule = () => {
|
|
517
|
+
if (frame !== 0) return;
|
|
518
|
+
frame = requestAnimationFrame(decorate);
|
|
519
|
+
};
|
|
520
|
+
decorate();
|
|
521
|
+
const observer = new MutationObserver(schedule);
|
|
522
|
+
observer.observe(document.body, {
|
|
523
|
+
childList: true,
|
|
524
|
+
subtree: true,
|
|
525
|
+
characterData: true
|
|
526
|
+
});
|
|
527
|
+
return () => {
|
|
528
|
+
observer.disconnect();
|
|
529
|
+
if (frame !== 0) cancelAnimationFrame(frame);
|
|
530
|
+
document.querySelectorAll("[data-voice-session-marker]").forEach((node) => {
|
|
531
|
+
node.remove();
|
|
532
|
+
});
|
|
533
|
+
document.querySelectorAll("[data-voice-session-marker-slot]").forEach((node) => {
|
|
534
|
+
node.remove();
|
|
535
|
+
});
|
|
536
|
+
};
|
|
537
|
+
}, [history, sessions]);
|
|
538
|
+
return null;
|
|
539
|
+
}
|
|
540
|
+
/** React keeps the keyed SessionNodeItem identity on the row's owner fiber. */
|
|
541
|
+
function findSessionKey(row, sessionIds) {
|
|
542
|
+
const fiberKey = Object.keys(row).find((key) => key.startsWith("__reactFiber$"));
|
|
543
|
+
if (fiberKey === void 0) return void 0;
|
|
544
|
+
let fiber = row[fiberKey];
|
|
545
|
+
while (fiber !== void 0) {
|
|
546
|
+
if (fiber.key !== null && sessionIds.has(fiber.key)) return fiber.key;
|
|
547
|
+
fiber = fiber.return;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
function createMarkerSlot(row) {
|
|
551
|
+
const slot = document.createElement("span");
|
|
552
|
+
slot.dataset.voiceSessionMarkerSlot = "";
|
|
553
|
+
slot.className = VoiceSessionMarkers_module_css_default.slot ?? "voice-session-marker-slot";
|
|
554
|
+
const title = row.querySelector("[class*=\"title\"]");
|
|
555
|
+
row.insertBefore(slot, title ?? row.firstChild ?? null);
|
|
556
|
+
return slot;
|
|
557
|
+
}
|
|
558
|
+
function createMarker() {
|
|
559
|
+
const marker = document.createElement("span");
|
|
560
|
+
marker.dataset.voiceSessionMarker = "";
|
|
561
|
+
marker.className = VoiceSessionMarkers_module_css_default.marker ?? "voice-session-marker";
|
|
562
|
+
marker.setAttribute("aria-hidden", "true");
|
|
563
|
+
marker.innerHTML = "<svg viewBox=\"0 0 16 16\" aria-hidden=\"true\"><path d=\"M3 8h1.5M6 5v6M9 3.5v9M12 5.5v5M14 7h-1\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.35\" stroke-linecap=\"round\"/></svg>";
|
|
564
|
+
return marker;
|
|
565
|
+
}
|
|
566
|
+
//#endregion
|
|
435
567
|
//#region ../ui-voice/src/client/voice-controller.ts
|
|
436
568
|
const INITIAL_SNAPSHOT = {
|
|
437
569
|
state: "off",
|
|
@@ -547,6 +679,14 @@ window.__ModuleLoader__.load({
|
|
|
547
679
|
if (this.transport === void 0) throw new Error("voice task cancellation requires an active connection");
|
|
548
680
|
this.transport.cancelTask(taskId);
|
|
549
681
|
}
|
|
682
|
+
/** Stop the active assistant response without ending the Voice Session. */
|
|
683
|
+
interruptResponse() {
|
|
684
|
+
if (this.snapshot.state === "off" || this.snapshot.state === "error" || this.snapshot.sessionId === void 0) throw new Error("voice response interruption requires an active connection");
|
|
685
|
+
const transport = this.transport ?? this.openingTransport;
|
|
686
|
+
if (transport === void 0) throw new Error("voice response interruption requires an active connection");
|
|
687
|
+
transport.interruptResponse();
|
|
688
|
+
this.setState("listening");
|
|
689
|
+
}
|
|
550
690
|
/** Submit composer text as a voice turn, queueing it while the transport connects. */
|
|
551
691
|
submitText(text) {
|
|
552
692
|
const value = text.trim();
|
|
@@ -718,6 +858,11 @@ window.__ModuleLoader__.load({
|
|
|
718
858
|
taskId
|
|
719
859
|
}));
|
|
720
860
|
},
|
|
861
|
+
interruptResponse: () => {
|
|
862
|
+
if (socket.readyState !== WebSocket.OPEN) throw new Error("voice transport is not open");
|
|
863
|
+
socket.send(JSON.stringify({ type: "response.interrupt" }));
|
|
864
|
+
stopPlayback();
|
|
865
|
+
},
|
|
721
866
|
setInputMuted: (muted) => {
|
|
722
867
|
if (inputMuted === muted) return;
|
|
723
868
|
inputMuted = muted;
|
|
@@ -1340,6 +1485,7 @@ registerProcessor('dsh-pcm-capture', DshPcmCaptureProcessor)
|
|
|
1340
1485
|
"badge.voice": "VOICE",
|
|
1341
1486
|
"control.start": "开始语音对话",
|
|
1342
1487
|
"control.retry": "语音连接失败,点击重试",
|
|
1488
|
+
"control.interrupt": "打断播放",
|
|
1343
1489
|
"control.mute": "静音麦克风",
|
|
1344
1490
|
"control.unmute": "解除静音",
|
|
1345
1491
|
"overlay.connecting": "正在连接语音",
|
|
@@ -1378,6 +1524,7 @@ registerProcessor('dsh-pcm-capture', DshPcmCaptureProcessor)
|
|
|
1378
1524
|
"badge.voice": "VOICE",
|
|
1379
1525
|
"control.start": "Start voice conversation",
|
|
1380
1526
|
"control.retry": "Voice connection failed, press to retry",
|
|
1527
|
+
"control.interrupt": "Stop playback",
|
|
1381
1528
|
"control.mute": "Mute microphone",
|
|
1382
1529
|
"control.unmute": "Unmute microphone",
|
|
1383
1530
|
"overlay.connecting": "Connecting voice",
|
|
@@ -1454,6 +1601,9 @@ registerProcessor('dsh-pcm-capture', DshPcmCaptureProcessor)
|
|
|
1454
1601
|
const sessionId = controller.getSnapshot().sessionId;
|
|
1455
1602
|
if (sessionId !== void 0) history.record(sessionId);
|
|
1456
1603
|
},
|
|
1604
|
+
interruptResponse: () => {
|
|
1605
|
+
controller.interruptResponse();
|
|
1606
|
+
},
|
|
1457
1607
|
setVoiceMuted: (muted) => {
|
|
1458
1608
|
controller.setInputMuted(muted);
|
|
1459
1609
|
}
|
|
@@ -1465,6 +1615,7 @@ registerProcessor('dsh-pcm-capture', DshPcmCaptureProcessor)
|
|
|
1465
1615
|
},
|
|
1466
1616
|
stopVoice
|
|
1467
1617
|
});
|
|
1618
|
+
const voiceSessionMarkersInjected = () => ({ hooks: { voiceHistory: history.snapshot } });
|
|
1468
1619
|
const utteranceInjected = () => ({ hooks: { voice: controller } });
|
|
1469
1620
|
const delegationInjected = () => ({
|
|
1470
1621
|
hooks: { voice: controller },
|
|
@@ -1514,6 +1665,13 @@ registerProcessor('dsh-pcm-capture', DshPcmCaptureProcessor)
|
|
|
1514
1665
|
locale: NS,
|
|
1515
1666
|
inject: voiceOverlayInjected
|
|
1516
1667
|
}, VoiceOverlay));
|
|
1668
|
+
ctx.slots.inject("shell.overlay", () => ctx.slots.register({
|
|
1669
|
+
name: "shell.overlay",
|
|
1670
|
+
id: "voice-session-markers",
|
|
1671
|
+
order: 10,
|
|
1672
|
+
locale: NS,
|
|
1673
|
+
inject: voiceSessionMarkersInjected
|
|
1674
|
+
}, VoiceSessionMarkers));
|
|
1517
1675
|
ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register({
|
|
1518
1676
|
name: "sidebar.footer.action",
|
|
1519
1677
|
id: "voice-history",
|