@burdenoff/fe-libs 2026.1013.9 → 2026.1013.11
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/i18nManifest.d.ts +1 -0
- package/dist/shared/assistant/i18nManifest.js +1 -0
- package/dist/shared/assistant/index.d.ts +1 -0
- package/dist/shared/assistant/speech/hostedTtsSpeechEngine.js +96 -72
- package/dist/shared/assistant/speech/pieceSink.d.ts +51 -0
- package/dist/shared/assistant/speech/pieceSink.js +90 -0
- package/dist/shared/assistant/speech/routingSpeechEngine.js +47 -37
- package/dist/shared/assistant/speech/types.d.ts +105 -1
- package/dist/shared/assistant/speech/types.js +4 -0
- package/dist/shared/assistant/ui/AssistantSpeechProvider.d.ts +11 -0
- package/dist/shared/assistant/ui/AssistantSpeechProvider.js +255 -250
- package/dist/shared/assistant/ui/useVoiceSession.d.ts +7 -1
- package/dist/shared/assistant/ui/useVoiceSession.js +253 -245
- package/dist/shared/assistant/ui/voice/AssistantVoiceSession.js +157 -145
- package/dist/shared-assistant.js +240 -238
- package/package.json +1 -1
|
@@ -515,6 +515,7 @@ export declare const ASSISTANT_I18N_LITERAL_COPY: {
|
|
|
515
515
|
readonly "voiceSession.noticeNotCapturing": "The microphone did not start. Check that this site is allowed to use it, then try again.";
|
|
516
516
|
readonly "voiceSession.noticeNothingHeard": "Nothing heard yet. Check your microphone is not muted or in use by another app.";
|
|
517
517
|
readonly "voiceSession.noticeRecognitionFailed": "Speech recognition stopped unexpectedly. It will retry — if it keeps happening, reload the page.";
|
|
518
|
+
readonly "voiceSession.noticeReplyNotHeard": "That reply was not read aloud: earlier audio may still be playing. Read it in the transcript.";
|
|
518
519
|
readonly "voiceSession.save": "Save transcript";
|
|
519
520
|
readonly "voiceSession.savedAt": "Saved";
|
|
520
521
|
readonly "voiceSession.sessionLabel": "Session";
|
|
@@ -409,6 +409,7 @@ var m = {
|
|
|
409
409
|
"voiceSession.noticeNotCapturing": "The microphone did not start. Check that this site is allowed to use it, then try again.",
|
|
410
410
|
"voiceSession.noticeNothingHeard": "Nothing heard yet. Check your microphone is not muted or in use by another app.",
|
|
411
411
|
"voiceSession.noticeRecognitionFailed": "Speech recognition stopped unexpectedly. It will retry — if it keeps happening, reload the page.",
|
|
412
|
+
"voiceSession.noticeReplyNotHeard": "That reply was not read aloud: earlier audio may still be playing. Read it in the transcript.",
|
|
412
413
|
"voiceSession.save": "Save transcript",
|
|
413
414
|
"voiceSession.savedAt": "Saved",
|
|
414
415
|
"voiceSession.sessionLabel": "Session",
|
|
@@ -44,6 +44,7 @@ export * from './speech/browserSpeechEngine';
|
|
|
44
44
|
export * from './speech/hostedTtsSpeechEngine';
|
|
45
45
|
export * from './speech/routingSpeechEngine';
|
|
46
46
|
export * from './speech/hostedVoiceCatalogue';
|
|
47
|
+
export * from './speech/pieceSink';
|
|
47
48
|
export * from './speech/speechFeed';
|
|
48
49
|
export * from './voice/useVoiceInput';
|
|
49
50
|
export * from './voice/voiceStageState';
|
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
import { tapPlaybackElement as e } from "../voice/handsfree/playbackReference.js";
|
|
2
2
|
import { HOSTED_TTS_TIER as t, HOSTED_VOICES as n, hostedLocaleFor as r } from "./hostedVoiceCatalogue.js";
|
|
3
3
|
import { buildRequest as i, classifyHttpFailure as a, decodeAudioResponse as o, disableDurationMs as s, shouldDisableEngine as c, speakableChunks as l } from "./hostedTtsProtocol.js";
|
|
4
|
+
import { createPieceSink as u, isOutputRefusal as d } from "./pieceSink.js";
|
|
4
5
|
//#region src/shared/assistant/speech/hostedTtsSpeechEngine.ts
|
|
5
|
-
function
|
|
6
|
+
function f(e) {
|
|
6
7
|
let t = Object.entries(e).map(([e, t]) => `${e.toLowerCase()}:${t}`).sort().join("\n"), n = 5381;
|
|
7
8
|
for (let e = 0; e < t.length; e += 1) n = (n << 5) + n + t.charCodeAt(e) | 0;
|
|
8
9
|
return `${t.length}:${n >>> 0}`;
|
|
9
10
|
}
|
|
10
|
-
var
|
|
11
|
+
var p = new Set([
|
|
11
12
|
429,
|
|
12
13
|
502,
|
|
13
14
|
503,
|
|
14
15
|
504
|
|
15
|
-
]),
|
|
16
|
-
function
|
|
16
|
+
]), m = 3, h = 400, g = 2e3;
|
|
17
|
+
function _(e, t) {
|
|
17
18
|
let n = e === null ? NaN : Number(e);
|
|
18
|
-
return Math.min(Number.isFinite(n) && n >= 0 ? n * 1e3 :
|
|
19
|
+
return Math.min(Number.isFinite(n) && n >= 0 ? n * 1e3 : h * 2 ** (t - 1), g);
|
|
19
20
|
}
|
|
20
|
-
function
|
|
21
|
+
function v(e, t) {
|
|
21
22
|
return new Promise((n) => {
|
|
22
23
|
if (t.aborted) {
|
|
23
24
|
n();
|
|
@@ -32,44 +33,44 @@ function g(e, t) {
|
|
|
32
33
|
t.addEventListener("abort", i, { once: !0 });
|
|
33
34
|
});
|
|
34
35
|
}
|
|
35
|
-
function
|
|
36
|
-
let
|
|
36
|
+
function y(h) {
|
|
37
|
+
let g = h.fetchImpl ?? ((...e) => fetch(...e)), y = h.now ?? (() => Date.now()), b = null, x = null, S = 0, C = null, w = null, T = 0, E = null, D = null, O = () => {
|
|
37
38
|
try {
|
|
38
|
-
return
|
|
39
|
+
return h.getHeaders?.() ?? {};
|
|
39
40
|
} catch {
|
|
40
41
|
return {};
|
|
41
42
|
}
|
|
42
|
-
},
|
|
43
|
-
for (let e of [...
|
|
44
|
-
},
|
|
45
|
-
|
|
46
|
-
},
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
let e =
|
|
43
|
+
}, k = () => y() >= T ? !1 : D === null ? !0 : f(O()) === D, A = /* @__PURE__ */ new Set(), j = () => {
|
|
44
|
+
for (let e of [...A]) e();
|
|
45
|
+
}, M = () => {
|
|
46
|
+
E !== null && clearTimeout(E), E = null;
|
|
47
|
+
}, N = (e) => {
|
|
48
|
+
M(), E = setTimeout(() => {
|
|
49
|
+
E = null;
|
|
50
|
+
let e = T - y();
|
|
50
51
|
if (e > 0) {
|
|
51
|
-
|
|
52
|
+
N(e);
|
|
52
53
|
return;
|
|
53
54
|
}
|
|
54
|
-
|
|
55
|
+
j();
|
|
55
56
|
}, e);
|
|
56
|
-
},
|
|
57
|
-
|
|
58
|
-
},
|
|
59
|
-
|
|
60
|
-
},
|
|
61
|
-
if (
|
|
62
|
-
|
|
57
|
+
}, P = (e, t) => {
|
|
58
|
+
T = y() + e, D = t, N(e), j();
|
|
59
|
+
}, F = () => {
|
|
60
|
+
x &&= (URL.revokeObjectURL(x), null);
|
|
61
|
+
}, I = () => {
|
|
62
|
+
if (b) {
|
|
63
|
+
b.onended = null, b.onerror = null;
|
|
63
64
|
try {
|
|
64
|
-
|
|
65
|
+
b.pause();
|
|
65
66
|
} catch {}
|
|
66
|
-
|
|
67
|
+
b = null;
|
|
67
68
|
}
|
|
68
|
-
|
|
69
|
+
F();
|
|
69
70
|
};
|
|
70
|
-
async function
|
|
71
|
-
let c = i(e, r(n.lang) ?? n.lang, t, n.voice?.name ?? null, n.rate), l =
|
|
72
|
-
for (let e = 1;
|
|
71
|
+
async function L(e, n, s) {
|
|
72
|
+
let c = i(e, r(n.lang) ?? n.lang, t, n.voice?.name ?? null, n.rate), l = h.getHeaders?.() ?? {}, u;
|
|
73
|
+
for (let e = 1; u = await g(h.endpoint, {
|
|
73
74
|
method: "POST",
|
|
74
75
|
signal: s,
|
|
75
76
|
headers: {
|
|
@@ -77,42 +78,42 @@ function _(p) {
|
|
|
77
78
|
...l
|
|
78
79
|
},
|
|
79
80
|
body: JSON.stringify(c)
|
|
80
|
-
}), !
|
|
81
|
-
if (!(
|
|
82
|
-
let e = /* @__PURE__ */ Error(`hosted tts ${
|
|
83
|
-
throw e.reason = a(
|
|
81
|
+
}), !u.ok; e += 1) {
|
|
82
|
+
if (!(p.has(u.status) && e < m && !s.aborted)) {
|
|
83
|
+
let e = /* @__PURE__ */ Error(`hosted tts ${u.status}`);
|
|
84
|
+
throw e.reason = a(u.status), e.headers = f(l), e;
|
|
84
85
|
}
|
|
85
|
-
await
|
|
86
|
+
await v(_(u.headers.get("retry-after"), e), s);
|
|
86
87
|
}
|
|
87
|
-
let
|
|
88
|
+
let d = u.headers.get("content-type"), y = o(d, d?.includes("json") ? await u.json() : await u.arrayBuffer());
|
|
88
89
|
if (!y) {
|
|
89
90
|
let e = /* @__PURE__ */ Error("hosted tts returned no audio");
|
|
90
91
|
throw e.reason = "unknown", e;
|
|
91
92
|
}
|
|
92
93
|
return y;
|
|
93
94
|
}
|
|
94
|
-
function
|
|
95
|
+
function R(t, n, r) {
|
|
95
96
|
return new Promise((i, a) => {
|
|
96
|
-
if (n !==
|
|
97
|
+
if (n !== S) {
|
|
97
98
|
i();
|
|
98
99
|
return;
|
|
99
100
|
}
|
|
100
101
|
let o = new Blob([t.slice().buffer], { type: "audio/mpeg" });
|
|
101
|
-
|
|
102
|
-
let s = new Audio(
|
|
103
|
-
e(s),
|
|
104
|
-
n ===
|
|
102
|
+
F(), x = URL.createObjectURL(o);
|
|
103
|
+
let s = new Audio(x);
|
|
104
|
+
e(s), b = s, s.onended = () => {
|
|
105
|
+
n === S && i();
|
|
105
106
|
}, s.onerror = () => {
|
|
106
|
-
if (n !==
|
|
107
|
+
if (n !== S) {
|
|
107
108
|
i();
|
|
108
109
|
return;
|
|
109
110
|
}
|
|
110
111
|
let e = /* @__PURE__ */ Error("audio playback failed");
|
|
111
112
|
e.reason = "unknown", a(e);
|
|
112
113
|
}, s.play().then(() => {
|
|
113
|
-
n ===
|
|
114
|
+
n === S && r?.();
|
|
114
115
|
}, (e) => {
|
|
115
|
-
if (n !==
|
|
116
|
+
if (n !== S) {
|
|
116
117
|
i();
|
|
117
118
|
return;
|
|
118
119
|
}
|
|
@@ -124,14 +125,14 @@ function _(p) {
|
|
|
124
125
|
return {
|
|
125
126
|
id: "hosted-tts",
|
|
126
127
|
isSupported() {
|
|
127
|
-
return
|
|
128
|
+
return k() ? !1 : typeof window < "u" && typeof window.Audio == "function" && typeof fetch == "function";
|
|
128
129
|
},
|
|
129
130
|
listVoices() {
|
|
130
|
-
return
|
|
131
|
+
return k() ? [] : [...n];
|
|
131
132
|
},
|
|
132
133
|
subscribeVoices(e) {
|
|
133
|
-
return
|
|
134
|
-
|
|
134
|
+
return A.add(e), () => {
|
|
135
|
+
A.delete(e);
|
|
135
136
|
};
|
|
136
137
|
},
|
|
137
138
|
speak(e, t, n = {}) {
|
|
@@ -140,43 +141,66 @@ function _(p) {
|
|
|
140
141
|
n.onEnd?.();
|
|
141
142
|
return;
|
|
142
143
|
}
|
|
143
|
-
|
|
144
|
-
let i =
|
|
145
|
-
|
|
144
|
+
S += 1;
|
|
145
|
+
let i = S;
|
|
146
|
+
I(), w?.cancel();
|
|
146
147
|
let a = new AbortController();
|
|
147
|
-
|
|
148
|
-
let o = !1,
|
|
148
|
+
C = a;
|
|
149
|
+
let o = !1, f = () => {
|
|
149
150
|
o || (o = !0, n.onStart?.());
|
|
150
|
-
},
|
|
151
|
-
let n =
|
|
151
|
+
}, p = (e) => {
|
|
152
|
+
let n = L(e, t, a.signal);
|
|
152
153
|
return n.catch(() => {}), n;
|
|
153
|
-
}
|
|
154
|
-
|
|
154
|
+
}, m = t.audioOutput ? u(t.audioOutput, {
|
|
155
|
+
play: (e) => R(e, i, f),
|
|
156
|
+
isCurrent: () => i === S,
|
|
157
|
+
onChunkStart: (e) => n.onChunkStart?.(e),
|
|
158
|
+
onStart: f
|
|
159
|
+
}) : null;
|
|
160
|
+
w = m, (async () => {
|
|
155
161
|
try {
|
|
156
|
-
let e =
|
|
162
|
+
let e = p(r[0]);
|
|
157
163
|
for (let t = 0; t < r.length; t += 1) {
|
|
158
|
-
if (i !==
|
|
164
|
+
if (i !== S) return;
|
|
159
165
|
let a = await e;
|
|
160
|
-
if (i !==
|
|
166
|
+
if (i !== S) return;
|
|
161
167
|
let o = r[t + 1];
|
|
162
|
-
o !== void 0 && (e =
|
|
168
|
+
if (o !== void 0 && (e = p(o)), m) {
|
|
169
|
+
await m.write(a);
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
n.onChunkStart?.(t), await R(a, i, f);
|
|
163
173
|
}
|
|
164
|
-
|
|
174
|
+
if (m) {
|
|
175
|
+
let e = await m.drain();
|
|
176
|
+
if (i !== S) return;
|
|
177
|
+
if (!e) throw Object.assign(/* @__PURE__ */ Error("audio output did not finish"), { reason: "unknown" });
|
|
178
|
+
}
|
|
179
|
+
i === S && n.onEnd?.();
|
|
165
180
|
} catch (e) {
|
|
166
|
-
if (a.abort(), i !==
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
181
|
+
if (a.abort(), i !== S) return;
|
|
182
|
+
let t = null;
|
|
183
|
+
if (m) {
|
|
184
|
+
let n = await m.drain().then(() => null, (e) => e);
|
|
185
|
+
if (i !== S) return;
|
|
186
|
+
m.cancel(), d(e) ? t = e : d(n) && (t = n);
|
|
187
|
+
}
|
|
188
|
+
if (S += 1, I(), t) {
|
|
189
|
+
n.onError?.("output-not-cleared");
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
let r = e?.reason;
|
|
193
|
+
c(r, e?.transient === !0) && P(s(r), r === "not-allowed" ? e.headers ?? null : null), n.onError?.(r === "not-allowed" || r === "unsupported" || r === "cancelled" ? r : "unknown");
|
|
170
194
|
}
|
|
171
195
|
})();
|
|
172
196
|
},
|
|
173
197
|
headersChanged() {
|
|
174
|
-
|
|
198
|
+
y() >= T || D === null || k() || (T = 0, D = null, M(), j());
|
|
175
199
|
},
|
|
176
200
|
cancel() {
|
|
177
|
-
|
|
201
|
+
S += 1, C?.abort(), C = null, I(), w?.cancel(), w = null;
|
|
178
202
|
}
|
|
179
203
|
};
|
|
180
204
|
}
|
|
181
205
|
//#endregion
|
|
182
|
-
export {
|
|
206
|
+
export { y as createHostedTtsEngine, _ as retryDelayMs };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { SpeechAudioOutput, SpeechOutputRefusal } from './types';
|
|
2
|
+
/** @internal What the sink needs from the reply it belongs to. */
|
|
3
|
+
export interface PieceSinkReply {
|
|
4
|
+
/** Plays one piece on the speakers and resolves when it has finished: the engine's own `play`. */
|
|
5
|
+
play(bytes: Uint8Array): Promise<void>;
|
|
6
|
+
/** False once the reply was cancelled or replaced: nothing more is played. */
|
|
7
|
+
isCurrent(): boolean;
|
|
8
|
+
/** Piece `index` begins: the live caption's sync signal. */
|
|
9
|
+
onChunkStart(index: number): void;
|
|
10
|
+
/** The reply's first sound (the engine announces it once per reply). */
|
|
11
|
+
onStart(): void;
|
|
12
|
+
}
|
|
13
|
+
/** @internal The engine's side of one reply's audio output. */
|
|
14
|
+
export interface PieceSink {
|
|
15
|
+
/**
|
|
16
|
+
* Hand over the reply's next piece. Pieces are numbered 0, 1, 2… by ONE
|
|
17
|
+
* counter for the whole reply: a queue's count continues across appends and
|
|
18
|
+
* across drains, and a retracted number is never given again. Resolves when
|
|
19
|
+
* the next piece may follow; rejects as `drain` does once the speakers fail
|
|
20
|
+
* or the output refused the reply.
|
|
21
|
+
*/
|
|
22
|
+
write(bytes: Uint8Array): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Resolves once everything written so far has finished playing: `true`, or
|
|
25
|
+
* `false` when the output FAILED after every piece had begun, so the end was
|
|
26
|
+
* never confirmed (a leave is not a failure: `true`). Callable any number of
|
|
27
|
+
* times; writing may go on after it, even while it is pending (a piece written
|
|
28
|
+
* meanwhile is not part of it). Never rejects with the output's reason, only
|
|
29
|
+
* with the speakers' own failure, which the engine reports as it always has,
|
|
30
|
+
* or with the output's REFUSAL (`SpeechOutputRefusal`, operator decision
|
|
31
|
+
* D7 b), which the engine reports as `output-not-cleared`. Either one is kept:
|
|
32
|
+
* every later or queued `write` and `drain` rejects with it until `cancel()`,
|
|
33
|
+
* nothing more plays, and nothing is confirmed.
|
|
34
|
+
*/
|
|
35
|
+
drain(): Promise<boolean>;
|
|
36
|
+
/**
|
|
37
|
+
* Withdraw every piece from `fromIndex` on that has not begun, on the output
|
|
38
|
+
* and in the record a failure replays from; the one playing finishes.
|
|
39
|
+
*/
|
|
40
|
+
retract(fromIndex: number): void;
|
|
41
|
+
/** The hard stop: silence the output and drop everything. Nothing is replayed. */
|
|
42
|
+
cancel(): void;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* @internal The output REFUSED the reply (`SpeechOutputRefusal`, operator
|
|
46
|
+
* decision D7 b): nothing of it may be heard anywhere. The engine reads it to
|
|
47
|
+
* report `output-not-cleared`.
|
|
48
|
+
*/
|
|
49
|
+
export declare const isOutputRefusal: (cause: unknown) => cause is SpeechOutputRefusal;
|
|
50
|
+
/** @internal One reply's piece sink, playing on `output` until it fails, leaves or refuses. */
|
|
51
|
+
export declare function createPieceSink(output: SpeechAudioOutput, reply: PieceSinkReply): PieceSink;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { SPEECH_OUTPUT_LEFT as e, SPEECH_OUTPUT_REFUSE_AUDIBLE as t } from "./types.js";
|
|
2
|
+
//#region src/shared/assistant/speech/pieceSink.ts
|
|
3
|
+
var n = (t) => t?.reason === e, r = (e) => e?.reason === t;
|
|
4
|
+
function i(e, t) {
|
|
5
|
+
let i = e, a = !1, o = 0, s = /* @__PURE__ */ new Map(), c = null, l = () => !a && t.isCurrent(), u = () => {
|
|
6
|
+
let e = i;
|
|
7
|
+
i = null;
|
|
8
|
+
try {
|
|
9
|
+
e?.cancel();
|
|
10
|
+
} catch {}
|
|
11
|
+
}, d = (e) => (c === null && (c = e), s.clear(), u(), c), f = () => {
|
|
12
|
+
if (c !== null && l()) throw c;
|
|
13
|
+
}, p = (e, n) => () => {
|
|
14
|
+
if (!(i !== e || !l() || !s.has(n))) {
|
|
15
|
+
for (let e of s.keys()) {
|
|
16
|
+
if (e > n) break;
|
|
17
|
+
s.delete(e);
|
|
18
|
+
}
|
|
19
|
+
t.onChunkStart(n), t.onStart();
|
|
20
|
+
}
|
|
21
|
+
}, m = !1, h = async () => {
|
|
22
|
+
for (let [e, n] of s) {
|
|
23
|
+
if (!l()) return;
|
|
24
|
+
s.delete(e), m = !0, t.onChunkStart(e);
|
|
25
|
+
try {
|
|
26
|
+
await t.play(n);
|
|
27
|
+
} catch (e) {
|
|
28
|
+
throw s.clear(), c ?? e;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}, g = Promise.resolve(), _ = () => {
|
|
32
|
+
if (!l()) return Promise.resolve();
|
|
33
|
+
if (c !== null) return Promise.reject(c);
|
|
34
|
+
let e = g.then(h);
|
|
35
|
+
return g = e, e;
|
|
36
|
+
};
|
|
37
|
+
return {
|
|
38
|
+
async write(e) {
|
|
39
|
+
let t = o;
|
|
40
|
+
if (o += 1, !l()) return;
|
|
41
|
+
if (c !== null) throw c;
|
|
42
|
+
s.set(t, e);
|
|
43
|
+
let n = i;
|
|
44
|
+
if (n) try {
|
|
45
|
+
await n.write(e, t, p(n, t));
|
|
46
|
+
} catch (e) {
|
|
47
|
+
if (!l()) return;
|
|
48
|
+
if (r(e)) throw d(e);
|
|
49
|
+
i === n && u();
|
|
50
|
+
}
|
|
51
|
+
i === null && await _(), f();
|
|
52
|
+
},
|
|
53
|
+
async drain() {
|
|
54
|
+
let e = i;
|
|
55
|
+
if (e && l()) {
|
|
56
|
+
let t = o;
|
|
57
|
+
try {
|
|
58
|
+
if (await e.drain(), i === e) {
|
|
59
|
+
for (let e of s.keys()) {
|
|
60
|
+
if (e >= t) break;
|
|
61
|
+
s.delete(e);
|
|
62
|
+
}
|
|
63
|
+
return !0;
|
|
64
|
+
}
|
|
65
|
+
} catch (t) {
|
|
66
|
+
if (!l()) return !0;
|
|
67
|
+
if (r(t)) throw d(t);
|
|
68
|
+
let a = n(t) || s.size > 0;
|
|
69
|
+
return i === e && u(), await _(), f(), a || m;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return await _(), f(), !0;
|
|
73
|
+
},
|
|
74
|
+
retract(e) {
|
|
75
|
+
if (!l()) return;
|
|
76
|
+
let t = i;
|
|
77
|
+
if (t) try {
|
|
78
|
+
t.retract(e);
|
|
79
|
+
} catch {
|
|
80
|
+
i === t && u();
|
|
81
|
+
}
|
|
82
|
+
for (let t of s.keys()) t >= e && s.delete(t);
|
|
83
|
+
},
|
|
84
|
+
cancel() {
|
|
85
|
+
a = !0, s.clear(), u();
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
//#endregion
|
|
90
|
+
export { i as createPieceSink, r as isOutputRefusal };
|
|
@@ -2,82 +2,92 @@ import { hostedSupportsLanguage as e } from "./hostedVoiceCatalogue.js";
|
|
|
2
2
|
import { speakableChunks as t } from "./hostedTtsProtocol.js";
|
|
3
3
|
import { selectVoiceForLocale as n } from "../voice/speechVoices.js";
|
|
4
4
|
//#region src/shared/assistant/speech/routingSpeechEngine.ts
|
|
5
|
-
function r(
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
function r(e) {
|
|
6
|
+
switch (e) {
|
|
7
|
+
case "cancelled":
|
|
8
|
+
case "output-not-cleared": return !1;
|
|
9
|
+
case "not-allowed":
|
|
10
|
+
case "unsupported":
|
|
11
|
+
case "unknown": return !0;
|
|
12
|
+
default: return e;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function i({ device: i, hosted: a }) {
|
|
16
|
+
if (!a) return i;
|
|
17
|
+
let o = new Set(a.listVoices().map((e) => e.name)), s = (e) => e.source === "hosted" || o.has(e.name), c = (e, t, r) => {
|
|
18
|
+
if (!t.voice || !s(t.voice)) {
|
|
19
|
+
i.speak(e, t, r);
|
|
10
20
|
return;
|
|
11
21
|
}
|
|
12
22
|
if (t.fallback === !1) {
|
|
13
|
-
|
|
23
|
+
r?.onError?.("unsupported");
|
|
14
24
|
return;
|
|
15
25
|
}
|
|
16
|
-
let a = n(
|
|
26
|
+
let a = n(i.listVoices(), t.lang);
|
|
17
27
|
if (!a) {
|
|
18
|
-
|
|
28
|
+
r?.onError?.("unsupported");
|
|
19
29
|
return;
|
|
20
30
|
}
|
|
21
|
-
|
|
31
|
+
i.speak(e, {
|
|
22
32
|
...t,
|
|
23
33
|
voice: a
|
|
24
|
-
},
|
|
25
|
-
},
|
|
34
|
+
}, r);
|
|
35
|
+
}, l = (t) => a.isSupported() ? t.voice ? o.has(t.voice.name) ? a : i : e(t.lang) ? a : i : i;
|
|
26
36
|
return {
|
|
27
|
-
id: `routing(${
|
|
37
|
+
id: `routing(${a.id}+${i.id})`,
|
|
28
38
|
isSupported() {
|
|
29
|
-
return
|
|
39
|
+
return a.isSupported() || i.isSupported();
|
|
30
40
|
},
|
|
31
41
|
listVoices() {
|
|
32
|
-
return
|
|
42
|
+
return a.isSupported() ? [...a.listVoices(), ...i.listVoices()] : i.listVoices();
|
|
33
43
|
},
|
|
34
44
|
subscribeVoices(e) {
|
|
35
|
-
let t =
|
|
45
|
+
let t = i.subscribeVoices(e), n = a.subscribeVoices(e);
|
|
36
46
|
return () => {
|
|
37
47
|
t(), n();
|
|
38
48
|
};
|
|
39
49
|
},
|
|
40
|
-
speak(e, n,
|
|
41
|
-
if (
|
|
42
|
-
|
|
50
|
+
speak(e, n, o) {
|
|
51
|
+
if (i.cancel(), a.cancel(), l(n) !== a) {
|
|
52
|
+
c(e, n, o);
|
|
43
53
|
return;
|
|
44
54
|
}
|
|
45
|
-
let
|
|
46
|
-
|
|
47
|
-
...
|
|
55
|
+
let s = !1, u = -1;
|
|
56
|
+
a.speak(e, n, {
|
|
57
|
+
...o,
|
|
48
58
|
onStart: () => {
|
|
49
|
-
|
|
59
|
+
s = !0, o?.onStart?.();
|
|
50
60
|
},
|
|
51
61
|
onChunkStart: (e) => {
|
|
52
|
-
|
|
62
|
+
u = e, o?.onChunkStart?.(e);
|
|
53
63
|
},
|
|
54
|
-
onError: (
|
|
55
|
-
if (r
|
|
56
|
-
|
|
64
|
+
onError: (i) => {
|
|
65
|
+
if (!r(i) || n.fallback === !1) {
|
|
66
|
+
o?.onError?.(i);
|
|
57
67
|
return;
|
|
58
68
|
}
|
|
59
|
-
if (!
|
|
60
|
-
|
|
69
|
+
if (!s) {
|
|
70
|
+
c(e, n, o);
|
|
61
71
|
return;
|
|
62
72
|
}
|
|
63
|
-
let
|
|
64
|
-
if (
|
|
65
|
-
|
|
73
|
+
let a = u >= 0 ? t(e).slice(u + 1) : [];
|
|
74
|
+
if (a.length === 0) {
|
|
75
|
+
o?.onError?.(i);
|
|
66
76
|
return;
|
|
67
77
|
}
|
|
68
|
-
let
|
|
69
|
-
|
|
70
|
-
...
|
|
78
|
+
let l = u + 1;
|
|
79
|
+
c(a, n, {
|
|
80
|
+
...o,
|
|
71
81
|
onStart: void 0,
|
|
72
|
-
onChunkStart: (e) =>
|
|
82
|
+
onChunkStart: (e) => o?.onChunkStart?.(l + e)
|
|
73
83
|
});
|
|
74
84
|
}
|
|
75
85
|
});
|
|
76
86
|
},
|
|
77
87
|
cancel() {
|
|
78
|
-
|
|
88
|
+
i.cancel(), a.cancel();
|
|
79
89
|
}
|
|
80
90
|
};
|
|
81
91
|
}
|
|
82
92
|
//#endregion
|
|
83
|
-
export {
|
|
93
|
+
export { i as createRoutingSpeechEngine };
|