@burdenoff/website-sdk 2026.1104.1 → 2026.1104.3
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 +45 -0
- package/dist/avatar-live/index.d.mts +2 -2
- package/dist/avatar-live/index.d.ts +2 -2
- package/dist/avatar-live/index.js +29 -4
- package/dist/avatar-live/index.js.map +1 -1
- package/dist/avatar-live/index.mjs +29 -4
- package/dist/avatar-live/index.mjs.map +1 -1
- package/dist/avatar-live-view/index.d.mts +2 -2
- package/dist/avatar-live-view/index.d.ts +2 -2
- package/dist/avatar-live-view/index.js +130 -13
- package/dist/avatar-live-view/index.js.map +1 -1
- package/dist/avatar-live-view/index.mjs +125 -8
- package/dist/avatar-live-view/index.mjs.map +1 -1
- package/dist/{chunk-K3QZGJEH.mjs → chunk-7MSB3EUI.mjs} +4 -3
- package/dist/chunk-7MSB3EUI.mjs.map +1 -0
- package/dist/{chunk-7O2I32ZN.js → chunk-WSEQ2I6I.js} +4 -3
- package/dist/chunk-WSEQ2I6I.js.map +1 -0
- package/dist/{explore-avatar-live-config-N4WhJzgS.d.mts → explore-avatar-live-config-B6_p0q1c.d.mts} +14 -1
- package/dist/{explore-avatar-live-config-CAfN5eAX.d.ts → explore-avatar-live-config-DRpS-mqQ.d.ts} +14 -1
- package/dist/index.d.mts +10 -4
- package/dist/index.d.ts +10 -4
- package/dist/index.js +10 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +6 -3
- package/dist/index.mjs.map +1 -1
- package/dist/{types-CndbmBK-.d.mts → types-CXqaLlNB.d.mts} +14 -1
- package/dist/{types-CndbmBK-.d.ts → types-CXqaLlNB.d.ts} +14 -1
- package/package.json +1 -1
- package/dist/chunk-7O2I32ZN.js.map +0 -1
- package/dist/chunk-K3QZGJEH.mjs.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { turnstileSiteKeyOf, isAvatarLiveLocaleReviewed, isAvatarSite, isAvatarVersion } from '../chunk-
|
|
1
|
+
import { turnstileSiteKeyOf, isAvatarLiveLocaleReviewed, isAvatarSite, isAvatarVersion } from '../chunk-7MSB3EUI.mjs';
|
|
2
2
|
import { fill } from '../chunk-TT3MHN42.mjs';
|
|
3
3
|
import { cn } from '../chunk-R7G6TWIS.mjs';
|
|
4
4
|
import '../chunk-VNS5WDWO.mjs';
|
|
@@ -119,7 +119,8 @@ function readCreated(body) {
|
|
|
119
119
|
endSecret,
|
|
120
120
|
endsAt,
|
|
121
121
|
join: { livekitUrl, participantToken, workerIdentity },
|
|
122
|
-
captions: { locale, text }
|
|
122
|
+
captions: { locale, text },
|
|
123
|
+
excerpt: body.excerpt === true
|
|
123
124
|
}
|
|
124
125
|
};
|
|
125
126
|
}
|
|
@@ -292,6 +293,7 @@ var EN = {
|
|
|
292
293
|
failed: "The live avatar couldn't start.",
|
|
293
294
|
interrupted: "The live avatar stopped early.",
|
|
294
295
|
answerInChat: "The full answer is in Chat.",
|
|
296
|
+
excerpt: "The avatar reads the first part of this answer. The full answer is in Chat.",
|
|
295
297
|
backToChat: "Back to Chat",
|
|
296
298
|
busy: "The live avatar is busy right now. Please try again in a few minutes.",
|
|
297
299
|
limits: "The live avatar has reached its limit for now. Please try again later.",
|
|
@@ -349,6 +351,8 @@ var ZH = {
|
|
|
349
351
|
failed: "\u5B9E\u65F6\u865A\u62DF\u5F62\u8C61\u65E0\u6CD5\u542F\u52A8\u3002",
|
|
350
352
|
interrupted: "\u5B9E\u65F6\u865A\u62DF\u5F62\u8C61\u63D0\u524D\u505C\u6B62\u4E86\u3002",
|
|
351
353
|
answerInChat: "\u5B8C\u6574\u56DE\u7B54\u5728\u804A\u5929\u4E2D\u3002",
|
|
354
|
+
// TRANSLATION REVIEW PENDING (BOFF-9797): draft, the note for a part-read answer (Stage B).
|
|
355
|
+
excerpt: "\u865A\u62DF\u5F62\u8C61\u6717\u8BFB\u8FD9\u4E2A\u56DE\u7B54\u7684\u7B2C\u4E00\u90E8\u5206\u3002\u5B8C\u6574\u56DE\u7B54\u5728\u804A\u5929\u4E2D\u3002",
|
|
352
356
|
backToChat: "\u8FD4\u56DE\u804A\u5929",
|
|
353
357
|
busy: "\u5B9E\u65F6\u865A\u62DF\u5F62\u8C61\u76EE\u524D\u7E41\u5FD9\uFF0C\u8BF7\u51E0\u5206\u949F\u540E\u518D\u8BD5\u3002",
|
|
354
358
|
limits: "\u5B9E\u65F6\u865A\u62DF\u5F62\u8C61\u6682\u65F6\u5DF2\u8FBE\u5230\u4F7F\u7528\u4E0A\u9650\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5\u3002",
|
|
@@ -408,6 +412,8 @@ var HI = {
|
|
|
408
412
|
failed: "\u0932\u093E\u0907\u0935 \u0905\u0935\u0924\u093E\u0930 \u0936\u0941\u0930\u0942 \u0928\u0939\u0940\u0902 \u0939\u094B \u0938\u0915\u093E\u0964",
|
|
409
413
|
interrupted: "\u0932\u093E\u0907\u0935 \u0905\u0935\u0924\u093E\u0930 \u092C\u0940\u091A \u092E\u0947\u0902 \u0939\u0940 \u0930\u0941\u0915 \u0917\u092F\u093E\u0964",
|
|
410
414
|
answerInChat: "\u092A\u0942\u0930\u093E \u0909\u0924\u094D\u0924\u0930 \u091A\u0948\u091F \u092E\u0947\u0902 \u0939\u0948\u0964",
|
|
415
|
+
// TRANSLATION REVIEW PENDING (BOFF-9797): draft, the note for a part-read answer (Stage B).
|
|
416
|
+
excerpt: "\u0905\u0935\u0924\u093E\u0930 \u0907\u0938 \u0909\u0924\u094D\u0924\u0930 \u0915\u093E \u092A\u0939\u0932\u093E \u092D\u093E\u0917 \u092A\u0922\u093C\u0924\u093E \u0939\u0948\u0964 \u092A\u0942\u0930\u093E \u0909\u0924\u094D\u0924\u0930 \u091A\u0948\u091F \u092E\u0947\u0902 \u0939\u0948\u0964",
|
|
411
417
|
backToChat: "\u091A\u0948\u091F \u092A\u0930 \u0935\u093E\u092A\u0938 \u091C\u093E\u090F\u0901",
|
|
412
418
|
busy: "\u0932\u093E\u0907\u0935 \u0905\u0935\u0924\u093E\u0930 \u0905\u092D\u0940 \u0935\u094D\u092F\u0938\u094D\u0924 \u0939\u0948\u0964 \u0915\u0943\u092A\u092F\u093E \u0915\u0941\u091B \u092E\u093F\u0928\u091F \u092C\u093E\u0926 \u092B\u093F\u0930 \u0915\u094B\u0936\u093F\u0936 \u0915\u0930\u0947\u0902\u0964",
|
|
413
419
|
limits: "\u0932\u093E\u0907\u0935 \u0905\u0935\u0924\u093E\u0930 \u0905\u092D\u0940 \u0905\u092A\u0928\u0940 \u0938\u0940\u092E\u093E \u0924\u0915 \u092A\u0939\u0941\u0901\u091A \u0917\u092F\u093E \u0939\u0948\u0964 \u0915\u0943\u092A\u092F\u093E \u092C\u093E\u0926 \u092E\u0947\u0902 \u092B\u093F\u0930 \u0915\u094B\u0936\u093F\u0936 \u0915\u0930\u0947\u0902\u0964",
|
|
@@ -467,6 +473,8 @@ var ES = {
|
|
|
467
473
|
failed: "No se pudo iniciar el avatar en vivo.",
|
|
468
474
|
interrupted: "El avatar en vivo se detuvo antes de tiempo.",
|
|
469
475
|
answerInChat: "La respuesta completa est\xE1 en el chat.",
|
|
476
|
+
// TRANSLATION REVIEW PENDING (BOFF-9797): draft, the note for a part-read answer (Stage B).
|
|
477
|
+
excerpt: "El avatar lee la primera parte de esta respuesta. La respuesta completa est\xE1 en el chat.",
|
|
470
478
|
backToChat: "Volver al chat",
|
|
471
479
|
busy: "El avatar en vivo est\xE1 ocupado en este momento. Vuelve a intentarlo en unos minutos.",
|
|
472
480
|
limits: "El avatar en vivo ha alcanzado su l\xEDmite por ahora. Vuelve a intentarlo m\xE1s tarde.",
|
|
@@ -526,6 +534,8 @@ var AR = {
|
|
|
526
534
|
failed: "\u062A\u0639\u0630\u0651\u0631 \u0628\u062F\u0621 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0645\u0628\u0627\u0634\u0631.",
|
|
527
535
|
interrupted: "\u062A\u0648\u0642\u0641 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0645\u0628\u0627\u0634\u0631 \u0642\u0628\u0644 \u0623\u0646 \u064A\u0646\u062A\u0647\u064A.",
|
|
528
536
|
answerInChat: "\u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0627\u0644\u0643\u0627\u0645\u0644\u0629 \u0645\u0648\u062C\u0648\u062F\u0629 \u0641\u064A \u0627\u0644\u062F\u0631\u062F\u0634\u0629.",
|
|
537
|
+
// TRANSLATION REVIEW PENDING (BOFF-9797): draft, the note for a part-read answer (Stage B).
|
|
538
|
+
excerpt: "\u064A\u0642\u0631\u0623 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u062C\u0632\u0621 \u0627\u0644\u0623\u0648\u0644 \u0645\u0646 \u0647\u0630\u0647 \u0627\u0644\u0625\u062C\u0627\u0628\u0629. \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0627\u0644\u0643\u0627\u0645\u0644\u0629 \u0645\u0648\u062C\u0648\u062F\u0629 \u0641\u064A \u0627\u0644\u062F\u0631\u062F\u0634\u0629.",
|
|
529
539
|
backToChat: "\u0627\u0644\u0639\u0648\u062F\u0629 \u0625\u0644\u0649 \u0627\u0644\u062F\u0631\u062F\u0634\u0629",
|
|
530
540
|
busy: "\u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0645\u0628\u0627\u0634\u0631 \u0645\u0634\u063A\u0648\u0644 \u0627\u0644\u0622\u0646. \u064A\u064F\u0631\u062C\u0649 \u0627\u0644\u0645\u062D\u0627\u0648\u0644\u0629 \u0645\u0631\u0629 \u0623\u062E\u0631\u0649 \u0628\u0639\u062F \u0628\u0636\u0639 \u062F\u0642\u0627\u0626\u0642.",
|
|
531
541
|
limits: "\u0628\u0644\u063A \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0645\u0628\u0627\u0634\u0631 \u062D\u062F\u0651\u0647 \u0641\u064A \u0627\u0644\u0648\u0642\u062A \u0627\u0644\u062D\u0627\u0644\u064A. \u064A\u064F\u0631\u062C\u0649 \u0627\u0644\u0645\u062D\u0627\u0648\u0644\u0629 \u0644\u0627\u062D\u0642\u064B\u0627.",
|
|
@@ -585,6 +595,8 @@ var TA = {
|
|
|
585
595
|
failed: "\u0BA8\u0BC7\u0BB0\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BC8\u0BA4\u0BCD \u0BA4\u0BCA\u0B9F\u0B99\u0BCD\u0B95 \u0BAE\u0BC1\u0B9F\u0BBF\u0BAF\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8.",
|
|
586
596
|
interrupted: "\u0BA8\u0BC7\u0BB0\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0B87\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BC7\u0BAF\u0BC7 \u0BA8\u0BBF\u0BA9\u0BCD\u0BB1\u0BC1\u0BB5\u0BBF\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1.",
|
|
587
597
|
answerInChat: "\u0BAE\u0BC1\u0BB4\u0BC1\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD \u0B89\u0BB3\u0BCD\u0BB3\u0BA4\u0BC1.",
|
|
598
|
+
// TRANSLATION REVIEW PENDING (BOFF-9797): draft, the note for a part-read answer (Stage B).
|
|
599
|
+
excerpt: "\u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0B87\u0BA8\u0BCD\u0BA4\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BBF\u0BA9\u0BCD \u0BAE\u0BC1\u0BA4\u0BB2\u0BCD \u0BAA\u0B95\u0BC1\u0BA4\u0BBF\u0BAF\u0BC8\u0BAA\u0BCD \u0BAA\u0B9F\u0BBF\u0B95\u0BCD\u0B95\u0BBF\u0BB1\u0BA4\u0BC1. \u0BAE\u0BC1\u0BB4\u0BC1\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD \u0B89\u0BB3\u0BCD\u0BB3\u0BA4\u0BC1.",
|
|
588
600
|
backToChat: "\u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0B95\u0BCD\u0B95\u0BC1\u0BA4\u0BCD \u0BA4\u0BBF\u0BB0\u0BC1\u0BAE\u0BCD\u0BAA\u0BC1",
|
|
589
601
|
busy: "\u0BA8\u0BC7\u0BB0\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0B87\u0BAA\u0BCD\u0BAA\u0BCB\u0BA4\u0BC1 \u0BB5\u0BC7\u0BB1\u0BC1 \u0BAA\u0BAF\u0BA9\u0BCD\u0BAA\u0BBE\u0B9F\u0BCD\u0B9F\u0BBF\u0BB2\u0BCD \u0B89\u0BB3\u0BCD\u0BB3\u0BA4\u0BC1. \u0B9A\u0BBF\u0BB2 \u0BA8\u0BBF\u0BAE\u0BBF\u0B9F\u0B99\u0BCD\u0B95\u0BB3\u0BBF\u0BB2\u0BCD \u0BAE\u0BC0\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD \u0BAE\u0BC1\u0BAF\u0BB2\u0BB5\u0BC1\u0BAE\u0BCD.",
|
|
590
602
|
limits: "\u0BA8\u0BC7\u0BB0\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0BA4\u0BB1\u0BCD\u0BAA\u0BCB\u0BA4\u0BC8\u0B95\u0BCD\u0B95\u0BC1\u0BA4\u0BCD \u0BA4\u0BA9\u0BCD \u0BB5\u0BB0\u0BAE\u0BCD\u0BAA\u0BC8 \u0B8E\u0B9F\u0BCD\u0B9F\u0BBF\u0BB5\u0BBF\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1. \u0BAA\u0BBF\u0BB1\u0B95\u0BC1 \u0BAE\u0BC0\u0BA3\u0BCD\u0B9F\u0BC1\u0BAE\u0BCD \u0BAE\u0BC1\u0BAF\u0BB2\u0BB5\u0BC1\u0BAE\u0BCD.",
|
|
@@ -732,6 +744,42 @@ var CONSENT = /* @__PURE__ */ new Map([
|
|
|
732
744
|
questions: "any"
|
|
733
745
|
}
|
|
734
746
|
}
|
|
747
|
+
],
|
|
748
|
+
[
|
|
749
|
+
// Stage B (operator decision 2026-11-04): web-consent-2026-11-05 with only its timing sentence changed. A session
|
|
750
|
+
// lasts up to three minutes, sized by the server to the answer's audio; an answer longer than that is read in part,
|
|
751
|
+
// which the avatar says and the Avatar tab notes (`excerpt`), and the full answer stays in Chat. A cap still
|
|
752
|
+
// applies, so the words never say every answer is read whole (gitops docs/avatar-web/en-web-consent-2026-11-12-b.txt).
|
|
753
|
+
"web-consent-2026-11-12-b",
|
|
754
|
+
{
|
|
755
|
+
en: {
|
|
756
|
+
title: "Live AI avatar (beta)",
|
|
757
|
+
introProduct: null,
|
|
758
|
+
intro: "This is an AI avatar, not a real person. It reads aloud the first answer in a new chat started in the Avatar tab, provided it passes the speech checks, whether you chose a suggested question or typed your own. It reads for up to three minutes; if an answer is longer, it reads the first part, says so, and the full answer stays in Chat. The answer is AI-generated and can be wrong. Don't put personal details in a question you type.",
|
|
759
|
+
processing: "When you start, Cloudflare checks for bots. The answer text goes to Google to create the voice. Our server sends that voice through LiveKit to Protoface, which makes the avatar video streamed through LiveKit. Your browser connects to LiveKit, which sees your IP address.",
|
|
760
|
+
storage: "Your microphone and camera are not used. We do not record the live session or store the generated voice. We keep a record of this consent. The privacy notice explains our safeguards, storage periods and the providers' processing. For people aged eighteen and over.",
|
|
761
|
+
privacyLink: "How we handle this",
|
|
762
|
+
botCheck: "turnstile",
|
|
763
|
+
questions: "any"
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
],
|
|
767
|
+
[
|
|
768
|
+
// The words of web-consent-2026-11-12-b without "When you start, Cloudflare checks for bots.", for a server that runs
|
|
769
|
+
// no bot check (gitops docs/avatar-web/en-web-consent-2026-11-13-b.txt).
|
|
770
|
+
"web-consent-2026-11-13-b",
|
|
771
|
+
{
|
|
772
|
+
en: {
|
|
773
|
+
title: "Live AI avatar (beta)",
|
|
774
|
+
introProduct: null,
|
|
775
|
+
intro: "This is an AI avatar, not a real person. It reads aloud the first answer in a new chat started in the Avatar tab, provided it passes the speech checks, whether you chose a suggested question or typed your own. It reads for up to three minutes; if an answer is longer, it reads the first part, says so, and the full answer stays in Chat. The answer is AI-generated and can be wrong. Don't put personal details in a question you type.",
|
|
776
|
+
processing: "The answer text goes to Google to create the voice. Our server sends that voice through LiveKit to Protoface, which makes the avatar video streamed through LiveKit. Your browser connects to LiveKit, which sees your IP address.",
|
|
777
|
+
storage: "Your microphone and camera are not used. We do not record the live session or store the generated voice. We keep a record of this consent. The privacy notice explains our safeguards, storage periods and the providers' processing. For people aged eighteen and over.",
|
|
778
|
+
privacyLink: "How we handle this",
|
|
779
|
+
botCheck: "off",
|
|
780
|
+
questions: "any"
|
|
781
|
+
}
|
|
782
|
+
}
|
|
735
783
|
]
|
|
736
784
|
]);
|
|
737
785
|
function avatarConsentCopy(version, locale) {
|
|
@@ -857,6 +905,8 @@ var PRIVACY_HREF = "/privacy#live-avatar";
|
|
|
857
905
|
var SPEAKER_WAIT_MS = 3e4;
|
|
858
906
|
var END_GRACE_MS = 1e4;
|
|
859
907
|
var CLOCK_TOLERANCE_MS = 5e3;
|
|
908
|
+
var UNHEARD_GRACE_MS = 5e3;
|
|
909
|
+
var PLAYOUT_TAIL_MS = 5e3;
|
|
860
910
|
var SERVICE_MAX_AGE_MS = 15 * 6e4;
|
|
861
911
|
var ANSWER_OFFER_MS = SERVICE_MAX_AGE_MS - 6e4;
|
|
862
912
|
var MAX_TIMER_MS = 2147483647;
|
|
@@ -866,6 +916,12 @@ var USED_ON_KEY = "boff.explore.avatarUsedOn";
|
|
|
866
916
|
var PRIMARY = '[data-avatar-primary], [data-boff-explore="panel-continue-chat"]';
|
|
867
917
|
var IDLE = { name: "idle" };
|
|
868
918
|
var INERT2 = { name: "inert" };
|
|
919
|
+
function stopAttending(handle) {
|
|
920
|
+
if (handle.unheard !== null) clearTimeout(handle.unheard);
|
|
921
|
+
if (handle.tail !== null) clearTimeout(handle.tail);
|
|
922
|
+
handle.unheard = null;
|
|
923
|
+
handle.tail = null;
|
|
924
|
+
}
|
|
869
925
|
var REFUSAL_TEXT = {
|
|
870
926
|
busy: "busy",
|
|
871
927
|
limits: "limits",
|
|
@@ -1149,6 +1205,7 @@ function AvatarLiveView({
|
|
|
1149
1205
|
const handle = sessionRef.current;
|
|
1150
1206
|
if (!handle || handle.done) return;
|
|
1151
1207
|
handle.done = true;
|
|
1208
|
+
stopAttending(handle);
|
|
1152
1209
|
sessionRef.current = null;
|
|
1153
1210
|
if (reason !== null) {
|
|
1154
1211
|
sendEnd({
|
|
@@ -1178,6 +1235,33 @@ function AvatarLiveView({
|
|
|
1178
1235
|
}
|
|
1179
1236
|
go({ name: "live", session: current.session });
|
|
1180
1237
|
}, [go]);
|
|
1238
|
+
const attend = useCallback(() => {
|
|
1239
|
+
const handle = sessionRef.current;
|
|
1240
|
+
if (!handle || handle.done || latest.current.live.endUnattended !== true) {
|
|
1241
|
+
return;
|
|
1242
|
+
}
|
|
1243
|
+
const current = phaseRef.current.name;
|
|
1244
|
+
if (current !== "pending" && current !== "live") return;
|
|
1245
|
+
const away = !inSight();
|
|
1246
|
+
if (away && handle.playedOut && current === "live") {
|
|
1247
|
+
finish("finished", "user");
|
|
1248
|
+
return;
|
|
1249
|
+
}
|
|
1250
|
+
if (!(away && handle.soundHeld && handle.voiceArrived)) {
|
|
1251
|
+
if (handle.unheard !== null) {
|
|
1252
|
+
clearTimeout(handle.unheard);
|
|
1253
|
+
handle.unheard = null;
|
|
1254
|
+
}
|
|
1255
|
+
return;
|
|
1256
|
+
}
|
|
1257
|
+
if (handle.unheard !== null) return;
|
|
1258
|
+
handle.unheard = setTimeout(() => {
|
|
1259
|
+
handle.unheard = null;
|
|
1260
|
+
if (sessionRef.current === handle && !handle.done && latest.current.live.endUnattended === true && handle.soundHeld && handle.voiceArrived && !inSight()) {
|
|
1261
|
+
finish("interrupted", "user");
|
|
1262
|
+
}
|
|
1263
|
+
}, UNHEARD_GRACE_MS);
|
|
1264
|
+
}, [finish, inSight]);
|
|
1181
1265
|
const cancelStart = useCallback((reason) => {
|
|
1182
1266
|
const run = startRef.current;
|
|
1183
1267
|
if (!run) return;
|
|
@@ -1254,13 +1338,22 @@ function AvatarLiveView({
|
|
|
1254
1338
|
joined: null,
|
|
1255
1339
|
endsAt,
|
|
1256
1340
|
speakerArrived: false,
|
|
1341
|
+
voiceArrived: false,
|
|
1342
|
+
soundHeld: false,
|
|
1343
|
+
playedOut: false,
|
|
1344
|
+
unheard: null,
|
|
1345
|
+
tail: null,
|
|
1257
1346
|
done: false
|
|
1258
1347
|
};
|
|
1259
1348
|
setBlocked(false);
|
|
1260
1349
|
setNow(received);
|
|
1261
1350
|
go({
|
|
1262
1351
|
name: "pending",
|
|
1263
|
-
session: {
|
|
1352
|
+
session: {
|
|
1353
|
+
endsAt,
|
|
1354
|
+
captions: session.captions,
|
|
1355
|
+
excerpt: session.excerpt
|
|
1356
|
+
}
|
|
1264
1357
|
});
|
|
1265
1358
|
},
|
|
1266
1359
|
[go]
|
|
@@ -1579,6 +1672,9 @@ function AvatarLiveView({
|
|
|
1579
1672
|
check();
|
|
1580
1673
|
}
|
|
1581
1674
|
}, [showing, behindChat, check, leave, offeredNow]);
|
|
1675
|
+
useEffect(() => {
|
|
1676
|
+
attend();
|
|
1677
|
+
}, [showing, attend]);
|
|
1582
1678
|
useEffect(() => {
|
|
1583
1679
|
if (askedLocale.current === locale) return;
|
|
1584
1680
|
askedLocale.current = locale;
|
|
@@ -1665,12 +1761,29 @@ function AvatarLiveView({
|
|
|
1665
1761
|
const wasLive = phaseRef.current.name === "live";
|
|
1666
1762
|
switch (event.type) {
|
|
1667
1763
|
case "speaker-track":
|
|
1668
|
-
if (event.kind !== "video")
|
|
1764
|
+
if (event.kind !== "video") {
|
|
1765
|
+
handle.voiceArrived = true;
|
|
1766
|
+
attend();
|
|
1767
|
+
return;
|
|
1768
|
+
}
|
|
1669
1769
|
handle.speakerArrived = true;
|
|
1670
1770
|
if (!inSight()) goLive();
|
|
1671
1771
|
return;
|
|
1672
1772
|
case "playback-blocked":
|
|
1673
1773
|
setBlocked(event.blocked);
|
|
1774
|
+
handle.soundHeld = event.sound ?? event.blocked;
|
|
1775
|
+
attend();
|
|
1776
|
+
return;
|
|
1777
|
+
case "speech-ended":
|
|
1778
|
+
if (latest.current.live.endUnattended !== true || handle.tail !== null || handle.playedOut) {
|
|
1779
|
+
return;
|
|
1780
|
+
}
|
|
1781
|
+
handle.tail = setTimeout(() => {
|
|
1782
|
+
handle.tail = null;
|
|
1783
|
+
if (sessionRef.current !== handle || handle.done) return;
|
|
1784
|
+
handle.playedOut = true;
|
|
1785
|
+
attend();
|
|
1786
|
+
}, PLAYOUT_TAIL_MS);
|
|
1674
1787
|
return;
|
|
1675
1788
|
case "speaker-left":
|
|
1676
1789
|
finish(
|
|
@@ -1684,7 +1797,7 @@ function AvatarLiveView({
|
|
|
1684
1797
|
return;
|
|
1685
1798
|
}
|
|
1686
1799
|
},
|
|
1687
|
-
[finish, goLive, inSight]
|
|
1800
|
+
[attend, finish, goLive, inSight]
|
|
1688
1801
|
);
|
|
1689
1802
|
useEffect(() => {
|
|
1690
1803
|
if (phase.name !== "pending") return;
|
|
@@ -1771,10 +1884,12 @@ function AvatarLiveView({
|
|
|
1771
1884
|
const onVisibility = () => {
|
|
1772
1885
|
if (document.visibilityState === "hidden") {
|
|
1773
1886
|
leave("hidden");
|
|
1887
|
+
attend();
|
|
1774
1888
|
return;
|
|
1775
1889
|
}
|
|
1776
1890
|
const current = phaseRef.current.name;
|
|
1777
1891
|
if (current === "pending" || current === "live") setNow(Date.now());
|
|
1892
|
+
attend();
|
|
1778
1893
|
};
|
|
1779
1894
|
window.addEventListener("pagehide", onPageHide);
|
|
1780
1895
|
document.addEventListener("visibilitychange", onVisibility);
|
|
@@ -1782,7 +1897,7 @@ function AvatarLiveView({
|
|
|
1782
1897
|
window.removeEventListener("pagehide", onPageHide);
|
|
1783
1898
|
document.removeEventListener("visibilitychange", onVisibility);
|
|
1784
1899
|
};
|
|
1785
|
-
}, [leave]);
|
|
1900
|
+
}, [attend, leave]);
|
|
1786
1901
|
useEffect(
|
|
1787
1902
|
() => () => {
|
|
1788
1903
|
const controller = checkRef.current;
|
|
@@ -1801,6 +1916,7 @@ function AvatarLiveView({
|
|
|
1801
1916
|
sessionRef.current = null;
|
|
1802
1917
|
if (handle && !handle.done) {
|
|
1803
1918
|
handle.done = true;
|
|
1919
|
+
stopAttending(handle);
|
|
1804
1920
|
sendEnd({
|
|
1805
1921
|
base: handle.base,
|
|
1806
1922
|
headers: handle.headers,
|
|
@@ -2059,6 +2175,7 @@ function AvatarLiveView({
|
|
|
2059
2175
|
]
|
|
2060
2176
|
}
|
|
2061
2177
|
);
|
|
2178
|
+
const speakingLine = (session) => session.excerpt ? S.excerpt : S.speaking;
|
|
2062
2179
|
const liveBody = (session) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2063
2180
|
/* @__PURE__ */ jsx(
|
|
2064
2181
|
"section",
|
|
@@ -2272,7 +2389,7 @@ function AvatarLiveView({
|
|
|
2272
2389
|
break;
|
|
2273
2390
|
case "pending":
|
|
2274
2391
|
case "live":
|
|
2275
|
-
status = phase.name === "live" ?
|
|
2392
|
+
status = phase.name === "live" ? speakingLine(phase.session) : S.connecting;
|
|
2276
2393
|
top2 = badge;
|
|
2277
2394
|
media2 = liveMedia(phase.name === "live");
|
|
2278
2395
|
body2 = liveBody(phase.session);
|
|
@@ -2398,7 +2515,7 @@ function AvatarLiveView({
|
|
|
2398
2515
|
"bot-check": S.botCheck,
|
|
2399
2516
|
creating: S.connecting,
|
|
2400
2517
|
pending: S.connecting,
|
|
2401
|
-
live:
|
|
2518
|
+
live: phase.name === "live" ? speakingLine(phase.session) : "",
|
|
2402
2519
|
ended: phase.name === "ended" ? S[phase.how] : ""
|
|
2403
2520
|
};
|
|
2404
2521
|
const outcome = phase.name === "needs-answer" || phase.name === "refused" || phase.name === "ended";
|