@streamoji/aitwin 0.3.3 → 0.3.5
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 +1 -1
- package/dist/aitwin.cjs +3 -3
- package/dist/aitwin.js +1202 -1110
- package/dist/index.d.ts +5 -1
- package/package.json +1 -1
package/dist/aitwin.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsxs as Kn, jsx as zt } from "react/jsx-runtime";
|
|
2
|
-
import { forwardRef as jn, useRef as
|
|
2
|
+
import { forwardRef as jn, useRef as L, useState as Je, useEffect as Me, useCallback as ge, useMemo as Yt, useImperativeHandle as Gn } from "react";
|
|
3
3
|
import { PipecatClient as zn } from "@pipecat-ai/client-js";
|
|
4
|
-
import { WebSocketTransport as
|
|
5
|
-
const
|
|
6
|
-
publicBase:
|
|
7
|
-
}, Zn = "0.3.
|
|
4
|
+
import { WebSocketTransport as Yn, DailyMediaManager as Jn, ProtobufFrameSerializer as Xn } from "@pipecat-ai/websocket-transport";
|
|
5
|
+
const Qn = "https://aitwin.bubu.social", _n = {
|
|
6
|
+
publicBase: Qn
|
|
7
|
+
}, Zn = "0.3.5", er = {
|
|
8
8
|
version: Zn
|
|
9
9
|
}, tr = {}, tt = "https://ai.aitwin.me", xt = `${_n.publicBase}/custom-faces`, nr = `${_n.publicBase}/aitwin-workers/v${er.version}/visemeDiffPreview.worker.js`;
|
|
10
10
|
function rr(e) {
|
|
@@ -12,29 +12,29 @@ function rr(e) {
|
|
|
12
12
|
const t = typeof import.meta < "u" ? tr?.VITE_AITWIN_WORKER_URL : void 0;
|
|
13
13
|
return t?.trim() ? t.trim() : nr;
|
|
14
14
|
}
|
|
15
|
-
const sr = "https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwin", yn = "eng_a7f2b9c1", Pt = "eng_d4e8f3a2",
|
|
15
|
+
const sr = "https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwin", yn = "eng_a7f2b9c1", Pt = "eng_d4e8f3a2", Ve = "eng_c9b1e6d4", Ue = Ve, Sn = /* @__PURE__ */ new Set([
|
|
16
16
|
Pt,
|
|
17
|
-
|
|
17
|
+
Ve
|
|
18
18
|
]), kn = {
|
|
19
19
|
[yn]: "oculus_direct",
|
|
20
|
-
[
|
|
20
|
+
[Ve]: "oculus_direct",
|
|
21
21
|
[Pt]: "inworld_word"
|
|
22
|
-
},
|
|
22
|
+
}, Jt = {
|
|
23
23
|
google: yn,
|
|
24
24
|
inworld: Pt,
|
|
25
|
-
cartesia:
|
|
25
|
+
cartesia: Ve
|
|
26
26
|
};
|
|
27
27
|
function ir(e) {
|
|
28
28
|
return kn[e];
|
|
29
29
|
}
|
|
30
30
|
function ar(e) {
|
|
31
|
-
return e ===
|
|
31
|
+
return e === Ve;
|
|
32
32
|
}
|
|
33
33
|
function or(e) {
|
|
34
34
|
if (e.ttsEngineId && e.ttsEngineId in kn)
|
|
35
35
|
return e.ttsEngineId;
|
|
36
36
|
const t = e.tts?.toLowerCase();
|
|
37
|
-
return t && t in
|
|
37
|
+
return t && t in Jt ? Jt[t] : Ue;
|
|
38
38
|
}
|
|
39
39
|
class Tt extends Error {
|
|
40
40
|
constructor(t = "AI twin not found") {
|
|
@@ -90,7 +90,7 @@ async function hr(e, t = tt) {
|
|
|
90
90
|
if (!r.value) throw new Error("Session value response missing value");
|
|
91
91
|
return r;
|
|
92
92
|
}
|
|
93
|
-
function
|
|
93
|
+
function gr(e) {
|
|
94
94
|
const t = e.trim();
|
|
95
95
|
if (t.length % 2 !== 0) throw new Error("Invalid hex key");
|
|
96
96
|
const n = new Uint8Array(t.length / 2);
|
|
@@ -98,10 +98,10 @@ function wr(e) {
|
|
|
98
98
|
n[r / 2] = Number.parseInt(t.slice(r, r + 2), 16);
|
|
99
99
|
return n;
|
|
100
100
|
}
|
|
101
|
-
function
|
|
101
|
+
function at(e) {
|
|
102
102
|
return Uint8Array.from(e);
|
|
103
103
|
}
|
|
104
|
-
function
|
|
104
|
+
function wr(e, t) {
|
|
105
105
|
const n = new Uint8Array(e.length + t.length);
|
|
106
106
|
return n.set(e, 0), n.set(t, e.length), n;
|
|
107
107
|
}
|
|
@@ -109,9 +109,9 @@ async function pr(e, t) {
|
|
|
109
109
|
if (!t) throw new Error("Asset key is required for encrypted assets");
|
|
110
110
|
if (e.byteLength < 28)
|
|
111
111
|
throw new Error("Encrypted payload too small");
|
|
112
|
-
const n = new Uint8Array(e), r =
|
|
112
|
+
const n = new Uint8Array(e), r = at(n.subarray(0, 12)), s = at(n.subarray(12, 28)), i = at(n.subarray(28)), o = at(wr(i, s)), a = await crypto.subtle.importKey(
|
|
113
113
|
"raw",
|
|
114
|
-
|
|
114
|
+
gr(t),
|
|
115
115
|
{ name: "AES-GCM" },
|
|
116
116
|
!1,
|
|
117
117
|
["decrypt"]
|
|
@@ -124,20 +124,20 @@ async function pr(e, t) {
|
|
|
124
124
|
}
|
|
125
125
|
let At = null;
|
|
126
126
|
const It = /* @__PURE__ */ new Set();
|
|
127
|
-
function
|
|
127
|
+
function ot(e) {
|
|
128
128
|
return e.includes("/custom-faces/");
|
|
129
129
|
}
|
|
130
|
-
function
|
|
130
|
+
function lt(e) {
|
|
131
131
|
const t = e.binBase.trim().replace(/\/$/, ""), n = e.twinBase.trim().replace(/\/$/, "");
|
|
132
|
-
if (!(e.encrypted ||
|
|
132
|
+
if (!(e.encrypted || ot(t) || ot(n)))
|
|
133
133
|
return { twinBase: n, binBase: t, encrypted: !1 };
|
|
134
|
-
const s =
|
|
134
|
+
const s = ot(t) ? t : ot(n) ? n : t;
|
|
135
135
|
return { twinBase: s, binBase: s, encrypted: !0 };
|
|
136
136
|
}
|
|
137
|
-
function
|
|
138
|
-
return
|
|
137
|
+
function $e(e) {
|
|
138
|
+
return lt(e).encrypted;
|
|
139
139
|
}
|
|
140
|
-
function
|
|
140
|
+
function Xt(e, t = xt) {
|
|
141
141
|
const n = `${t.replace(/\/$/, "")}/${e}`;
|
|
142
142
|
return { twinBase: n, binBase: n, encrypted: !0 };
|
|
143
143
|
}
|
|
@@ -145,12 +145,12 @@ function _r(e, t) {
|
|
|
145
145
|
return (e ?? t)?.trim() || void 0;
|
|
146
146
|
}
|
|
147
147
|
function yr(e) {
|
|
148
|
-
At =
|
|
148
|
+
At = lt(e);
|
|
149
149
|
for (const t of It) t();
|
|
150
150
|
}
|
|
151
151
|
function Sr(e, t) {
|
|
152
152
|
const n = typeof globalThis.location < "u" ? globalThis.location.href : void 0;
|
|
153
|
-
if (!n) return
|
|
153
|
+
if (!n) return lt(e);
|
|
154
154
|
const r = (s) => {
|
|
155
155
|
try {
|
|
156
156
|
return new URL(s, n).href.replace(/\/$/, "");
|
|
@@ -158,13 +158,13 @@ function Sr(e, t) {
|
|
|
158
158
|
return s;
|
|
159
159
|
}
|
|
160
160
|
};
|
|
161
|
-
return
|
|
161
|
+
return lt({
|
|
162
162
|
twinBase: r(e.twinBase),
|
|
163
163
|
binBase: r(e.binBase),
|
|
164
164
|
encrypted: e.encrypted
|
|
165
165
|
});
|
|
166
166
|
}
|
|
167
|
-
function
|
|
167
|
+
function Fe() {
|
|
168
168
|
if (!At)
|
|
169
169
|
throw new Error("Twin assets not configured; call setActiveTwinAssets first");
|
|
170
170
|
return At;
|
|
@@ -172,28 +172,28 @@ function Pe() {
|
|
|
172
172
|
function kr(e) {
|
|
173
173
|
return It.add(e), () => It.delete(e);
|
|
174
174
|
}
|
|
175
|
-
function
|
|
176
|
-
const e =
|
|
177
|
-
return
|
|
175
|
+
function Qt() {
|
|
176
|
+
const e = Fe();
|
|
177
|
+
return $e(e) ? `${e.binBase}/sil.bin` : `${e.twinBase}/sil.png`;
|
|
178
178
|
}
|
|
179
179
|
function vr() {
|
|
180
|
-
const e =
|
|
181
|
-
return
|
|
180
|
+
const e = Fe();
|
|
181
|
+
return $e(e) ? `${e.binBase}/idle.bin` : `${e.twinBase}/idle.mp4`;
|
|
182
182
|
}
|
|
183
|
-
function
|
|
184
|
-
const e =
|
|
185
|
-
return
|
|
183
|
+
function br() {
|
|
184
|
+
const e = Fe();
|
|
185
|
+
return $e(e) ? e.binBase : e.twinBase;
|
|
186
186
|
}
|
|
187
|
-
function
|
|
188
|
-
return
|
|
187
|
+
function ht() {
|
|
188
|
+
return $e(Fe());
|
|
189
189
|
}
|
|
190
|
-
function
|
|
191
|
-
const e =
|
|
192
|
-
return
|
|
190
|
+
function Er() {
|
|
191
|
+
const e = Fe();
|
|
192
|
+
return $e(e) ? `${e.binBase}/atlas.bin` : `${e.twinBase}/atlas.json`;
|
|
193
193
|
}
|
|
194
194
|
function Tr() {
|
|
195
|
-
const e =
|
|
196
|
-
return
|
|
195
|
+
const e = Fe();
|
|
196
|
+
return $e(e) ? `${e.binBase}/expression_atlas.bin` : `${e.twinBase}/expression_atlas.json`;
|
|
197
197
|
}
|
|
198
198
|
function vn(e) {
|
|
199
199
|
const t = e.split(/\r?\n/);
|
|
@@ -258,16 +258,16 @@ function Cr(e, t) {
|
|
|
258
258
|
const s = Math.max(0, Math.min(1, (t - e.wtime) / r));
|
|
259
259
|
return Math.min(n - 1, Math.floor(s * n));
|
|
260
260
|
}
|
|
261
|
-
function
|
|
261
|
+
function Ne(e, t) {
|
|
262
262
|
const n = Math.max(0, Math.min(e.length - 1, t));
|
|
263
263
|
return e[n] ?? "";
|
|
264
264
|
}
|
|
265
265
|
function Ft(e, t) {
|
|
266
266
|
const n = e.toLowerCase().replace(/[^a-z']/g, "");
|
|
267
|
-
return !n ||
|
|
267
|
+
return !n || Ne(n, t) !== "w" || t > 0 && Ne(n, t - 1) === "q" ? !1 : t === 0 && /^w[aeiouy]/.test(n);
|
|
268
268
|
}
|
|
269
269
|
function xr(e, t) {
|
|
270
|
-
const n = e.toLowerCase(), r =
|
|
270
|
+
const n = e.toLowerCase(), r = Ne(n, t), s = n.slice(Math.max(0, t - 1), t + 2);
|
|
271
271
|
return r === "i" || r === "y" ? "I" : s.includes("ee") || r === "e" || n.includes("ea") ? "E" : "aa";
|
|
272
272
|
}
|
|
273
273
|
function Pr(e, t) {
|
|
@@ -277,7 +277,7 @@ function Pr(e, t) {
|
|
|
277
277
|
);
|
|
278
278
|
if (/oo|ou|uw/.test(r)) return "U";
|
|
279
279
|
if (Ft(n, t)) return "FF";
|
|
280
|
-
const s =
|
|
280
|
+
const s = Ne(n, t);
|
|
281
281
|
return s === "u" || s === "w" ? "U" : "O";
|
|
282
282
|
}
|
|
283
283
|
function Fr(e, t) {
|
|
@@ -289,9 +289,9 @@ function Fr(e, t) {
|
|
|
289
289
|
Math.max(0, t - 1),
|
|
290
290
|
Math.min(n.length, t + 3)
|
|
291
291
|
);
|
|
292
|
-
return /wo|wh/.test(s) ||
|
|
292
|
+
return /wo|wh/.test(s) || Ne(n, t) === "o" ? "O" : "U";
|
|
293
293
|
}
|
|
294
|
-
const
|
|
294
|
+
const ct = {
|
|
295
295
|
d: "DD",
|
|
296
296
|
t: "DD",
|
|
297
297
|
n: "DD",
|
|
@@ -304,15 +304,15 @@ const ot = {
|
|
|
304
304
|
j: "CH"
|
|
305
305
|
};
|
|
306
306
|
function Br(e, t) {
|
|
307
|
-
const n = e.toLowerCase(), r =
|
|
308
|
-
if (
|
|
307
|
+
const n = e.toLowerCase(), r = Ne(n, t);
|
|
308
|
+
if (ct[r]) return ct[r];
|
|
309
309
|
for (let s = 0; s < n.length; s++) {
|
|
310
310
|
const i = n[s];
|
|
311
|
-
if (
|
|
311
|
+
if (ct[i]) return ct[i];
|
|
312
312
|
}
|
|
313
313
|
return "DD";
|
|
314
314
|
}
|
|
315
|
-
function
|
|
315
|
+
function Lr(e, t, n) {
|
|
316
316
|
const r = Mr(e);
|
|
317
317
|
if (r.length === 1) return r[0];
|
|
318
318
|
const s = t.trim();
|
|
@@ -332,11 +332,11 @@ function Or(e, t, n) {
|
|
|
332
332
|
}
|
|
333
333
|
}
|
|
334
334
|
const Bt = 16e3;
|
|
335
|
-
function
|
|
335
|
+
function bn(e) {
|
|
336
336
|
const t = Number(e);
|
|
337
337
|
return Number.isFinite(t) && t > 0 ? t : Bt;
|
|
338
338
|
}
|
|
339
|
-
function
|
|
339
|
+
function Or(e) {
|
|
340
340
|
let t = e.trim();
|
|
341
341
|
const n = t.indexOf(",");
|
|
342
342
|
t.startsWith("data:") && n >= 0 && (t = t.slice(n + 1)), t = t.replace(/\s+/g, "").replace(/-/g, "+").replace(/_/g, "/");
|
|
@@ -358,13 +358,13 @@ function Zt(e, t, n = Bt) {
|
|
|
358
358
|
return o.copyToChannel(i, 0), o;
|
|
359
359
|
}
|
|
360
360
|
function Nr(e) {
|
|
361
|
-
const t =
|
|
361
|
+
const t = Or(e), n = window.atob(t), r = new Uint8Array(n.length);
|
|
362
362
|
for (let s = 0; s < n.length; s++)
|
|
363
363
|
r[s] = n.charCodeAt(s);
|
|
364
364
|
return r;
|
|
365
365
|
}
|
|
366
366
|
async function Vr(e, t, n = Bt) {
|
|
367
|
-
const r = Nr(t), s =
|
|
367
|
+
const r = Nr(t), s = bn(n);
|
|
368
368
|
if (Ur(r)) {
|
|
369
369
|
const i = r.buffer.slice(
|
|
370
370
|
r.byteOffset,
|
|
@@ -384,7 +384,7 @@ async function Vr(e, t, n = Bt) {
|
|
|
384
384
|
return Zt(e, r, s);
|
|
385
385
|
}
|
|
386
386
|
}
|
|
387
|
-
function
|
|
387
|
+
function Ce(e) {
|
|
388
388
|
let t = 0;
|
|
389
389
|
for (const n of e)
|
|
390
390
|
t = Math.max(t, n.vtime + n.vduration);
|
|
@@ -396,235 +396,253 @@ function $r(e, t) {
|
|
|
396
396
|
return n;
|
|
397
397
|
return null;
|
|
398
398
|
}
|
|
399
|
-
function
|
|
399
|
+
function En(e, t) {
|
|
400
400
|
const n = [], r = [];
|
|
401
|
-
let s = null, i = !1, o = !1, a = !1, l = !1, f = 0, u = 0,
|
|
401
|
+
let s = null, i = !1, o = !1, a = !1, l = !1, f = 0, u = 0, S = 0, m = 0, p = null, A = 1, d = t, h = !1, g = null, k = 0;
|
|
402
402
|
const b = () => {
|
|
403
403
|
p != null && (clearTimeout(p), p = null);
|
|
404
|
-
},
|
|
405
|
-
for (const
|
|
404
|
+
}, W = () => {
|
|
405
|
+
for (const y of r) {
|
|
406
406
|
try {
|
|
407
|
-
|
|
407
|
+
y.onended = null, y.stop(0);
|
|
408
408
|
} catch {
|
|
409
409
|
}
|
|
410
410
|
try {
|
|
411
|
-
|
|
411
|
+
y.disconnect();
|
|
412
412
|
} catch {
|
|
413
413
|
}
|
|
414
414
|
}
|
|
415
415
|
r.length = 0;
|
|
416
|
-
},
|
|
417
|
-
for (const
|
|
418
|
-
|
|
419
|
-
},
|
|
420
|
-
if (!(
|
|
416
|
+
}, Z = () => {
|
|
417
|
+
for (const y of r)
|
|
418
|
+
y.playbackRate.value = A;
|
|
419
|
+
}, Y = () => {
|
|
420
|
+
if (!(h || !l || i || r.length > 0 || n.length > 0)) {
|
|
421
421
|
if (a && s && u > 0) {
|
|
422
|
-
const
|
|
423
|
-
if (
|
|
422
|
+
const y = (s.currentTime - u) * 1e3;
|
|
423
|
+
if (y < k) {
|
|
424
424
|
b();
|
|
425
|
-
const D =
|
|
425
|
+
const D = A > 0 ? (k - y) / A : k - y;
|
|
426
426
|
p = setTimeout(() => {
|
|
427
|
-
|
|
427
|
+
h || (o = !1, p = null, e.onSpeakingDone(), e.onNotify());
|
|
428
428
|
}, Math.max(0, D));
|
|
429
429
|
return;
|
|
430
430
|
}
|
|
431
431
|
}
|
|
432
432
|
o = !1, b(), e.onSpeakingDone(), e.onNotify();
|
|
433
433
|
}
|
|
434
|
-
},
|
|
435
|
-
const D =
|
|
434
|
+
}, R = (y) => {
|
|
435
|
+
const D = Ce(y);
|
|
436
436
|
if (D <= 0) {
|
|
437
437
|
e.onSpeakingDone(), e.onNotify();
|
|
438
438
|
return;
|
|
439
439
|
}
|
|
440
440
|
o = !0, f = performance.now(), e.onSpeakingStart(), e.onNotify(), b();
|
|
441
|
-
const
|
|
441
|
+
const V = A > 0 ? D / A : D;
|
|
442
442
|
p = setTimeout(() => {
|
|
443
|
-
|
|
444
|
-
},
|
|
445
|
-
},
|
|
446
|
-
D.length !== 0 && (F && (
|
|
447
|
-
const
|
|
448
|
-
if (!
|
|
449
|
-
const ee = Math.round((
|
|
450
|
-
|
|
451
|
-
word:
|
|
452
|
-
wtime:
|
|
453
|
-
wduration:
|
|
454
|
-
queueIndex:
|
|
455
|
-
gesture:
|
|
456
|
-
emphasis:
|
|
443
|
+
h || (o = !1, p = null, e.onSpeakingDone(), e.onNotify());
|
|
444
|
+
}, V);
|
|
445
|
+
}, j = (y, D, V, F) => {
|
|
446
|
+
D.length !== 0 && (F && (S = V), D.forEach((x) => {
|
|
447
|
+
const K = String(x.word ?? "").trim();
|
|
448
|
+
if (!K) return;
|
|
449
|
+
const ee = Math.round((x.start ?? 0) * 1e3), Q = x.duration != null ? Math.round(x.duration * 1e3) : x.end != null ? Math.max(1, Math.round((x.end - (x.start ?? 0)) * 1e3)) : 0;
|
|
450
|
+
y.push({
|
|
451
|
+
word: K,
|
|
452
|
+
wtime: S + ee,
|
|
453
|
+
wduration: Q,
|
|
454
|
+
queueIndex: y.length,
|
|
455
|
+
gesture: x.gesture ?? null,
|
|
456
|
+
emphasis: x.emphasis === !0
|
|
457
457
|
});
|
|
458
458
|
}));
|
|
459
|
-
},
|
|
460
|
-
|
|
461
|
-
const ee = String(
|
|
459
|
+
}, _ = (y, D, V, F, x, N) => {
|
|
460
|
+
V.length !== 0 && (x && (S = F), V.forEach((K) => {
|
|
461
|
+
const ee = String(K.symbol ?? K.viseme ?? "").trim();
|
|
462
462
|
if (!ee) return;
|
|
463
|
-
const
|
|
464
|
-
let
|
|
465
|
-
ir(
|
|
463
|
+
const Q = Math.round((K.start ?? 0) * 1e3), E = Math.max(1, Math.round((K.duration ?? 0) * 1e3)), O = S + Q, J = $r(D, O), se = J ? Cr(J, O) : 0;
|
|
464
|
+
let $;
|
|
465
|
+
ir(N) === "oculus_direct" ? ($ = Rr(ee), $ === "U" && J && Ft(J.word, se) && ($ = "FF")) : $ = Lr(
|
|
466
466
|
ee,
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
),
|
|
470
|
-
viseme:
|
|
467
|
+
J?.word ?? "",
|
|
468
|
+
se
|
|
469
|
+
), y.push({
|
|
470
|
+
viseme: $,
|
|
471
471
|
weight: 1,
|
|
472
|
-
vtime:
|
|
473
|
-
vduration:
|
|
472
|
+
vtime: O,
|
|
473
|
+
vduration: E
|
|
474
474
|
});
|
|
475
475
|
}), e.onNotify());
|
|
476
|
-
},
|
|
477
|
-
|
|
478
|
-
|
|
476
|
+
}, T = (y, D, V, F, x, N, K) => {
|
|
477
|
+
j(D, F, x, N), _(
|
|
478
|
+
y,
|
|
479
479
|
D,
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
480
|
+
V,
|
|
481
|
+
x,
|
|
482
|
+
N,
|
|
483
|
+
K
|
|
484
484
|
);
|
|
485
|
-
}, M = async (
|
|
486
|
-
if (
|
|
485
|
+
}, M = async (y, D, V, F, x, N, K) => {
|
|
486
|
+
if (h) return;
|
|
487
|
+
const ee = bn(K?.sampleRate), Q = K?.newStream === !0;
|
|
488
|
+
if (!V?.trim()) {
|
|
489
|
+
if (F.length === 0 && x.length === 0) return;
|
|
490
|
+
Q && (S = 0, k = 0, y.length = 0, D.length = 0, K?.onNewStream?.());
|
|
491
|
+
let E = S;
|
|
492
|
+
N && y.length > 0 && !Q && (E = Ce(y)), T(
|
|
493
|
+
y,
|
|
494
|
+
D,
|
|
495
|
+
F,
|
|
496
|
+
x,
|
|
497
|
+
E,
|
|
498
|
+
N,
|
|
499
|
+
d
|
|
500
|
+
), k = Math.max(k, Ce(y)), !o && k > 0 && R(y), e.onNotify();
|
|
487
501
|
return;
|
|
488
|
-
|
|
502
|
+
}
|
|
489
503
|
if (i) {
|
|
490
504
|
n.push({
|
|
491
|
-
audio:
|
|
505
|
+
audio: V,
|
|
492
506
|
visemes: F,
|
|
493
|
-
words:
|
|
494
|
-
isNewSegment:
|
|
507
|
+
words: x,
|
|
508
|
+
isNewSegment: N,
|
|
495
509
|
sampleRate: ee,
|
|
496
|
-
newStream:
|
|
510
|
+
newStream: Q
|
|
497
511
|
});
|
|
498
512
|
return;
|
|
499
513
|
}
|
|
500
514
|
i = !0;
|
|
501
515
|
try {
|
|
502
|
-
const
|
|
503
|
-
s || (s = new
|
|
504
|
-
const
|
|
505
|
-
|
|
506
|
-
const
|
|
507
|
-
|
|
508
|
-
|
|
516
|
+
const E = window.AudioContext || window.webkitAudioContext;
|
|
517
|
+
s || (s = new E());
|
|
518
|
+
const O = s;
|
|
519
|
+
O.state === "suspended" && await O.resume(), g || (g = O.createMediaStreamDestination());
|
|
520
|
+
const J = await Vr(
|
|
521
|
+
O,
|
|
522
|
+
V,
|
|
509
523
|
ee
|
|
510
524
|
);
|
|
511
525
|
a = !0;
|
|
512
|
-
const
|
|
513
|
-
let
|
|
514
|
-
const
|
|
515
|
-
|
|
516
|
-
const te =
|
|
517
|
-
if (te.buffer =
|
|
526
|
+
const se = O.currentTime;
|
|
527
|
+
let $ = m;
|
|
528
|
+
const de = !o;
|
|
529
|
+
$ < se && ($ = se + 0.1), m = $ + J.duration;
|
|
530
|
+
const te = O.createBufferSource();
|
|
531
|
+
if (te.buffer = J, te.playbackRate.value = A, te.connect(O.destination), g && te.connect(g), r.push(te), h) {
|
|
518
532
|
r.pop();
|
|
519
533
|
return;
|
|
520
534
|
}
|
|
521
|
-
if (
|
|
522
|
-
o = !0, e.onSpeakingStart(),
|
|
523
|
-
const
|
|
524
|
-
f = performance.now() +
|
|
535
|
+
if (de) {
|
|
536
|
+
o = !0, e.onSpeakingStart(), Q ? (u = $, S = 0, k = 0, y.length = 0, D.length = 0, K?.onNewStream?.()) : u <= 0 && (u = $);
|
|
537
|
+
const Se = ($ - se) * 1e3;
|
|
538
|
+
f = performance.now() + Se;
|
|
525
539
|
}
|
|
526
540
|
te.onended = () => {
|
|
527
|
-
const
|
|
528
|
-
|
|
529
|
-
}, te.start(
|
|
530
|
-
const
|
|
531
|
-
|
|
532
|
-
|
|
541
|
+
const Se = r.indexOf(te);
|
|
542
|
+
Se >= 0 && r.splice(Se, 1), Y(), e.onNotify();
|
|
543
|
+
}, te.start($);
|
|
544
|
+
const Be = ($ - u) * 1e3;
|
|
545
|
+
T(
|
|
546
|
+
y,
|
|
533
547
|
D,
|
|
534
548
|
F,
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
549
|
+
x,
|
|
550
|
+
Be,
|
|
551
|
+
N,
|
|
538
552
|
d
|
|
539
|
-
),
|
|
540
|
-
} catch (
|
|
541
|
-
console.error("[avatarChunkPlayback] audio chunk failed:",
|
|
553
|
+
), k = Math.max(k, Ce(y));
|
|
554
|
+
} catch (E) {
|
|
555
|
+
console.error("[avatarChunkPlayback] audio chunk failed:", E);
|
|
542
556
|
} finally {
|
|
543
|
-
if (i = !1,
|
|
544
|
-
const
|
|
545
|
-
|
|
546
|
-
|
|
557
|
+
if (i = !1, h) return;
|
|
558
|
+
const E = n.shift();
|
|
559
|
+
E ? await M(
|
|
560
|
+
y,
|
|
547
561
|
D,
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
562
|
+
E.audio,
|
|
563
|
+
E.visemes,
|
|
564
|
+
E.words,
|
|
565
|
+
E.isNewSegment,
|
|
552
566
|
{
|
|
553
|
-
sampleRate:
|
|
554
|
-
newStream:
|
|
555
|
-
onNewStream:
|
|
567
|
+
sampleRate: E.sampleRate,
|
|
568
|
+
newStream: E.newStream,
|
|
569
|
+
onNewStream: K?.onNewStream
|
|
556
570
|
}
|
|
557
|
-
) :
|
|
571
|
+
) : Y();
|
|
558
572
|
}
|
|
559
573
|
};
|
|
560
574
|
return {
|
|
561
|
-
setStreamTtsEngineId: (
|
|
562
|
-
d =
|
|
575
|
+
setStreamTtsEngineId: (y) => {
|
|
576
|
+
d = y;
|
|
563
577
|
},
|
|
564
|
-
setPlaybackSpeed: (
|
|
565
|
-
|
|
578
|
+
setPlaybackSpeed: (y) => {
|
|
579
|
+
A = Math.max(0.1, Math.min(1, y)), Z();
|
|
566
580
|
},
|
|
567
|
-
getPlaybackSpeed: () =>
|
|
568
|
-
resetForNewStream: (
|
|
569
|
-
|
|
581
|
+
getPlaybackSpeed: () => A,
|
|
582
|
+
resetForNewStream: (y) => {
|
|
583
|
+
h = !1, l = !1, d = y, k = 0;
|
|
570
584
|
},
|
|
571
585
|
/** Next sentence in the same bot turn — keep viseme tail, allow more chunks. */
|
|
572
586
|
resumeBotStream: () => {
|
|
573
|
-
l = !1;
|
|
587
|
+
h = !1, l = !1;
|
|
588
|
+
},
|
|
589
|
+
/** After interrupt — allow the next utterance to queue/play again. */
|
|
590
|
+
clearAborted: () => {
|
|
591
|
+
h = !1;
|
|
574
592
|
},
|
|
575
593
|
/** Call from a user gesture before bot audio (connect / unlock). */
|
|
576
594
|
primeAudioContext: async () => {
|
|
577
|
-
const
|
|
578
|
-
s || (s = new
|
|
595
|
+
const y = window.AudioContext || window.webkitAudioContext;
|
|
596
|
+
s || (s = new y()), s.state === "suspended" && await s.resume(), s && !g && (g = s.createMediaStreamDestination());
|
|
579
597
|
},
|
|
580
598
|
stop: () => {
|
|
581
|
-
|
|
599
|
+
h = !0, b(), W(), n.length = 0, i = !1, o = !1, a = !1, l = !1, S = 0, m = 0, u = 0, f = 0, k = 0;
|
|
582
600
|
},
|
|
583
|
-
markStreamComplete: (
|
|
584
|
-
if (
|
|
585
|
-
|
|
601
|
+
markStreamComplete: (y) => {
|
|
602
|
+
if (k = Math.max(k, Ce(y)), l = !0, !a && y.length > 0) {
|
|
603
|
+
R(y);
|
|
586
604
|
return;
|
|
587
605
|
}
|
|
588
|
-
|
|
606
|
+
Y();
|
|
589
607
|
},
|
|
590
608
|
playAudioChunk: M,
|
|
591
|
-
queueTimingsOnly: (
|
|
592
|
-
if (
|
|
593
|
-
let
|
|
594
|
-
|
|
595
|
-
|
|
609
|
+
queueTimingsOnly: (y, D, V, F, x) => {
|
|
610
|
+
if (h) return;
|
|
611
|
+
let N = S;
|
|
612
|
+
x && y.length > 0 && (N = Ce(y)), T(
|
|
613
|
+
y,
|
|
596
614
|
D,
|
|
597
|
-
|
|
615
|
+
V,
|
|
598
616
|
F,
|
|
599
|
-
|
|
600
|
-
|
|
617
|
+
N,
|
|
618
|
+
x,
|
|
601
619
|
d
|
|
602
|
-
),
|
|
620
|
+
), k = Math.max(k, Ce(y));
|
|
603
621
|
},
|
|
604
622
|
getPlaybackElapsedMs: () => a && s && u > 0 ? Math.max(
|
|
605
623
|
0,
|
|
606
624
|
(s.currentTime - u) * 1e3
|
|
607
|
-
) : o ? Math.max(0, (performance.now() - f) *
|
|
608
|
-
isSpeaking: () => o ? !0 : !a || !s || u <= 0 ? !1 : (s.currentTime - u) * 1e3 <
|
|
609
|
-
getVoiceStream: () =>
|
|
625
|
+
) : o ? Math.max(0, (performance.now() - f) * A) : 0,
|
|
626
|
+
isSpeaking: () => o ? !0 : !a || !s || u <= 0 ? !1 : (s.currentTime - u) * 1e3 < k,
|
|
627
|
+
getVoiceStream: () => g ? g.stream : null,
|
|
610
628
|
getPlaybackStartPerf: () => f,
|
|
611
629
|
/** User spoke over the bot — drop in-flight chunks until the next utterance. */
|
|
612
630
|
bargeIn: () => {
|
|
613
|
-
|
|
631
|
+
h = !0, l = !1, b(), W(), n.length = 0, i = !1, o = !1, a = !1, S = 0, m = 0, u = 0, f = 0, k = 0;
|
|
614
632
|
},
|
|
615
633
|
interrupt: () => {
|
|
616
|
-
|
|
634
|
+
h = !0, l = !1, b(), W(), n.length = 0, i = !1, o = !1, a = !1, S = 0, m = 0, u = 0, f = 0, k = 0;
|
|
617
635
|
}
|
|
618
636
|
};
|
|
619
637
|
}
|
|
620
|
-
function
|
|
638
|
+
function nt(e, t) {
|
|
621
639
|
let n = null;
|
|
622
640
|
for (const r of e)
|
|
623
641
|
t < r.vtime || t >= r.vtime + r.vduration || (!n || r.vtime >= n.vtime) && (n = r);
|
|
624
642
|
return n ? n.viseme : "sil";
|
|
625
643
|
}
|
|
626
|
-
function
|
|
627
|
-
const r =
|
|
644
|
+
function qr(e, t, n = 120) {
|
|
645
|
+
const r = nt(e, t);
|
|
628
646
|
if (r !== "sil") return r;
|
|
629
647
|
let s = null;
|
|
630
648
|
for (const i of e) {
|
|
@@ -634,146 +652,215 @@ function Wr(e, t, n = 120) {
|
|
|
634
652
|
}
|
|
635
653
|
return s?.viseme ?? "sil";
|
|
636
654
|
}
|
|
637
|
-
function
|
|
655
|
+
function Si(e, t) {
|
|
638
656
|
for (const n of e)
|
|
639
657
|
if (t >= n.wtime && t < n.wtime + n.wduration)
|
|
640
658
|
return n;
|
|
641
659
|
return null;
|
|
642
660
|
}
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
661
|
+
function Wr(e, t) {
|
|
662
|
+
const n = e.trim();
|
|
663
|
+
if (!n) return null;
|
|
664
|
+
try {
|
|
665
|
+
const r = n.replace(/\s+/g, ""), s = atob(r).length, i = Number.isFinite(t) && (t ?? 0) > 0 ? Number(t) : 16e3;
|
|
666
|
+
return s / 2 / i * 1e3;
|
|
667
|
+
} catch {
|
|
668
|
+
return null;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
const Lt = 0.5, Ot = 1.5, Tn = "Olivia", An = "f786b574-daa5-4673-aa0c-cbe3e8534c02", gt = 0.85;
|
|
672
|
+
function en(e, t = tt, n = {}) {
|
|
673
|
+
const r = `${t.replace(/\/$/, "")}/avatar_ttsWithPoses`, s = [], i = [], o = [], a = [];
|
|
674
|
+
let l = "", f = "neutral", u = "", S = Ue;
|
|
675
|
+
const m = /* @__PURE__ */ new Set();
|
|
676
|
+
let p = 0, A = null;
|
|
677
|
+
const d = () => m.forEach((R) => R()), h = En(
|
|
648
678
|
{
|
|
649
679
|
onSpeakingStart: () => e("speaking"),
|
|
650
680
|
onSpeakingDone: () => e("done"),
|
|
651
|
-
onNotify:
|
|
681
|
+
onNotify: d
|
|
652
682
|
},
|
|
653
|
-
|
|
654
|
-
),
|
|
655
|
-
|
|
683
|
+
Ue
|
|
684
|
+
), g = () => h.getPlaybackElapsedMs(), k = (R, j = l) => {
|
|
685
|
+
if (!n.onLipsyncDebug) return;
|
|
686
|
+
const _ = g(), T = s;
|
|
687
|
+
n.onLipsyncDebug({
|
|
688
|
+
event: R,
|
|
689
|
+
spokenText: j,
|
|
690
|
+
mood: f,
|
|
691
|
+
playbackAnchorPerf: h.getPlaybackStartPerf(),
|
|
692
|
+
playbackElapsedMs: _,
|
|
693
|
+
queueLength: T.length,
|
|
694
|
+
activeViseme: nt(T, _),
|
|
695
|
+
segments: a.map((M) => ({
|
|
696
|
+
...M,
|
|
697
|
+
visemes: [...M.visemes]
|
|
698
|
+
}))
|
|
699
|
+
});
|
|
700
|
+
}, b = (R, j) => {
|
|
701
|
+
n.onLipsyncDebug && (A = { event: R, spokenText: j }, p === 0 && (p = requestAnimationFrame(() => {
|
|
702
|
+
p = 0;
|
|
703
|
+
const _ = A;
|
|
704
|
+
A = null, _ && k(_.event, _.spokenText);
|
|
705
|
+
})));
|
|
706
|
+
}, W = (R, j, _, T, M) => {
|
|
707
|
+
if (!n.onLipsyncDebug) return;
|
|
708
|
+
const I = s.slice(j), y = _.filter(
|
|
709
|
+
(D) => String(D.symbol ?? D.viseme ?? "").trim()
|
|
710
|
+
);
|
|
711
|
+
a.push({
|
|
712
|
+
spokenText: R,
|
|
713
|
+
audioOffsetMs: I[0]?.vtime ?? 0,
|
|
714
|
+
isNewSegment: T,
|
|
715
|
+
chunkDurationMs: M,
|
|
716
|
+
receivedAtMs: performance.now(),
|
|
717
|
+
visemes: I.map((D, V) => {
|
|
718
|
+
const F = y[V];
|
|
719
|
+
return {
|
|
720
|
+
rawSymbol: String(F?.symbol ?? F?.viseme ?? D.viseme).trim(),
|
|
721
|
+
viseme: D.viseme,
|
|
722
|
+
startSec: Number(F?.start ?? 0),
|
|
723
|
+
durationSec: Number(F?.duration ?? 0),
|
|
724
|
+
vtimeMs: D.vtime,
|
|
725
|
+
vdurationMs: D.vduration
|
|
726
|
+
};
|
|
727
|
+
})
|
|
728
|
+
});
|
|
729
|
+
}, Z = () => {
|
|
730
|
+
h.stop(), s.length = 0, i.length = 0, o.length = 0, f = "neutral", a.length = 0, l = "", e("idle"), b("reset"), d();
|
|
656
731
|
};
|
|
657
732
|
return {
|
|
658
|
-
setDeveloperToken: (
|
|
659
|
-
|
|
733
|
+
setDeveloperToken: (R) => {
|
|
734
|
+
u = R;
|
|
660
735
|
},
|
|
661
|
-
setTtsEngineId: (
|
|
662
|
-
|
|
736
|
+
setTtsEngineId: (R) => {
|
|
737
|
+
S = R;
|
|
663
738
|
},
|
|
664
|
-
getTtsEngineId: () =>
|
|
665
|
-
speak: async (
|
|
666
|
-
|
|
667
|
-
const
|
|
668
|
-
if (!
|
|
739
|
+
getTtsEngineId: () => S,
|
|
740
|
+
speak: async (R, j) => {
|
|
741
|
+
Z(), e("loading"), l = R, a.length = 0;
|
|
742
|
+
const _ = u.trim();
|
|
743
|
+
if (!_)
|
|
669
744
|
throw new Error("Developer token required for avatar_ttsWithPoses");
|
|
670
|
-
const
|
|
671
|
-
|
|
672
|
-
const
|
|
673
|
-
|
|
674
|
-
Math.min(
|
|
675
|
-
),
|
|
676
|
-
user_query:
|
|
677
|
-
ttsEngineId:
|
|
678
|
-
speakingRate:
|
|
745
|
+
const T = j?.ttsEngineId ?? S ?? Ue;
|
|
746
|
+
h.resetForNewStream(T), h.setStreamTtsEngineId(T);
|
|
747
|
+
const M = j?.voiceId ?? Tn, I = j?.speakingRate ?? gt, y = Math.max(
|
|
748
|
+
Lt,
|
|
749
|
+
Math.min(Ot, I)
|
|
750
|
+
), D = {
|
|
751
|
+
user_query: R,
|
|
752
|
+
ttsEngineId: T,
|
|
753
|
+
speakingRate: y,
|
|
679
754
|
tenant: "aiTwin"
|
|
680
755
|
};
|
|
681
|
-
Sn.has(
|
|
756
|
+
Sn.has(T) && (D.voice_id = M);
|
|
682
757
|
try {
|
|
683
|
-
const
|
|
758
|
+
const V = await fetch(r, {
|
|
684
759
|
method: "POST",
|
|
685
760
|
headers: {
|
|
686
761
|
"Content-Type": "application/json",
|
|
687
|
-
Authorization: `Bearer ${
|
|
762
|
+
Authorization: `Bearer ${_}`
|
|
688
763
|
},
|
|
689
|
-
body: JSON.stringify(
|
|
764
|
+
body: JSON.stringify(D)
|
|
690
765
|
});
|
|
691
|
-
if (!
|
|
692
|
-
throw new Error(`avatar_ttsWithPoses failed (${
|
|
693
|
-
const
|
|
694
|
-
if (!
|
|
695
|
-
const
|
|
696
|
-
let
|
|
697
|
-
const
|
|
698
|
-
const
|
|
699
|
-
if (
|
|
700
|
-
if (
|
|
701
|
-
const
|
|
702
|
-
|
|
703
|
-
r,
|
|
766
|
+
if (!V.ok)
|
|
767
|
+
throw new Error(`avatar_ttsWithPoses failed (${V.status})`);
|
|
768
|
+
const F = V.body;
|
|
769
|
+
if (!F) throw new Error("No response body");
|
|
770
|
+
const x = F.getReader(), N = new TextDecoder();
|
|
771
|
+
let K = "";
|
|
772
|
+
const ee = async (Q) => {
|
|
773
|
+
const E = vn(Q);
|
|
774
|
+
if (E) {
|
|
775
|
+
if (E.event === "audio") {
|
|
776
|
+
const O = E.data.chunk, J = E.data.visemes ?? [], se = E.data.words ?? [], $ = E.data.is_new_segment ?? !1, de = E.data.sample_rate, te = s.length;
|
|
777
|
+
O ? (await h.playAudioChunk(
|
|
704
778
|
s,
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
779
|
+
i,
|
|
780
|
+
O,
|
|
781
|
+
J,
|
|
782
|
+
se,
|
|
783
|
+
$,
|
|
784
|
+
{ sampleRate: de }
|
|
785
|
+
), W(
|
|
786
|
+
R,
|
|
787
|
+
te,
|
|
788
|
+
J,
|
|
789
|
+
$,
|
|
790
|
+
Wr(O, de)
|
|
791
|
+
), b("audio_chunk", R)) : (J.length > 0 || se.length > 0) && (h.queueTimingsOnly(
|
|
712
792
|
s,
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
793
|
+
i,
|
|
794
|
+
J,
|
|
795
|
+
se,
|
|
796
|
+
$
|
|
797
|
+
), W(
|
|
798
|
+
R,
|
|
799
|
+
te,
|
|
800
|
+
J,
|
|
801
|
+
$,
|
|
802
|
+
null
|
|
803
|
+
), b("audio_chunk", R));
|
|
804
|
+
} else if (E.event === "metadata") {
|
|
805
|
+
const O = E.data.mood;
|
|
806
|
+
typeof O == "string" && O.trim() && (f = O.trim());
|
|
807
|
+
const J = E.data.sentence_emotions;
|
|
808
|
+
if (Array.isArray(J)) {
|
|
809
|
+
o.length = 0;
|
|
810
|
+
for (const se of J) {
|
|
811
|
+
if (!se || typeof se != "object") continue;
|
|
812
|
+
const $ = se;
|
|
813
|
+
o.push({
|
|
814
|
+
sentence_index: Number($.sentence_index ?? 0),
|
|
815
|
+
text: String($.text ?? ""),
|
|
816
|
+
sentiment: typeof $.sentiment == "string" ? $.sentiment : void 0,
|
|
817
|
+
emotion: String($.emotion ?? f),
|
|
818
|
+
start_word: Number($.start_word ?? 0),
|
|
819
|
+
end_word: Number($.end_word ?? 0)
|
|
733
820
|
});
|
|
734
821
|
}
|
|
735
822
|
}
|
|
736
|
-
|
|
737
|
-
} else if (
|
|
823
|
+
d(), b("metadata", R);
|
|
824
|
+
} else if (E.event === "error")
|
|
738
825
|
throw new Error(
|
|
739
|
-
String(
|
|
826
|
+
String(E.data.message ?? "avatar_ttsWithPoses stream error")
|
|
740
827
|
);
|
|
741
828
|
}
|
|
742
829
|
};
|
|
743
830
|
for (; ; ) {
|
|
744
|
-
const { done:
|
|
745
|
-
|
|
746
|
-
const
|
|
831
|
+
const { done: Q, value: E } = await x.read();
|
|
832
|
+
E && (K += N.decode(E, { stream: !0 }));
|
|
833
|
+
const O = K.split(`
|
|
747
834
|
|
|
748
835
|
`);
|
|
749
|
-
|
|
750
|
-
for (const
|
|
751
|
-
if (
|
|
752
|
-
|
|
836
|
+
K = O.pop() ?? "";
|
|
837
|
+
for (const J of O) await ee(J);
|
|
838
|
+
if (Q) {
|
|
839
|
+
K.trim() && await ee(K.trim()), h.markStreamComplete(s), b("bot_stopped", R);
|
|
753
840
|
break;
|
|
754
841
|
}
|
|
755
842
|
}
|
|
756
|
-
} catch (
|
|
757
|
-
throw console.error("[avatarTtsLipsync]",
|
|
843
|
+
} catch (V) {
|
|
844
|
+
throw console.error("[avatarTtsLipsync]", V), Z(), e("error"), V;
|
|
758
845
|
}
|
|
759
846
|
},
|
|
760
|
-
stop:
|
|
761
|
-
getVisemeQueue: () =>
|
|
762
|
-
getWordQueue: () =>
|
|
763
|
-
getSentenceEmotions: () =>
|
|
764
|
-
getStreamMood: () =>
|
|
765
|
-
getPlaybackElapsedMs: () =>
|
|
766
|
-
isSpeaking: () =>
|
|
767
|
-
getVoiceStream: () =>
|
|
768
|
-
setPlaybackSpeed: (
|
|
769
|
-
|
|
847
|
+
stop: Z,
|
|
848
|
+
getVisemeQueue: () => s,
|
|
849
|
+
getWordQueue: () => i,
|
|
850
|
+
getSentenceEmotions: () => o,
|
|
851
|
+
getStreamMood: () => f,
|
|
852
|
+
getPlaybackElapsedMs: () => h.getPlaybackElapsedMs(),
|
|
853
|
+
isSpeaking: () => h.isSpeaking(),
|
|
854
|
+
getVoiceStream: () => h.getVoiceStream(),
|
|
855
|
+
setPlaybackSpeed: (R) => {
|
|
856
|
+
h.setPlaybackSpeed(R);
|
|
770
857
|
},
|
|
771
|
-
getPlaybackSpeed: () =>
|
|
772
|
-
subscribe: (
|
|
858
|
+
getPlaybackSpeed: () => h.getPlaybackSpeed(),
|
|
859
|
+
subscribe: (R) => (m.add(R), () => m.delete(R))
|
|
773
860
|
};
|
|
774
861
|
}
|
|
775
862
|
const In = 16e3, Rn = 16e3;
|
|
776
|
-
class
|
|
863
|
+
class Hr extends Xn {
|
|
777
864
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
778
865
|
async deserialize(t) {
|
|
779
866
|
try {
|
|
@@ -785,7 +872,7 @@ class qr extends Jn {
|
|
|
785
872
|
}
|
|
786
873
|
}
|
|
787
874
|
}
|
|
788
|
-
class
|
|
875
|
+
class Kr extends Jn {
|
|
789
876
|
constructor() {
|
|
790
877
|
super(
|
|
791
878
|
!0,
|
|
@@ -801,31 +888,31 @@ class Hr extends Yn {
|
|
|
801
888
|
bufferBotAudio(t, n) {
|
|
802
889
|
}
|
|
803
890
|
}
|
|
804
|
-
const
|
|
805
|
-
function jr(e) {
|
|
806
|
-
return Kr.test(e.trim());
|
|
807
|
-
}
|
|
891
|
+
const jr = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
808
892
|
function Gr(e) {
|
|
893
|
+
return jr.test(e.trim());
|
|
894
|
+
}
|
|
895
|
+
function zr(e) {
|
|
809
896
|
const t = e.replace(/\/$/, "");
|
|
810
897
|
return t.startsWith("https://") ? `wss://${t.slice(8)}` : t.startsWith("http://") ? `ws://${t.slice(7)}` : t;
|
|
811
898
|
}
|
|
812
|
-
function
|
|
899
|
+
function Yr(e) {
|
|
813
900
|
if (e.wsUrl?.trim()) return e.wsUrl.trim();
|
|
814
901
|
const t = e.authToken?.trim();
|
|
815
902
|
if (!t)
|
|
816
903
|
throw new Error(
|
|
817
904
|
"Voice connect requires authToken (same JWT as SSE Authorization Bearer)."
|
|
818
905
|
);
|
|
819
|
-
const n = e.apiBase ?? tt, r = new URL(`${
|
|
906
|
+
const n = e.apiBase ?? tt, r = new URL(`${zr(n)}/ws/voice`);
|
|
820
907
|
r.searchParams.set("authToken", t), r.searchParams.set("tenant", "aiTwin");
|
|
821
908
|
const s = e.voiceId?.trim();
|
|
822
|
-
s &&
|
|
909
|
+
s && Gr(s) && r.searchParams.set("voiceId", s);
|
|
823
910
|
const i = e.personaId?.trim();
|
|
824
911
|
i && r.searchParams.set("personaId", i);
|
|
825
|
-
const o = e.speakingRate ??
|
|
912
|
+
const o = e.speakingRate ?? gt;
|
|
826
913
|
return r.searchParams.set(
|
|
827
914
|
"speaking_rate",
|
|
828
|
-
String(Math.max(
|
|
915
|
+
String(Math.max(Lt, Math.min(Ot, o)))
|
|
829
916
|
), e.ttsStream === !1 ? r.searchParams.set("tts_stream", "false") : r.searchParams.set("tts_stream", "true"), r.toString();
|
|
830
917
|
}
|
|
831
918
|
function vt(e, t) {
|
|
@@ -842,7 +929,7 @@ function vt(e, t) {
|
|
|
842
929
|
});
|
|
843
930
|
return n;
|
|
844
931
|
}
|
|
845
|
-
function
|
|
932
|
+
function Jr(e) {
|
|
846
933
|
if (!e || typeof e != "object") return null;
|
|
847
934
|
const t = e, r = (t.data && typeof t.data == "object" && !Array.isArray(t.data) ? t.data : null) || t;
|
|
848
935
|
return {
|
|
@@ -850,292 +937,292 @@ function Qr(e) {
|
|
|
850
937
|
type: String(r.type ?? t.type ?? "server-message")
|
|
851
938
|
};
|
|
852
939
|
}
|
|
853
|
-
function
|
|
940
|
+
function bt(e) {
|
|
854
941
|
return e.is_new_segment === !0 || Number(e.audio_offset_ms ?? -1) === 0 ? !0 : Number(e.chunk_index ?? -1) === 0;
|
|
855
942
|
}
|
|
856
|
-
function
|
|
943
|
+
function Xr(e) {
|
|
857
944
|
return e?.transport?._mediaManager?._wavStreamPlayer ?? null;
|
|
858
945
|
}
|
|
859
|
-
function
|
|
946
|
+
function Qr(e, t = {}) {
|
|
860
947
|
const n = [], r = [], s = [], i = [];
|
|
861
|
-
let o = "", a = "neutral", l =
|
|
862
|
-
const d = /* @__PURE__ */ new Set(),
|
|
863
|
-
let
|
|
864
|
-
const
|
|
865
|
-
let
|
|
866
|
-
const
|
|
867
|
-
|
|
868
|
-
}, M = () => d.forEach((c) => c()), I =
|
|
948
|
+
let o = "", a = "neutral", l = Ve, f = !1, u = null, S = null, m = { ...t }, p = 0, A = null;
|
|
949
|
+
const d = /* @__PURE__ */ new Set(), h = [];
|
|
950
|
+
let g = !1, k = null, b = !0, W = "default";
|
|
951
|
+
const Z = /* @__PURE__ */ new Set();
|
|
952
|
+
let Y = null, R = 0, j = !1, _ = null;
|
|
953
|
+
const T = () => {
|
|
954
|
+
_ != null && (clearTimeout(_), _ = null);
|
|
955
|
+
}, M = () => d.forEach((c) => c()), I = En(
|
|
869
956
|
{
|
|
870
957
|
onSpeakingStart: () => e("speaking"),
|
|
871
958
|
onSpeakingDone: () => e("done"),
|
|
872
959
|
onNotify: M
|
|
873
960
|
},
|
|
874
961
|
l
|
|
875
|
-
),
|
|
876
|
-
if (
|
|
962
|
+
), y = () => {
|
|
963
|
+
if (k) return k;
|
|
877
964
|
const c = new MessageChannel();
|
|
878
965
|
return c.port1.onmessage = () => {
|
|
879
|
-
const
|
|
880
|
-
|
|
881
|
-
},
|
|
966
|
+
const v = h.shift();
|
|
967
|
+
v !== void 0 && qe(v), h.length > 0 ? c.port2.postMessage(null) : g = !1;
|
|
968
|
+
}, k = c, c;
|
|
882
969
|
}, D = (c) => {
|
|
883
|
-
|
|
884
|
-
},
|
|
970
|
+
h.push(c), !g && (g = !0, y().port2.postMessage(null));
|
|
971
|
+
}, V = () => I.getPlaybackElapsedMs(), F = (c, v = o) => {
|
|
885
972
|
if (!m.onLipsyncDebug) return;
|
|
886
|
-
const
|
|
973
|
+
const B = V(), X = n;
|
|
887
974
|
m.onLipsyncDebug({
|
|
888
975
|
event: c,
|
|
889
|
-
spokenText:
|
|
976
|
+
spokenText: v,
|
|
890
977
|
mood: a,
|
|
891
978
|
playbackAnchorPerf: I.getPlaybackStartPerf(),
|
|
892
|
-
playbackElapsedMs:
|
|
893
|
-
queueLength:
|
|
894
|
-
activeViseme:
|
|
895
|
-
segments: i.map((
|
|
896
|
-
...
|
|
897
|
-
visemes: [...
|
|
979
|
+
playbackElapsedMs: B,
|
|
980
|
+
queueLength: X.length,
|
|
981
|
+
activeViseme: nt(X, B),
|
|
982
|
+
segments: i.map((ie) => ({
|
|
983
|
+
...ie,
|
|
984
|
+
visemes: [...ie.visemes]
|
|
898
985
|
}))
|
|
899
986
|
});
|
|
900
|
-
},
|
|
901
|
-
m.onLipsyncDebug && (
|
|
987
|
+
}, x = (c, v) => {
|
|
988
|
+
m.onLipsyncDebug && (A = { event: c, spokenText: v }, p === 0 && (p = requestAnimationFrame(() => {
|
|
902
989
|
p = 0;
|
|
903
|
-
const
|
|
904
|
-
|
|
990
|
+
const B = A;
|
|
991
|
+
A = null, B && F(B.event, B.spokenText);
|
|
905
992
|
})));
|
|
906
|
-
},
|
|
907
|
-
b = !0,
|
|
908
|
-
},
|
|
909
|
-
const c =
|
|
993
|
+
}, N = () => {
|
|
994
|
+
b = !0, Z.clear(), I.clearAborted();
|
|
995
|
+
}, K = () => {
|
|
996
|
+
const c = Xr(u);
|
|
910
997
|
if (c) {
|
|
911
|
-
|
|
998
|
+
W = `bot-${Date.now()}`, c.interruptedTrackIds = { [W]: !0 };
|
|
912
999
|
try {
|
|
913
1000
|
c.interrupt?.();
|
|
914
1001
|
} catch {
|
|
915
1002
|
}
|
|
916
1003
|
}
|
|
917
|
-
const
|
|
1004
|
+
const v = S;
|
|
918
1005
|
try {
|
|
919
|
-
|
|
1006
|
+
v?.interrupt?.();
|
|
920
1007
|
} catch {
|
|
921
1008
|
}
|
|
922
1009
|
}, ee = (c) => {
|
|
923
|
-
const
|
|
924
|
-
return
|
|
925
|
-
},
|
|
1010
|
+
const v = c.context_id?.trim();
|
|
1011
|
+
return v && Z.has(v) ? !0 : b ? !1 : !(c.type === "avatar_metadata" || bt(c));
|
|
1012
|
+
}, Q = (c) => {
|
|
926
1013
|
b = !1;
|
|
927
|
-
const
|
|
928
|
-
|
|
929
|
-
},
|
|
1014
|
+
const v = c.context_id?.trim();
|
|
1015
|
+
v && Z.add(v), T(), j = !1, h.length = 0, g = !1, Y?.abort(), Y = null, R += 1, K(), I.bargeIn(), E(), e("idle"), x("interrupt"), M();
|
|
1016
|
+
}, E = () => {
|
|
930
1017
|
n.length = 0, r.length = 0, i.length = 0, o = "", a = "neutral", s.length = 0;
|
|
931
|
-
},
|
|
932
|
-
I.stop(),
|
|
933
|
-
},
|
|
934
|
-
|
|
935
|
-
},
|
|
936
|
-
typeof c.mood == "string" && c.mood.trim() && (a = c.mood.trim()), Array.isArray(c.sentence_emotions) && c.sentence_emotions.length > 0 && (
|
|
1018
|
+
}, O = () => {
|
|
1019
|
+
I.stop(), E(), x("reset"), M();
|
|
1020
|
+
}, J = () => {
|
|
1021
|
+
O(), e("idle"), M();
|
|
1022
|
+
}, se = (c, v) => {
|
|
1023
|
+
typeof c.mood == "string" && c.mood.trim() && (a = c.mood.trim()), Array.isArray(c.sentence_emotions) && c.sentence_emotions.length > 0 && (v && (s.length = 0), s.push(
|
|
937
1024
|
...vt(c.sentence_emotions, a)
|
|
938
1025
|
));
|
|
939
|
-
},
|
|
1026
|
+
}, $ = (c) => {
|
|
940
1027
|
if (ee({ ...c, type: "avatar_metadata" }))
|
|
941
1028
|
return;
|
|
942
|
-
|
|
943
|
-
const
|
|
944
|
-
|
|
1029
|
+
N(), j = !0;
|
|
1030
|
+
const v = String(c.spoken_text ?? c.text ?? "").trim();
|
|
1031
|
+
v && (o = v), I.resetForNewStream(l), typeof c.mood == "string" && c.mood.trim() && (a = c.mood.trim()), s.length = 0, s.push(
|
|
945
1032
|
...vt(c.sentence_emotions, a)
|
|
946
|
-
), Array.isArray(c.gestures) && c.gestures,
|
|
947
|
-
},
|
|
1033
|
+
), Array.isArray(c.gestures) && c.gestures, x("metadata", v), M();
|
|
1034
|
+
}, de = (c, v, B, X) => {
|
|
948
1035
|
if (!m.onLipsyncDebug) return;
|
|
949
|
-
const
|
|
950
|
-
(
|
|
1036
|
+
const ie = n.slice(B), ve = X.filter(
|
|
1037
|
+
(oe) => String(oe.symbol ?? oe.viseme ?? "").trim()
|
|
951
1038
|
);
|
|
952
1039
|
i.push({
|
|
953
|
-
spokenText:
|
|
954
|
-
audioOffsetMs:
|
|
1040
|
+
spokenText: v,
|
|
1041
|
+
audioOffsetMs: ie[0]?.vtime ?? 0,
|
|
955
1042
|
isNewSegment: !!c.is_new_segment,
|
|
956
1043
|
chunkDurationMs: c.chunk_duration_ms != null ? Number(c.chunk_duration_ms) : null,
|
|
957
1044
|
receivedAtMs: performance.now(),
|
|
958
|
-
visemes:
|
|
959
|
-
const
|
|
1045
|
+
visemes: ie.map((oe, ne) => {
|
|
1046
|
+
const _e = ve[ne];
|
|
960
1047
|
return {
|
|
961
|
-
rawSymbol: String(
|
|
962
|
-
viseme:
|
|
963
|
-
startSec: Number(
|
|
964
|
-
durationSec: Number(
|
|
965
|
-
vtimeMs:
|
|
966
|
-
vdurationMs:
|
|
1048
|
+
rawSymbol: String(_e?.symbol ?? _e?.viseme ?? oe.viseme).trim(),
|
|
1049
|
+
viseme: oe.viseme,
|
|
1050
|
+
startSec: Number(_e?.start ?? 0),
|
|
1051
|
+
durationSec: Number(_e?.duration ?? 0),
|
|
1052
|
+
vtimeMs: oe.vtime,
|
|
1053
|
+
vdurationMs: oe.vduration
|
|
967
1054
|
};
|
|
968
1055
|
})
|
|
969
1056
|
});
|
|
970
1057
|
}, te = (c) => {
|
|
971
1058
|
if (ee(c)) return;
|
|
972
|
-
|
|
973
|
-
const
|
|
974
|
-
|
|
975
|
-
const
|
|
1059
|
+
T(), bt(c) && N();
|
|
1060
|
+
const v = String(c.spoken_text ?? c.text ?? "").trim(), B = bt(c), X = c.visemes ?? [], ie = c.words ?? [], ve = String(c.chunk ?? "").trim(), oe = j;
|
|
1061
|
+
oe && (j = !1), v && (o = v), se(c, B), oe ? I.resetForNewStream(l) : B && I.resumeBotStream();
|
|
1062
|
+
const ne = n.length;
|
|
976
1063
|
I.playAudioChunk(
|
|
977
1064
|
n,
|
|
978
1065
|
r,
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
1066
|
+
ve,
|
|
1067
|
+
X,
|
|
1068
|
+
ie,
|
|
1069
|
+
B,
|
|
983
1070
|
{
|
|
984
1071
|
sampleRate: c.sample_rate,
|
|
985
|
-
newStream:
|
|
1072
|
+
newStream: oe,
|
|
986
1073
|
onNewStream: () => {
|
|
987
1074
|
i.length = 0;
|
|
988
1075
|
}
|
|
989
1076
|
}
|
|
990
1077
|
).then(() => {
|
|
991
|
-
|
|
1078
|
+
de(c, v, ne, X), x("audio_chunk", v);
|
|
992
1079
|
});
|
|
993
|
-
},
|
|
1080
|
+
}, Be = (c) => {
|
|
994
1081
|
if (ee(c)) return;
|
|
995
|
-
(c.is_new_segment || Number(c.audio_offset_ms ?? -1) === 0) &&
|
|
1082
|
+
(c.is_new_segment || Number(c.audio_offset_ms ?? -1) === 0) && N(), console.warn(
|
|
996
1083
|
"[realtimeVoice] avatar_lipsync is deprecated — expect avatar_audio_chunk"
|
|
997
1084
|
);
|
|
998
|
-
const
|
|
999
|
-
|
|
1000
|
-
const
|
|
1085
|
+
const v = String(c.spoken_text ?? c.text ?? "").trim();
|
|
1086
|
+
v && (o = v), se(c, !!c.is_new_segment);
|
|
1087
|
+
const B = n.length;
|
|
1001
1088
|
I.queueTimingsOnly(
|
|
1002
1089
|
n,
|
|
1003
1090
|
r,
|
|
1004
1091
|
c.visemes ?? [],
|
|
1005
1092
|
c.words ?? [],
|
|
1006
1093
|
!!c.is_new_segment
|
|
1007
|
-
),
|
|
1094
|
+
), de(
|
|
1008
1095
|
c,
|
|
1009
|
-
|
|
1010
|
-
|
|
1096
|
+
v,
|
|
1097
|
+
B,
|
|
1011
1098
|
c.visemes ?? []
|
|
1012
|
-
),
|
|
1013
|
-
},
|
|
1014
|
-
const
|
|
1015
|
-
if (!
|
|
1016
|
-
const
|
|
1017
|
-
if (!
|
|
1099
|
+
), x("lipsync", v), M();
|
|
1100
|
+
}, Se = async (c) => {
|
|
1101
|
+
const v = String(c.text ?? "").trim();
|
|
1102
|
+
if (!v) return;
|
|
1103
|
+
const B = m.authToken?.trim();
|
|
1104
|
+
if (!B) {
|
|
1018
1105
|
console.error("[realtimeVoice] avatar_speak requires authToken");
|
|
1019
1106
|
return;
|
|
1020
1107
|
}
|
|
1021
|
-
|
|
1022
|
-
const
|
|
1023
|
-
|
|
1024
|
-
const
|
|
1025
|
-
|
|
1026
|
-
const
|
|
1027
|
-
|
|
1028
|
-
Math.min(
|
|
1029
|
-
),
|
|
1030
|
-
user_query:
|
|
1108
|
+
Y?.abort();
|
|
1109
|
+
const X = new AbortController();
|
|
1110
|
+
Y = X;
|
|
1111
|
+
const ie = ++R;
|
|
1112
|
+
N(), I.resetForNewStream(l), o = v;
|
|
1113
|
+
const oe = `${(m.apiBase ?? tt).replace(/\/$/, "")}/avatar_ttsWithPoses`, ne = m.voiceId?.trim() || An, _e = m.speakingRate ?? gt, st = Math.max(
|
|
1114
|
+
Lt,
|
|
1115
|
+
Math.min(Ot, _e)
|
|
1116
|
+
), He = {
|
|
1117
|
+
user_query: v,
|
|
1031
1118
|
ttsEngineId: l,
|
|
1032
|
-
speakingRate:
|
|
1119
|
+
speakingRate: st,
|
|
1033
1120
|
tenant: "aiTwin"
|
|
1034
1121
|
};
|
|
1035
|
-
Sn.has(l) && (
|
|
1122
|
+
Sn.has(l) && (He.voice_id = ne);
|
|
1036
1123
|
try {
|
|
1037
|
-
const
|
|
1124
|
+
const we = await fetch(oe, {
|
|
1038
1125
|
method: "POST",
|
|
1039
1126
|
headers: {
|
|
1040
1127
|
"Content-Type": "application/json",
|
|
1041
|
-
Authorization: `Bearer ${
|
|
1128
|
+
Authorization: `Bearer ${B}`
|
|
1042
1129
|
},
|
|
1043
|
-
body: JSON.stringify(
|
|
1044
|
-
signal:
|
|
1130
|
+
body: JSON.stringify(He),
|
|
1131
|
+
signal: X.signal
|
|
1045
1132
|
});
|
|
1046
|
-
if (!
|
|
1047
|
-
throw new Error(`avatar_ttsWithPoses failed (${
|
|
1048
|
-
const
|
|
1049
|
-
if (!
|
|
1050
|
-
const Ie =
|
|
1051
|
-
let
|
|
1052
|
-
const
|
|
1053
|
-
if (
|
|
1133
|
+
if (!we.ok)
|
|
1134
|
+
throw new Error(`avatar_ttsWithPoses failed (${we.status})`);
|
|
1135
|
+
const Ke = we.body;
|
|
1136
|
+
if (!Ke) throw new Error("No response body");
|
|
1137
|
+
const Ie = Ke.getReader(), it = new TextDecoder();
|
|
1138
|
+
let ce = "";
|
|
1139
|
+
const be = async (G) => {
|
|
1140
|
+
if (ie !== R || X.signal.aborted || !b)
|
|
1054
1141
|
return;
|
|
1055
|
-
const
|
|
1056
|
-
if (
|
|
1057
|
-
if (
|
|
1058
|
-
const
|
|
1059
|
-
|
|
1142
|
+
const P = vn(G);
|
|
1143
|
+
if (P) {
|
|
1144
|
+
if (P.event === "audio") {
|
|
1145
|
+
const me = P.data.chunk, re = P.data.visemes ?? [], fe = P.data.words ?? [], je = P.data.is_new_segment ?? !1, Re = P.data.sample_rate;
|
|
1146
|
+
me ? await I.playAudioChunk(
|
|
1060
1147
|
n,
|
|
1061
1148
|
r,
|
|
1149
|
+
me,
|
|
1150
|
+
re,
|
|
1062
1151
|
fe,
|
|
1063
|
-
|
|
1064
|
-
le,
|
|
1065
|
-
Ke,
|
|
1152
|
+
je,
|
|
1066
1153
|
{ sampleRate: Re }
|
|
1067
|
-
) : (
|
|
1154
|
+
) : (re.length > 0 || fe.length > 0) && I.queueTimingsOnly(
|
|
1068
1155
|
n,
|
|
1069
1156
|
r,
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1157
|
+
re,
|
|
1158
|
+
fe,
|
|
1159
|
+
je
|
|
1073
1160
|
);
|
|
1074
|
-
} else if (
|
|
1075
|
-
const
|
|
1076
|
-
typeof
|
|
1077
|
-
const
|
|
1078
|
-
Array.isArray(
|
|
1079
|
-
...vt(
|
|
1161
|
+
} else if (P.event === "metadata") {
|
|
1162
|
+
const me = P.data.mood;
|
|
1163
|
+
typeof me == "string" && me.trim() && (a = me.trim());
|
|
1164
|
+
const re = P.data.sentence_emotions;
|
|
1165
|
+
Array.isArray(re) && (s.length = 0, s.push(
|
|
1166
|
+
...vt(re, a)
|
|
1080
1167
|
)), M();
|
|
1081
|
-
} else if (
|
|
1168
|
+
} else if (P.event === "error")
|
|
1082
1169
|
throw new Error(
|
|
1083
|
-
String(
|
|
1170
|
+
String(P.data.message ?? "avatar_ttsWithPoses stream error")
|
|
1084
1171
|
);
|
|
1085
1172
|
}
|
|
1086
1173
|
};
|
|
1087
|
-
for (; !(
|
|
1088
|
-
const { done:
|
|
1089
|
-
|
|
1090
|
-
const
|
|
1174
|
+
for (; !(ie !== R || X.signal.aborted || !b); ) {
|
|
1175
|
+
const { done: G, value: P } = await Ie.read();
|
|
1176
|
+
P && (ce += it.decode(P, { stream: !0 }));
|
|
1177
|
+
const me = ce.split(`
|
|
1091
1178
|
|
|
1092
1179
|
`);
|
|
1093
|
-
|
|
1094
|
-
for (const
|
|
1095
|
-
if (
|
|
1096
|
-
|
|
1180
|
+
ce = me.pop() ?? "";
|
|
1181
|
+
for (const re of me) await be(re);
|
|
1182
|
+
if (G) {
|
|
1183
|
+
ce.trim() && await be(ce.trim()), ie === R && !X.signal.aborted && b && I.markStreamComplete(n);
|
|
1097
1184
|
break;
|
|
1098
1185
|
}
|
|
1099
1186
|
}
|
|
1100
|
-
} catch (
|
|
1101
|
-
if (
|
|
1102
|
-
console.error("[realtimeVoice] avatar_speak failed:",
|
|
1187
|
+
} catch (we) {
|
|
1188
|
+
if (X.signal.aborted || !b) return;
|
|
1189
|
+
console.error("[realtimeVoice] avatar_speak failed:", we), e("error"), M();
|
|
1103
1190
|
} finally {
|
|
1104
|
-
|
|
1191
|
+
Y === X && (Y = null);
|
|
1105
1192
|
}
|
|
1106
|
-
},
|
|
1107
|
-
const
|
|
1108
|
-
if (!
|
|
1193
|
+
}, qe = (c) => {
|
|
1194
|
+
const v = Jr(c);
|
|
1195
|
+
if (!v) {
|
|
1109
1196
|
console.warn("[realtimeVoice] server message with no payload", c);
|
|
1110
1197
|
return;
|
|
1111
1198
|
}
|
|
1112
|
-
const
|
|
1113
|
-
switch (
|
|
1199
|
+
const B = String(v.type ?? "unknown");
|
|
1200
|
+
switch (B !== "avatar_metadata" && B !== "avatar_audio_chunk" && B !== "avatar_lipsync" && B !== "avatar_interrupt" && B !== "error" && console.debug("[realtimeVoice] server message", B, v), B) {
|
|
1114
1201
|
case "avatar_metadata":
|
|
1115
|
-
|
|
1202
|
+
$(v);
|
|
1116
1203
|
break;
|
|
1117
1204
|
case "avatar_audio_chunk":
|
|
1118
|
-
te(
|
|
1205
|
+
te(v);
|
|
1119
1206
|
break;
|
|
1120
1207
|
case "avatar_lipsync":
|
|
1121
|
-
|
|
1208
|
+
Be(v);
|
|
1122
1209
|
break;
|
|
1123
1210
|
case "avatar_interrupt":
|
|
1124
|
-
|
|
1211
|
+
Q(v);
|
|
1125
1212
|
break;
|
|
1126
1213
|
case "error": {
|
|
1127
|
-
const
|
|
1128
|
-
console.error("[realtimeVoice] server error:",
|
|
1214
|
+
const X = String(v.message ?? "Voice session error");
|
|
1215
|
+
console.error("[realtimeVoice] server error:", X), e("error"), M();
|
|
1129
1216
|
break;
|
|
1130
1217
|
}
|
|
1131
1218
|
case "avatar_speak":
|
|
1132
|
-
|
|
1219
|
+
Se(v);
|
|
1133
1220
|
break;
|
|
1134
1221
|
}
|
|
1135
|
-
},
|
|
1136
|
-
transport: new
|
|
1137
|
-
mediaManager:
|
|
1138
|
-
serializer: new
|
|
1222
|
+
}, rt = () => u || (S = new Kr(), u = new zn({
|
|
1223
|
+
transport: new Yn({
|
|
1224
|
+
mediaManager: S,
|
|
1225
|
+
serializer: new Hr(),
|
|
1139
1226
|
recorderSampleRate: In,
|
|
1140
1227
|
playerSampleRate: Rn
|
|
1141
1228
|
}),
|
|
@@ -1146,11 +1233,11 @@ function Jr(e, t = {}) {
|
|
|
1146
1233
|
f = !0, e("idle"), M();
|
|
1147
1234
|
},
|
|
1148
1235
|
onDisconnected: () => {
|
|
1149
|
-
f = !1,
|
|
1236
|
+
f = !1, J();
|
|
1150
1237
|
},
|
|
1151
1238
|
onError: (c) => {
|
|
1152
|
-
const
|
|
1153
|
-
console.error("[realtimeVoice]",
|
|
1239
|
+
const v = typeof c == "object" && c !== null && "data" in c ? String(c.data ?? c) : String(c);
|
|
1240
|
+
console.error("[realtimeVoice]", v, c), e("error"), M();
|
|
1154
1241
|
},
|
|
1155
1242
|
onTransportStateChanged: (c) => {
|
|
1156
1243
|
c === "error" && (e("error"), M());
|
|
@@ -1159,14 +1246,14 @@ function Jr(e, t = {}) {
|
|
|
1159
1246
|
D(c);
|
|
1160
1247
|
},
|
|
1161
1248
|
onUserStartedSpeaking: () => {
|
|
1162
|
-
|
|
1249
|
+
Q({});
|
|
1163
1250
|
},
|
|
1164
1251
|
onBotStartedSpeaking: () => {
|
|
1165
|
-
|
|
1252
|
+
N(), x("bot_started");
|
|
1166
1253
|
},
|
|
1167
1254
|
onBotStoppedSpeaking: () => {
|
|
1168
|
-
b && (
|
|
1169
|
-
|
|
1255
|
+
b && (T(), _ = setTimeout(() => {
|
|
1256
|
+
_ = null, b && (I.markStreamComplete(n), x("bot_stopped"));
|
|
1170
1257
|
}, 450));
|
|
1171
1258
|
},
|
|
1172
1259
|
onUserTranscript: (c) => {
|
|
@@ -1184,18 +1271,18 @@ function Jr(e, t = {}) {
|
|
|
1184
1271
|
l = c, I.setStreamTtsEngineId(c);
|
|
1185
1272
|
},
|
|
1186
1273
|
getTtsEngineId: () => l,
|
|
1187
|
-
speak: async (c,
|
|
1188
|
-
const
|
|
1189
|
-
if (
|
|
1274
|
+
speak: async (c, v) => {
|
|
1275
|
+
const B = c.trim();
|
|
1276
|
+
if (B) {
|
|
1190
1277
|
if (!u || !f)
|
|
1191
1278
|
throw new Error(
|
|
1192
1279
|
"Realtime voice is not connected. Call connect() first."
|
|
1193
1280
|
);
|
|
1194
|
-
|
|
1281
|
+
O(), await u.sendText(B);
|
|
1195
1282
|
}
|
|
1196
1283
|
},
|
|
1197
1284
|
stop: () => {
|
|
1198
|
-
|
|
1285
|
+
Y?.abort(), Y = null, R += 1, N(), O(), e("idle"), M();
|
|
1199
1286
|
},
|
|
1200
1287
|
connect: async (c) => {
|
|
1201
1288
|
if (c && (m = { ...m, ...c }), !m.authToken?.trim())
|
|
@@ -1203,27 +1290,27 @@ function Jr(e, t = {}) {
|
|
|
1203
1290
|
"Voice connect requires authToken (same JWT as SSE Authorization Bearer)."
|
|
1204
1291
|
);
|
|
1205
1292
|
e("loading");
|
|
1206
|
-
const
|
|
1207
|
-
await
|
|
1208
|
-
const
|
|
1209
|
-
console.info("[realtimeVoice] connecting (avatar_audio_chunk RTVI):",
|
|
1293
|
+
const v = rt();
|
|
1294
|
+
await v.initDevices();
|
|
1295
|
+
const B = Yr(m);
|
|
1296
|
+
console.info("[realtimeVoice] connecting (avatar_audio_chunk RTVI):", B);
|
|
1210
1297
|
try {
|
|
1211
|
-
await
|
|
1212
|
-
} catch (
|
|
1298
|
+
await v.connect({ wsUrl: B });
|
|
1299
|
+
} catch (X) {
|
|
1213
1300
|
f = !1, e("error"), M();
|
|
1214
|
-
const
|
|
1215
|
-
throw new Error(`${
|
|
1301
|
+
const ie = X instanceof Error ? X.message : "Realtime voice connect failed (WebSocket 101 only means upgrade OK — check authToken/origin/RTVI handshake)";
|
|
1302
|
+
throw new Error(`${ie} — ${B}`);
|
|
1216
1303
|
}
|
|
1217
1304
|
f = !0, e("idle"), M();
|
|
1218
1305
|
},
|
|
1219
1306
|
disconnect: async () => {
|
|
1220
|
-
if (
|
|
1307
|
+
if (T(), j = !1, h.length = 0, g = !1, Y?.abort(), Y = null, R += 1, N(), u)
|
|
1221
1308
|
try {
|
|
1222
1309
|
await u.disconnect();
|
|
1223
1310
|
} catch (c) {
|
|
1224
1311
|
console.error("[realtimeVoice] disconnect failed:", c);
|
|
1225
1312
|
}
|
|
1226
|
-
f = !1,
|
|
1313
|
+
f = !1, J();
|
|
1227
1314
|
},
|
|
1228
1315
|
isConnected: () => f,
|
|
1229
1316
|
unlockAudio: async () => {
|
|
@@ -1233,7 +1320,7 @@ function Jr(e, t = {}) {
|
|
|
1233
1320
|
getWordQueue: () => r,
|
|
1234
1321
|
getSentenceEmotions: () => s,
|
|
1235
1322
|
getStreamMood: () => a,
|
|
1236
|
-
getPlaybackElapsedMs:
|
|
1323
|
+
getPlaybackElapsedMs: V,
|
|
1237
1324
|
isSpeaking: () => I.isSpeaking(),
|
|
1238
1325
|
getVoiceStream: () => I.getVoiceStream(),
|
|
1239
1326
|
setPlaybackSpeed: (c) => {
|
|
@@ -1243,13 +1330,13 @@ function Jr(e, t = {}) {
|
|
|
1243
1330
|
subscribe: (c) => (d.add(c), () => d.delete(c))
|
|
1244
1331
|
};
|
|
1245
1332
|
}
|
|
1246
|
-
function
|
|
1333
|
+
function Zr(e, t, n) {
|
|
1247
1334
|
return {
|
|
1248
1335
|
width: e.crop?.source_width ?? t,
|
|
1249
1336
|
height: e.crop?.source_height ?? n
|
|
1250
1337
|
};
|
|
1251
1338
|
}
|
|
1252
|
-
function
|
|
1339
|
+
function es(e, t) {
|
|
1253
1340
|
const n = e.crop;
|
|
1254
1341
|
return {
|
|
1255
1342
|
x: t?.source_x ?? n?.x ?? 0,
|
|
@@ -1258,21 +1345,21 @@ function Zr(e, t) {
|
|
|
1258
1345
|
height: t?.source_h ?? n?.height ?? e.frame_height ?? 0
|
|
1259
1346
|
};
|
|
1260
1347
|
}
|
|
1261
|
-
function
|
|
1348
|
+
function ts(e) {
|
|
1262
1349
|
return e ? (e.w ?? 0) > 0 && (e.h ?? 0) > 0 : !1;
|
|
1263
1350
|
}
|
|
1264
|
-
async function
|
|
1351
|
+
async function wt(e, t) {
|
|
1265
1352
|
const n = await fetch(e);
|
|
1266
1353
|
if (!n.ok) throw new Error(`Failed to load encrypted asset: ${e}`);
|
|
1267
1354
|
const r = await n.arrayBuffer();
|
|
1268
1355
|
return pr(r, t);
|
|
1269
1356
|
}
|
|
1270
|
-
async function
|
|
1357
|
+
async function ns(e, t) {
|
|
1271
1358
|
if (!t) throw new Error("Missing asset key for encrypted JSON");
|
|
1272
|
-
const n = await
|
|
1359
|
+
const n = await wt(e, t), r = new TextDecoder().decode(n);
|
|
1273
1360
|
return JSON.parse(r);
|
|
1274
1361
|
}
|
|
1275
|
-
async function
|
|
1362
|
+
async function rs(e) {
|
|
1276
1363
|
const t = new Blob([e], { type: "image/webp" }), n = URL.createObjectURL(t);
|
|
1277
1364
|
return new Promise((r, s) => {
|
|
1278
1365
|
const i = new Image();
|
|
@@ -1283,7 +1370,7 @@ async function ns(e) {
|
|
|
1283
1370
|
}, i.src = n;
|
|
1284
1371
|
});
|
|
1285
1372
|
}
|
|
1286
|
-
async function
|
|
1373
|
+
async function ss(e) {
|
|
1287
1374
|
const t = new Blob([e], { type: "image/png" }), n = URL.createObjectURL(t);
|
|
1288
1375
|
return new Promise((r, s) => {
|
|
1289
1376
|
const i = new Image();
|
|
@@ -1294,16 +1381,16 @@ async function rs(e) {
|
|
|
1294
1381
|
}, i.src = n;
|
|
1295
1382
|
});
|
|
1296
1383
|
}
|
|
1297
|
-
function
|
|
1384
|
+
function is(e) {
|
|
1298
1385
|
const t = new Blob([e], { type: "video/mp4" });
|
|
1299
1386
|
return URL.createObjectURL(t);
|
|
1300
1387
|
}
|
|
1301
|
-
async function
|
|
1388
|
+
async function as(e) {
|
|
1302
1389
|
const t = vr();
|
|
1303
|
-
if (!
|
|
1390
|
+
if (!ht()) return t;
|
|
1304
1391
|
if (!e) throw new Error("Missing asset key for encrypted idle video");
|
|
1305
|
-
const n = await
|
|
1306
|
-
return
|
|
1392
|
+
const n = await wt(t, e);
|
|
1393
|
+
return is(n);
|
|
1307
1394
|
}
|
|
1308
1395
|
function Ut(e, t) {
|
|
1309
1396
|
return `${e}/${t}_minus_sil.png`;
|
|
@@ -1315,7 +1402,7 @@ function Mn(e) {
|
|
|
1315
1402
|
const n = e?.crop?.content_threshold;
|
|
1316
1403
|
return typeof n == "number" && n > 0 ? n : Dn;
|
|
1317
1404
|
}
|
|
1318
|
-
const
|
|
1405
|
+
const ki = [
|
|
1319
1406
|
"aa",
|
|
1320
1407
|
"E",
|
|
1321
1408
|
"I",
|
|
@@ -1334,7 +1421,7 @@ const Si = [
|
|
|
1334
1421
|
"t01_0.25",
|
|
1335
1422
|
"t02_0.50",
|
|
1336
1423
|
"t03_0.75"
|
|
1337
|
-
],
|
|
1424
|
+
], os = Rt.length, tn = /* @__PURE__ */ new Set([
|
|
1338
1425
|
"aa__kk",
|
|
1339
1426
|
"aa__nn",
|
|
1340
1427
|
"aa__sil",
|
|
@@ -1447,22 +1534,22 @@ function nn(e, t) {
|
|
|
1447
1534
|
function rn(e, t) {
|
|
1448
1535
|
return `pairs/${e}/${t}_minus_sil.png`;
|
|
1449
1536
|
}
|
|
1450
|
-
function
|
|
1537
|
+
function ft(e) {
|
|
1451
1538
|
return `${e}_minus_sil.png`;
|
|
1452
1539
|
}
|
|
1453
|
-
function
|
|
1540
|
+
function cs(e, t) {
|
|
1454
1541
|
if (t.has(e)) return e;
|
|
1455
1542
|
const n = /^pairs\/([^/]+)\//.exec(e);
|
|
1456
1543
|
if (!n) return null;
|
|
1457
1544
|
const r = n[1].split("__")[1];
|
|
1458
1545
|
if (!r || r === "sil") return null;
|
|
1459
|
-
const s =
|
|
1546
|
+
const s = ft(r);
|
|
1460
1547
|
return t.has(s) ? s : null;
|
|
1461
1548
|
}
|
|
1462
1549
|
function Cn(e, t) {
|
|
1463
1550
|
return e.filter((n) => t.has(n));
|
|
1464
1551
|
}
|
|
1465
|
-
function
|
|
1552
|
+
function us(e, t, n) {
|
|
1466
1553
|
const r = Nt(e, t);
|
|
1467
1554
|
return Cn(r, n).length > 0;
|
|
1468
1555
|
}
|
|
@@ -1476,40 +1563,40 @@ function Nt(e, t) {
|
|
|
1476
1563
|
}
|
|
1477
1564
|
const s = nn(t, e);
|
|
1478
1565
|
if (tn.has(s)) {
|
|
1479
|
-
for (let i =
|
|
1566
|
+
for (let i = os - 1; i >= 0; i--)
|
|
1480
1567
|
n.push(rn(s, Rt[i]));
|
|
1481
1568
|
return n;
|
|
1482
1569
|
}
|
|
1483
1570
|
return [];
|
|
1484
1571
|
}
|
|
1485
|
-
function
|
|
1572
|
+
function ls(e) {
|
|
1486
1573
|
return e < 16 ? [] : e < 35 ? [1] : e < 51 ? [0, 2] : [0, 1, 2];
|
|
1487
1574
|
}
|
|
1488
|
-
function
|
|
1489
|
-
return
|
|
1575
|
+
function fs(e, t) {
|
|
1576
|
+
return ls(t).map((r) => e[r]).filter((r) => r != null);
|
|
1490
1577
|
}
|
|
1491
|
-
function
|
|
1578
|
+
function ds(e, t, n, r) {
|
|
1492
1579
|
if (r <= 0) return 0;
|
|
1493
1580
|
const i = Math.max(1, n - t) / r, o = e - t, a = Math.floor(o / i);
|
|
1494
1581
|
return Math.min(r - 1, Math.max(0, a));
|
|
1495
1582
|
}
|
|
1496
|
-
function
|
|
1583
|
+
function ms(e, t, n) {
|
|
1497
1584
|
if (!n) return `${e}/${t}`;
|
|
1498
1585
|
const r = t.split("/").pop() ?? t, s = r.includes(".") ? r.slice(0, r.lastIndexOf(".")) : r;
|
|
1499
1586
|
return `${e}/${s}.bin`;
|
|
1500
1587
|
}
|
|
1501
|
-
const
|
|
1588
|
+
const hs = [0.32, 0.24, 0.16, 0.08, 0], gs = hs.map(
|
|
1502
1589
|
(e) => `eyes_${e.toFixed(2)}`
|
|
1503
1590
|
), ws = [
|
|
1504
1591
|
"eyes_0.32",
|
|
1505
1592
|
"eyes_0.16",
|
|
1506
1593
|
"eyes_0.00"
|
|
1507
|
-
],
|
|
1594
|
+
], ps = [
|
|
1508
1595
|
"eyes_0.32",
|
|
1509
1596
|
"eyes_0.16",
|
|
1510
1597
|
"eyes_0.08",
|
|
1511
1598
|
"eyes_0.00"
|
|
1512
|
-
], sn = 2,
|
|
1599
|
+
], sn = 2, _s = -30, Dt = 20, ys = {
|
|
1513
1600
|
fear: -30,
|
|
1514
1601
|
anger: -20,
|
|
1515
1602
|
sad: -10,
|
|
@@ -1522,12 +1609,12 @@ function Vt(e) {
|
|
|
1522
1609
|
return `brow_${e}`;
|
|
1523
1610
|
}
|
|
1524
1611
|
function $t(e) {
|
|
1525
|
-
return
|
|
1612
|
+
return ys[e];
|
|
1526
1613
|
}
|
|
1527
|
-
function
|
|
1528
|
-
return Math.max(
|
|
1614
|
+
function Pe(e) {
|
|
1615
|
+
return Math.max(_s, Math.min(Dt, e));
|
|
1529
1616
|
}
|
|
1530
|
-
function
|
|
1617
|
+
function Ss(e, t) {
|
|
1531
1618
|
if (e === t) return [];
|
|
1532
1619
|
const n = e < t ? sn : -sn, r = [];
|
|
1533
1620
|
let s = e;
|
|
@@ -1535,7 +1622,7 @@ function ys(e, t) {
|
|
|
1535
1622
|
s += n, r.push(s);
|
|
1536
1623
|
return r;
|
|
1537
1624
|
}
|
|
1538
|
-
const
|
|
1625
|
+
const ks = {
|
|
1539
1626
|
fear: "fear",
|
|
1540
1627
|
afraid: "fear",
|
|
1541
1628
|
anxiety: "fear",
|
|
@@ -1560,7 +1647,7 @@ const Ss = {
|
|
|
1560
1647
|
};
|
|
1561
1648
|
function Oe(e, t = "neutral") {
|
|
1562
1649
|
const n = String(e ?? "").trim().toLowerCase();
|
|
1563
|
-
return n ?
|
|
1650
|
+
return n ? ks[n] ?? t : t;
|
|
1564
1651
|
}
|
|
1565
1652
|
function xn(e) {
|
|
1566
1653
|
return e === 0 ? null : Ut(Vt(e), "eyes_standard");
|
|
@@ -1572,7 +1659,7 @@ function an(e, t) {
|
|
|
1572
1659
|
const n = Vt($t(e));
|
|
1573
1660
|
return !t || t === "eyes_standard" ? Pn(e) : e === "neutral" && t === "eyes_standard" ? null : Ut(n, t);
|
|
1574
1661
|
}
|
|
1575
|
-
function
|
|
1662
|
+
function vs(e, t) {
|
|
1576
1663
|
const n = [];
|
|
1577
1664
|
for (const r of t)
|
|
1578
1665
|
n.push(an(e, r));
|
|
@@ -1580,41 +1667,41 @@ function ks(e, t) {
|
|
|
1580
1667
|
n.push(an(e, t[r]));
|
|
1581
1668
|
return n.push(Pn(e)), n;
|
|
1582
1669
|
}
|
|
1583
|
-
function
|
|
1670
|
+
function bs(e) {
|
|
1584
1671
|
return e === 0 ? null : Ut(Vt(e), "eyes_standard");
|
|
1585
1672
|
}
|
|
1586
1673
|
function Es(e, t) {
|
|
1587
|
-
return
|
|
1674
|
+
return Ss(e, t).map(bs).filter((n) => n != null);
|
|
1588
1675
|
}
|
|
1589
|
-
const
|
|
1590
|
-
function
|
|
1676
|
+
const Ts = 6;
|
|
1677
|
+
function As(e, t) {
|
|
1591
1678
|
for (const n of e)
|
|
1592
1679
|
if (t >= n.wtime && t < n.wtime + n.wduration)
|
|
1593
1680
|
return n;
|
|
1594
1681
|
return null;
|
|
1595
1682
|
}
|
|
1596
|
-
function
|
|
1597
|
-
const t =
|
|
1598
|
-
return t >= Dt ? Dt :
|
|
1683
|
+
function Is(e) {
|
|
1684
|
+
const t = Pe(e);
|
|
1685
|
+
return t >= Dt ? Dt : Pe(t + Ts);
|
|
1599
1686
|
}
|
|
1600
|
-
function
|
|
1601
|
-
const r =
|
|
1602
|
-
return
|
|
1687
|
+
function Rs(e, t, n) {
|
|
1688
|
+
const r = Pe(n);
|
|
1689
|
+
return As(t, e)?.emphasis ? Is(r) : r;
|
|
1603
1690
|
}
|
|
1604
1691
|
function on(e) {
|
|
1605
1692
|
if (!e) return 0;
|
|
1606
1693
|
const t = e.match(/^brow_(-?\d+)\//);
|
|
1607
1694
|
if (!t?.[1]) return null;
|
|
1608
1695
|
const n = Number.parseInt(t[1], 10);
|
|
1609
|
-
return Number.isFinite(n) ?
|
|
1696
|
+
return Number.isFinite(n) ? Pe(n) : null;
|
|
1610
1697
|
}
|
|
1611
|
-
function
|
|
1698
|
+
function Qe(e, t) {
|
|
1612
1699
|
return e + Math.random() * (t - e);
|
|
1613
1700
|
}
|
|
1614
|
-
function
|
|
1615
|
-
return
|
|
1701
|
+
function ut() {
|
|
1702
|
+
return Qe(14, 32);
|
|
1616
1703
|
}
|
|
1617
|
-
function
|
|
1704
|
+
function Ds(e = {}) {
|
|
1618
1705
|
const {
|
|
1619
1706
|
initialDelayMs: t = 800 + Math.random() * 1200,
|
|
1620
1707
|
intervalMinMs: n = 2200,
|
|
@@ -1626,130 +1713,130 @@ function Rs(e = {}) {
|
|
|
1626
1713
|
postEmotionChangeDelayMs: l = 380,
|
|
1627
1714
|
minDwellMs: f = 550
|
|
1628
1715
|
} = e;
|
|
1629
|
-
let u = "neutral",
|
|
1716
|
+
let u = "neutral", S = "neutral", m = 0, p = 0, A = 0, d = {
|
|
1630
1717
|
kind: "idle",
|
|
1631
1718
|
nextBlinkAt: performance.now() + t
|
|
1632
|
-
},
|
|
1633
|
-
function
|
|
1634
|
-
|
|
1719
|
+
}, h = null, g = "__eyes_open__|neutral|brow:0";
|
|
1720
|
+
function k(_ = u) {
|
|
1721
|
+
g = `${h ?? "__eyes_open__"}|${_}|brow:${p}`;
|
|
1635
1722
|
}
|
|
1636
|
-
function b(
|
|
1637
|
-
|
|
1638
|
-
const M = on(
|
|
1639
|
-
M != null ? p = M :
|
|
1723
|
+
function b(_, T = u) {
|
|
1724
|
+
h = _;
|
|
1725
|
+
const M = on(_);
|
|
1726
|
+
M != null ? p = M : _ == null && (p = 0), k(T);
|
|
1640
1727
|
}
|
|
1641
|
-
function
|
|
1642
|
-
return xn(
|
|
1728
|
+
function W(_) {
|
|
1729
|
+
return xn(_);
|
|
1643
1730
|
}
|
|
1644
|
-
function
|
|
1645
|
-
const I =
|
|
1646
|
-
if (m =
|
|
1647
|
-
b(
|
|
1731
|
+
function Z(_, T, M) {
|
|
1732
|
+
const I = Pe(T), y = Pe(M);
|
|
1733
|
+
if (m = y, I === y) {
|
|
1734
|
+
b(W(y));
|
|
1648
1735
|
return;
|
|
1649
1736
|
}
|
|
1650
1737
|
const D = [
|
|
1651
|
-
...Es(I,
|
|
1652
|
-
|
|
1738
|
+
...Es(I, y),
|
|
1739
|
+
W(y)
|
|
1653
1740
|
];
|
|
1654
1741
|
d = {
|
|
1655
1742
|
kind: "browBlend",
|
|
1656
1743
|
paths: D,
|
|
1657
1744
|
index: 0,
|
|
1658
|
-
holdUntil:
|
|
1659
|
-
targetBrow:
|
|
1745
|
+
holdUntil: _ + ut(),
|
|
1746
|
+
targetBrow: y
|
|
1660
1747
|
}, b(D[0] ?? null);
|
|
1661
1748
|
}
|
|
1662
|
-
function
|
|
1749
|
+
function Y(_, T) {
|
|
1663
1750
|
d = {
|
|
1664
1751
|
kind: "idle",
|
|
1665
|
-
nextBlinkAt:
|
|
1666
|
-
},
|
|
1752
|
+
nextBlinkAt: _ + Qe(n, r)
|
|
1753
|
+
}, S = T, b(W(m), T);
|
|
1667
1754
|
}
|
|
1668
|
-
function
|
|
1669
|
-
const I = M ? ws : Math.random() < a ?
|
|
1755
|
+
function R(_, T, M) {
|
|
1756
|
+
const I = M ? ws : Math.random() < a ? gs : ps;
|
|
1670
1757
|
d = {
|
|
1671
1758
|
kind: "playing",
|
|
1672
|
-
paths:
|
|
1759
|
+
paths: vs(T, I),
|
|
1673
1760
|
index: 0,
|
|
1674
|
-
holdUntil:
|
|
1761
|
+
holdUntil: _ + ut(),
|
|
1675
1762
|
after: "idle",
|
|
1676
|
-
blinkEmotion:
|
|
1677
|
-
},
|
|
1763
|
+
blinkEmotion: T
|
|
1764
|
+
}, S = T, b(d.paths[0] ?? null, T);
|
|
1678
1765
|
}
|
|
1679
|
-
function
|
|
1766
|
+
function j(_) {
|
|
1680
1767
|
if (d.kind === "browBlend") {
|
|
1681
|
-
for (;
|
|
1682
|
-
d.index += 1, d.holdUntil =
|
|
1683
|
-
const
|
|
1684
|
-
b(
|
|
1768
|
+
for (; _ >= d.holdUntil && d.index < d.paths.length - 1; )
|
|
1769
|
+
d.index += 1, d.holdUntil = _ + ut();
|
|
1770
|
+
const T = d.paths[d.index] ?? null;
|
|
1771
|
+
b(T), _ >= d.holdUntil && d.index >= d.paths.length - 1 && (p = d.targetBrow, m = d.targetBrow, b(W(d.targetBrow)), d = {
|
|
1685
1772
|
kind: "idle",
|
|
1686
|
-
nextBlinkAt:
|
|
1773
|
+
nextBlinkAt: _ + l
|
|
1687
1774
|
});
|
|
1688
1775
|
return;
|
|
1689
1776
|
}
|
|
1690
1777
|
if (d.kind === "idle") {
|
|
1691
|
-
b(
|
|
1778
|
+
b(W(m), S), _ >= d.nextBlinkAt && R(_, S, !1);
|
|
1692
1779
|
return;
|
|
1693
1780
|
}
|
|
1694
1781
|
if (d.kind === "doublePause") {
|
|
1695
|
-
b(
|
|
1782
|
+
b(W(m), d.blinkEmotion), _ >= d.resumeAt && R(_, d.blinkEmotion, !0);
|
|
1696
1783
|
return;
|
|
1697
1784
|
}
|
|
1698
1785
|
if (d.kind === "playing") {
|
|
1699
|
-
for (;
|
|
1700
|
-
d.index += 1, d.holdUntil =
|
|
1701
|
-
if (b(d.paths[d.index] ?? null, d.blinkEmotion),
|
|
1786
|
+
for (; _ >= d.holdUntil && d.index < d.paths.length - 1; )
|
|
1787
|
+
d.index += 1, d.holdUntil = _ + ut();
|
|
1788
|
+
if (b(d.paths[d.index] ?? null, d.blinkEmotion), _ >= d.holdUntil && d.index >= d.paths.length - 1) {
|
|
1702
1789
|
if (d.after === "resumeIdle") {
|
|
1703
|
-
|
|
1790
|
+
Y(_ + l, u);
|
|
1704
1791
|
return;
|
|
1705
1792
|
}
|
|
1706
1793
|
if (d.after === "doublePause") {
|
|
1707
1794
|
d = {
|
|
1708
1795
|
kind: "doublePause",
|
|
1709
|
-
resumeAt:
|
|
1796
|
+
resumeAt: _ + Qe(i, o),
|
|
1710
1797
|
blinkEmotion: d.blinkEmotion
|
|
1711
|
-
}, b(
|
|
1798
|
+
}, b(W(m), d.blinkEmotion);
|
|
1712
1799
|
return;
|
|
1713
1800
|
}
|
|
1714
1801
|
if (d.after === "idle" && Math.random() < s) {
|
|
1715
1802
|
d = {
|
|
1716
1803
|
kind: "doublePause",
|
|
1717
|
-
resumeAt:
|
|
1804
|
+
resumeAt: _ + Qe(i, o),
|
|
1718
1805
|
blinkEmotion: d.blinkEmotion
|
|
1719
|
-
}, b(
|
|
1806
|
+
}, b(W(m), d.blinkEmotion);
|
|
1720
1807
|
return;
|
|
1721
1808
|
}
|
|
1722
|
-
|
|
1809
|
+
Y(_, d.blinkEmotion);
|
|
1723
1810
|
}
|
|
1724
1811
|
}
|
|
1725
1812
|
}
|
|
1726
1813
|
return {
|
|
1727
|
-
advance:
|
|
1728
|
-
setTargetEmotion(
|
|
1729
|
-
const
|
|
1730
|
-
if (
|
|
1814
|
+
advance: j,
|
|
1815
|
+
setTargetEmotion(_) {
|
|
1816
|
+
const T = Oe(_, u);
|
|
1817
|
+
if (T === u) return;
|
|
1731
1818
|
const M = performance.now();
|
|
1732
|
-
f > 0 &&
|
|
1819
|
+
f > 0 && T !== u && !(u === "neutral" && T !== "neutral") && M - A < f || (u = T, S = T, A = M);
|
|
1733
1820
|
},
|
|
1734
|
-
setTargetEyebrow(
|
|
1735
|
-
const
|
|
1736
|
-
if (
|
|
1737
|
-
const M = performance.now(), I = d.kind === "browBlend" ? on(
|
|
1738
|
-
m =
|
|
1821
|
+
setTargetEyebrow(_) {
|
|
1822
|
+
const T = Pe(_);
|
|
1823
|
+
if (T === m && d.kind !== "browBlend") return;
|
|
1824
|
+
const M = performance.now(), I = d.kind === "browBlend" ? on(h) ?? p : p;
|
|
1825
|
+
m = T, !(T === I && d.kind !== "browBlend") && (d.kind === "playing" || d.kind === "doublePause" || Z(M, I, T));
|
|
1739
1826
|
},
|
|
1740
1827
|
getTargetEmotion: () => u,
|
|
1741
1828
|
getTargetEyebrow: () => m,
|
|
1742
|
-
getExpressionPath: () =>
|
|
1743
|
-
getDrawKey: () =>
|
|
1829
|
+
getExpressionPath: () => h,
|
|
1830
|
+
getDrawKey: () => g,
|
|
1744
1831
|
reset() {
|
|
1745
|
-
u = "neutral",
|
|
1746
|
-
performance.now() +
|
|
1832
|
+
u = "neutral", S = "neutral", m = 0, p = 0, A = 0, Y(
|
|
1833
|
+
performance.now() + Qe(n, r),
|
|
1747
1834
|
"neutral"
|
|
1748
1835
|
);
|
|
1749
1836
|
}
|
|
1750
1837
|
};
|
|
1751
1838
|
}
|
|
1752
|
-
function
|
|
1839
|
+
function Ms() {
|
|
1753
1840
|
const e = document.createElement("video");
|
|
1754
1841
|
e.muted = !0, e.playsInline = !0, e.preload = "auto", e.setAttribute("playsinline", ""), e.loop = !0;
|
|
1755
1842
|
let t = !1, n = null, r = "";
|
|
@@ -1792,17 +1879,17 @@ function Ds() {
|
|
|
1792
1879
|
}
|
|
1793
1880
|
};
|
|
1794
1881
|
}
|
|
1795
|
-
const
|
|
1796
|
-
function
|
|
1882
|
+
const Cs = 50, Fn = 400;
|
|
1883
|
+
function xs(e, t, n) {
|
|
1797
1884
|
return e.filter((r) => {
|
|
1798
1885
|
const s = r.queueIndex ?? -1;
|
|
1799
1886
|
return s >= t && s <= n;
|
|
1800
1887
|
});
|
|
1801
1888
|
}
|
|
1802
|
-
function
|
|
1889
|
+
function Ps(e, t) {
|
|
1803
1890
|
const n = [];
|
|
1804
1891
|
for (const r of e) {
|
|
1805
|
-
const s =
|
|
1892
|
+
const s = xs(
|
|
1806
1893
|
t,
|
|
1807
1894
|
r.start_word,
|
|
1808
1895
|
r.end_word
|
|
@@ -1811,18 +1898,18 @@ function xs(e, t) {
|
|
|
1811
1898
|
const i = s[0], o = s[s.length - 1];
|
|
1812
1899
|
n.push({
|
|
1813
1900
|
sentence: r,
|
|
1814
|
-
startMs: Math.max(0, i.wtime -
|
|
1901
|
+
startMs: Math.max(0, i.wtime - Cs),
|
|
1815
1902
|
endMs: o.wtime + o.wduration + Fn
|
|
1816
1903
|
});
|
|
1817
1904
|
}
|
|
1818
1905
|
return n.sort((r, s) => r.startMs - s.startMs);
|
|
1819
1906
|
}
|
|
1820
|
-
function
|
|
1907
|
+
function Fs(e, t, n, r = "neutral") {
|
|
1821
1908
|
const s = Oe(r);
|
|
1822
1909
|
if (t.length === 0) return s;
|
|
1823
1910
|
if (n.length === 0 || e < n[0].wtime)
|
|
1824
1911
|
return Oe(t[0]?.emotion, s);
|
|
1825
|
-
const i =
|
|
1912
|
+
const i = Ps(t, n);
|
|
1826
1913
|
let o = null;
|
|
1827
1914
|
for (const f of i)
|
|
1828
1915
|
e >= f.startMs && e <= f.endMs && (o = f);
|
|
@@ -1840,48 +1927,48 @@ function Bn(e, t, n, r, s = Dn) {
|
|
|
1840
1927
|
const a = o.getImageData(0, 0, n, r), l = o.createImageData(n, r);
|
|
1841
1928
|
l.data.set(a.data);
|
|
1842
1929
|
const u = new OffscreenCanvas(n, r).getContext("2d", { willReadFrequently: !0 });
|
|
1843
|
-
for (const
|
|
1844
|
-
u.clearRect(0, 0, n, r), u.drawImage(
|
|
1930
|
+
for (const S of t) {
|
|
1931
|
+
u.clearRect(0, 0, n, r), u.drawImage(S, 0, 0, n, r);
|
|
1845
1932
|
const m = u.getImageData(0, 0, n, r);
|
|
1846
1933
|
for (let p = 0; p < l.data.length; p += 4) {
|
|
1847
|
-
const
|
|
1848
|
-
Math.max(
|
|
1934
|
+
const A = m.data[p], d = m.data[p + 1], h = m.data[p + 2];
|
|
1935
|
+
Math.max(A, d, h) > s && (l.data[p] = A, l.data[p + 1] = d, l.data[p + 2] = h, l.data[p + 3] = 255);
|
|
1849
1936
|
}
|
|
1850
1937
|
}
|
|
1851
1938
|
return o.putImageData(l, 0, 0), i;
|
|
1852
1939
|
}
|
|
1853
|
-
let
|
|
1854
|
-
const
|
|
1855
|
-
function
|
|
1856
|
-
|
|
1940
|
+
let xe = null, Ze = null;
|
|
1941
|
+
const dt = /* @__PURE__ */ new Map();
|
|
1942
|
+
function Bs() {
|
|
1943
|
+
xe = null, Ze = null, dt.clear();
|
|
1857
1944
|
}
|
|
1858
|
-
kr(
|
|
1859
|
-
function
|
|
1945
|
+
kr(Bs);
|
|
1946
|
+
function Ls(e) {
|
|
1860
1947
|
return e ?? Ze ?? void 0;
|
|
1861
1948
|
}
|
|
1862
|
-
function
|
|
1949
|
+
function qt(e) {
|
|
1863
1950
|
return new Promise((t, n) => {
|
|
1864
1951
|
const r = new Image();
|
|
1865
1952
|
r.decoding = "async", r.onload = () => t(r), r.onerror = () => n(new Error(`Failed to load image: ${e}`)), r.src = e;
|
|
1866
1953
|
});
|
|
1867
1954
|
}
|
|
1868
1955
|
async function Os(e) {
|
|
1869
|
-
return
|
|
1870
|
-
await
|
|
1871
|
-
) :
|
|
1956
|
+
return ht() ? ss(
|
|
1957
|
+
await wt(Qt(), e ?? "")
|
|
1958
|
+
) : qt(Qt());
|
|
1872
1959
|
}
|
|
1873
1960
|
async function cn(e, t, n, r) {
|
|
1874
|
-
const s = n ? await
|
|
1961
|
+
const s = n ? await ns(e, r) : await fetch(e).then((f) => {
|
|
1875
1962
|
if (!f.ok) throw new Error(`Failed to load ${e}`);
|
|
1876
1963
|
return f.json();
|
|
1877
1964
|
}), i = s.sheets?.[0];
|
|
1878
1965
|
if (!i?.path) throw new Error(`${e} has no sheets[0].path`);
|
|
1879
|
-
const o = n ? await
|
|
1880
|
-
await
|
|
1881
|
-
|
|
1966
|
+
const o = n ? await rs(
|
|
1967
|
+
await wt(
|
|
1968
|
+
ms(t, i.path, n),
|
|
1882
1969
|
r ?? ""
|
|
1883
1970
|
)
|
|
1884
|
-
) : await
|
|
1971
|
+
) : await qt(`${t}/${i.path}`), a = /* @__PURE__ */ new Map();
|
|
1885
1972
|
for (const f of s.cells ?? [])
|
|
1886
1973
|
f.path && a.set(f.path, f);
|
|
1887
1974
|
const l = /* @__PURE__ */ new Map();
|
|
@@ -1890,21 +1977,21 @@ async function cn(e, t, n, r) {
|
|
|
1890
1977
|
return { atlas: o, atlasMeta: s, cellByPath: a, sheetByIndex: l, diffBase: t };
|
|
1891
1978
|
}
|
|
1892
1979
|
async function Mt(e) {
|
|
1893
|
-
const t =
|
|
1980
|
+
const t = Ls(e), n = ht();
|
|
1894
1981
|
if (n && !t)
|
|
1895
1982
|
throw new Error("Encrypted assets enabled but no key provided");
|
|
1896
|
-
if (
|
|
1897
|
-
const i = await
|
|
1983
|
+
if (xe && (!n || Ze === (t ?? null))) {
|
|
1984
|
+
const i = await xe;
|
|
1898
1985
|
return {
|
|
1899
1986
|
...et(i),
|
|
1900
1987
|
visemePaths: [...i.viseme.cellByPath.keys()]
|
|
1901
1988
|
};
|
|
1902
1989
|
}
|
|
1903
|
-
Ze = t ?? null,
|
|
1904
|
-
const r =
|
|
1905
|
-
|
|
1990
|
+
Ze = t ?? null, dt.clear();
|
|
1991
|
+
const r = br();
|
|
1992
|
+
xe = (async () => {
|
|
1906
1993
|
const i = await Os(t), o = await cn(
|
|
1907
|
-
|
|
1994
|
+
Er(),
|
|
1908
1995
|
r,
|
|
1909
1996
|
n,
|
|
1910
1997
|
t
|
|
@@ -1922,80 +2009,80 @@ async function Mt(e) {
|
|
|
1922
2009
|
}
|
|
1923
2010
|
return { sil: i, viseme: o, expression: a };
|
|
1924
2011
|
})();
|
|
1925
|
-
const s = await
|
|
2012
|
+
const s = await xe;
|
|
1926
2013
|
return { ...et(s), visemePaths: [...s.viseme.cellByPath.keys()] };
|
|
1927
2014
|
}
|
|
1928
|
-
async function
|
|
1929
|
-
if (await Mt(e), !
|
|
1930
|
-
return
|
|
2015
|
+
async function Ln(e) {
|
|
2016
|
+
if (await Mt(e), !xe) throw new Error("Assets not loaded");
|
|
2017
|
+
return xe;
|
|
1931
2018
|
}
|
|
1932
2019
|
function et(e) {
|
|
1933
|
-
return
|
|
2020
|
+
return Zr(
|
|
1934
2021
|
e.viseme.atlasMeta,
|
|
1935
2022
|
e.sil.naturalWidth,
|
|
1936
2023
|
e.sil.naturalHeight
|
|
1937
2024
|
);
|
|
1938
2025
|
}
|
|
1939
|
-
function
|
|
2026
|
+
function Us(e, t) {
|
|
1940
2027
|
const n = document.createElement("canvas");
|
|
1941
2028
|
return n.width = t.w, n.height = t.h, n.getContext("2d", { willReadFrequently: !0 }).drawImage(e.atlas, t.x, t.y, t.w, t.h, 0, 0, t.w, t.h), n;
|
|
1942
2029
|
}
|
|
1943
2030
|
async function un(e, t, n) {
|
|
1944
|
-
const r = `${t.diffBase}::${n}`, s =
|
|
2031
|
+
const r = `${t.diffBase}::${n}`, s = dt.get(r);
|
|
1945
2032
|
if (s) return s;
|
|
1946
2033
|
const i = (async () => {
|
|
1947
2034
|
const o = t.cellByPath.get(n);
|
|
1948
2035
|
if (!o) throw new Error(`No atlas cell for path: ${n}`);
|
|
1949
|
-
const a =
|
|
1950
|
-
if (
|
|
1951
|
-
const
|
|
2036
|
+
const a = es(t.atlasMeta, o), l = et(e);
|
|
2037
|
+
if (ts(o)) {
|
|
2038
|
+
const S = Us(t, o), m = document.createElement("canvas");
|
|
1952
2039
|
m.width = l.width, m.height = l.height;
|
|
1953
2040
|
const p = m.getContext("2d");
|
|
1954
|
-
return p.fillStyle = "#000", p.fillRect(0, 0, l.width, l.height), p.drawImage(
|
|
2041
|
+
return p.fillStyle = "#000", p.fillRect(0, 0, l.width, l.height), p.drawImage(S, a.x, a.y), m;
|
|
1955
2042
|
}
|
|
1956
|
-
const f = `${t.diffBase}/${n}`, u = await
|
|
2043
|
+
const f = `${t.diffBase}/${n}`, u = await qt(f);
|
|
1957
2044
|
if (u.naturalWidth === l.width && u.naturalHeight === l.height)
|
|
1958
2045
|
return u;
|
|
1959
2046
|
throw new Error(`Diff PNG wrong size for ${n}`);
|
|
1960
2047
|
})();
|
|
1961
|
-
return
|
|
2048
|
+
return dt.set(r, i), i;
|
|
1962
2049
|
}
|
|
1963
2050
|
async function ln(e, t, n, r, s, i) {
|
|
1964
2051
|
if (s) {
|
|
1965
|
-
const { width: p, height:
|
|
2052
|
+
const { width: p, height: A } = s;
|
|
1966
2053
|
if (i && !i() || t.readyState < HTMLMediaElement.HAVE_CURRENT_DATA)
|
|
1967
2054
|
return;
|
|
1968
2055
|
const d = document.createElement("canvas");
|
|
1969
|
-
d.width = p, d.height =
|
|
1970
|
-
const
|
|
1971
|
-
if (
|
|
1972
|
-
(e.width !== p || e.height !==
|
|
1973
|
-
const
|
|
1974
|
-
|
|
2056
|
+
d.width = p, d.height = A;
|
|
2057
|
+
const h = d.getContext("2d");
|
|
2058
|
+
if (h.clearRect(0, 0, p, A), h.drawImage(t, 0, 0, p, A), i && !i()) return;
|
|
2059
|
+
(e.width !== p || e.height !== A) && (e.width = p, e.height = A);
|
|
2060
|
+
const g = e.getContext("2d");
|
|
2061
|
+
g.clearRect(0, 0, p, A), g.drawImage(d, 0, 0);
|
|
1975
2062
|
return;
|
|
1976
2063
|
}
|
|
1977
|
-
const o = await
|
|
2064
|
+
const o = await Ln(), a = Mn(o.viseme.atlasMeta), { width: l, height: f } = et(o);
|
|
1978
2065
|
(e.width !== l || e.height !== f) && (e.width = l, e.height = f);
|
|
1979
|
-
const u = [],
|
|
1980
|
-
if (
|
|
2066
|
+
const u = [], S = e.getContext("2d");
|
|
2067
|
+
if (S.clearRect(0, 0, l, f), t.readyState < HTMLMediaElement.HAVE_CURRENT_DATA) {
|
|
1981
2068
|
const p = o.sil;
|
|
1982
|
-
|
|
2069
|
+
S.drawImage(p, 0, 0, l, f);
|
|
1983
2070
|
return;
|
|
1984
2071
|
}
|
|
1985
2072
|
if (u.length === 0) {
|
|
1986
|
-
|
|
2073
|
+
S.drawImage(t, 0, 0, l, f);
|
|
1987
2074
|
return;
|
|
1988
2075
|
}
|
|
1989
2076
|
const m = Bn(t, u, l, f, a);
|
|
1990
|
-
|
|
2077
|
+
S.drawImage(m, 0, 0);
|
|
1991
2078
|
}
|
|
1992
2079
|
async function Ct(e, t, n) {
|
|
1993
|
-
const r = await
|
|
2080
|
+
const r = await Ln(Ze ?? void 0), s = Mn(r.viseme.atlasMeta), { width: i, height: o } = et(r);
|
|
1994
2081
|
(e.width !== i || e.height !== o) && (e.width = i, e.height = o);
|
|
1995
2082
|
const a = [];
|
|
1996
2083
|
if (t.mouthPath) {
|
|
1997
|
-
const u = new Set(r.viseme.cellByPath.keys()),
|
|
1998
|
-
|
|
2084
|
+
const u = new Set(r.viseme.cellByPath.keys()), S = cs(t.mouthPath, u) ?? (u.has(t.mouthPath) ? t.mouthPath : null);
|
|
2085
|
+
S && a.push(await un(r, r.viseme, S));
|
|
1999
2086
|
}
|
|
2000
2087
|
t.expressionPath && r.expression && a.push(
|
|
2001
2088
|
await un(r, r.expression, t.expressionPath)
|
|
@@ -2014,24 +2101,24 @@ async function Ct(e, t, n) {
|
|
|
2014
2101
|
);
|
|
2015
2102
|
l.drawImage(f, 0, 0);
|
|
2016
2103
|
}
|
|
2017
|
-
async function
|
|
2104
|
+
async function Ns(e) {
|
|
2018
2105
|
await Ct(e, { mouthPath: null, expressionPath: null });
|
|
2019
2106
|
}
|
|
2020
|
-
function
|
|
2107
|
+
function Vs(e) {
|
|
2021
2108
|
const t = /* @__PURE__ */ new Map();
|
|
2022
2109
|
for (const n of e)
|
|
2023
2110
|
t.has(n.vtime) || t.set(n.vtime, n);
|
|
2024
2111
|
return [...t.values()].sort((n, r) => n.vtime - r.vtime);
|
|
2025
2112
|
}
|
|
2026
|
-
function
|
|
2027
|
-
const t =
|
|
2113
|
+
function $s(e) {
|
|
2114
|
+
const t = Vs(e), n = [];
|
|
2028
2115
|
for (let r = 0; r < t.length - 1; r++) {
|
|
2029
2116
|
const s = t[r].viseme, i = t[r + 1].viseme, o = t[r].vtime, a = t[r + 1].vtime;
|
|
2030
2117
|
s === i || a <= o || n.push({ from: s, to: i, fromVtime: o, toVtime: a });
|
|
2031
2118
|
}
|
|
2032
2119
|
return n;
|
|
2033
2120
|
}
|
|
2034
|
-
function
|
|
2121
|
+
function qs(e, t) {
|
|
2035
2122
|
let n = null;
|
|
2036
2123
|
for (const r of e)
|
|
2037
2124
|
t >= r.fromVtime && t < r.toVtime && (n = r);
|
|
@@ -2040,14 +2127,14 @@ function $s(e, t) {
|
|
|
2040
2127
|
function Ws(e, t) {
|
|
2041
2128
|
return { gapMs: Math.max(0, t - e), holdEnd: e, transStart: e };
|
|
2042
2129
|
}
|
|
2043
|
-
let
|
|
2130
|
+
let On = null;
|
|
2044
2131
|
function fn(e) {
|
|
2045
|
-
|
|
2132
|
+
On = e;
|
|
2046
2133
|
}
|
|
2047
|
-
function
|
|
2048
|
-
return
|
|
2134
|
+
function mt() {
|
|
2135
|
+
return On;
|
|
2049
2136
|
}
|
|
2050
|
-
function
|
|
2137
|
+
function Hs(e) {
|
|
2051
2138
|
return `${e.from}→${e.to}@${e.fromVtime}`;
|
|
2052
2139
|
}
|
|
2053
2140
|
function dn() {
|
|
@@ -2064,7 +2151,7 @@ function dn() {
|
|
|
2064
2151
|
transitionFramesMissed: 0
|
|
2065
2152
|
};
|
|
2066
2153
|
}
|
|
2067
|
-
function
|
|
2154
|
+
function Ks() {
|
|
2068
2155
|
let e = dn();
|
|
2069
2156
|
const t = /* @__PURE__ */ new Set(), n = /* @__PURE__ */ new Set(), r = /* @__PURE__ */ new Set();
|
|
2070
2157
|
let s = "", i = -1, o = "";
|
|
@@ -2092,11 +2179,11 @@ function Hs() {
|
|
|
2092
2179
|
onWorkerStale() {
|
|
2093
2180
|
e.workerStale += 1;
|
|
2094
2181
|
},
|
|
2095
|
-
onTransitionSample(u,
|
|
2096
|
-
const m =
|
|
2097
|
-
e.transitionFramesSampled += 1, m !== s && (s = m, i = -1, o !== m && (o = m, e.rifeFramesOmittedByGap += u.omittedByGap)),
|
|
2182
|
+
onTransitionSample(u, S) {
|
|
2183
|
+
const m = Hs(u);
|
|
2184
|
+
e.transitionFramesSampled += 1, m !== s && (s = m, i = -1, o !== m && (o = m, e.rifeFramesOmittedByGap += u.omittedByGap)), S && n.add(S), i >= 0 && u.frameIdx > i + 1 && (e.transitionFramesMissed += u.frameIdx - i - 1), i = u.frameIdx;
|
|
2098
2185
|
},
|
|
2099
|
-
onDrawDisplayed(u,
|
|
2186
|
+
onDrawDisplayed(u, S) {
|
|
2100
2187
|
if (e.drawsDisplayed += 1, u.transitionMeta) {
|
|
2101
2188
|
e.transitionFramesDisplayed += 1;
|
|
2102
2189
|
const p = u.transitionMeta;
|
|
@@ -2109,139 +2196,139 @@ function Hs() {
|
|
|
2109
2196
|
}
|
|
2110
2197
|
const m = u.label.trim();
|
|
2111
2198
|
if (!(!m || m === "sil")) {
|
|
2112
|
-
for (const p of
|
|
2199
|
+
for (const p of S)
|
|
2113
2200
|
if (p.viseme === m && u.elapsedMs >= p.vtime && u.elapsedMs < p.vtime + p.vduration) {
|
|
2114
2201
|
l(p.vtime);
|
|
2115
2202
|
break;
|
|
2116
2203
|
}
|
|
2117
2204
|
}
|
|
2118
2205
|
},
|
|
2119
|
-
snapshot(u,
|
|
2206
|
+
snapshot(u, S) {
|
|
2120
2207
|
let m = 0, p = 0;
|
|
2121
|
-
for (const
|
|
2122
|
-
if (
|
|
2123
|
-
if (
|
|
2124
|
-
m += 1, t.has(
|
|
2208
|
+
for (const g of u)
|
|
2209
|
+
if (g.viseme !== "sil") {
|
|
2210
|
+
if (g.vtime >= S) break;
|
|
2211
|
+
m += 1, t.has(g.vtime) && (p += 1);
|
|
2125
2212
|
}
|
|
2126
|
-
const
|
|
2213
|
+
const A = m > 0 ? Math.round(p / m * 100) : 100, d = e.queueSuperseded + e.workerStale + Math.max(0, e.drawsRequested - e.drawsDisplayed), h = m - p;
|
|
2127
2214
|
return {
|
|
2128
2215
|
...e,
|
|
2129
2216
|
renderLoss: d,
|
|
2130
2217
|
visemeSlotsTotal: m,
|
|
2131
2218
|
visemeSlotsCovered: p,
|
|
2132
|
-
visemeCoveragePct:
|
|
2219
|
+
visemeCoveragePct: A,
|
|
2133
2220
|
transitionFramesUniqueSampled: n.size,
|
|
2134
2221
|
transitionFramesUniquePainted: r.size,
|
|
2135
2222
|
drawsDeduped: e.rafTicksDeduped,
|
|
2136
2223
|
renderSkips: e.rafTicksDeduped + d,
|
|
2137
2224
|
visemesShown: p,
|
|
2138
|
-
visemesSkipped:
|
|
2225
|
+
visemesSkipped: h,
|
|
2139
2226
|
rifeTransitionFramesSkipped: e.transitionFramesMissed
|
|
2140
2227
|
};
|
|
2141
2228
|
}
|
|
2142
2229
|
};
|
|
2143
2230
|
}
|
|
2144
|
-
const Un = 400,
|
|
2145
|
-
function
|
|
2231
|
+
const Un = 400, js = 200, Gs = 600, Nn = "__sil__";
|
|
2232
|
+
function zs(e) {
|
|
2146
2233
|
return e.lastDrawnKey ? e.lastDrawnKey.split("|")[0] === Nn : !1;
|
|
2147
2234
|
}
|
|
2148
|
-
function
|
|
2235
|
+
function Ys() {
|
|
2149
2236
|
return { lastDrawnKey: "" };
|
|
2150
2237
|
}
|
|
2151
|
-
function
|
|
2238
|
+
function ye(e) {
|
|
2152
2239
|
e.lastDrawnKey = "", e.transitionCache = void 0;
|
|
2153
2240
|
}
|
|
2154
|
-
function
|
|
2241
|
+
function Js(e, t) {
|
|
2155
2242
|
if (t?.transitionCache && t.transitionCache.queueLength === e.length)
|
|
2156
2243
|
return t.transitionCache.transitions;
|
|
2157
|
-
const n =
|
|
2244
|
+
const n = $s(e);
|
|
2158
2245
|
return t && (t.transitionCache = { queueLength: e.length, transitions: n }), n;
|
|
2159
2246
|
}
|
|
2160
|
-
function
|
|
2247
|
+
function Xs(e, t) {
|
|
2161
2248
|
let n = "sil";
|
|
2162
2249
|
for (const r of e)
|
|
2163
2250
|
r.viseme !== "sil" && (t != null && r.vtime > t || (n = r.viseme));
|
|
2164
2251
|
return n;
|
|
2165
2252
|
}
|
|
2166
|
-
function
|
|
2253
|
+
function Qs(e, t, n, r = 120) {
|
|
2167
2254
|
if (n !== "sil")
|
|
2168
2255
|
return n;
|
|
2169
|
-
const s =
|
|
2170
|
-
return s !== "sil" ? s :
|
|
2256
|
+
const s = qr(e, t, r);
|
|
2257
|
+
return s !== "sil" ? s : Xs(e, t);
|
|
2171
2258
|
}
|
|
2172
|
-
function
|
|
2173
|
-
return e === "sil" ? !1 : t ?
|
|
2259
|
+
function Zs(e, t) {
|
|
2260
|
+
return e === "sil" ? !1 : t ? us(e, "sil", t) : Nt(e, "sil").length > 0;
|
|
2174
2261
|
}
|
|
2175
|
-
function
|
|
2176
|
-
return Un +
|
|
2262
|
+
function ei() {
|
|
2263
|
+
return Un + Gs;
|
|
2177
2264
|
}
|
|
2178
2265
|
function mn(e) {
|
|
2179
2266
|
return e ?? Nn;
|
|
2180
2267
|
}
|
|
2181
|
-
function
|
|
2268
|
+
function ti(e, t, n, r) {
|
|
2182
2269
|
if (e.length === 0)
|
|
2183
2270
|
return { diffPath: null, label: "sil" };
|
|
2184
|
-
const s =
|
|
2271
|
+
const s = Js(e, r), i = qs(s, t);
|
|
2185
2272
|
if (i) {
|
|
2186
2273
|
const a = i.toVtime - i.fromVtime, l = Ws(i.fromVtime, i.toVtime);
|
|
2187
2274
|
if (t >= l.transStart && t < i.toVtime) {
|
|
2188
2275
|
let f = Nt(i.from, i.to);
|
|
2189
2276
|
n && (f = Cn(f, n));
|
|
2190
|
-
const u =
|
|
2277
|
+
const u = fs(f, a);
|
|
2191
2278
|
if (u.length > 0) {
|
|
2192
|
-
const
|
|
2279
|
+
const S = ds(
|
|
2193
2280
|
t,
|
|
2194
2281
|
l.transStart,
|
|
2195
2282
|
i.toVtime,
|
|
2196
2283
|
u.length
|
|
2197
2284
|
);
|
|
2198
2285
|
return {
|
|
2199
|
-
diffPath: u[
|
|
2286
|
+
diffPath: u[S] ?? u[u.length - 1],
|
|
2200
2287
|
label: `${i.from}→${i.to}`,
|
|
2201
2288
|
transitionMeta: {
|
|
2202
2289
|
from: i.from,
|
|
2203
2290
|
to: i.to,
|
|
2204
2291
|
fromVtime: i.fromVtime,
|
|
2205
2292
|
toVtime: i.toVtime,
|
|
2206
|
-
frameIdx:
|
|
2293
|
+
frameIdx: S,
|
|
2207
2294
|
frameCount: u.length,
|
|
2208
2295
|
fullFrameCount: f.length,
|
|
2209
2296
|
omittedByGap: Math.max(0, f.length - u.length)
|
|
2210
2297
|
}
|
|
2211
2298
|
};
|
|
2212
2299
|
}
|
|
2213
|
-
return { diffPath:
|
|
2300
|
+
return { diffPath: ft(i.to), label: i.to };
|
|
2214
2301
|
}
|
|
2215
2302
|
}
|
|
2216
|
-
const o =
|
|
2217
|
-
return o === "sil" ? { diffPath: null, label: "sil" } : { diffPath:
|
|
2303
|
+
const o = nt(e, t);
|
|
2304
|
+
return o === "sil" ? { diffPath: null, label: "sil" } : { diffPath: ft(o), label: o };
|
|
2218
2305
|
}
|
|
2219
2306
|
function Vn(e, t) {
|
|
2220
2307
|
const n = t ?? mn(e.expressionPath);
|
|
2221
2308
|
return `${mn(e.mouthPath)}|${n}`;
|
|
2222
2309
|
}
|
|
2223
|
-
function
|
|
2224
|
-
const u =
|
|
2310
|
+
function ni(e, t, n, r, s, i, o, a, l, f) {
|
|
2311
|
+
const u = ti(t, n, l, i), S = {
|
|
2225
2312
|
mouthPath: u.diffPath,
|
|
2226
2313
|
expressionPath: r
|
|
2227
|
-
}, m = Vn(
|
|
2314
|
+
}, m = Vn(S, s), p = mt();
|
|
2228
2315
|
if (u.transitionMeta && p?.onTransitionSample(u.transitionMeta, u.diffPath), m === i.lastDrawnKey) {
|
|
2229
2316
|
p?.onDrawDeduped();
|
|
2230
2317
|
return;
|
|
2231
2318
|
}
|
|
2232
|
-
p?.onDrawRequested(), a(u), o(e,
|
|
2233
|
-
|
|
2319
|
+
p?.onDrawRequested(), a(u), o(e, S, m, (A) => {
|
|
2320
|
+
A === m && (i.lastDrawnKey = m);
|
|
2234
2321
|
});
|
|
2235
2322
|
}
|
|
2236
2323
|
function hn(e, t, n, r, s, i, o = null) {
|
|
2237
2324
|
const a = { mouthPath: null, expressionPath: t }, l = o != null ? `|idle@${Math.round(o * 1e3)}` : "", f = Vn(a, n) + l;
|
|
2238
2325
|
!(o != null) && f === r.lastDrawnKey || (i(
|
|
2239
2326
|
o != null ? "idle" : "sil"
|
|
2240
|
-
), s(e, a, f, (
|
|
2241
|
-
|
|
2327
|
+
), s(e, a, f, (S) => {
|
|
2328
|
+
S === f && (r.lastDrawnKey = f);
|
|
2242
2329
|
}));
|
|
2243
2330
|
}
|
|
2244
|
-
const
|
|
2331
|
+
const ri = 3;
|
|
2245
2332
|
function $n(e) {
|
|
2246
2333
|
let t = 0;
|
|
2247
2334
|
const n = [];
|
|
@@ -2251,8 +2338,8 @@ function $n(e) {
|
|
|
2251
2338
|
r = !0;
|
|
2252
2339
|
try {
|
|
2253
2340
|
for (; n.length > 0; ) {
|
|
2254
|
-
const a = n.shift(), l = ++t
|
|
2255
|
-
|
|
2341
|
+
const a = n.shift(), l = ++t;
|
|
2342
|
+
await e(a.diffs, l, a) && l === t && a.onDisplayed?.(a.drawKey);
|
|
2256
2343
|
}
|
|
2257
2344
|
} finally {
|
|
2258
2345
|
r = !1, n.length > 0 && i();
|
|
@@ -2265,8 +2352,8 @@ function $n(e) {
|
|
|
2265
2352
|
};
|
|
2266
2353
|
return {
|
|
2267
2354
|
enqueue(a, l, f) {
|
|
2268
|
-
const u = n.findIndex((
|
|
2269
|
-
u >= 0 ? n[u] = { diffs: a, drawKey: l, onDisplayed: f } : (n.length >=
|
|
2355
|
+
const u = n.findIndex((S) => S.drawKey === l);
|
|
2356
|
+
u >= 0 ? n[u] = { diffs: a, drawKey: l, onDisplayed: f } : (n.length >= ri && (n.shift(), mt()?.onQueueSuperseded()), n.push({ diffs: a, drawKey: l, onDisplayed: f })), o();
|
|
2270
2357
|
},
|
|
2271
2358
|
reset() {
|
|
2272
2359
|
t += 1, n.length = 0;
|
|
@@ -2279,9 +2366,9 @@ function $n(e) {
|
|
|
2279
2366
|
}
|
|
2280
2367
|
};
|
|
2281
2368
|
}
|
|
2282
|
-
const
|
|
2283
|
-
async function
|
|
2284
|
-
let t =
|
|
2369
|
+
const gn = -1, wn = /* @__PURE__ */ new Map();
|
|
2370
|
+
async function si(e) {
|
|
2371
|
+
let t = wn.get(e);
|
|
2285
2372
|
if (!t) {
|
|
2286
2373
|
const n = await fetch(e);
|
|
2287
2374
|
if (!n.ok)
|
|
@@ -2289,14 +2376,14 @@ async function ri(e) {
|
|
|
2289
2376
|
`Failed to fetch worker script (${n.status}): ${e}`
|
|
2290
2377
|
);
|
|
2291
2378
|
const r = await n.blob();
|
|
2292
|
-
t = URL.createObjectURL(r),
|
|
2379
|
+
t = URL.createObjectURL(r), wn.set(e, t);
|
|
2293
2380
|
}
|
|
2294
2381
|
return new Worker(t, { name: "visemeDiffPreview" });
|
|
2295
2382
|
}
|
|
2296
|
-
function
|
|
2383
|
+
function ii() {
|
|
2297
2384
|
return typeof Worker < "u" && typeof OffscreenCanvas < "u";
|
|
2298
2385
|
}
|
|
2299
|
-
function
|
|
2386
|
+
function ai(e, t) {
|
|
2300
2387
|
(e.width !== t.width || e.height !== t.height) && (e.width = t.width, e.height = t.height);
|
|
2301
2388
|
const n = e.getContext("2d");
|
|
2302
2389
|
n && n.drawImage(t, 0, 0);
|
|
@@ -2314,7 +2401,7 @@ function pn(e, t) {
|
|
|
2314
2401
|
return r;
|
|
2315
2402
|
},
|
|
2316
2403
|
async renderSilOnly() {
|
|
2317
|
-
n += 1, s.reset(), await
|
|
2404
|
+
n += 1, s.reset(), await Ns(e);
|
|
2318
2405
|
},
|
|
2319
2406
|
drawLiveFrame(i, o, a, l) {
|
|
2320
2407
|
s.enqueue(o, a, l);
|
|
@@ -2323,7 +2410,7 @@ function pn(e, t) {
|
|
|
2323
2410
|
n += 1;
|
|
2324
2411
|
const a = n;
|
|
2325
2412
|
t.onStatus?.(o), await Ct(i, {
|
|
2326
|
-
mouthPath:
|
|
2413
|
+
mouthPath: ft(o),
|
|
2327
2414
|
expressionPath: null
|
|
2328
2415
|
});
|
|
2329
2416
|
},
|
|
@@ -2332,111 +2419,111 @@ function pn(e, t) {
|
|
|
2332
2419
|
}
|
|
2333
2420
|
};
|
|
2334
2421
|
}
|
|
2335
|
-
function
|
|
2422
|
+
function oi(e, t, n) {
|
|
2336
2423
|
let r = null, s = 1, i = 0, o = !1, a = !1, l = null;
|
|
2337
|
-
const f = /* @__PURE__ */ new Map(), u = $n(async (
|
|
2338
|
-
drawKey:
|
|
2339
|
-
onDisplayed:
|
|
2340
|
-
}), await
|
|
2424
|
+
const f = /* @__PURE__ */ new Map(), u = $n(async (h, g, k) => (f.set(g, {
|
|
2425
|
+
drawKey: k.drawKey,
|
|
2426
|
+
onDisplayed: k.onDisplayed
|
|
2427
|
+
}), await A(
|
|
2341
2428
|
{
|
|
2342
2429
|
type: "drawFrame",
|
|
2343
|
-
diffPath:
|
|
2344
|
-
expressionDiffPath:
|
|
2345
|
-
liveSeq:
|
|
2430
|
+
diffPath: h.mouthPath,
|
|
2431
|
+
expressionDiffPath: h.expressionPath,
|
|
2432
|
+
liveSeq: g
|
|
2346
2433
|
},
|
|
2347
2434
|
void 0,
|
|
2348
2435
|
!0
|
|
2349
|
-
), !1)),
|
|
2350
|
-
if (
|
|
2351
|
-
let b = -1,
|
|
2352
|
-
for (const [
|
|
2353
|
-
|
|
2354
|
-
b >= 0 && f.delete(b),
|
|
2436
|
+
), !1)), S = (h) => {
|
|
2437
|
+
if (h === gn) {
|
|
2438
|
+
let b = -1, W;
|
|
2439
|
+
for (const [Z, Y] of f)
|
|
2440
|
+
Z >= b && (b = Z, W = Y);
|
|
2441
|
+
b >= 0 && f.delete(b), W?.onDisplayed?.(W.drawKey);
|
|
2355
2442
|
return;
|
|
2356
2443
|
}
|
|
2357
|
-
const
|
|
2358
|
-
f.delete(
|
|
2359
|
-
}, m = /* @__PURE__ */ new Map(), p = (
|
|
2360
|
-
a || !r || r.postMessage(
|
|
2361
|
-
},
|
|
2444
|
+
const g = -h, k = f.get(g);
|
|
2445
|
+
f.delete(g), k?.onDisplayed?.(k.drawKey);
|
|
2446
|
+
}, m = /* @__PURE__ */ new Map(), p = (h, g) => {
|
|
2447
|
+
a || !r || r.postMessage(h, []);
|
|
2448
|
+
}, A = (h, g, k = !1) => {
|
|
2362
2449
|
if (a) return Promise.resolve();
|
|
2363
2450
|
const b = s++;
|
|
2364
|
-
return new Promise((
|
|
2451
|
+
return new Promise((W, Z) => {
|
|
2365
2452
|
m.set(b, {
|
|
2366
|
-
resolve: (
|
|
2367
|
-
reject:
|
|
2368
|
-
generation: typeof
|
|
2369
|
-
expectRenderDone:
|
|
2370
|
-
}), p({ ...
|
|
2453
|
+
resolve: (Y) => W(Y),
|
|
2454
|
+
reject: Z,
|
|
2455
|
+
generation: typeof h.generation == "number" ? h.generation : void 0,
|
|
2456
|
+
expectRenderDone: k
|
|
2457
|
+
}), p({ ...h, requestId: b });
|
|
2371
2458
|
});
|
|
2372
2459
|
}, d = (async () => {
|
|
2373
|
-
r = await
|
|
2460
|
+
r = await si(n), r.onmessage = (h) => {
|
|
2374
2461
|
if (a) return;
|
|
2375
|
-
const
|
|
2376
|
-
if (
|
|
2377
|
-
t.onStatus?.(
|
|
2462
|
+
const g = h.data;
|
|
2463
|
+
if (g.type === "status") {
|
|
2464
|
+
t.onStatus?.(g.label);
|
|
2378
2465
|
return;
|
|
2379
2466
|
}
|
|
2380
|
-
if (
|
|
2381
|
-
const b =
|
|
2382
|
-
if (!b &&
|
|
2383
|
-
|
|
2467
|
+
if (g.type === "frame") {
|
|
2468
|
+
const b = g.generation < 0;
|
|
2469
|
+
if (!b && g.generation !== i) {
|
|
2470
|
+
g.bitmap.close();
|
|
2384
2471
|
return;
|
|
2385
2472
|
}
|
|
2386
|
-
if (b && !(
|
|
2387
|
-
const
|
|
2388
|
-
if (!u.isLatestSeq(
|
|
2389
|
-
|
|
2473
|
+
if (b && !(g.generation === gn)) {
|
|
2474
|
+
const Z = -g.generation;
|
|
2475
|
+
if (!u.isLatestSeq(Z)) {
|
|
2476
|
+
mt()?.onWorkerStale(), g.bitmap.close();
|
|
2390
2477
|
return;
|
|
2391
2478
|
}
|
|
2392
2479
|
}
|
|
2393
2480
|
if (b && t.shouldAcceptLiveFrame && !t.shouldAcceptLiveFrame()) {
|
|
2394
|
-
|
|
2481
|
+
mt()?.onWorkerStale(), g.bitmap.close();
|
|
2395
2482
|
return;
|
|
2396
2483
|
}
|
|
2397
|
-
|
|
2484
|
+
ai(e, g.bitmap), g.bitmap.close(), b && S(g.generation);
|
|
2398
2485
|
return;
|
|
2399
2486
|
}
|
|
2400
|
-
const
|
|
2401
|
-
if (
|
|
2402
|
-
switch (
|
|
2487
|
+
const k = m.get(g.requestId);
|
|
2488
|
+
if (k)
|
|
2489
|
+
switch (g.type) {
|
|
2403
2490
|
case "ready":
|
|
2404
|
-
m.delete(
|
|
2491
|
+
m.delete(g.requestId), k.resolve();
|
|
2405
2492
|
break;
|
|
2406
2493
|
case "loadAssetsDone":
|
|
2407
|
-
m.delete(
|
|
2494
|
+
m.delete(g.requestId), l = g.visemePaths?.length ? new Set(g.visemePaths) : null, k.resolve({ width: g.width, height: g.height, visemePaths: g.visemePaths });
|
|
2408
2495
|
break;
|
|
2409
2496
|
case "renderDone":
|
|
2410
|
-
if (
|
|
2497
|
+
if (k.expectRenderDone && k.generation != null && g.generation !== k.generation)
|
|
2411
2498
|
return;
|
|
2412
|
-
m.delete(
|
|
2499
|
+
m.delete(g.requestId), k.resolve();
|
|
2413
2500
|
break;
|
|
2414
2501
|
case "renderAborted":
|
|
2415
|
-
m.delete(
|
|
2502
|
+
m.delete(g.requestId), k.resolve();
|
|
2416
2503
|
break;
|
|
2417
2504
|
case "error":
|
|
2418
|
-
m.delete(
|
|
2505
|
+
m.delete(g.requestId), t.onError?.(g.message), k.reject(new Error(g.message));
|
|
2419
2506
|
break;
|
|
2420
2507
|
}
|
|
2421
|
-
}, r.onerror = (
|
|
2508
|
+
}, r.onerror = (h) => {
|
|
2422
2509
|
if (a) return;
|
|
2423
|
-
const
|
|
2424
|
-
t.onError?.(
|
|
2425
|
-
for (const [,
|
|
2426
|
-
|
|
2510
|
+
const g = h.message || "Worker error";
|
|
2511
|
+
t.onError?.(g);
|
|
2512
|
+
for (const [, k] of m)
|
|
2513
|
+
k.reject(new Error(g));
|
|
2427
2514
|
m.clear();
|
|
2428
|
-
}, await
|
|
2515
|
+
}, await A({ type: "init" }), o = !0;
|
|
2429
2516
|
})();
|
|
2430
2517
|
return {
|
|
2431
2518
|
usesWorker: !0,
|
|
2432
|
-
async loadAssets(
|
|
2519
|
+
async loadAssets(h) {
|
|
2433
2520
|
if (a) return { width: 842, height: 1264 };
|
|
2434
2521
|
if (await d, a) return { width: 842, height: 1264 };
|
|
2435
2522
|
if (!o) throw new Error("Worker init failed");
|
|
2436
|
-
return await
|
|
2523
|
+
return await A({
|
|
2437
2524
|
type: "loadAssets",
|
|
2438
|
-
keyHex:
|
|
2439
|
-
urls: Sr(
|
|
2525
|
+
keyHex: h,
|
|
2526
|
+
urls: Sr(Fe())
|
|
2440
2527
|
}) ?? { width: 842, height: 1264 };
|
|
2441
2528
|
},
|
|
2442
2529
|
getVisemeAtlasPaths() {
|
|
@@ -2445,70 +2532,70 @@ function ai(e, t, n) {
|
|
|
2445
2532
|
async renderSilOnly() {
|
|
2446
2533
|
if (a || (await d, a)) return;
|
|
2447
2534
|
i += 1, u.reset(), f.clear();
|
|
2448
|
-
const
|
|
2449
|
-
await
|
|
2450
|
-
{ type: "renderSil", generation:
|
|
2535
|
+
const h = i;
|
|
2536
|
+
await A({ type: "cancelLiveDraws" }), await A(
|
|
2537
|
+
{ type: "renderSil", generation: h },
|
|
2451
2538
|
void 0,
|
|
2452
2539
|
!0
|
|
2453
2540
|
);
|
|
2454
2541
|
},
|
|
2455
|
-
drawLiveFrame(
|
|
2542
|
+
drawLiveFrame(h, g, k, b) {
|
|
2456
2543
|
a || d.then(() => {
|
|
2457
|
-
a || u.enqueue(
|
|
2544
|
+
a || u.enqueue(g, k, b);
|
|
2458
2545
|
});
|
|
2459
2546
|
},
|
|
2460
|
-
async renderViseme(
|
|
2547
|
+
async renderViseme(h, g, k = {}) {
|
|
2461
2548
|
if (a || (await d, a)) return;
|
|
2462
2549
|
i += 1, u.reset(), f.clear();
|
|
2463
2550
|
const b = i;
|
|
2464
2551
|
try {
|
|
2465
|
-
await
|
|
2552
|
+
await A({ type: "cancelLiveDraws" }), await A(
|
|
2466
2553
|
{
|
|
2467
2554
|
type: "renderViseme",
|
|
2468
2555
|
generation: b,
|
|
2469
|
-
to:
|
|
2470
|
-
from:
|
|
2471
|
-
transitionDurationMs:
|
|
2472
|
-
gapMs:
|
|
2473
|
-
threshold:
|
|
2556
|
+
to: g,
|
|
2557
|
+
from: k.from,
|
|
2558
|
+
transitionDurationMs: k.transitionDurationMs,
|
|
2559
|
+
gapMs: k.gapMs,
|
|
2560
|
+
threshold: k.threshold
|
|
2474
2561
|
},
|
|
2475
2562
|
void 0,
|
|
2476
2563
|
!0
|
|
2477
2564
|
);
|
|
2478
|
-
} catch (
|
|
2479
|
-
if (
|
|
2480
|
-
throw
|
|
2565
|
+
} catch (W) {
|
|
2566
|
+
if (W?.name === "AbortError") return;
|
|
2567
|
+
throw W;
|
|
2481
2568
|
}
|
|
2482
2569
|
},
|
|
2483
2570
|
dispose() {
|
|
2484
2571
|
if (!a) {
|
|
2485
2572
|
a = !0, i += 1, u.reset(), f.clear();
|
|
2486
|
-
for (const [,
|
|
2487
|
-
|
|
2573
|
+
for (const [, h] of m)
|
|
2574
|
+
h.resolve();
|
|
2488
2575
|
m.clear(), r?.terminate(), r = null;
|
|
2489
2576
|
}
|
|
2490
2577
|
}
|
|
2491
2578
|
};
|
|
2492
2579
|
}
|
|
2493
|
-
function
|
|
2494
|
-
if (!
|
|
2580
|
+
function ci(e, t = {}) {
|
|
2581
|
+
if (!ii())
|
|
2495
2582
|
return pn(e, t);
|
|
2496
2583
|
const n = rr(t.workerScriptUrl);
|
|
2497
2584
|
try {
|
|
2498
|
-
return
|
|
2585
|
+
return oi(e, t, n);
|
|
2499
2586
|
} catch {
|
|
2500
2587
|
return pn(e, t);
|
|
2501
2588
|
}
|
|
2502
2589
|
}
|
|
2503
|
-
class
|
|
2590
|
+
class ui extends Error {
|
|
2504
2591
|
constructor(t, n) {
|
|
2505
2592
|
super(`${t} timed out after ${Math.round(n / 1e3)}s`), this.name = "LoadTimeoutError";
|
|
2506
2593
|
}
|
|
2507
2594
|
}
|
|
2508
|
-
function
|
|
2595
|
+
function Et(e, t, n) {
|
|
2509
2596
|
return new Promise((r, s) => {
|
|
2510
2597
|
const i = globalThis.setTimeout(() => {
|
|
2511
|
-
s(new
|
|
2598
|
+
s(new ui(n, t));
|
|
2512
2599
|
}, t);
|
|
2513
2600
|
e.then(
|
|
2514
2601
|
(o) => {
|
|
@@ -2520,15 +2607,15 @@ function bt(e, t, n) {
|
|
|
2520
2607
|
);
|
|
2521
2608
|
});
|
|
2522
2609
|
}
|
|
2523
|
-
const
|
|
2610
|
+
const li = {
|
|
2524
2611
|
position: "relative",
|
|
2525
2612
|
display: "inline-block",
|
|
2526
2613
|
lineHeight: 0
|
|
2527
|
-
},
|
|
2614
|
+
}, fi = {
|
|
2528
2615
|
display: "block",
|
|
2529
2616
|
maxWidth: "100%",
|
|
2530
2617
|
height: "auto"
|
|
2531
|
-
},
|
|
2618
|
+
}, di = {
|
|
2532
2619
|
position: "absolute",
|
|
2533
2620
|
inset: 0,
|
|
2534
2621
|
display: "flex",
|
|
@@ -2540,545 +2627,550 @@ const ui = {
|
|
|
2540
2627
|
fontSize: "0.875rem",
|
|
2541
2628
|
textAlign: "center"
|
|
2542
2629
|
};
|
|
2543
|
-
function
|
|
2630
|
+
function Xe(e) {
|
|
2544
2631
|
return ar(e) ? An : Tn;
|
|
2545
2632
|
}
|
|
2546
2633
|
function Te(e, t) {
|
|
2547
2634
|
return t?.isSpeaking() ? t : e.isSpeaking() ? e : t?.isConnected() ? t : e;
|
|
2548
2635
|
}
|
|
2549
|
-
const
|
|
2636
|
+
const vi = jn(function({
|
|
2550
2637
|
id: t,
|
|
2551
2638
|
avatarId: n,
|
|
2552
2639
|
faceId: r,
|
|
2553
2640
|
assets: s,
|
|
2554
2641
|
authToken: i,
|
|
2555
2642
|
apiBase: o,
|
|
2556
|
-
ttsEngineId: a =
|
|
2643
|
+
ttsEngineId: a = Ue,
|
|
2557
2644
|
voiceId: l,
|
|
2558
|
-
speakingRate: f =
|
|
2645
|
+
speakingRate: f = gt,
|
|
2559
2646
|
className: u,
|
|
2560
|
-
style:
|
|
2647
|
+
style: S,
|
|
2561
2648
|
canvasStyle: m,
|
|
2562
2649
|
onStatusChange: p,
|
|
2563
|
-
onDisplayStatus:
|
|
2650
|
+
onDisplayStatus: A,
|
|
2564
2651
|
onError: d,
|
|
2565
|
-
onReady:
|
|
2566
|
-
showErrorOverlay:
|
|
2567
|
-
onUserTranscript:
|
|
2652
|
+
onReady: h,
|
|
2653
|
+
showErrorOverlay: g = !0,
|
|
2654
|
+
onUserTranscript: k,
|
|
2568
2655
|
onBotOutput: b,
|
|
2569
|
-
onRealtimeLipsyncDebug:
|
|
2570
|
-
onFrameRenderStats:
|
|
2571
|
-
},
|
|
2572
|
-
const
|
|
2656
|
+
onRealtimeLipsyncDebug: W,
|
|
2657
|
+
onFrameRenderStats: Z
|
|
2658
|
+
}, Y) {
|
|
2659
|
+
const R = L(null), j = L(null), _ = L(Ys()), T = L(Ds()), M = L(0), I = L(0), y = L(0), D = L(null), V = L(null), F = L(!1), x = L(!1), N = L(!1), K = L("sil"), ee = L(0), Q = L(!1), E = L(
|
|
2573
2660
|
null
|
|
2574
|
-
),
|
|
2575
|
-
|
|
2661
|
+
), O = L(!1), [J, se] = Je("idle"), [$, de] = Je(null), [te, Be] = Je(!1), [Se, qe] = Je(!1), [rt, Wt] = Je({ width: 842, height: 1264 }), ke = L(i ?? null), Ae = o?.trim() || tt, We = L(null), le = L(null), c = L(!1), v = L({ width: 842, height: 1264 }), B = L(null), X = L("sil"), ie = L(void 0), ve = L(/* @__PURE__ */ new Map()), oe = L(h), ne = L(A), _e = L(d), st = L(k), He = L(b), we = L(W), Ke = L(Z), Ie = L(Ks());
|
|
2662
|
+
oe.current = h, ne.current = A, _e.current = d, st.current = k, He.current = b, we.current = W, Ke.current = Z, Me(() => {
|
|
2576
2663
|
const w = Ie.current;
|
|
2577
2664
|
return fn(w), () => fn(null);
|
|
2578
2665
|
}, []);
|
|
2579
|
-
const
|
|
2666
|
+
const it = ge(
|
|
2580
2667
|
(w) => {
|
|
2581
|
-
const
|
|
2582
|
-
return { ttsEngineId:
|
|
2668
|
+
const C = w?.ttsEngineId ?? a ?? le.current?.ttsEngineId ?? Ue, U = w?.voiceId ?? l ?? le.current?.voiceId ?? Xe(C);
|
|
2669
|
+
return { ttsEngineId: C, voiceId: U };
|
|
2583
2670
|
},
|
|
2584
2671
|
[a, l]
|
|
2585
|
-
),
|
|
2586
|
-
|
|
2587
|
-
}, []),
|
|
2672
|
+
), ce = ge((w) => {
|
|
2673
|
+
de(w), _e.current?.(w);
|
|
2674
|
+
}, []), be = ge(
|
|
2588
2675
|
(w) => {
|
|
2589
|
-
|
|
2676
|
+
se(w), p?.(w);
|
|
2590
2677
|
},
|
|
2591
2678
|
[p]
|
|
2592
|
-
),
|
|
2593
|
-
en(
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2679
|
+
), G = L(
|
|
2680
|
+
en(be, Ae, {
|
|
2681
|
+
onLipsyncDebug: (w) => we.current?.(w)
|
|
2682
|
+
})
|
|
2683
|
+
), P = L(null);
|
|
2684
|
+
Me(() => (G.current = en(
|
|
2685
|
+
be,
|
|
2686
|
+
Ae,
|
|
2687
|
+
{
|
|
2688
|
+
onLipsyncDebug: (w) => we.current?.(w)
|
|
2689
|
+
}
|
|
2690
|
+
), i && G.current.setDeveloperToken(i), G.current.setTtsEngineId(a), () => {
|
|
2691
|
+
G.current.stop();
|
|
2692
|
+
const w = P.current;
|
|
2693
|
+
w && (w.disconnect(), P.current = null);
|
|
2694
|
+
}), [be, i, a, Ae]);
|
|
2695
|
+
const me = ge(() => (P.current || (P.current = Qr(
|
|
2696
|
+
be,
|
|
2605
2697
|
{
|
|
2606
2698
|
speakingRate: f,
|
|
2607
|
-
onUserTranscript: (w,
|
|
2608
|
-
onBotOutput: (w) =>
|
|
2609
|
-
onLipsyncDebug: (w) =>
|
|
2699
|
+
onUserTranscript: (w, C) => st.current?.(w, C),
|
|
2700
|
+
onBotOutput: (w) => He.current?.(w),
|
|
2701
|
+
onLipsyncDebug: (w) => we.current?.(w)
|
|
2610
2702
|
}
|
|
2611
|
-
),
|
|
2703
|
+
), P.current.setTtsEngineId(a)), P.current), [be, f, a]), re = ge(() => {
|
|
2612
2704
|
D.current != null && (clearTimeout(D.current), D.current = null);
|
|
2613
|
-
}, []),
|
|
2614
|
-
|
|
2615
|
-
}, []),
|
|
2616
|
-
!
|
|
2617
|
-
if (
|
|
2618
|
-
|
|
2619
|
-
|
|
2705
|
+
}, []), fe = ge(() => {
|
|
2706
|
+
V.current != null && (clearTimeout(V.current), V.current = null), N.current = !1;
|
|
2707
|
+
}, []), je = ge(() => {
|
|
2708
|
+
!O.current || !E.current || (fe(), N.current = !0, V.current = setTimeout(() => {
|
|
2709
|
+
if (V.current = null, Te(
|
|
2710
|
+
G.current,
|
|
2711
|
+
P.current
|
|
2620
2712
|
).isSpeaking()) {
|
|
2621
|
-
|
|
2713
|
+
N.current = !1;
|
|
2622
2714
|
return;
|
|
2623
2715
|
}
|
|
2624
2716
|
if (F.current) {
|
|
2625
|
-
|
|
2717
|
+
N.current = !1;
|
|
2626
2718
|
return;
|
|
2627
2719
|
}
|
|
2628
|
-
const w =
|
|
2720
|
+
const w = E.current;
|
|
2629
2721
|
if (!w) {
|
|
2630
|
-
|
|
2722
|
+
N.current = !1;
|
|
2631
2723
|
return;
|
|
2632
2724
|
}
|
|
2633
2725
|
w.restart(), w.setActive(!0);
|
|
2634
|
-
const
|
|
2635
|
-
let
|
|
2636
|
-
const
|
|
2637
|
-
|
|
2638
|
-
},
|
|
2639
|
-
|
|
2726
|
+
const C = w.getVideo();
|
|
2727
|
+
let U = !1;
|
|
2728
|
+
const H = () => {
|
|
2729
|
+
U || (U = !0, C.removeEventListener("playing", q), N.current = !1);
|
|
2730
|
+
}, q = () => {
|
|
2731
|
+
H();
|
|
2640
2732
|
};
|
|
2641
|
-
if (
|
|
2642
|
-
|
|
2733
|
+
if (C.addEventListener("playing", q, { once: !0 }), C.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA && !C.paused) {
|
|
2734
|
+
H();
|
|
2643
2735
|
return;
|
|
2644
2736
|
}
|
|
2645
|
-
setTimeout(
|
|
2646
|
-
},
|
|
2647
|
-
}, [
|
|
2648
|
-
if (
|
|
2649
|
-
|
|
2737
|
+
setTimeout(H, 300);
|
|
2738
|
+
}, js));
|
|
2739
|
+
}, [fe]), Re = ge(() => {
|
|
2740
|
+
if (re(), ne.current?.("sil"), F.current = !1, !O.current || !E.current) {
|
|
2741
|
+
N.current = !1;
|
|
2650
2742
|
return;
|
|
2651
2743
|
}
|
|
2652
|
-
|
|
2653
|
-
}, [
|
|
2744
|
+
je();
|
|
2745
|
+
}, [re, je]), pt = ge(
|
|
2654
2746
|
async (w) => {
|
|
2655
|
-
const
|
|
2747
|
+
const C = I.current, U = j.current, H = R.current, q = () => {
|
|
2656
2748
|
w?.fallbackOnly || (F.current = !1);
|
|
2657
2749
|
};
|
|
2658
|
-
if (!
|
|
2659
|
-
|
|
2750
|
+
if (!U || !H || !te) {
|
|
2751
|
+
q();
|
|
2660
2752
|
return;
|
|
2661
2753
|
}
|
|
2662
2754
|
if (Te(
|
|
2663
|
-
|
|
2664
|
-
|
|
2755
|
+
G.current,
|
|
2756
|
+
P.current
|
|
2665
2757
|
).isSpeaking()) {
|
|
2666
|
-
|
|
2758
|
+
q();
|
|
2667
2759
|
return;
|
|
2668
2760
|
}
|
|
2669
2761
|
if (w?.fallbackOnly) {
|
|
2670
|
-
if (!F.current || (
|
|
2671
|
-
|
|
2672
|
-
|
|
2762
|
+
if (!F.current || (ye(_.current), await U.renderSilOnly(), C !== I.current) || Te(
|
|
2763
|
+
G.current,
|
|
2764
|
+
P.current
|
|
2673
2765
|
).isSpeaking())
|
|
2674
2766
|
return;
|
|
2675
2767
|
Re();
|
|
2676
2768
|
return;
|
|
2677
2769
|
}
|
|
2678
|
-
if (
|
|
2679
|
-
|
|
2770
|
+
if (zs(_.current)) {
|
|
2771
|
+
ye(_.current), Re();
|
|
2680
2772
|
return;
|
|
2681
2773
|
}
|
|
2682
|
-
const
|
|
2774
|
+
const ue = Qs(
|
|
2683
2775
|
Te(
|
|
2684
|
-
|
|
2685
|
-
|
|
2776
|
+
G.current,
|
|
2777
|
+
P.current
|
|
2686
2778
|
).getVisemeQueue(),
|
|
2687
2779
|
ee.current,
|
|
2688
|
-
|
|
2689
|
-
),
|
|
2690
|
-
|
|
2691
|
-
|
|
2780
|
+
K.current
|
|
2781
|
+
), pe = Zs(
|
|
2782
|
+
ue,
|
|
2783
|
+
B.current
|
|
2692
2784
|
);
|
|
2693
|
-
if (
|
|
2694
|
-
if (await
|
|
2695
|
-
|
|
2696
|
-
|
|
2785
|
+
if (ye(_.current), !pe) {
|
|
2786
|
+
if (await U.renderSilOnly(), C !== I.current || Te(
|
|
2787
|
+
G.current,
|
|
2788
|
+
P.current
|
|
2697
2789
|
).isSpeaking())
|
|
2698
2790
|
return;
|
|
2699
2791
|
Re();
|
|
2700
2792
|
return;
|
|
2701
2793
|
}
|
|
2702
2794
|
try {
|
|
2703
|
-
await
|
|
2704
|
-
from:
|
|
2795
|
+
await U.renderViseme(H, "sil", {
|
|
2796
|
+
from: ue,
|
|
2705
2797
|
transitionDurationMs: Un
|
|
2706
2798
|
});
|
|
2707
|
-
} catch (
|
|
2708
|
-
if (
|
|
2709
|
-
throw
|
|
2799
|
+
} catch (Ee) {
|
|
2800
|
+
if (Ee?.name !== "AbortError")
|
|
2801
|
+
throw Ee;
|
|
2710
2802
|
}
|
|
2711
|
-
if (
|
|
2712
|
-
|
|
2803
|
+
if (C !== I.current) {
|
|
2804
|
+
q();
|
|
2713
2805
|
return;
|
|
2714
2806
|
}
|
|
2715
2807
|
if (Te(
|
|
2716
|
-
|
|
2717
|
-
|
|
2808
|
+
G.current,
|
|
2809
|
+
P.current
|
|
2718
2810
|
).isSpeaking()) {
|
|
2719
|
-
|
|
2811
|
+
q();
|
|
2720
2812
|
return;
|
|
2721
2813
|
}
|
|
2722
2814
|
Re();
|
|
2723
2815
|
},
|
|
2724
2816
|
[te, Re]
|
|
2725
|
-
),
|
|
2726
|
-
if (
|
|
2727
|
-
|
|
2817
|
+
), Ge = ge(() => {
|
|
2818
|
+
if (x.current || F.current) return;
|
|
2819
|
+
x.current = !0, F.current = !0, re();
|
|
2728
2820
|
const w = I.current;
|
|
2729
2821
|
pt().finally(() => {
|
|
2730
|
-
|
|
2822
|
+
x.current = !1;
|
|
2731
2823
|
}), D.current = setTimeout(() => {
|
|
2732
2824
|
D.current = null, w === I.current && pt({ fallbackOnly: !0 });
|
|
2733
|
-
},
|
|
2734
|
-
}, [
|
|
2825
|
+
}, ei());
|
|
2826
|
+
}, [re, pt]), Ht = ge(async () => {
|
|
2735
2827
|
const w = Math.floor(Date.now() / 1e3);
|
|
2736
2828
|
if (We.current && w < We.current.expiresAt - 60)
|
|
2737
2829
|
return We.current.key;
|
|
2738
|
-
const
|
|
2739
|
-
|
|
2740
|
-
const
|
|
2830
|
+
const C = ke.current ?? await kt();
|
|
2831
|
+
ke.current = C, G.current.setDeveloperToken(C);
|
|
2832
|
+
const U = await hr(C, Ae);
|
|
2741
2833
|
return We.current = {
|
|
2742
|
-
key:
|
|
2743
|
-
expiresAt:
|
|
2744
|
-
},
|
|
2834
|
+
key: U.value,
|
|
2835
|
+
expiresAt: U.expiresAt
|
|
2836
|
+
}, U.value;
|
|
2745
2837
|
}, [Ae]);
|
|
2746
2838
|
Me(() => {
|
|
2747
|
-
i && (
|
|
2839
|
+
i && (ke.current = i, G.current.setDeveloperToken(i));
|
|
2748
2840
|
}, [i]), Me(() => {
|
|
2749
|
-
|
|
2841
|
+
G.current.setTtsEngineId(a), P.current?.setTtsEngineId(a), le.current && (le.current.ttsEngineId = a);
|
|
2750
2842
|
}, [a]), Me(() => {
|
|
2751
|
-
const w = l ??
|
|
2752
|
-
|
|
2843
|
+
const w = l ?? Xe(a);
|
|
2844
|
+
le.current && (le.current.voiceId = w);
|
|
2753
2845
|
}, [l, a]);
|
|
2754
|
-
const De =
|
|
2846
|
+
const De = Yt(
|
|
2755
2847
|
() => _r(n, r),
|
|
2756
2848
|
[n, r]
|
|
2757
|
-
),
|
|
2849
|
+
), qn = Yt(() => s ? JSON.stringify(s) : De ? `face:${De}` : `id:${t ?? ""}`, [s, De, t]);
|
|
2758
2850
|
return Me(() => {
|
|
2759
2851
|
if (!t && !s && !De) {
|
|
2760
|
-
|
|
2852
|
+
ce("AiTwin requires `assets`, `avatarId`/`faceId`, or `id`");
|
|
2761
2853
|
return;
|
|
2762
2854
|
}
|
|
2763
2855
|
let w = !1;
|
|
2764
|
-
c.current = !1,
|
|
2765
|
-
const
|
|
2766
|
-
if (!
|
|
2767
|
-
let
|
|
2856
|
+
c.current = !1, Be(!1), qe(!1), de(null), le.current = null, E.current = null, O.current = !1;
|
|
2857
|
+
const C = R.current;
|
|
2858
|
+
if (!C) return;
|
|
2859
|
+
let U = null;
|
|
2768
2860
|
return (async () => {
|
|
2769
2861
|
try {
|
|
2770
|
-
let
|
|
2862
|
+
let H, q, ue, pe;
|
|
2771
2863
|
if (s)
|
|
2772
|
-
|
|
2864
|
+
H = s, q = a, ue = l ?? Xe(q);
|
|
2773
2865
|
else if (De)
|
|
2774
|
-
|
|
2866
|
+
ne.current?.("loadFace"), H = Xt(De), q = a, ue = l ?? Xe(q);
|
|
2775
2867
|
else {
|
|
2776
|
-
|
|
2777
|
-
const
|
|
2868
|
+
ne.current?.("getAiTwin");
|
|
2869
|
+
const z = await Et(
|
|
2778
2870
|
cr(t),
|
|
2779
2871
|
3e4,
|
|
2780
2872
|
"getAiTwin"
|
|
2781
2873
|
);
|
|
2782
2874
|
if (w) return;
|
|
2783
|
-
if (!
|
|
2875
|
+
if (!z.faceId?.trim())
|
|
2784
2876
|
throw new Error("getAiTwin returned no faceId");
|
|
2785
|
-
|
|
2877
|
+
q = z.ttsEngineId, ue = l ?? z.voiceId ?? Xe(q), pe = z.knowledgeContextId?.trim() || void 0, H = Xt(z.faceId);
|
|
2786
2878
|
}
|
|
2787
|
-
|
|
2788
|
-
onStatus: (
|
|
2789
|
-
w ||
|
|
2879
|
+
le.current = { ttsEngineId: q, voiceId: ue, personaId: pe }, yr(H), E.current = Ms(), U = ci(C, {
|
|
2880
|
+
onStatus: (z) => {
|
|
2881
|
+
w || ne.current?.(z);
|
|
2790
2882
|
},
|
|
2791
|
-
onError: (
|
|
2792
|
-
w ||
|
|
2883
|
+
onError: (z) => {
|
|
2884
|
+
w || ce(z);
|
|
2793
2885
|
},
|
|
2794
2886
|
shouldAcceptLiveFrame: () => Te(
|
|
2795
|
-
|
|
2796
|
-
|
|
2887
|
+
G.current,
|
|
2888
|
+
P.current
|
|
2797
2889
|
).isSpeaking() && !F.current
|
|
2798
|
-
}),
|
|
2799
|
-
const
|
|
2890
|
+
}), j.current = U, ne.current?.("auth");
|
|
2891
|
+
const Ee = ke.current ?? i ?? await Et(kt(), 3e4, "getAuthToken");
|
|
2800
2892
|
if (w) return;
|
|
2801
|
-
|
|
2802
|
-
const
|
|
2893
|
+
ke.current = Ee, G.current.setDeveloperToken(Ee), G.current.setTtsEngineId(q);
|
|
2894
|
+
const ze = ht() ? await Ht() : void 0;
|
|
2803
2895
|
if (w) return;
|
|
2804
|
-
|
|
2805
|
-
const
|
|
2806
|
-
|
|
2896
|
+
ne.current?.("loadAssets");
|
|
2897
|
+
const ae = await Et(
|
|
2898
|
+
U.loadAssets(ze),
|
|
2807
2899
|
18e4,
|
|
2808
2900
|
"load face assets"
|
|
2809
2901
|
);
|
|
2810
|
-
if (!w &&
|
|
2811
|
-
|
|
2812
|
-
w ||
|
|
2902
|
+
if (!w && ae.width > 0 && ae.height > 0 && (v.current = ae, Wt(ae)), w) return;
|
|
2903
|
+
B.current = U.getVisemeAtlasPaths(), c.current = !0, Be(!0), oe.current?.(), U.renderSilOnly().then(() => {
|
|
2904
|
+
w || ne.current?.("sil");
|
|
2813
2905
|
}), (async () => {
|
|
2814
2906
|
try {
|
|
2815
|
-
const
|
|
2816
|
-
if (await
|
|
2817
|
-
|
|
2818
|
-
const
|
|
2907
|
+
const z = await as(ze);
|
|
2908
|
+
if (await E.current.load(z), w) return;
|
|
2909
|
+
O.current = !0, qe(!0), ye(_.current), E.current.setActive(!0);
|
|
2910
|
+
const he = E.current.getVideo();
|
|
2819
2911
|
await ln(
|
|
2820
|
-
|
|
2821
|
-
|
|
2912
|
+
C,
|
|
2913
|
+
he,
|
|
2822
2914
|
null,
|
|
2823
2915
|
void 0,
|
|
2824
|
-
|
|
2825
|
-
), w ||
|
|
2826
|
-
} catch (
|
|
2916
|
+
v.current
|
|
2917
|
+
), w || ne.current?.("idle");
|
|
2918
|
+
} catch (z) {
|
|
2827
2919
|
if (w) return;
|
|
2828
|
-
|
|
2920
|
+
O.current = !1, qe(!1), console.warn("[AiTwin] Idle video unavailable:", z);
|
|
2829
2921
|
}
|
|
2830
2922
|
})();
|
|
2831
|
-
} catch (
|
|
2923
|
+
} catch (H) {
|
|
2832
2924
|
if (w) return;
|
|
2833
|
-
if (
|
|
2834
|
-
|
|
2925
|
+
if (H instanceof Tt) {
|
|
2926
|
+
ce(H.message);
|
|
2835
2927
|
return;
|
|
2836
2928
|
}
|
|
2837
|
-
|
|
2929
|
+
ce(H instanceof Error ? H.message : "Failed to load AI twin");
|
|
2838
2930
|
}
|
|
2839
2931
|
})(), () => {
|
|
2840
|
-
w = !0,
|
|
2932
|
+
w = !0, E.current?.dispose(), U?.dispose(), j.current = null;
|
|
2841
2933
|
};
|
|
2842
|
-
}, [
|
|
2843
|
-
const w = { current: !1 },
|
|
2844
|
-
const
|
|
2845
|
-
|
|
2846
|
-
|
|
2934
|
+
}, [qn, s, De, t, a, l, i, Ht, ce]), Me(() => {
|
|
2935
|
+
const w = { current: !1 }, C = () => {
|
|
2936
|
+
const U = R.current, H = j.current, q = Te(
|
|
2937
|
+
G.current,
|
|
2938
|
+
P.current
|
|
2847
2939
|
);
|
|
2848
|
-
if (!
|
|
2849
|
-
M.current = requestAnimationFrame(
|
|
2940
|
+
if (!U || !H || !te) {
|
|
2941
|
+
M.current = requestAnimationFrame(C);
|
|
2850
2942
|
return;
|
|
2851
2943
|
}
|
|
2852
|
-
const
|
|
2853
|
-
|
|
2854
|
-
const
|
|
2855
|
-
if (
|
|
2856
|
-
|
|
2857
|
-
const
|
|
2858
|
-
ee.current =
|
|
2859
|
-
const
|
|
2860
|
-
|
|
2861
|
-
const
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2944
|
+
const ue = q.isSpeaking(), pe = ue && !Q.current, Ee = Q.current && !ue;
|
|
2945
|
+
pe && (re(), fe(), F.current = !1, x.current = !1, ye(_.current), Ie.current.reset(), ie.current = void 0, y.current = 0, K.current = "sil", ee.current = 0, E.current?.setActive(!1)), Ee && (T.current.reset(), E.current?.setActive(!1), Ge());
|
|
2946
|
+
const ze = Ee || F.current || N.current;
|
|
2947
|
+
if (ue) {
|
|
2948
|
+
O.current && E.current?.setActive(!1);
|
|
2949
|
+
const ae = q.getVisemeQueue(), z = q.getPlaybackElapsedMs();
|
|
2950
|
+
ee.current = z;
|
|
2951
|
+
const he = ae.length > 0 ? nt(ae, z) : "sil";
|
|
2952
|
+
he !== "sil" && (K.current = he);
|
|
2953
|
+
const Le = Fs(
|
|
2954
|
+
z,
|
|
2955
|
+
q.getSentenceEmotions(),
|
|
2956
|
+
q.getWordQueue(),
|
|
2957
|
+
q.getStreamMood()
|
|
2866
2958
|
);
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
$t(
|
|
2959
|
+
T.current.setTargetEmotion(Le), T.current.setTargetEyebrow(
|
|
2960
|
+
Rs(
|
|
2961
|
+
z,
|
|
2962
|
+
q.getWordQueue(),
|
|
2963
|
+
$t(Le)
|
|
2872
2964
|
)
|
|
2873
|
-
),
|
|
2874
|
-
const _t =
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2965
|
+
), T.current.advance(performance.now());
|
|
2966
|
+
const _t = T.current.getExpressionPath(), yt = T.current.getDrawKey();
|
|
2967
|
+
ni(
|
|
2968
|
+
U,
|
|
2969
|
+
ae,
|
|
2970
|
+
z,
|
|
2879
2971
|
_t,
|
|
2880
2972
|
yt,
|
|
2881
|
-
|
|
2882
|
-
(
|
|
2973
|
+
_.current,
|
|
2974
|
+
(Ye, Kt, jt, Wn) => {
|
|
2883
2975
|
const Gt = {
|
|
2884
|
-
label:
|
|
2885
|
-
elapsedMs:
|
|
2976
|
+
label: X.current,
|
|
2977
|
+
elapsedMs: z,
|
|
2886
2978
|
mouthPath: Kt.mouthPath,
|
|
2887
|
-
transitionMeta:
|
|
2979
|
+
transitionMeta: ie.current
|
|
2888
2980
|
};
|
|
2889
|
-
|
|
2890
|
-
const Hn =
|
|
2891
|
-
|
|
2981
|
+
ve.current.set(jt, Gt), H.drawLiveFrame(Ye, Kt, jt, (St) => {
|
|
2982
|
+
const Hn = ve.current.get(St) ?? Gt;
|
|
2983
|
+
ve.current.delete(St), Ie.current.onDrawDisplayed(
|
|
2892
2984
|
Hn,
|
|
2893
|
-
|
|
2894
|
-
),
|
|
2985
|
+
ae
|
|
2986
|
+
), Wn?.(St);
|
|
2895
2987
|
});
|
|
2896
2988
|
},
|
|
2897
|
-
(
|
|
2898
|
-
|
|
2989
|
+
(Ye) => {
|
|
2990
|
+
X.current = Ye.label, ie.current = Ye.transitionMeta, ne.current?.(Ye.label);
|
|
2899
2991
|
},
|
|
2900
|
-
|
|
2901
|
-
), Ie.current.onRafTickSpeaking(),
|
|
2902
|
-
Ie.current.snapshot(
|
|
2992
|
+
B.current
|
|
2993
|
+
), Ie.current.onRafTickSpeaking(), Ke.current?.(
|
|
2994
|
+
Ie.current.snapshot(ae, z)
|
|
2903
2995
|
);
|
|
2904
|
-
} else if (!
|
|
2905
|
-
const
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2996
|
+
} else if (!ze && O.current && E.current) {
|
|
2997
|
+
const ae = E.current, z = ae.getVideo();
|
|
2998
|
+
z.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA ? (ae.setActive(!0), w.current || (w.current = !0, ln(
|
|
2999
|
+
U,
|
|
3000
|
+
z,
|
|
2909
3001
|
null,
|
|
2910
3002
|
void 0,
|
|
2911
|
-
|
|
2912
|
-
() => !
|
|
2913
|
-
).then(() =>
|
|
3003
|
+
v.current,
|
|
3004
|
+
() => !q.isSpeaking() && !F.current && !N.current
|
|
3005
|
+
).then(() => ne.current?.("idle")).finally(() => {
|
|
2914
3006
|
w.current = !1;
|
|
2915
3007
|
}))) : hn(
|
|
2916
|
-
|
|
3008
|
+
U,
|
|
2917
3009
|
null,
|
|
2918
3010
|
"__sil__",
|
|
2919
|
-
|
|
2920
|
-
(
|
|
2921
|
-
(
|
|
3011
|
+
_.current,
|
|
3012
|
+
(he, Le, _t, yt) => H.drawLiveFrame(he, Le, _t, yt),
|
|
3013
|
+
(he) => ne.current?.(he)
|
|
2922
3014
|
);
|
|
2923
|
-
} else
|
|
2924
|
-
|
|
3015
|
+
} else ze || hn(
|
|
3016
|
+
U,
|
|
2925
3017
|
null,
|
|
2926
3018
|
"__sil__",
|
|
2927
|
-
|
|
2928
|
-
(
|
|
2929
|
-
(
|
|
3019
|
+
_.current,
|
|
3020
|
+
(ae, z, he, Le) => H.drawLiveFrame(ae, z, he, Le),
|
|
3021
|
+
(ae) => ne.current?.(ae)
|
|
2930
3022
|
);
|
|
2931
|
-
|
|
3023
|
+
Q.current = ue, M.current = requestAnimationFrame(C);
|
|
2932
3024
|
};
|
|
2933
|
-
return M.current = requestAnimationFrame(
|
|
2934
|
-
cancelAnimationFrame(M.current),
|
|
3025
|
+
return M.current = requestAnimationFrame(C), () => {
|
|
3026
|
+
cancelAnimationFrame(M.current), re(), fe(), G.current.stop(), P.current?.stop();
|
|
2935
3027
|
};
|
|
2936
3028
|
}, [
|
|
2937
3029
|
te,
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
3030
|
+
Se,
|
|
3031
|
+
Ge,
|
|
3032
|
+
re,
|
|
3033
|
+
fe
|
|
2942
3034
|
]), Gn(
|
|
2943
|
-
|
|
3035
|
+
Y,
|
|
2944
3036
|
() => ({
|
|
2945
|
-
speakText: async (w,
|
|
2946
|
-
const
|
|
2947
|
-
if (!
|
|
2948
|
-
const
|
|
2949
|
-
if (!
|
|
3037
|
+
speakText: async (w, C) => {
|
|
3038
|
+
const U = w.trim();
|
|
3039
|
+
if (!U) return;
|
|
3040
|
+
const H = j.current;
|
|
3041
|
+
if (!H || !c.current && !te)
|
|
2950
3042
|
throw new Error("AI twin is not ready");
|
|
2951
|
-
const { ttsEngineId:
|
|
2952
|
-
|
|
3043
|
+
const { ttsEngineId: q, voiceId: ue } = it(C);
|
|
3044
|
+
de(null), I.current += 1, re(), fe(), F.current = !1, x.current = !1, K.current = "sil", ee.current = 0, ye(_.current), T.current.reset(), Q.current = !1;
|
|
2953
3045
|
try {
|
|
2954
|
-
|
|
2955
|
-
voiceId:
|
|
2956
|
-
speakingRate:
|
|
2957
|
-
ttsEngineId:
|
|
3046
|
+
O.current ? (E.current?.setActive(!1), E.current?.restart(), ye(_.current)) : await H.renderSilOnly(), await G.current.speak(U, {
|
|
3047
|
+
voiceId: ue,
|
|
3048
|
+
speakingRate: C?.speakingRate ?? f,
|
|
3049
|
+
ttsEngineId: q
|
|
2958
3050
|
});
|
|
2959
|
-
} catch (
|
|
2960
|
-
throw
|
|
3051
|
+
} catch (pe) {
|
|
3052
|
+
throw ce(pe instanceof Error ? pe.message : "TTS failed"), pe;
|
|
2961
3053
|
}
|
|
2962
3054
|
},
|
|
2963
3055
|
stop: () => {
|
|
2964
|
-
I.current += 1,
|
|
3056
|
+
I.current += 1, re(), fe(), F.current = !1, x.current = !1, G.current.stop(), P.current?.stop(), ye(_.current), Q.current = !1, Ge();
|
|
2965
3057
|
},
|
|
2966
3058
|
setTtsEngineId: (w) => {
|
|
2967
|
-
|
|
3059
|
+
G.current.setTtsEngineId(w), P.current?.setTtsEngineId(w), le.current && (le.current.ttsEngineId = w);
|
|
2968
3060
|
},
|
|
2969
|
-
renderViseme: async (w,
|
|
2970
|
-
const
|
|
2971
|
-
if (!
|
|
3061
|
+
renderViseme: async (w, C) => {
|
|
3062
|
+
const U = j.current, H = R.current;
|
|
3063
|
+
if (!U || !H || !c.current)
|
|
2972
3064
|
throw new Error("AI twin is not ready");
|
|
2973
|
-
await
|
|
2974
|
-
from:
|
|
2975
|
-
transitionDurationMs:
|
|
2976
|
-
gapMs:
|
|
2977
|
-
onStatus: (
|
|
3065
|
+
await U.renderViseme(H, w, {
|
|
3066
|
+
from: C?.from,
|
|
3067
|
+
transitionDurationMs: C?.transitionDurationMs,
|
|
3068
|
+
gapMs: C?.gapMs,
|
|
3069
|
+
onStatus: (q) => ne.current?.(q)
|
|
2978
3070
|
});
|
|
2979
3071
|
},
|
|
2980
3072
|
isReady: () => c.current,
|
|
2981
|
-
getStatus: () =>
|
|
3073
|
+
getStatus: () => J,
|
|
2982
3074
|
connect: async (w = {}) => {
|
|
2983
|
-
|
|
3075
|
+
de(null);
|
|
2984
3076
|
try {
|
|
2985
|
-
let
|
|
2986
|
-
|
|
2987
|
-
const
|
|
2988
|
-
await
|
|
3077
|
+
let C = w.authToken?.trim();
|
|
3078
|
+
C || (C = ke.current ?? i ?? await kt(), ke.current = C);
|
|
3079
|
+
const U = w.voiceId?.trim() ?? l ?? le.current?.voiceId, H = w.personaId?.trim() ?? le.current?.personaId, q = me();
|
|
3080
|
+
await q.unlockAudio(), await q.connect({
|
|
2989
3081
|
...w,
|
|
2990
3082
|
apiBase: w.apiBase?.trim() || Ae,
|
|
2991
|
-
authToken:
|
|
2992
|
-
voiceId:
|
|
2993
|
-
personaId:
|
|
3083
|
+
authToken: C,
|
|
3084
|
+
voiceId: U,
|
|
3085
|
+
personaId: H,
|
|
2994
3086
|
speakingRate: w.speakingRate ?? f
|
|
2995
3087
|
});
|
|
2996
|
-
} catch (
|
|
2997
|
-
throw
|
|
2998
|
-
|
|
2999
|
-
),
|
|
3088
|
+
} catch (C) {
|
|
3089
|
+
throw ce(
|
|
3090
|
+
C instanceof Error ? C.message : "Voice connect failed"
|
|
3091
|
+
), C;
|
|
3000
3092
|
}
|
|
3001
3093
|
},
|
|
3002
3094
|
disconnect: async () => {
|
|
3003
|
-
const w =
|
|
3004
|
-
w && (I.current += 1,
|
|
3095
|
+
const w = P.current;
|
|
3096
|
+
w && (I.current += 1, re(), fe(), F.current = !1, x.current = !1, ye(_.current), Q.current = !1, await w.disconnect(), Ge());
|
|
3005
3097
|
},
|
|
3006
|
-
isConnected: () =>
|
|
3007
|
-
getVoiceStream: () =>
|
|
3098
|
+
isConnected: () => P.current?.isConnected() ?? !1,
|
|
3099
|
+
getVoiceStream: () => P.current?.getVoiceStream() ?? G.current?.getVoiceStream() ?? null
|
|
3008
3100
|
}),
|
|
3009
3101
|
[
|
|
3010
3102
|
te,
|
|
3011
3103
|
f,
|
|
3012
3104
|
i,
|
|
3013
3105
|
l,
|
|
3014
|
-
|
|
3015
|
-
le,
|
|
3016
|
-
je,
|
|
3017
|
-
oe,
|
|
3018
|
-
st,
|
|
3106
|
+
re,
|
|
3019
3107
|
fe,
|
|
3020
|
-
|
|
3108
|
+
Ge,
|
|
3109
|
+
ce,
|
|
3110
|
+
it,
|
|
3111
|
+
me,
|
|
3112
|
+
J
|
|
3021
3113
|
]
|
|
3022
|
-
), /* @__PURE__ */ Kn("div", { className: u, style: { ...
|
|
3114
|
+
), /* @__PURE__ */ Kn("div", { className: u, style: { ...li, ...S }, children: [
|
|
3023
3115
|
/* @__PURE__ */ zt(
|
|
3024
3116
|
"canvas",
|
|
3025
3117
|
{
|
|
3026
|
-
ref:
|
|
3027
|
-
width:
|
|
3028
|
-
height:
|
|
3029
|
-
style: { ...
|
|
3118
|
+
ref: R,
|
|
3119
|
+
width: rt.width,
|
|
3120
|
+
height: rt.height,
|
|
3121
|
+
style: { ...fi, ...m },
|
|
3030
3122
|
"aria-label": t ? `AI twin ${t}` : "AI twin face"
|
|
3031
3123
|
}
|
|
3032
3124
|
),
|
|
3033
|
-
|
|
3125
|
+
g && $ ? /* @__PURE__ */ zt("div", { style: di, children: $ }) : null
|
|
3034
3126
|
] });
|
|
3035
|
-
}),
|
|
3036
|
-
function
|
|
3127
|
+
}), mi = "thumbnail.webp";
|
|
3128
|
+
function bi(e, t = xt) {
|
|
3037
3129
|
const n = e.trim();
|
|
3038
3130
|
if (!n)
|
|
3039
3131
|
throw new Error("faceId is required");
|
|
3040
|
-
return `${t.replace(/\/$/, "")}/${n}/${
|
|
3132
|
+
return `${t.replace(/\/$/, "")}/${n}/${mi}`;
|
|
3041
3133
|
}
|
|
3042
|
-
const
|
|
3043
|
-
function
|
|
3134
|
+
const hi = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".webp"]);
|
|
3135
|
+
function gi(e = ".png") {
|
|
3044
3136
|
const t = e.toLowerCase();
|
|
3045
|
-
return
|
|
3137
|
+
return hi.has(t) ? `source${t}` : "source.png";
|
|
3046
3138
|
}
|
|
3047
3139
|
function Ei(e, t = xt, n = ".png") {
|
|
3048
3140
|
const r = e.trim();
|
|
3049
3141
|
if (!r)
|
|
3050
3142
|
throw new Error("faceId is required");
|
|
3051
|
-
return `${t.replace(/\/$/, "")}/${r}/${
|
|
3143
|
+
return `${t.replace(/\/$/, "")}/${r}/${gi(n)}`;
|
|
3052
3144
|
}
|
|
3053
3145
|
export {
|
|
3054
|
-
|
|
3055
|
-
|
|
3146
|
+
mi as AI_TWIN_THUMBNAIL_FILENAME,
|
|
3147
|
+
vi as AiTwin,
|
|
3056
3148
|
Tt as AiTwinNotFoundError,
|
|
3057
|
-
|
|
3149
|
+
Ue as DEFAULT_TTS_ENGINE_ID,
|
|
3058
3150
|
In as MIC_SAMPLE_RATE,
|
|
3059
3151
|
Ar as OCULUS_VISEME_IDS,
|
|
3060
3152
|
Rn as PLAYBACK_SAMPLE_RATE,
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3153
|
+
Ot as SPEAKING_RATE_MAX,
|
|
3154
|
+
Lt as SPEAKING_RATE_MIN,
|
|
3155
|
+
Ve as TTS_ENGINE_CARTESIA,
|
|
3064
3156
|
yn as TTS_ENGINE_GOOGLE,
|
|
3065
3157
|
Pt as TTS_ENGINE_INWORLD,
|
|
3066
|
-
|
|
3158
|
+
ki as VISEME_IDS,
|
|
3067
3159
|
An as VISEME_TEST_CARTESIA_VOICE_ID,
|
|
3068
|
-
|
|
3160
|
+
gt as VISEME_TEST_SPEAKING_RATE,
|
|
3069
3161
|
Tn as VISEME_TEST_VOICE_ID,
|
|
3070
|
-
|
|
3071
|
-
|
|
3162
|
+
gi as aiTwinSourceFilename,
|
|
3163
|
+
Yr as buildVoiceWebSocketUrl,
|
|
3072
3164
|
en as createAvatarTtsLipsyncController,
|
|
3073
|
-
|
|
3074
|
-
|
|
3165
|
+
Qr as createRealtimeVoiceLipsyncController,
|
|
3166
|
+
Xt as faceAssetUrls,
|
|
3075
3167
|
cr as fetchAiTwin,
|
|
3076
3168
|
kt as fetchDevAuthToken,
|
|
3077
3169
|
Ei as getAiTwinSourceUrl,
|
|
3078
|
-
|
|
3170
|
+
bi as getAiTwinThumbnailUrl,
|
|
3079
3171
|
Rr as normalizeOculusViseme,
|
|
3080
3172
|
_r as resolveDirectFaceId,
|
|
3081
|
-
|
|
3082
|
-
|
|
3173
|
+
nt as resolveVisemeAtTime,
|
|
3174
|
+
Si as resolveWordAtTime,
|
|
3083
3175
|
yr as setActiveTwinAssets
|
|
3084
3176
|
};
|