@burdenoff/fe-libs 2026.1016.2 → 2026.1017.1
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/shared/assistant/avatar/live/AvatarFace.d.ts +13 -0
- package/dist/shared/assistant/avatar/live/AvatarFace.js +46 -0
- package/dist/shared/assistant/avatar/live/LiveAvatarTabView.d.ts +2 -0
- package/dist/shared/assistant/avatar/live/LiveAvatarTabView.js +172 -145
- package/dist/shared/assistant/avatar/live/avatarFaces.d.ts +31 -0
- package/dist/shared/assistant/avatar/live/avatarFaces.js +33 -0
- package/dist/shared/assistant/avatar/live/createLiveAvatarSeam.d.ts +12 -0
- package/dist/shared/assistant/avatar/live/createLiveAvatarSeam.js +142 -75
- package/dist/shared/assistant/avatar/live/liveAvatarController.d.ts +5 -0
- package/dist/shared/assistant/avatar/live/liveAvatarController.js +3 -1
- package/dist/shared/assistant/avatar/live/liveAvatarStatus.d.ts +14 -0
- package/dist/shared/assistant/avatar/live/liveAvatarStatus.js +11 -2
- package/dist/shared/assistant/avatar/useAvatarCopy.d.ts +42 -0
- package/dist/shared/assistant/avatar/useAvatarCopy.js +113 -75
- package/dist/shared/assistant/i18nManifest.d.ts +29 -0
- package/dist/shared/assistant/i18nManifest.js +29 -0
- package/dist/shared/assistant/index.d.ts +8 -0
- package/dist/shared/assistant/speech/hostedTtsSpeechEngine.d.ts +6 -0
- package/dist/shared/assistant/speech/hostedTtsSpeechEngine.js +118 -101
- package/dist/shared/assistant/speech/notifyCancellationSpeechEngine.js +3 -0
- package/dist/shared/assistant/speech/replySpeechRequests.d.ts +84 -0
- package/dist/shared/assistant/speech/replySpeechRequests.js +70 -0
- package/dist/shared/assistant/speech/routingSpeechEngine.js +13 -9
- package/dist/shared/assistant/speech/types.d.ts +39 -1
- package/dist/shared/assistant/ui/AIAssistantPanel.js +128 -119
- package/dist/shared/assistant/ui/AssistantChatArea.js +1572 -1430
- package/dist/shared/assistant/ui/AssistantMessageItem.js +110 -100
- package/dist/shared/assistant/ui/AssistantSpeechProvider.d.ts +10 -0
- package/dist/shared/assistant/ui/AssistantSpeechProvider.js +286 -225
- package/dist/shared/assistant/ui/assistantLiveAvatarSeam.d.ts +40 -0
- package/dist/shared/assistant/ui/avatar/AssistantAvatarTab.d.ts +6 -0
- package/dist/shared/assistant/ui/avatar/AssistantAvatarTab.js +99 -52
- package/dist/shared/assistant/ui/avatar/AvatarTabAskBox.d.ts +8 -0
- package/dist/shared/assistant/ui/avatar/AvatarTabAskBox.js +87 -0
- package/dist/shared/assistant/ui/avatar/AvatarTabLastExchange.d.ts +13 -0
- package/dist/shared/assistant/ui/avatar/AvatarTabLastExchange.js +97 -0
- package/dist/shared/assistant/ui/avatar/avatarAskGate.d.ts +104 -0
- package/dist/shared/assistant/ui/avatar/avatarAskGate.js +39 -0
- package/dist/shared/assistant/ui/avatar/avatarTabDraft.d.ts +17 -0
- package/dist/shared/assistant/ui/avatar/avatarTabDraft.js +22 -0
- package/dist/shared/assistant/ui/avatar/avatarTabExchange.d.ts +47 -0
- package/dist/shared/assistant/ui/avatar/avatarTabExchange.js +50 -0
- package/dist/shared/assistant/ui/panelOverlays.d.ts +8 -1
- package/dist/shared/assistant/ui/panelOverlays.js +1 -1
- package/dist/shared/assistant/ui/useVoiceSession.js +222 -227
- package/dist/shared/assistant/voice/handsfree/playbackReference.d.ts +15 -4
- package/dist/shared/assistant/voice/handsfree/playbackReference.js +9 -6
- package/dist/shared-assistant.js +270 -262
- package/package.json +1 -1
|
@@ -2,262 +2,263 @@ import { useVoiceInput as e } from "../voice/useVoiceInput.js";
|
|
|
2
2
|
import { planSubmitTimer as t, resolveVoiceGraceMs as n } from "../voice/handsFree.js";
|
|
3
3
|
import { readHandsFreeOverride as r, resolveHandsFreeEnabled as ee } from "../voice/handsfree/handsFreeSetting.js";
|
|
4
4
|
import { silencePlaybackReference as te } from "../voice/handsfree/playbackReference.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
5
|
+
import { primeHostedPlayback as ne } from "../speech/hostedTtsSpeechEngine.js";
|
|
6
|
+
import { speechFeed as re } from "../speech/speechFeed.js";
|
|
7
|
+
import { INITIAL_SESSION as ie, INTERRUPT_MAX_MS as ae, NOTHING_HEARD as i, advanceHeardClock as oe, isCapturing as a, isSubmittable as se, planListeningHold as ce, planReplyConsumption as le, planVoiceAnnouncement as ue, shouldRecognise as de, spokenSoFar as o, voiceSessionReducer as fe } from "../voice/voiceSession.js";
|
|
8
|
+
import { useHandsFreeInterrupt as pe } from "../voice/handsfree/useHandsFreeInterrupt.js";
|
|
9
|
+
import { isTurnSuperseded as me } from "../voice/supersededTurns.js";
|
|
10
|
+
import { captionChunks as he } from "../voice/speechPlayback.js";
|
|
10
11
|
import { turnClockMs as s } from "../turnTimeline.js";
|
|
11
|
-
import { useAssistantSpeech as
|
|
12
|
-
import { useLiveAvatarOn as
|
|
13
|
-
import { useCallback as c, useEffect as l, useLayoutEffect as
|
|
12
|
+
import { useAssistantSpeech as ge } from "./AssistantSpeechProvider.js";
|
|
13
|
+
import { useLiveAvatarOn as _e } from "./assistantLiveAvatarSeam.js";
|
|
14
|
+
import { useCallback as c, useEffect as l, useLayoutEffect as ve, useMemo as ye, useReducer as be, useRef as u, useState as d } from "react";
|
|
14
15
|
//#region src/shared/assistant/ui/useVoiceSession.ts
|
|
15
|
-
var
|
|
16
|
-
function Te({ onSubmit: Te, latestReply: f, language: p, graceMs: Ee, onSupersede: De, handsFreeInterrupt: Oe, handsFreeStreamNoticeAccepted: ke, onAcceptHandsFreeStreamNotice: Ae, onBargeIn:
|
|
17
|
-
let
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}, [
|
|
21
|
-
let
|
|
22
|
-
|
|
23
|
-
let
|
|
24
|
-
|
|
25
|
-
}, []),
|
|
16
|
+
var xe = 4e3, Se = 2500, Ce = 5e3, we = 12e3;
|
|
17
|
+
function Te({ onSubmit: Te, latestReply: f, language: p, graceMs: Ee, onSupersede: De, handsFreeInterrupt: Oe, handsFreeStreamNoticeAccepted: ke, onAcceptHandsFreeStreamNotice: Ae, onBargeIn: je }) {
|
|
18
|
+
let Me = n(Ee), m = u(null), [h, g] = be(c((e, t) => fe(e, t, m.current), []), ie), _ = ge(), { setSessionSpeaking: v, setSessionMicOpen: y, speakingMessageId: b, stop: x } = _, S = u(_.toggle), C = _.toggle;
|
|
19
|
+
ve(() => {
|
|
20
|
+
S.current = C;
|
|
21
|
+
}, [C]);
|
|
22
|
+
let w = u(null), T = u({}), E = u(i), D = u(null), O = u(!1), k = u(null), [Ne, A] = d(null), [j, M] = d(!1), [Pe, N] = d(!1), [P, F] = d(!1), I = u(h);
|
|
23
|
+
I.current = h;
|
|
24
|
+
let L = u([]), R = u(null), z = u(!1), B = c(() => {
|
|
25
|
+
L.current = [], R.current = null, z.current = !1;
|
|
26
|
+
}, []), V = c(() => {
|
|
26
27
|
for (;;) {
|
|
27
|
-
let e =
|
|
28
|
+
let e = L.current.shift();
|
|
28
29
|
if (!e) return !1;
|
|
29
30
|
if (!(e.stillWanted && !e.stillWanted())) {
|
|
30
|
-
|
|
31
|
+
R.current = e, m.current = m.current ? `${m.current} ${e.text}` : e.text;
|
|
31
32
|
try {
|
|
32
|
-
|
|
33
|
+
S.current(e.id, e.text, e.lang);
|
|
33
34
|
} catch {
|
|
34
|
-
|
|
35
|
+
R.current = null;
|
|
35
36
|
continue;
|
|
36
37
|
}
|
|
37
38
|
return !0;
|
|
38
39
|
}
|
|
39
40
|
}
|
|
40
|
-
}, []),
|
|
41
|
-
let t =
|
|
41
|
+
}, []), H = u(!1), Fe = c((e) => {
|
|
42
|
+
let t = ce({
|
|
42
43
|
requested: e,
|
|
43
|
-
held:
|
|
44
|
-
muted:
|
|
44
|
+
held: H.current,
|
|
45
|
+
muted: I.current.muted
|
|
45
46
|
});
|
|
46
|
-
|
|
47
|
+
H.current = t.held, t.mute !== null && g({
|
|
47
48
|
type: "mute",
|
|
48
49
|
muted: t.mute
|
|
49
50
|
});
|
|
50
|
-
}, []),
|
|
51
|
-
let t =
|
|
52
|
-
t !== "drop" && (
|
|
53
|
-
}, []),
|
|
54
|
-
if (
|
|
55
|
-
|
|
51
|
+
}, []), U = c((e) => {
|
|
52
|
+
let t = ue(I.current);
|
|
53
|
+
t !== "drop" && (R.current?.id === e.id || L.current.some((t) => t.id === e.id) || (L.current.push(e), t === "start" && !z.current && (z.current = !0, g({ type: "announce" }))));
|
|
54
|
+
}, []), Ie = c((e) => {
|
|
55
|
+
if (I.current.phase !== "thinking") {
|
|
56
|
+
U(e);
|
|
56
57
|
return;
|
|
57
58
|
}
|
|
58
|
-
|
|
59
|
-
}, [
|
|
60
|
-
|
|
61
|
-
if (
|
|
62
|
-
let e =
|
|
63
|
-
|
|
59
|
+
L.current.push(e), z.current = !0, g({ type: "answered-locally" });
|
|
60
|
+
}, [U]), Le = u(f);
|
|
61
|
+
Le.current = f, l(() => {
|
|
62
|
+
if (h.phase === "speaking") {
|
|
63
|
+
let e = k.current;
|
|
64
|
+
m.current = e && D.current === e.id && f?.id !== e.id ? e.text : f?.text ?? null;
|
|
64
65
|
return;
|
|
65
66
|
}
|
|
66
|
-
if (
|
|
67
|
+
if (m.current === null) return;
|
|
67
68
|
let e = setTimeout(() => {
|
|
68
|
-
|
|
69
|
-
},
|
|
69
|
+
m.current = null;
|
|
70
|
+
}, Se);
|
|
70
71
|
return () => clearTimeout(e);
|
|
71
|
-
}, [
|
|
72
|
-
let
|
|
73
|
-
|
|
74
|
-
let
|
|
75
|
-
|
|
72
|
+
}, [h.phase, f]);
|
|
73
|
+
let W = u(p);
|
|
74
|
+
W.current = p;
|
|
75
|
+
let G = c((e, t) => {
|
|
76
|
+
g({
|
|
76
77
|
type: "speech",
|
|
77
78
|
transcript: e,
|
|
78
79
|
final: t,
|
|
79
80
|
at: Date.now(),
|
|
80
|
-
language:
|
|
81
|
+
language: W.current
|
|
81
82
|
});
|
|
82
|
-
}, []),
|
|
83
|
-
|
|
83
|
+
}, []), Re = c((e, t, n) => {
|
|
84
|
+
g({
|
|
84
85
|
type: "speech",
|
|
85
86
|
transcript: e,
|
|
86
87
|
final: t,
|
|
87
88
|
at: Date.now(),
|
|
88
|
-
language: n ??
|
|
89
|
+
language: n ?? W.current,
|
|
89
90
|
gated: !0
|
|
90
91
|
});
|
|
91
|
-
}, []),
|
|
92
|
-
|
|
93
|
-
}, [
|
|
94
|
-
onFinalize: c((e) =>
|
|
92
|
+
}, []), K = u(0), ze = c(() => {
|
|
93
|
+
B(), x(), K.current = Date.now(), M(!0), g({ type: "interrupt" });
|
|
94
|
+
}, [x, B]), q = e({
|
|
95
|
+
onFinalize: c((e) => G(e, !0), [G]),
|
|
95
96
|
language: p
|
|
96
|
-
}),
|
|
97
|
-
|
|
98
|
-
let
|
|
99
|
-
|
|
100
|
-
}, [
|
|
101
|
-
enabled: ee(Oe, r(),
|
|
102
|
-
phase:
|
|
103
|
-
muted:
|
|
97
|
+
}), Be = u(je);
|
|
98
|
+
Be.current = je;
|
|
99
|
+
let Ve = c(() => {
|
|
100
|
+
B(), te(), x(), K.current = Date.now(), M(!0), g({ type: "interrupt" }), Be.current?.();
|
|
101
|
+
}, [x, B]), He = _e(), J = pe({
|
|
102
|
+
enabled: ee(Oe, r(), He),
|
|
103
|
+
phase: h.phase,
|
|
104
|
+
muted: h.muted,
|
|
104
105
|
language: p,
|
|
105
106
|
streamNoticeAccepted: ke ?? null,
|
|
106
107
|
onAcceptStreamNotice: Ae,
|
|
107
|
-
onBargeIn:
|
|
108
|
-
onTranscript:
|
|
109
|
-
}),
|
|
108
|
+
onBargeIn: Ve,
|
|
109
|
+
onTranscript: Re
|
|
110
|
+
}), Ue = J.mode === "notice", Y = q.isListening || J.suppressWebSpeech && J.mode === "active";
|
|
110
111
|
l(() => {
|
|
111
|
-
|
|
112
|
-
}, [
|
|
113
|
-
|
|
112
|
+
q.interim && G(q.interim, !1);
|
|
113
|
+
}, [q.interim, G]), l(() => {
|
|
114
|
+
w.current && clearTimeout(w.current), N(!1), E.current = oe(E.current, h, s());
|
|
114
115
|
let e = t({
|
|
115
|
-
phase:
|
|
116
|
-
muted:
|
|
117
|
-
spoken: o(
|
|
118
|
-
holding:
|
|
119
|
-
graceMs:
|
|
116
|
+
phase: h.phase,
|
|
117
|
+
muted: h.muted,
|
|
118
|
+
spoken: o(h),
|
|
119
|
+
holding: P,
|
|
120
|
+
graceMs: Me
|
|
120
121
|
});
|
|
121
122
|
if (!e.arm) return;
|
|
122
|
-
let n = setTimeout(() =>
|
|
123
|
-
return
|
|
124
|
-
|
|
125
|
-
speechEnded:
|
|
123
|
+
let n = setTimeout(() => N(!0), Math.min(800, e.delayMs)), r = s();
|
|
124
|
+
return w.current = setTimeout(() => {
|
|
125
|
+
T.current = {
|
|
126
|
+
speechEnded: E.current.at ?? r,
|
|
126
127
|
graceStarted: r,
|
|
127
128
|
graceEnded: s()
|
|
128
|
-
},
|
|
129
|
+
}, g({
|
|
129
130
|
type: "silence",
|
|
130
131
|
at: Date.now()
|
|
131
132
|
});
|
|
132
133
|
}, e.delayMs), () => {
|
|
133
|
-
clearTimeout(n),
|
|
134
|
+
clearTimeout(n), w.current && clearTimeout(w.current);
|
|
134
135
|
};
|
|
135
136
|
}, [
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
137
|
+
h,
|
|
138
|
+
P,
|
|
139
|
+
Me
|
|
139
140
|
]), l(() => {
|
|
140
|
-
(
|
|
141
|
-
}, [
|
|
142
|
-
if (!
|
|
143
|
-
let e = Date.now() -
|
|
141
|
+
(h.phase !== "listening" || h.muted) && F(!1);
|
|
142
|
+
}, [h.phase, h.muted]), l(() => {
|
|
143
|
+
if (!j) return;
|
|
144
|
+
let e = Date.now() - K.current, t = Y ? Math.max(0, 500 - e) : Math.max(0, ae - e), n = setTimeout(() => M(!1), t);
|
|
144
145
|
return () => clearTimeout(n);
|
|
145
|
-
}, [
|
|
146
|
-
let
|
|
147
|
-
|
|
148
|
-
if (
|
|
149
|
-
|
|
150
|
-
let e =
|
|
151
|
-
e && Te(e, Q.current ?? `vs-orphan-${Date.now().toString(36)}`,
|
|
152
|
-
}, [
|
|
153
|
-
let e =
|
|
154
|
-
e.claim && (
|
|
146
|
+
}, [j, Y]);
|
|
147
|
+
let We = u("");
|
|
148
|
+
h.phase === "listening" && (We.current = o(h)), l(() => {
|
|
149
|
+
if (h.phase !== "thinking") return;
|
|
150
|
+
y(!1), B(), A((e) => typeof e == "object" && e ? null : e);
|
|
151
|
+
let e = We.current.trim();
|
|
152
|
+
e && Te(e, Q.current ?? `vs-orphan-${Date.now().toString(36)}`, T.current, { correction: I.current.correcting }), T.current = {}, E.current = i;
|
|
153
|
+
}, [h.phase]), l(() => {
|
|
154
|
+
let e = le(f?.id, h.phase, D.current, me(f?.id));
|
|
155
|
+
e.claim && (D.current = f?.id ?? null, e.advance && f && (f.refused ? (B(), A({
|
|
155
156
|
kind: "turn-refused",
|
|
156
157
|
text: f.text
|
|
157
|
-
}),
|
|
158
|
+
}), g({ type: "turn-refused" })) : g({
|
|
158
159
|
type: "reply",
|
|
159
160
|
text: f.text
|
|
160
161
|
})));
|
|
161
162
|
}, [
|
|
162
163
|
f,
|
|
163
|
-
|
|
164
|
-
|
|
164
|
+
h.phase,
|
|
165
|
+
B
|
|
165
166
|
]), l(() => {
|
|
166
|
-
if (
|
|
167
|
-
if (
|
|
168
|
-
|
|
167
|
+
if (b === null || h.phase !== "thinking" || D.current === b) return;
|
|
168
|
+
if (me(b)) {
|
|
169
|
+
x();
|
|
169
170
|
return;
|
|
170
171
|
}
|
|
171
|
-
let e =
|
|
172
|
-
!e || e.channel !== "voice" || e.voiceSessionId === void 0 || e.voiceSessionId !== Q.current || (
|
|
173
|
-
id:
|
|
172
|
+
let e = re.peek(b);
|
|
173
|
+
!e || e.channel !== "voice" || e.voiceSessionId === void 0 || e.voiceSessionId !== Q.current || (D.current = b, k.current = {
|
|
174
|
+
id: b,
|
|
174
175
|
text: e.text
|
|
175
|
-
},
|
|
176
|
+
}, g({
|
|
176
177
|
type: "reply-audio-started",
|
|
177
|
-
replyId:
|
|
178
|
+
replyId: b
|
|
178
179
|
}));
|
|
179
180
|
}, [
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
181
|
+
b,
|
|
182
|
+
h.phase,
|
|
183
|
+
x
|
|
183
184
|
]), l(() => {
|
|
184
|
-
let e =
|
|
185
|
-
|
|
186
|
-
}, [
|
|
187
|
-
|
|
188
|
-
}, [
|
|
189
|
-
if (
|
|
185
|
+
let e = b !== null;
|
|
186
|
+
O.current && !e && (R.current = null, (I.current.phase !== "speaking" || !V()) && g({ type: "speech-ended" })), O.current = e;
|
|
187
|
+
}, [b, V]), l(() => {
|
|
188
|
+
h.phase !== "listening" && A((e) => e === "nothing-heard" ? null : e);
|
|
189
|
+
}, [h.phase]), l(() => {
|
|
190
|
+
if (h.phase !== "speaking" || b !== null) return;
|
|
190
191
|
let e = setTimeout(() => {
|
|
191
|
-
|
|
192
|
-
},
|
|
192
|
+
O.current || (B(), g({ type: "speech-ended" }));
|
|
193
|
+
}, xe);
|
|
193
194
|
return () => clearTimeout(e);
|
|
194
195
|
}, [
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
196
|
+
h.phase,
|
|
197
|
+
b,
|
|
198
|
+
B
|
|
198
199
|
]);
|
|
199
|
-
let
|
|
200
|
+
let X = _.outputNotCleared;
|
|
200
201
|
l(() => {
|
|
201
|
-
if (
|
|
202
|
-
let { phase: e } =
|
|
203
|
-
e === "idle" || e === "ended" || e === "thinking" ||
|
|
204
|
-
}, [
|
|
205
|
-
|
|
206
|
-
}, [
|
|
207
|
-
let
|
|
208
|
-
|
|
202
|
+
if (X === null || D.current !== X.messageId) return;
|
|
203
|
+
let { phase: e } = I.current;
|
|
204
|
+
e === "idle" || e === "ended" || e === "thinking" || A("reply-not-heard");
|
|
205
|
+
}, [X]), l(() => {
|
|
206
|
+
h.phase === "listening" || h.phase === "thinking" || A((e) => e === "reply-not-heard" ? null : e);
|
|
207
|
+
}, [h.phase]);
|
|
208
|
+
let Z = u(De);
|
|
209
|
+
Z.current = De;
|
|
209
210
|
let Ge = u(0);
|
|
210
211
|
l(() => {
|
|
211
|
-
let e =
|
|
212
|
-
e !== Ge.current && (Ge.current = e, e !== 0 && (
|
|
212
|
+
let e = h.superseded;
|
|
213
|
+
e !== Ge.current && (Ge.current = e, e !== 0 && (B(), x(), Z.current?.()));
|
|
213
214
|
}, [
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
215
|
+
h.superseded,
|
|
216
|
+
B,
|
|
217
|
+
x
|
|
217
218
|
]), l(() => {
|
|
218
|
-
|
|
219
|
+
y(a(h)), de(h) && !J.suppressWebSpeech ? q.isActive || q.start("auto") : q.isActive && q.stop();
|
|
219
220
|
}, [
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
221
|
+
h,
|
|
222
|
+
q,
|
|
223
|
+
y,
|
|
224
|
+
J.suppressWebSpeech
|
|
224
225
|
]), l(() => {
|
|
225
|
-
|
|
226
|
-
}, [
|
|
227
|
-
|
|
226
|
+
h.phase !== "speaking" || !z.current || (z.current = !1, V() || g({ type: "speech-ended" }));
|
|
227
|
+
}, [h.phase, V]), l(() => {
|
|
228
|
+
q.error === "not-allowed" || q.error === "audio-capture" ? g({
|
|
228
229
|
type: "fail",
|
|
229
230
|
error: "mic-denied"
|
|
230
|
-
}) :
|
|
231
|
+
}) : q.error === "language-not-supported" ? g({
|
|
231
232
|
type: "fail",
|
|
232
233
|
error: "no-speech-support"
|
|
233
|
-
}) :
|
|
234
|
-
}, [
|
|
235
|
-
|
|
236
|
-
}, [
|
|
237
|
-
if (
|
|
238
|
-
let e = setTimeout(() =>
|
|
234
|
+
}) : q.error === "network" ? A("network") : q.error === "unknown" && A("recognition-failed");
|
|
235
|
+
}, [q.error]), l(() => {
|
|
236
|
+
q.error !== null || !Y || A((e) => e === "network" || e === "recognition-failed" ? null : e);
|
|
237
|
+
}, [q.error, Y]), l(() => {
|
|
238
|
+
if (Y && A((e) => e === "not-capturing" ? null : e), !a(h) || Y || Ue) return;
|
|
239
|
+
let e = setTimeout(() => A("not-capturing"), Ce);
|
|
239
240
|
return () => clearTimeout(e);
|
|
240
241
|
}, [
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
242
|
+
h,
|
|
243
|
+
Y,
|
|
244
|
+
Ue
|
|
244
245
|
]), l(() => {
|
|
245
|
-
if (
|
|
246
|
-
let e = setTimeout(() =>
|
|
246
|
+
if (h.phase !== "listening" || h.muted || !Y || o(h) !== "") return;
|
|
247
|
+
let e = setTimeout(() => A("nothing-heard"), we);
|
|
247
248
|
return () => clearTimeout(e);
|
|
248
|
-
}, [
|
|
249
|
-
o(
|
|
250
|
-
}, [
|
|
249
|
+
}, [h, Y]), l(() => {
|
|
250
|
+
o(h) !== "" && A(null);
|
|
251
|
+
}, [h]);
|
|
251
252
|
let Q = u(null), Ke = c(() => {
|
|
252
|
-
if (
|
|
253
|
-
|
|
253
|
+
if (M(!1), N(!1), F(!1), B(), H.current = !1, !q.isSupported) {
|
|
254
|
+
g({
|
|
254
255
|
type: "fail",
|
|
255
256
|
error: "no-speech-support"
|
|
256
257
|
});
|
|
257
258
|
return;
|
|
258
259
|
}
|
|
259
|
-
if (
|
|
260
|
-
|
|
260
|
+
if (_.isBlocked) {
|
|
261
|
+
g({
|
|
261
262
|
type: "fail",
|
|
262
263
|
error: "no-voice-support"
|
|
263
264
|
});
|
|
@@ -270,103 +271,97 @@ function Te({ onSubmit: Te, latestReply: f, language: p, graceMs: Ee, onSupersed
|
|
|
270
271
|
t.volume = 0, e.speak(t);
|
|
271
272
|
}
|
|
272
273
|
} catch {}
|
|
273
|
-
|
|
274
|
-
if (typeof window < "u" && typeof window.Audio == "function") {
|
|
275
|
-
let e = new window.Audio(we);
|
|
276
|
-
e.volume = 0, e.play().catch(() => {});
|
|
277
|
-
}
|
|
278
|
-
} catch {}
|
|
279
|
-
b(!0), j(null), O.current = Ie.current?.id ?? null, A.current = null, Q.current = `vs-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`, v({ type: "start" });
|
|
274
|
+
ne(), v(!0), A(null), D.current = Le.current?.id ?? null, k.current = null, Q.current = `vs-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`, g({ type: "start" });
|
|
280
275
|
}, [
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
276
|
+
q.isSupported,
|
|
277
|
+
_.isBlocked,
|
|
278
|
+
v,
|
|
279
|
+
B
|
|
285
280
|
]), qe = c(() => {
|
|
286
|
-
|
|
281
|
+
M(!1), N(!1), F(!1), B(), H.current = !1, Q.current = null, g({ type: "end" }), x(), v(!1);
|
|
287
282
|
}, [
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
283
|
+
x,
|
|
284
|
+
v,
|
|
285
|
+
B
|
|
291
286
|
]), Je = c((e) => Q.current === e, []), Ye = c(() => {
|
|
292
|
-
let e =
|
|
293
|
-
e.phase !== "listening" || e.muted ||
|
|
287
|
+
let e = I.current;
|
|
288
|
+
e.phase !== "listening" || e.muted || F(!0);
|
|
294
289
|
}, []), Xe = c(() => {
|
|
295
|
-
|
|
296
|
-
let e =
|
|
297
|
-
if (e.phase !== "listening" || e.muted || !
|
|
290
|
+
F(!1);
|
|
291
|
+
let e = I.current;
|
|
292
|
+
if (e.phase !== "listening" || e.muted || !se(o(e))) return;
|
|
298
293
|
let t = s();
|
|
299
|
-
|
|
300
|
-
speechEnded:
|
|
294
|
+
T.current = {
|
|
295
|
+
speechEnded: E.current.at ?? t,
|
|
301
296
|
graceStarted: t,
|
|
302
297
|
graceEnded: t
|
|
303
|
-
},
|
|
298
|
+
}, g({
|
|
304
299
|
type: "silence",
|
|
305
300
|
at: Date.now()
|
|
306
301
|
});
|
|
307
302
|
}, []), Ze = c(() => {
|
|
308
|
-
|
|
303
|
+
g({
|
|
309
304
|
type: "mute",
|
|
310
|
-
muted: !
|
|
305
|
+
muted: !I.current.muted
|
|
311
306
|
});
|
|
312
307
|
}, []);
|
|
313
308
|
l(() => () => {
|
|
314
|
-
|
|
315
|
-
}, [
|
|
316
|
-
let $ =
|
|
317
|
-
return
|
|
318
|
-
session:
|
|
319
|
-
notice:
|
|
309
|
+
v(!1), y(!1);
|
|
310
|
+
}, [v, y]);
|
|
311
|
+
let $ = he(_.spokenChunks, h.phase, b);
|
|
312
|
+
return ye(() => ({
|
|
313
|
+
session: h,
|
|
314
|
+
notice: Ne ?? (J.fallbackReason !== null && J.fallbackReason !== "notice-declined" ? "hands-free-fallback" : J.nothingHeard ? "hands-free-nothing-heard" : null),
|
|
320
315
|
spokenChunks: $,
|
|
321
|
-
capturing:
|
|
322
|
-
active:
|
|
323
|
-
interrupting:
|
|
324
|
-
awaitingEndpoint:
|
|
325
|
-
holding:
|
|
326
|
-
correcting:
|
|
316
|
+
capturing: Y,
|
|
317
|
+
active: h.phase !== "idle" && (h.phase !== "ended" || h.error !== null),
|
|
318
|
+
interrupting: j,
|
|
319
|
+
awaitingEndpoint: Pe,
|
|
320
|
+
holding: P,
|
|
321
|
+
correcting: h.correcting,
|
|
327
322
|
handsFree: {
|
|
328
|
-
mode:
|
|
329
|
-
nothingHeard:
|
|
330
|
-
transportKind:
|
|
331
|
-
fallbackReason:
|
|
332
|
-
privacyNotice:
|
|
323
|
+
mode: J.mode,
|
|
324
|
+
nothingHeard: J.nothingHeard,
|
|
325
|
+
transportKind: J.transportKind,
|
|
326
|
+
fallbackReason: J.fallbackReason,
|
|
327
|
+
privacyNotice: J.privacyNotice
|
|
333
328
|
},
|
|
334
|
-
available:
|
|
329
|
+
available: q.isSupported && !_.isBlocked,
|
|
335
330
|
start: Ke,
|
|
336
331
|
end: qe,
|
|
337
332
|
isCurrentSession: Je,
|
|
338
333
|
toggleMute: Ze,
|
|
339
|
-
interrupt:
|
|
334
|
+
interrupt: ze,
|
|
340
335
|
letMeFinish: Ye,
|
|
341
336
|
imDone: Xe,
|
|
342
|
-
announce:
|
|
343
|
-
holdListening:
|
|
344
|
-
answerLocally:
|
|
337
|
+
announce: U,
|
|
338
|
+
holdListening: Fe,
|
|
339
|
+
answerLocally: Ie
|
|
345
340
|
}), [
|
|
346
|
-
|
|
347
|
-
Me,
|
|
348
|
-
M,
|
|
341
|
+
h,
|
|
349
342
|
Ne,
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
Y
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
J.
|
|
358
|
-
|
|
343
|
+
j,
|
|
344
|
+
Pe,
|
|
345
|
+
P,
|
|
346
|
+
Y,
|
|
347
|
+
J.mode,
|
|
348
|
+
J.nothingHeard,
|
|
349
|
+
J.transportKind,
|
|
350
|
+
J.fallbackReason,
|
|
351
|
+
J.privacyNotice,
|
|
352
|
+
q.isSupported,
|
|
353
|
+
_.isBlocked,
|
|
359
354
|
$,
|
|
360
355
|
Ke,
|
|
361
356
|
qe,
|
|
362
357
|
Je,
|
|
363
358
|
Ze,
|
|
364
|
-
|
|
359
|
+
ze,
|
|
365
360
|
Ye,
|
|
366
361
|
Xe,
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
362
|
+
U,
|
|
363
|
+
Fe,
|
|
364
|
+
Ie
|
|
370
365
|
]);
|
|
371
366
|
}
|
|
372
367
|
//#endregion
|
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
* available to the capture worklet's second input so the echo gate can meter it
|
|
4
4
|
* on the microphone's clock.
|
|
5
5
|
*
|
|
6
|
-
* Process-wide registry, because the two sides are far apart:
|
|
7
|
-
* engine creates one `Audio` element per chunk and the
|
|
8
|
-
* the voice session. With nothing attached (hands-free
|
|
9
|
-
* started) `tapPlaybackElement` is a no-op and
|
|
6
|
+
* Process-wide registry, because the two sides are far apart: while capture is
|
|
7
|
+
* attached the hosted TTS engine creates one `Audio` element per chunk, and the
|
|
8
|
+
* capture graph lives in the voice session. With nothing attached (hands-free
|
|
9
|
+
* off, or capture not yet started) `tapPlaybackElement` is a no-op and the
|
|
10
|
+
* engine plays on its one reusable element instead (BOFF-9408).
|
|
10
11
|
*
|
|
11
12
|
* When attached, each element is routed
|
|
12
13
|
* element -> MediaElementSource -> gain -> { reference bus, speakers }
|
|
@@ -26,6 +27,16 @@ export declare function attachPlaybackReference(context: AudioContext, reference
|
|
|
26
27
|
* microphone never cuts a reply off mid-word.
|
|
27
28
|
*/
|
|
28
29
|
export declare function detachPlaybackReference(closeContext: () => void): void;
|
|
30
|
+
/**
|
|
31
|
+
* Is a capture graph listening for the assistant's output right now?
|
|
32
|
+
*
|
|
33
|
+
* The hosted engine asks before each piece (BOFF-9408): while attached it plays
|
|
34
|
+
* a fresh element and taps it; otherwise it reuses its one unlocked element.
|
|
35
|
+
* A tapped element is bound to THIS context for good (`createMediaElementSource`
|
|
36
|
+
* works once per element), so reusing it after the context closes would play
|
|
37
|
+
* into nothing.
|
|
38
|
+
*/
|
|
39
|
+
export declare function isPlaybackReferenceAttached(): boolean;
|
|
29
40
|
/** Route a freshly created playback element through the reference bus. */
|
|
30
41
|
export declare function tapPlaybackElement(element: HTMLMediaElement): void;
|
|
31
42
|
/** Cut every tapped element's output at once (a barge-in). */
|