@burdenoff/website-sdk 2026.1105.1 → 2026.1105.2
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 +40 -1
- package/dist/avatar-live/index.d.mts +2 -2
- package/dist/avatar-live/index.d.ts +2 -2
- package/dist/avatar-live/index.js +11 -1
- package/dist/avatar-live/index.js.map +1 -1
- package/dist/avatar-live/index.mjs +11 -1
- 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 +653 -32
- package/dist/avatar-live-view/index.js.map +1 -1
- package/dist/avatar-live-view/index.mjs +653 -32
- package/dist/avatar-live-view/index.mjs.map +1 -1
- package/dist/{explore-avatar-live-config-OO0hvQCK.d.mts → explore-avatar-live-config-BL8FTm0I.d.mts} +1 -1
- package/dist/{explore-avatar-live-config-C-OwXNje.d.ts → explore-avatar-live-config-auLKxSzx.d.ts} +1 -1
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/{types-CXqaLlNB.d.mts → types-CTUJNvQu.d.mts} +10 -0
- package/dist/{types-CXqaLlNB.d.ts → types-CTUJNvQu.d.ts} +10 -0
- package/package.json +1 -1
|
@@ -9,6 +9,8 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
|
9
9
|
// src/components/explore-avatar-api.ts
|
|
10
10
|
var AVAILABILITY_TIMEOUT_MS = 8e3;
|
|
11
11
|
var CREATE_TIMEOUT_MS = 3e4;
|
|
12
|
+
var TURN_TIMEOUT_MS = 8e3;
|
|
13
|
+
var TURN_ANSWER_TIMEOUT_MS = 25e3;
|
|
12
14
|
var MESSAGE_ID = /^[A-Za-z0-9_-]{1,64}$/;
|
|
13
15
|
var STT_TOKEN = /^[A-Za-z0-9._~-]{1,4096}$/;
|
|
14
16
|
var CONVERSATION_TOKEN = /^[A-Za-z0-9._~+/=-]{16,512}$/;
|
|
@@ -113,6 +115,21 @@ function errorCode(body) {
|
|
|
113
115
|
const { code } = body.error;
|
|
114
116
|
return typeof code === "string" ? code : null;
|
|
115
117
|
}
|
|
118
|
+
var MAX_FOLLOW_UP_ANSWERS = 16;
|
|
119
|
+
var MAX_FOLLOW_UP_SECONDS = 600;
|
|
120
|
+
var FOLLOW_UP_KEYS = ["idleSeconds", "maxAnswerWaitSeconds", "maxAnswers"];
|
|
121
|
+
function isWholeBetween(value, max) {
|
|
122
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 1 && value <= max;
|
|
123
|
+
}
|
|
124
|
+
function readFollowUps(value) {
|
|
125
|
+
if (!isRecord(value)) return void 0;
|
|
126
|
+
const keys = Object.keys(value).sort();
|
|
127
|
+
const { maxAnswers, idleSeconds, maxAnswerWaitSeconds } = value;
|
|
128
|
+
if (keys.length !== FOLLOW_UP_KEYS.length || keys.some((key, at) => key !== FOLLOW_UP_KEYS[at]) || !isWholeBetween(maxAnswers, MAX_FOLLOW_UP_ANSWERS) || !isWholeBetween(idleSeconds, MAX_FOLLOW_UP_SECONDS) || !isWholeBetween(maxAnswerWaitSeconds, MAX_FOLLOW_UP_SECONDS)) {
|
|
129
|
+
return void 0;
|
|
130
|
+
}
|
|
131
|
+
return { maxAnswers, idleSeconds, maxAnswerWaitSeconds };
|
|
132
|
+
}
|
|
116
133
|
function readCreated(body) {
|
|
117
134
|
if (!isRecord(body)) return FAILED;
|
|
118
135
|
const { sessionId, endSecret } = body;
|
|
@@ -130,6 +147,7 @@ function readCreated(body) {
|
|
|
130
147
|
if (typeof livekitUrl !== "string" || !livekitUrl.startsWith("wss://") || typeof participantToken !== "string" || participantToken === "" || typeof workerIdentity !== "string" || workerIdentity === "" || typeof locale !== "string" || typeof text !== "string") {
|
|
131
148
|
return unusable;
|
|
132
149
|
}
|
|
150
|
+
const followUps = readFollowUps(body.followUps);
|
|
133
151
|
return {
|
|
134
152
|
kind: "created",
|
|
135
153
|
session: {
|
|
@@ -138,7 +156,8 @@ function readCreated(body) {
|
|
|
138
156
|
endsAt,
|
|
139
157
|
join: { livekitUrl, participantToken, workerIdentity },
|
|
140
158
|
captions: { locale, text },
|
|
141
|
-
excerpt: body.excerpt === true
|
|
159
|
+
excerpt: body.excerpt === true,
|
|
160
|
+
...followUps === void 0 ? {} : { followUps }
|
|
142
161
|
}
|
|
143
162
|
};
|
|
144
163
|
}
|
|
@@ -269,6 +288,96 @@ function sendEnd(target) {
|
|
|
269
288
|
} catch {
|
|
270
289
|
}
|
|
271
290
|
}
|
|
291
|
+
var TURN_REFUSALS = /* @__PURE__ */ new Map([
|
|
292
|
+
["no_time", "no_time"],
|
|
293
|
+
["max_answers", "max_answers"],
|
|
294
|
+
["not_eligible", "not_eligible"],
|
|
295
|
+
["answer_claimed", "answer_claimed"],
|
|
296
|
+
["limits", "limits"],
|
|
297
|
+
["paused", "paused"],
|
|
298
|
+
["busy", "busy"]
|
|
299
|
+
]);
|
|
300
|
+
var MAX_TURN_RETRY_AFTER_SECONDS = 600;
|
|
301
|
+
function retryAfterOf(body) {
|
|
302
|
+
if (!isRecord(body) || !isRecord(body.error)) return void 0;
|
|
303
|
+
const { retryAfterSeconds } = body.error;
|
|
304
|
+
return isWholeBetween(retryAfterSeconds, MAX_TURN_RETRY_AFTER_SECONDS) ? retryAfterSeconds : void 0;
|
|
305
|
+
}
|
|
306
|
+
var TURN_KEY = /^[A-Za-z0-9_-]{8,64}$/;
|
|
307
|
+
var LOST = { kind: "failed", lost: true };
|
|
308
|
+
var TURN_FAILED = { kind: "failed", lost: false };
|
|
309
|
+
function readAccepted(body) {
|
|
310
|
+
if (!isRecord(body) || body.accepted !== true || !isRecord(body.captions)) {
|
|
311
|
+
return LOST;
|
|
312
|
+
}
|
|
313
|
+
const { locale, text } = body.captions;
|
|
314
|
+
if (typeof locale !== "string" || typeof text !== "string") return LOST;
|
|
315
|
+
return {
|
|
316
|
+
kind: "accepted",
|
|
317
|
+
captions: { locale, text },
|
|
318
|
+
excerpt: body.excerpt === true
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
function readTurn(kind, status, body) {
|
|
322
|
+
if (status === 200) {
|
|
323
|
+
if (kind === "answer") return readAccepted(body);
|
|
324
|
+
return isRecord(body) && body.ok === true ? { kind: "ok" } : LOST;
|
|
325
|
+
}
|
|
326
|
+
const code = errorCode(body);
|
|
327
|
+
const refusal = code === null ? void 0 : TURN_REFUSALS.get(code);
|
|
328
|
+
if (refusal !== void 0) {
|
|
329
|
+
const retryAfterSeconds = retryAfterOf(body);
|
|
330
|
+
return retryAfterSeconds === void 0 ? { kind: "refused", reason: refusal } : { kind: "refused", reason: refusal, retryAfterSeconds };
|
|
331
|
+
}
|
|
332
|
+
if (status === 404) return { kind: "gone" };
|
|
333
|
+
return status >= 500 ? LOST : TURN_FAILED;
|
|
334
|
+
}
|
|
335
|
+
function requestTurn(target) {
|
|
336
|
+
const { kind, messageId, idempotencyKey } = target;
|
|
337
|
+
const nonce = newIdempotencyKey();
|
|
338
|
+
if (!SESSION_ID.test(target.sessionId) || !END_SECRET.test(target.secret) || nonce === null || (kind === "answer" ? messageId === void 0 || !MESSAGE_ID.test(messageId) : messageId !== void 0 || idempotencyKey !== void 0) || idempotencyKey !== void 0 && !TURN_KEY.test(idempotencyKey)) {
|
|
339
|
+
return Promise.resolve(TURN_FAILED);
|
|
340
|
+
}
|
|
341
|
+
const payload = JSON.stringify({
|
|
342
|
+
secret: target.secret,
|
|
343
|
+
kind,
|
|
344
|
+
nonce,
|
|
345
|
+
...messageId === void 0 ? {} : { messageId },
|
|
346
|
+
...idempotencyKey === void 0 ? {} : { idempotencyKey }
|
|
347
|
+
});
|
|
348
|
+
const controller = new AbortController();
|
|
349
|
+
const answer = (async () => {
|
|
350
|
+
try {
|
|
351
|
+
const response = await fetch(
|
|
352
|
+
`${target.base}/sessions/${encodeURIComponent(target.sessionId)}/turn`,
|
|
353
|
+
{
|
|
354
|
+
method: "POST",
|
|
355
|
+
credentials: "omit",
|
|
356
|
+
cache: "no-store",
|
|
357
|
+
headers: { ...target.headers },
|
|
358
|
+
body: payload,
|
|
359
|
+
signal: controller.signal
|
|
360
|
+
}
|
|
361
|
+
);
|
|
362
|
+
return readTurn(kind, response.status, await readJson(response));
|
|
363
|
+
} catch {
|
|
364
|
+
return LOST;
|
|
365
|
+
}
|
|
366
|
+
})();
|
|
367
|
+
return new Promise((resolve) => {
|
|
368
|
+
const timer = setTimeout(
|
|
369
|
+
() => {
|
|
370
|
+
controller.abort();
|
|
371
|
+
resolve(LOST);
|
|
372
|
+
},
|
|
373
|
+
kind === "answer" ? TURN_ANSWER_TIMEOUT_MS : TURN_TIMEOUT_MS
|
|
374
|
+
);
|
|
375
|
+
void answer.then((result) => {
|
|
376
|
+
clearTimeout(timer);
|
|
377
|
+
resolve(result);
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
}
|
|
272
381
|
var BOT_BINDING_PREFIX = "boff-web-avatar-cdata/v1";
|
|
273
382
|
function webCryptoSubtle() {
|
|
274
383
|
const subtle = globalThis.crypto?.subtle;
|
|
@@ -366,7 +475,14 @@ var EN = {
|
|
|
366
475
|
usedToday: "You've had today's avatar session. Answers will show here as text.",
|
|
367
476
|
needsAnswerAny: "Ask a question here, and the avatar reads the answer aloud.",
|
|
368
477
|
startNewChatDetailAny: "The avatar reads aloud only the first answer in a new chat started in the Avatar tab, provided it passes the speech checks.",
|
|
369
|
-
notEligibleAny: "The avatar can't read this answer aloud. The answer and sources are in Chat."
|
|
478
|
+
notEligibleAny: "The avatar can't read this answer aloud. The answer and sources are in Chat.",
|
|
479
|
+
followUpIdle: "The avatar ends after about thirty seconds without a question.",
|
|
480
|
+
followUpNoTime: "There isn't enough time left in this session to read that answer. It's in Chat.",
|
|
481
|
+
followUpMaxAnswers: "The avatar has read all the answers it can in this session. This one is in Chat.",
|
|
482
|
+
followUpLast: "That was the last answer the avatar can read in this session.",
|
|
483
|
+
followUpLimits: "The live avatar has reached its limit for now. This answer is in Chat.",
|
|
484
|
+
followUpPaused: "The live avatar is paused right now. This answer is in Chat.",
|
|
485
|
+
followUpUnread: "The avatar couldn't read that answer. It's in Chat."
|
|
370
486
|
};
|
|
371
487
|
var ZH = {
|
|
372
488
|
checking: "\u6B63\u5728\u68C0\u67E5\u5B9E\u65F6\u865A\u62DF\u5F62\u8C61\u662F\u5426\u53EF\u7528\u2026",
|
|
@@ -427,7 +543,16 @@ var ZH = {
|
|
|
427
543
|
usedToday: "\u60A8\u4ECA\u5929\u5DF2\u4F7F\u7528\u8FC7\u865A\u62DF\u5F62\u8C61\u3002\u56DE\u7B54\u5C06\u4EE5\u6587\u5B57\u663E\u793A\u5728\u8FD9\u91CC\u3002",
|
|
428
544
|
needsAnswerAny: "\u5728\u8FD9\u91CC\u63D0\u95EE\uFF0C\u865A\u62DF\u5F62\u8C61\u4F1A\u6717\u8BFB\u56DE\u7B54\u3002",
|
|
429
545
|
startNewChatDetailAny: "\u865A\u62DF\u5F62\u8C61\u53EA\u6717\u8BFB\u5728\u201C\u865A\u62DF\u5F62\u8C61\u201D\u6807\u7B7E\u9875\u4E2D\u5F00\u59CB\u7684\u65B0\u804A\u5929\u7684\u7B2C\u4E00\u4E2A\u56DE\u7B54\uFF0C\u4E14\u8BE5\u56DE\u7B54\u987B\u901A\u8FC7\u8BED\u97F3\u68C0\u67E5\u3002",
|
|
430
|
-
notEligibleAny: "\u865A\u62DF\u5F62\u8C61\u65E0\u6CD5\u6717\u8BFB\u6B64\u56DE\u7B54\u3002\u56DE\u7B54\u548C\u6765\u6E90\u5728\u804A\u5929\u4E2D\u3002"
|
|
546
|
+
notEligibleAny: "\u865A\u62DF\u5F62\u8C61\u65E0\u6CD5\u6717\u8BFB\u6B64\u56DE\u7B54\u3002\u56DE\u7B54\u548C\u6765\u6E90\u5728\u804A\u5929\u4E2D\u3002",
|
|
547
|
+
// TRANSLATION REVIEW PENDING (BOFF-9797): draft, the lines of a session that reads the answers after the first
|
|
548
|
+
// (Stage D).
|
|
549
|
+
followUpIdle: "\u5982\u679C\u7EA6\u4E09\u5341\u79D2\u5185\u6CA1\u6709\u65B0\u95EE\u9898\uFF0C\u865A\u62DF\u5F62\u8C61\u5C31\u4F1A\u7ED3\u675F\u3002",
|
|
550
|
+
followUpNoTime: "\u672C\u6B21\u4F1A\u8BDD\u5269\u4F59\u65F6\u95F4\u4E0D\u8DB3\uFF0C\u65E0\u6CD5\u6717\u8BFB\u8BE5\u56DE\u7B54\u3002\u56DE\u7B54\u5728\u804A\u5929\u4E2D\u3002",
|
|
551
|
+
followUpMaxAnswers: "\u865A\u62DF\u5F62\u8C61\u5DF2\u6717\u8BFB\u672C\u6B21\u4F1A\u8BDD\u53EF\u6717\u8BFB\u7684\u5168\u90E8\u56DE\u7B54\u3002\u6B64\u56DE\u7B54\u5728\u804A\u5929\u4E2D\u3002",
|
|
552
|
+
followUpLast: "\u8FD9\u662F\u865A\u62DF\u5F62\u8C61\u5728\u672C\u6B21\u4F1A\u8BDD\u4E2D\u53EF\u6717\u8BFB\u7684\u6700\u540E\u4E00\u4E2A\u56DE\u7B54\u3002",
|
|
553
|
+
followUpLimits: "\u5B9E\u65F6\u865A\u62DF\u5F62\u8C61\u6682\u65F6\u5DF2\u8FBE\u5230\u4F7F\u7528\u4E0A\u9650\u3002\u6B64\u56DE\u7B54\u5728\u804A\u5929\u4E2D\u3002",
|
|
554
|
+
followUpPaused: "\u5B9E\u65F6\u865A\u62DF\u5F62\u8C61\u76EE\u524D\u5DF2\u6682\u505C\u3002\u6B64\u56DE\u7B54\u5728\u804A\u5929\u4E2D\u3002",
|
|
555
|
+
followUpUnread: "\u865A\u62DF\u5F62\u8C61\u65E0\u6CD5\u6717\u8BFB\u8BE5\u56DE\u7B54\u3002\u56DE\u7B54\u5728\u804A\u5929\u4E2D\u3002"
|
|
431
556
|
};
|
|
432
557
|
var HI = {
|
|
433
558
|
checking: "\u091C\u093E\u0901\u091A \u0939\u094B \u0930\u0939\u0940 \u0939\u0948 \u0915\u093F \u0932\u093E\u0907\u0935 \u0905\u0935\u0924\u093E\u0930 \u0909\u092A\u0932\u092C\u094D\u0927 \u0939\u0948 \u092F\u093E \u0928\u0939\u0940\u0902\u2026",
|
|
@@ -488,7 +613,16 @@ var HI = {
|
|
|
488
613
|
usedToday: "\u0906\u091C \u0915\u093E \u0905\u0935\u0924\u093E\u0930 \u0938\u0924\u094D\u0930 \u0906\u092A \u0932\u0947 \u091A\u0941\u0915\u0947 \u0939\u0948\u0902\u0964 \u0909\u0924\u094D\u0924\u0930 \u092F\u0939\u093E\u0901 \u091F\u0947\u0915\u094D\u0938\u094D\u091F \u0915\u0947 \u0930\u0942\u092A \u092E\u0947\u0902 \u0926\u093F\u0916\u0947\u0902\u0917\u0947\u0964",
|
|
489
614
|
needsAnswerAny: "\u092F\u0939\u093E\u0901 \u092A\u094D\u0930\u0936\u094D\u0928 \u092A\u0942\u091B\u0947\u0902, \u0914\u0930 \u0905\u0935\u0924\u093E\u0930 \u0909\u0924\u094D\u0924\u0930 \u091C\u093C\u094B\u0930 \u0938\u0947 \u092A\u0922\u093C\u0947\u0917\u093E\u0964",
|
|
490
615
|
startNewChatDetailAny: "\u0905\u0935\u0924\u093E\u0930 \u0915\u0947\u0935\u0932 \u0905\u0935\u0924\u093E\u0930 \u091F\u0948\u092C \u092E\u0947\u0902 \u0936\u0941\u0930\u0942 \u0915\u0940 \u0917\u0908 \u0928\u0908 \u091A\u0948\u091F \u0915\u093E \u092A\u0939\u0932\u093E \u0909\u0924\u094D\u0924\u0930 \u091C\u093C\u094B\u0930 \u0938\u0947 \u092A\u0922\u093C\u0924\u093E \u0939\u0948, \u092C\u0936\u0930\u094D\u0924\u0947 \u0935\u0939 \u0935\u093E\u0923\u0940 \u091C\u093E\u0901\u091A \u092E\u0947\u0902 \u092A\u093E\u0938 \u0939\u094B\u0964",
|
|
491
|
-
notEligibleAny: "\u0905\u0935\u0924\u093E\u0930 \u092F\u0939 \u0909\u0924\u094D\u0924\u0930 \u091C\u093C\u094B\u0930 \u0938\u0947 \u0928\u0939\u0940\u0902 \u092A\u0922\u093C \u0938\u0915\u0924\u093E\u0964 \u0909\u0924\u094D\u0924\u0930 \u0914\u0930 \u0938\u094D\u0930\u094B\u0924 \u091A\u0948\u091F \u092E\u0947\u0902 \u0939\u0948\u0902\u0964"
|
|
616
|
+
notEligibleAny: "\u0905\u0935\u0924\u093E\u0930 \u092F\u0939 \u0909\u0924\u094D\u0924\u0930 \u091C\u093C\u094B\u0930 \u0938\u0947 \u0928\u0939\u0940\u0902 \u092A\u0922\u093C \u0938\u0915\u0924\u093E\u0964 \u0909\u0924\u094D\u0924\u0930 \u0914\u0930 \u0938\u094D\u0930\u094B\u0924 \u091A\u0948\u091F \u092E\u0947\u0902 \u0939\u0948\u0902\u0964",
|
|
617
|
+
// TRANSLATION REVIEW PENDING (BOFF-9797): draft, the lines of a session that reads the answers after the first
|
|
618
|
+
// (Stage D).
|
|
619
|
+
followUpIdle: "\u092C\u093F\u0928\u093E \u0915\u093F\u0938\u0940 \u092A\u094D\u0930\u0936\u094D\u0928 \u0915\u0947 \u0932\u0917\u092D\u0917 \u0924\u0940\u0938 \u0938\u0947\u0915\u0902\u0921 \u092C\u093E\u0926 \u0905\u0935\u0924\u093E\u0930 \u0938\u092E\u093E\u092A\u094D\u0924 \u0939\u094B \u091C\u093E\u0924\u093E \u0939\u0948\u0964",
|
|
620
|
+
followUpNoTime: "\u0907\u0938 \u0938\u0924\u094D\u0930 \u092E\u0947\u0902 \u0935\u0939 \u0909\u0924\u094D\u0924\u0930 \u092A\u0922\u093C\u0928\u0947 \u0915\u0947 \u0932\u093F\u090F \u092A\u0930\u094D\u092F\u093E\u092A\u094D\u0924 \u0938\u092E\u092F \u0928\u0939\u0940\u0902 \u092C\u091A\u093E \u0939\u0948\u0964 \u0909\u0924\u094D\u0924\u0930 \u091A\u0948\u091F \u092E\u0947\u0902 \u0939\u0948\u0964",
|
|
621
|
+
followUpMaxAnswers: "\u0905\u0935\u0924\u093E\u0930 \u0907\u0938 \u0938\u0924\u094D\u0930 \u092E\u0947\u0902 \u091C\u093F\u0924\u0928\u0947 \u0909\u0924\u094D\u0924\u0930 \u092A\u0922\u093C \u0938\u0915\u0924\u093E \u0939\u0948, \u0938\u092C \u092A\u0922\u093C \u091A\u0941\u0915\u093E \u0939\u0948\u0964 \u092F\u0939 \u0909\u0924\u094D\u0924\u0930 \u091A\u0948\u091F \u092E\u0947\u0902 \u0939\u0948\u0964",
|
|
622
|
+
followUpLast: "\u092F\u0939 \u0907\u0938 \u0938\u0924\u094D\u0930 \u092E\u0947\u0902 \u0905\u0935\u0924\u093E\u0930 \u0926\u094D\u0935\u093E\u0930\u093E \u092A\u0922\u093C\u093E \u091C\u093E \u0938\u0915\u0928\u0947 \u0935\u093E\u0932\u093E \u0905\u0902\u0924\u093F\u092E \u0909\u0924\u094D\u0924\u0930 \u0925\u093E\u0964",
|
|
623
|
+
followUpLimits: "\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 \u092F\u0939 \u0909\u0924\u094D\u0924\u0930 \u091A\u0948\u091F \u092E\u0947\u0902 \u0939\u0948\u0964",
|
|
624
|
+
followUpPaused: "\u0932\u093E\u0907\u0935 \u0905\u0935\u0924\u093E\u0930 \u0905\u092D\u0940 \u0930\u0941\u0915\u093E \u0939\u0941\u0906 \u0939\u0948\u0964 \u092F\u0939 \u0909\u0924\u094D\u0924\u0930 \u091A\u0948\u091F \u092E\u0947\u0902 \u0939\u0948\u0964",
|
|
625
|
+
followUpUnread: "\u0905\u0935\u0924\u093E\u0930 \u0935\u0939 \u0909\u0924\u094D\u0924\u0930 \u0928\u0939\u0940\u0902 \u092A\u0922\u093C \u0938\u0915\u093E\u0964 \u0909\u0924\u094D\u0924\u0930 \u091A\u0948\u091F \u092E\u0947\u0902 \u0939\u0948\u0964"
|
|
492
626
|
};
|
|
493
627
|
var ES = {
|
|
494
628
|
checking: "Comprobando si el avatar en vivo est\xE1 disponible\u2026",
|
|
@@ -549,7 +683,16 @@ var ES = {
|
|
|
549
683
|
usedToday: "Ya has usado la sesi\xF3n de avatar de hoy. Las respuestas se mostrar\xE1n aqu\xED como texto.",
|
|
550
684
|
needsAnswerAny: "Haz una pregunta aqu\xED y el avatar leer\xE1 la respuesta en voz alta.",
|
|
551
685
|
startNewChatDetailAny: "El avatar solo lee en voz alta la primera respuesta de un chat nuevo iniciado en la pesta\xF1a Avatar, si supera las comprobaciones de voz.",
|
|
552
|
-
notEligibleAny: "El avatar no puede leer esta respuesta en voz alta. La respuesta y las fuentes est\xE1n en el chat."
|
|
686
|
+
notEligibleAny: "El avatar no puede leer esta respuesta en voz alta. La respuesta y las fuentes est\xE1n en el chat.",
|
|
687
|
+
// TRANSLATION REVIEW PENDING (BOFF-9797): draft, the lines of a session that reads the answers after the first
|
|
688
|
+
// (Stage D).
|
|
689
|
+
followUpIdle: "El avatar termina tras unos treinta segundos sin preguntas.",
|
|
690
|
+
followUpNoTime: "No queda tiempo suficiente en esta sesi\xF3n para leer esa respuesta. Est\xE1 en el chat.",
|
|
691
|
+
followUpMaxAnswers: "El avatar ya ha le\xEDdo todas las respuestas que puede en esta sesi\xF3n. Esta est\xE1 en el chat.",
|
|
692
|
+
followUpLast: "Esa fue la \xFAltima respuesta que el avatar puede leer en esta sesi\xF3n.",
|
|
693
|
+
followUpLimits: "El avatar en vivo ha alcanzado su l\xEDmite por ahora. Esta respuesta est\xE1 en el chat.",
|
|
694
|
+
followUpPaused: "El avatar en vivo est\xE1 en pausa ahora mismo. Esta respuesta est\xE1 en el chat.",
|
|
695
|
+
followUpUnread: "El avatar no pudo leer esa respuesta. Est\xE1 en el chat."
|
|
553
696
|
};
|
|
554
697
|
var AR = {
|
|
555
698
|
checking: "\u062C\u0627\u0631\u064D \u0627\u0644\u062A\u062D\u0642\u0642 \u0645\u0646 \u062A\u0648\u0641\u0631 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0645\u0628\u0627\u0634\u0631\u2026",
|
|
@@ -610,7 +753,16 @@ var AR = {
|
|
|
610
753
|
usedToday: "\u0644\u0642\u062F \u0627\u0633\u062A\u062E\u062F\u0645\u062A \u062C\u0644\u0633\u0629 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0644\u0647\u0630\u0627 \u0627\u0644\u064A\u0648\u0645. \u0633\u062A\u0638\u0647\u0631 \u0627\u0644\u0625\u062C\u0627\u0628\u0627\u062A \u0647\u0646\u0627 \u0646\u0635\u064B\u0627.",
|
|
611
754
|
needsAnswerAny: "\u0627\u0637\u0631\u062D \u0633\u0624\u0627\u0644\u064B\u0627 \u0647\u0646\u0627\u060C \u0648\u0633\u064A\u0642\u0631\u0623 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0628\u0635\u0648\u062A \u0639\u0627\u0644\u064D.",
|
|
612
755
|
startNewChatDetailAny: "\u064A\u0642\u0631\u0623 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0628\u0635\u0648\u062A \u0639\u0627\u0644\u064D \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0627\u0644\u0623\u0648\u0644\u0649 \u0641\u0642\u0637 \u0641\u064A \u062F\u0631\u062F\u0634\u0629 \u062C\u062F\u064A\u062F\u0629 \u0628\u062F\u0623\u062A \u0641\u064A \u0639\u0644\u0627\u0645\u0629 \u062A\u0628\u0648\u064A\u0628 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631\u060C \u0628\u0634\u0631\u0637 \u0623\u0646 \u062A\u062C\u062A\u0627\u0632 \u0641\u062D\u0648\u0635 \u0627\u0644\u0646\u0637\u0642.",
|
|
613
|
-
notEligibleAny: "\u0644\u0627 \u064A\u0645\u0643\u0646 \u0644\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0642\u0631\u0627\u0621\u0629 \u0647\u0630\u0647 \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0628\u0635\u0648\u062A \u0639\u0627\u0644\u064D. \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0648\u0627\u0644\u0645\u0635\u0627\u062F\u0631 \u0645\u0648\u062C\u0648\u062F\u0629 \u0641\u064A \u0627\u0644\u062F\u0631\u062F\u0634\u0629."
|
|
756
|
+
notEligibleAny: "\u0644\u0627 \u064A\u0645\u0643\u0646 \u0644\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0642\u0631\u0627\u0621\u0629 \u0647\u0630\u0647 \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0628\u0635\u0648\u062A \u0639\u0627\u0644\u064D. \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0648\u0627\u0644\u0645\u0635\u0627\u062F\u0631 \u0645\u0648\u062C\u0648\u062F\u0629 \u0641\u064A \u0627\u0644\u062F\u0631\u062F\u0634\u0629.",
|
|
757
|
+
// TRANSLATION REVIEW PENDING (BOFF-9797): draft, the lines of a session that reads the answers after the first
|
|
758
|
+
// (Stage D).
|
|
759
|
+
followUpIdle: "\u064A\u0646\u062A\u0647\u064A \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0628\u0639\u062F \u0646\u062D\u0648 \u062B\u0644\u0627\u062B\u064A\u0646 \u062B\u0627\u0646\u064A\u0629 \u0645\u0646 \u062F\u0648\u0646 \u0633\u0624\u0627\u0644.",
|
|
760
|
+
followUpNoTime: "\u0644\u0645 \u064A\u062A\u0628\u0642\u064E\u0651 \u0648\u0642\u062A \u0643\u0627\u0641\u064D \u0641\u064A \u0647\u0630\u0647 \u0627\u0644\u062C\u0644\u0633\u0629 \u0644\u0642\u0631\u0627\u0621\u0629 \u062A\u0644\u0643 \u0627\u0644\u0625\u062C\u0627\u0628\u0629. \u0625\u0646\u0647\u0627 \u0641\u064A \u0627\u0644\u062F\u0631\u062F\u0634\u0629.",
|
|
761
|
+
followUpMaxAnswers: "\u0642\u0631\u0623 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0643\u0644 \u0627\u0644\u0625\u062C\u0627\u0628\u0627\u062A \u0627\u0644\u062A\u064A \u064A\u0645\u0643\u0646\u0647 \u0642\u0631\u0627\u0621\u062A\u0647\u0627 \u0641\u064A \u0647\u0630\u0647 \u0627\u0644\u062C\u0644\u0633\u0629. \u0647\u0630\u0647 \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0641\u064A \u0627\u0644\u062F\u0631\u062F\u0634\u0629.",
|
|
762
|
+
followUpLast: "\u0643\u0627\u0646\u062A \u062A\u0644\u0643 \u0622\u062E\u0631 \u0625\u062C\u0627\u0628\u0629 \u064A\u0645\u0643\u0646 \u0644\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0642\u0631\u0627\u0621\u062A\u0647\u0627 \u0641\u064A \u0647\u0630\u0647 \u0627\u0644\u062C\u0644\u0633\u0629.",
|
|
763
|
+
followUpLimits: "\u0628\u0644\u063A \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0645\u0628\u0627\u0634\u0631 \u062D\u062F\u0647 \u0627\u0644\u0622\u0646. \u0647\u0630\u0647 \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0641\u064A \u0627\u0644\u062F\u0631\u062F\u0634\u0629.",
|
|
764
|
+
followUpPaused: "\u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0645\u0628\u0627\u0634\u0631 \u0645\u062A\u0648\u0642\u0641 \u0645\u0624\u0642\u062A\u064B\u0627 \u0627\u0644\u0622\u0646. \u0647\u0630\u0647 \u0627\u0644\u0625\u062C\u0627\u0628\u0629 \u0641\u064A \u0627\u0644\u062F\u0631\u062F\u0634\u0629.",
|
|
765
|
+
followUpUnread: "\u062A\u0639\u0630\u0651\u0631 \u0639\u0644\u0649 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0642\u0631\u0627\u0621\u0629 \u062A\u0644\u0643 \u0627\u0644\u0625\u062C\u0627\u0628\u0629. \u0625\u0646\u0647\u0627 \u0641\u064A \u0627\u0644\u062F\u0631\u062F\u0634\u0629."
|
|
614
766
|
};
|
|
615
767
|
var TA = {
|
|
616
768
|
checking: "\u0BA8\u0BC7\u0BB0\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0B95\u0BBF\u0B9F\u0BC8\u0B95\u0BCD\u0B95\u0BBF\u0BB1\u0BA4\u0BBE \u0B8E\u0BA9\u0B9A\u0BCD \u0B9A\u0BB0\u0BBF\u0BAA\u0BBE\u0BB0\u0BCD\u0B95\u0BCD\u0B95\u0BBF\u0BB1\u0BA4\u0BC1\u2026",
|
|
@@ -671,7 +823,16 @@ var TA = {
|
|
|
671
823
|
usedToday: "\u0B87\u0BA9\u0BCD\u0BB1\u0BC8\u0BAF \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0B85\u0BAE\u0BB0\u0BCD\u0BB5\u0BC8 \u0BA8\u0BC0\u0B99\u0BCD\u0B95\u0BB3\u0BCD \u0BAA\u0BAF\u0BA9\u0BCD\u0BAA\u0B9F\u0BC1\u0BA4\u0BCD\u0BA4\u0BBF\u0BB5\u0BBF\u0B9F\u0BCD\u0B9F\u0BC0\u0BB0\u0BCD\u0B95\u0BB3\u0BCD. \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD\u0B95\u0BB3\u0BCD \u0B87\u0B99\u0BCD\u0B95\u0BC7 \u0B89\u0BB0\u0BC8\u0BAF\u0BBE\u0B95\u0B95\u0BCD \u0B95\u0BBE\u0B9F\u0BCD\u0B9F\u0BAA\u0BCD\u0BAA\u0B9F\u0BC1\u0BAE\u0BCD.",
|
|
672
824
|
needsAnswerAny: "\u0B87\u0B99\u0BCD\u0B95\u0BC7 \u0B92\u0BB0\u0BC1 \u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF\u0BAF\u0BC8\u0B95\u0BCD \u0B95\u0BC7\u0BB3\u0BC1\u0B99\u0BCD\u0B95\u0BB3\u0BCD, \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BC8 \u0B89\u0BB0\u0B95\u0BCD\u0B95\u0BAA\u0BCD \u0BAA\u0B9F\u0BBF\u0B95\u0BCD\u0B95\u0BC1\u0BAE\u0BCD.",
|
|
673
825
|
startNewChatDetailAny: "\u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0BA4\u0BBE\u0BB5\u0BB2\u0BBF\u0BB2\u0BCD \u0BA4\u0BCA\u0B9F\u0B99\u0BCD\u0B95\u0BBF\u0BAF \u0BAA\u0BC1\u0BA4\u0BBF\u0BAF \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BBF\u0BA9\u0BCD \u0BAE\u0BC1\u0BA4\u0BB2\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BC8 \u0BAE\u0B9F\u0BCD\u0B9F\u0BC1\u0BAE\u0BC7, \u0B85\u0BA4\u0BC1 \u0BAA\u0BC7\u0B9A\u0BCD\u0B9A\u0BC1\u0B9A\u0BCD \u0B9A\u0BB0\u0BBF\u0BAA\u0BBE\u0BB0\u0BCD\u0BAA\u0BCD\u0BAA\u0BC1\u0B95\u0BB3\u0BBF\u0BB2\u0BCD \u0BA4\u0BC7\u0BB1\u0BBF\u0BA9\u0BBE\u0BB2\u0BCD, \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0B89\u0BB0\u0B95\u0BCD\u0B95\u0BAA\u0BCD \u0BAA\u0B9F\u0BBF\u0B95\u0BCD\u0B95\u0BC1\u0BAE\u0BCD.",
|
|
674
|
-
notEligibleAny: "\u0B87\u0BA8\u0BCD\u0BA4\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BBE\u0BB2\u0BCD \u0B89\u0BB0\u0B95\u0BCD\u0B95\u0BAA\u0BCD \u0BAA\u0B9F\u0BBF\u0B95\u0BCD\u0B95 \u0BAE\u0BC1\u0B9F\u0BBF\u0BAF\u0BBE\u0BA4\u0BC1. \u0BAA\u0BA4\u0BBF\u0BB2\u0BC1\u0BAE\u0BCD \u0B86\u0BA4\u0BBE\u0BB0\u0B99\u0BCD\u0B95\u0BB3\u0BC1\u0BAE\u0BCD \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD \u0B89\u0BB3\u0BCD\u0BB3\u0BA9."
|
|
826
|
+
notEligibleAny: "\u0B87\u0BA8\u0BCD\u0BA4\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BBE\u0BB2\u0BCD \u0B89\u0BB0\u0B95\u0BCD\u0B95\u0BAA\u0BCD \u0BAA\u0B9F\u0BBF\u0B95\u0BCD\u0B95 \u0BAE\u0BC1\u0B9F\u0BBF\u0BAF\u0BBE\u0BA4\u0BC1. \u0BAA\u0BA4\u0BBF\u0BB2\u0BC1\u0BAE\u0BCD \u0B86\u0BA4\u0BBE\u0BB0\u0B99\u0BCD\u0B95\u0BB3\u0BC1\u0BAE\u0BCD \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD \u0B89\u0BB3\u0BCD\u0BB3\u0BA9.",
|
|
827
|
+
// TRANSLATION REVIEW PENDING (BOFF-9797): draft, the lines of a session that reads the answers after the first
|
|
828
|
+
// (Stage D).
|
|
829
|
+
followUpIdle: "\u0B95\u0BC7\u0BB3\u0BCD\u0BB5\u0BBF \u0B87\u0BB2\u0BCD\u0BB2\u0BBE\u0BAE\u0BB2\u0BCD \u0B9A\u0BC1\u0BAE\u0BBE\u0BB0\u0BCD \u0BAE\u0BC1\u0BAA\u0BCD\u0BAA\u0BA4\u0BC1 \u0BB5\u0BBF\u0BA9\u0BBE\u0B9F\u0BBF\u0B95\u0BB3\u0BCD \u0B95\u0BB4\u0BBF\u0BA4\u0BCD\u0BA4\u0BC1 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0BAE\u0BC1\u0B9F\u0BBF\u0BB5\u0B9F\u0BC8\u0BAF\u0BC1\u0BAE\u0BCD.",
|
|
830
|
+
followUpNoTime: "\u0B85\u0BA8\u0BCD\u0BA4\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BC8\u0BAA\u0BCD \u0BAA\u0B9F\u0BBF\u0B95\u0BCD\u0B95 \u0B87\u0BA8\u0BCD\u0BA4 \u0B85\u0BAE\u0BB0\u0BCD\u0BB5\u0BBF\u0BB2\u0BCD \u0BAA\u0BCB\u0BA4\u0BC1\u0BAE\u0BBE\u0BA9 \u0BA8\u0BC7\u0BB0\u0BAE\u0BCD \u0B87\u0BB2\u0BCD\u0BB2\u0BC8. \u0B85\u0BA4\u0BC1 \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD \u0B89\u0BB3\u0BCD\u0BB3\u0BA4\u0BC1.",
|
|
831
|
+
followUpMaxAnswers: "\u0B87\u0BA8\u0BCD\u0BA4 \u0B85\u0BAE\u0BB0\u0BCD\u0BB5\u0BBF\u0BB2\u0BCD \u0BAA\u0B9F\u0BBF\u0B95\u0BCD\u0B95\u0B95\u0BCD\u0B95\u0BC2\u0B9F\u0BBF\u0BAF \u0B8E\u0BB2\u0BCD\u0BB2\u0BBE\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD\u0B95\u0BB3\u0BC8\u0BAF\u0BC1\u0BAE\u0BCD \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0BAA\u0B9F\u0BBF\u0BA4\u0BCD\u0BA4\u0BC1\u0BB5\u0BBF\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1. \u0B87\u0BA8\u0BCD\u0BA4\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD \u0B89\u0BB3\u0BCD\u0BB3\u0BA4\u0BC1.",
|
|
832
|
+
followUpLast: "\u0B87\u0BA8\u0BCD\u0BA4 \u0B85\u0BAE\u0BB0\u0BCD\u0BB5\u0BBF\u0BB2\u0BCD \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0BAA\u0B9F\u0BBF\u0B95\u0BCD\u0B95\u0B95\u0BCD\u0B95\u0BC2\u0B9F\u0BBF\u0BAF \u0B95\u0B9F\u0BC8\u0B9A\u0BBF \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0B85\u0BA4\u0BC1\u0BA4\u0BBE\u0BA9\u0BCD.",
|
|
833
|
+
followUpLimits: "\u0BA8\u0BC7\u0BB0\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0BA4\u0BB1\u0BCD\u0BAA\u0BCB\u0BA4\u0BC1 \u0B85\u0BA4\u0BA9\u0BCD \u0BB5\u0BB0\u0BAE\u0BCD\u0BAA\u0BC8 \u0B8E\u0B9F\u0BCD\u0B9F\u0BBF\u0BB5\u0BBF\u0B9F\u0BCD\u0B9F\u0BA4\u0BC1. \u0B87\u0BA8\u0BCD\u0BA4\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD \u0B89\u0BB3\u0BCD\u0BB3\u0BA4\u0BC1.",
|
|
834
|
+
followUpPaused: "\u0BA8\u0BC7\u0BB0\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BCD \u0BA4\u0BB1\u0BCD\u0BAA\u0BCB\u0BA4\u0BC1 \u0B87\u0B9F\u0BC8\u0BA8\u0BBF\u0BB1\u0BC1\u0BA4\u0BCD\u0BA4\u0BAA\u0BCD\u0BAA\u0B9F\u0BCD\u0B9F\u0BC1\u0BB3\u0BCD\u0BB3\u0BA4\u0BC1. \u0B87\u0BA8\u0BCD\u0BA4\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BCD \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD \u0B89\u0BB3\u0BCD\u0BB3\u0BA4\u0BC1.",
|
|
835
|
+
followUpUnread: "\u0B85\u0BA8\u0BCD\u0BA4\u0BAA\u0BCD \u0BAA\u0BA4\u0BBF\u0BB2\u0BC8 \u0B85\u0BB5\u0BA4\u0BBE\u0BB0\u0BBE\u0BB2\u0BCD \u0BAA\u0B9F\u0BBF\u0B95\u0BCD\u0B95 \u0BAE\u0BC1\u0B9F\u0BBF\u0BAF\u0BB5\u0BBF\u0BB2\u0BCD\u0BB2\u0BC8. \u0B85\u0BA4\u0BC1 \u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0BAF\u0BBF\u0BB2\u0BCD \u0B89\u0BB3\u0BCD\u0BB3\u0BA4\u0BC1."
|
|
675
836
|
};
|
|
676
837
|
var STRINGS = {
|
|
677
838
|
en: EN,
|
|
@@ -821,6 +982,46 @@ var CONSENT = /* @__PURE__ */ new Map([
|
|
|
821
982
|
questions: "any"
|
|
822
983
|
}
|
|
823
984
|
}
|
|
985
|
+
],
|
|
986
|
+
[
|
|
987
|
+
// Stage D (BOFF-9797), a DRAFT for the operator's review that no environment uses yet (global-speech-svc reserves the
|
|
988
|
+
// same two versions): web-consent-2026-11-12-b with only its intro changed. The avatar reads the answer to each
|
|
989
|
+
// question asked in the Avatar tab, in one session, waits about thirty seconds after an answer for the next question,
|
|
990
|
+
// then ends; the session lasts at most three minutes, and an answer that does not fit the time left is read in part
|
|
991
|
+
// (and said so) or not read, and stays in Chat. The notice files of record and their digests are a gitops change of
|
|
992
|
+
// their own, made with the review.
|
|
993
|
+
"web-consent-2026-11-19-d",
|
|
994
|
+
{
|
|
995
|
+
en: {
|
|
996
|
+
title: "Live AI avatar (beta)",
|
|
997
|
+
introProduct: null,
|
|
998
|
+
intro: "This is an AI avatar, not a real person. It reads aloud the answers to the questions you ask in the Avatar tab, provided each passes the speech checks. After an answer, it waits about thirty seconds for your next question, then ends. A session lasts at most three minutes; if an answer doesn't fit in the time left, it reads only the first part and says so, or doesn't read it, and the full answer stays in Chat. The answers are AI-generated and can be wrong. Don't put personal details in a question you type.",
|
|
999
|
+
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.",
|
|
1000
|
+
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.",
|
|
1001
|
+
privacyLink: "How we handle this",
|
|
1002
|
+
botCheck: "turnstile",
|
|
1003
|
+
questions: "any",
|
|
1004
|
+
followUps: true
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
],
|
|
1008
|
+
[
|
|
1009
|
+
// The words of web-consent-2026-11-19-d without "When you start, Cloudflare checks for bots.", for a server that runs
|
|
1010
|
+
// no bot check. A DRAFT, like it.
|
|
1011
|
+
"web-consent-2026-11-20-d",
|
|
1012
|
+
{
|
|
1013
|
+
en: {
|
|
1014
|
+
title: "Live AI avatar (beta)",
|
|
1015
|
+
introProduct: null,
|
|
1016
|
+
intro: "This is an AI avatar, not a real person. It reads aloud the answers to the questions you ask in the Avatar tab, provided each passes the speech checks. After an answer, it waits about thirty seconds for your next question, then ends. A session lasts at most three minutes; if an answer doesn't fit in the time left, it reads only the first part and says so, or doesn't read it, and the full answer stays in Chat. The answers are AI-generated and can be wrong. Don't put personal details in a question you type.",
|
|
1017
|
+
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.",
|
|
1018
|
+
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.",
|
|
1019
|
+
privacyLink: "How we handle this",
|
|
1020
|
+
botCheck: "off",
|
|
1021
|
+
questions: "any",
|
|
1022
|
+
followUps: true
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
824
1025
|
]
|
|
825
1026
|
]);
|
|
826
1027
|
function avatarConsentCopy(version, locale) {
|
|
@@ -911,7 +1112,8 @@ function useAvatarMic({
|
|
|
911
1112
|
base,
|
|
912
1113
|
offer,
|
|
913
1114
|
refreshOffer,
|
|
914
|
-
onText
|
|
1115
|
+
onText,
|
|
1116
|
+
onStart
|
|
915
1117
|
}) {
|
|
916
1118
|
const S = avatarMicStrings(locale);
|
|
917
1119
|
const copy = avatarMicNotice(AVATAR_MIC_NOTICE_VERSION, locale);
|
|
@@ -933,8 +1135,8 @@ function useAvatarMic({
|
|
|
933
1135
|
const buttonRef = useRef(null);
|
|
934
1136
|
const allowRef = useRef(null);
|
|
935
1137
|
const usedEpochRef = useRef(0);
|
|
936
|
-
const latest = useRef({ offer, refreshOffer, onText, base });
|
|
937
|
-
latest.current = { offer, refreshOffer, onText, base };
|
|
1138
|
+
const latest = useRef({ offer, refreshOffer, onText, onStart, base });
|
|
1139
|
+
latest.current = { offer, refreshOffer, onText, onStart, base };
|
|
938
1140
|
const cancel = useCallback(() => {
|
|
939
1141
|
seqRef.current += 1;
|
|
940
1142
|
setLoading(false);
|
|
@@ -997,6 +1199,7 @@ function useAvatarMic({
|
|
|
997
1199
|
cancel();
|
|
998
1200
|
return;
|
|
999
1201
|
}
|
|
1202
|
+
latest.current.onStart?.();
|
|
1000
1203
|
if (!agreedRef.current) {
|
|
1001
1204
|
setNoticeOpen(true);
|
|
1002
1205
|
void loadAvatarMic().catch(() => void 0);
|
|
@@ -1033,7 +1236,13 @@ function useAvatarMic({
|
|
|
1033
1236
|
}
|
|
1034
1237
|
}, [state]);
|
|
1035
1238
|
if (!possible || S === null || copy === null) {
|
|
1036
|
-
return {
|
|
1239
|
+
return {
|
|
1240
|
+
button: null,
|
|
1241
|
+
notice: null,
|
|
1242
|
+
lines: null,
|
|
1243
|
+
cancel,
|
|
1244
|
+
recording: false
|
|
1245
|
+
};
|
|
1037
1246
|
}
|
|
1038
1247
|
const status = withdrawn !== null ? S[FAILURE_TEXT[withdrawn]] : loading2 ? S.micStarting : loadFailed ? S.micFailed : state.name === "starting" ? S.micStarting : state.name === "listening" ? S.micListening : state.name === "finishing" ? S.micFinishing : state.name === "done" ? state.text === "" ? S.micNoSpeech : state.limit ? S.micDoneLimit : S.micDone : state.name === "failed" ? S[FAILURE_TEXT[state.reason]] : "";
|
|
1039
1248
|
const heard = offered && (state.name === "listening" || state.name === "finishing") ? state.text : "";
|
|
@@ -1137,7 +1346,13 @@ function useAvatarMic({
|
|
|
1137
1346
|
}
|
|
1138
1347
|
)
|
|
1139
1348
|
] });
|
|
1140
|
-
return {
|
|
1349
|
+
return {
|
|
1350
|
+
button,
|
|
1351
|
+
notice,
|
|
1352
|
+
lines,
|
|
1353
|
+
cancel,
|
|
1354
|
+
recording: offered && state.name === "listening"
|
|
1355
|
+
};
|
|
1141
1356
|
}
|
|
1142
1357
|
|
|
1143
1358
|
// src/components/explore-avatar-turnstile.ts
|
|
@@ -1260,6 +1475,12 @@ var END_GRACE_MS = 1e4;
|
|
|
1260
1475
|
var CLOCK_TOLERANCE_MS = 5e3;
|
|
1261
1476
|
var UNHEARD_GRACE_MS = 5e3;
|
|
1262
1477
|
var PLAYOUT_TAIL_MS = 5e3;
|
|
1478
|
+
var QUIET_PLAYED_OUT_MS = 2500;
|
|
1479
|
+
var OWED_VOICE_WAIT_MS = 15e3;
|
|
1480
|
+
var LISTENING_MARK_MS = 1e4;
|
|
1481
|
+
var BUSY_RETRY_MS = 2e3;
|
|
1482
|
+
var BUSY_RETRY_MAX_MS = 8e3;
|
|
1483
|
+
var MAX_BUSY_RETRIES = 24;
|
|
1263
1484
|
var SERVICE_MAX_AGE_MS = 15 * 6e4;
|
|
1264
1485
|
var ANSWER_OFFER_MS = SERVICE_MAX_AGE_MS - 6e4;
|
|
1265
1486
|
var MAX_TIMER_MS = 2147483647;
|
|
@@ -1274,6 +1495,12 @@ function stopAttending(handle) {
|
|
|
1274
1495
|
if (handle.tail !== null) clearTimeout(handle.tail);
|
|
1275
1496
|
handle.unheard = null;
|
|
1276
1497
|
handle.tail = null;
|
|
1498
|
+
const run = handle.followUps;
|
|
1499
|
+
if (run === null) return;
|
|
1500
|
+
if (run.quiet !== null) clearTimeout(run.quiet);
|
|
1501
|
+
if (run.retry !== null) clearTimeout(run.retry);
|
|
1502
|
+
run.quiet = null;
|
|
1503
|
+
run.retry = null;
|
|
1277
1504
|
}
|
|
1278
1505
|
var REFUSAL_TEXT = {
|
|
1279
1506
|
busy: "busy",
|
|
@@ -1284,6 +1511,18 @@ var REFUSAL_TEXT = {
|
|
|
1284
1511
|
not_eligible: "notEligible",
|
|
1285
1512
|
answer_claimed: "answerClaimed"
|
|
1286
1513
|
};
|
|
1514
|
+
var FOLLOW_UP_TEXT = {
|
|
1515
|
+
no_time: "followUpNoTime",
|
|
1516
|
+
max_answers: "followUpMaxAnswers",
|
|
1517
|
+
// The same line as a first answer the checks refuse: it stays in Chat as text.
|
|
1518
|
+
not_eligible: "notSpoken",
|
|
1519
|
+
answer_claimed: "answerClaimed",
|
|
1520
|
+
limits: "followUpLimits",
|
|
1521
|
+
paused: "followUpPaused",
|
|
1522
|
+
busy: "followUpUnread",
|
|
1523
|
+
answer_failed: "answerFailed",
|
|
1524
|
+
failed: "followUpUnread"
|
|
1525
|
+
};
|
|
1287
1526
|
var EMPTY = {
|
|
1288
1527
|
kind: "empty",
|
|
1289
1528
|
answerId: null,
|
|
@@ -1358,7 +1597,11 @@ function inFlight(conversation) {
|
|
|
1358
1597
|
return conversation?.phase === "sending" || conversation?.phase === "streaming";
|
|
1359
1598
|
}
|
|
1360
1599
|
function acceptsQuestion(slot) {
|
|
1361
|
-
|
|
1600
|
+
if (!slot.any || slot.textMode || slot.reason !== null) return false;
|
|
1601
|
+
return slot.phase === "needs-answer" ? slot.kind === "empty" : slot.phase === "live" && slot.followUp;
|
|
1602
|
+
}
|
|
1603
|
+
function followUpBox(phase, run, token) {
|
|
1604
|
+
return phase.name === "live" && run !== null && phase.session.followUp !== null && !phase.session.followUp.closed && token === run.token;
|
|
1362
1605
|
}
|
|
1363
1606
|
function micOfferOf(result) {
|
|
1364
1607
|
return result.kind === "available" && result.offer.stt !== void 0 ? { ...result.offer.stt, receivedAt: Date.now() } : null;
|
|
@@ -1513,6 +1756,7 @@ function AvatarLiveView({
|
|
|
1513
1756
|
const textBoxRef = useRef(false);
|
|
1514
1757
|
const [micOffer, setMicOffer] = useState(null);
|
|
1515
1758
|
const micCancelRef = useRef(() => void 0);
|
|
1759
|
+
const sendDueRef = useRef(() => void 0);
|
|
1516
1760
|
const checkRef = useRef(null);
|
|
1517
1761
|
const askedLocale = useRef(locale);
|
|
1518
1762
|
const startRef = useRef(null);
|
|
@@ -1601,10 +1845,13 @@ function AvatarLiveView({
|
|
|
1601
1845
|
if (!handle || handle.done || latest.current.live.endUnattended !== true) {
|
|
1602
1846
|
return;
|
|
1603
1847
|
}
|
|
1604
|
-
const
|
|
1605
|
-
if (
|
|
1848
|
+
const shown2 = phaseRef.current;
|
|
1849
|
+
if (shown2.name !== "pending" && shown2.name !== "live") return;
|
|
1850
|
+
const current = shown2.name;
|
|
1606
1851
|
const away = !inSight();
|
|
1607
|
-
|
|
1852
|
+
const followUp2 = shown2.session.followUp;
|
|
1853
|
+
const asking = followUp2 !== null && followUp2.pending !== null;
|
|
1854
|
+
if (away && handle.playedOut && current === "live" && !asking) {
|
|
1608
1855
|
finish("finished", "user");
|
|
1609
1856
|
return;
|
|
1610
1857
|
}
|
|
@@ -1623,6 +1870,184 @@ function AvatarLiveView({
|
|
|
1623
1870
|
}
|
|
1624
1871
|
}, UNHEARD_GRACE_MS);
|
|
1625
1872
|
}, [finish, inSight]);
|
|
1873
|
+
const showFollowUp = useCallback(
|
|
1874
|
+
(handle, next, spoken) => {
|
|
1875
|
+
const current = phaseRef.current;
|
|
1876
|
+
if (sessionRef.current !== handle || handle.done || current.name !== "pending" && current.name !== "live" || current.session.followUp === null) {
|
|
1877
|
+
return;
|
|
1878
|
+
}
|
|
1879
|
+
const session = {
|
|
1880
|
+
...current.session,
|
|
1881
|
+
...spoken,
|
|
1882
|
+
followUp: { ...current.session.followUp, ...next }
|
|
1883
|
+
};
|
|
1884
|
+
go(
|
|
1885
|
+
current.name === "live" ? { name: "live", session } : { name: "pending", session }
|
|
1886
|
+
);
|
|
1887
|
+
},
|
|
1888
|
+
[go]
|
|
1889
|
+
);
|
|
1890
|
+
const tell = useCallback(
|
|
1891
|
+
(handle, kind2) => {
|
|
1892
|
+
if (handle.done || handle.followUps === null) return;
|
|
1893
|
+
void requestTurn({
|
|
1894
|
+
base: handle.base,
|
|
1895
|
+
headers: handle.headers,
|
|
1896
|
+
sessionId: handle.session.sessionId,
|
|
1897
|
+
secret: handle.session.endSecret,
|
|
1898
|
+
kind: kind2
|
|
1899
|
+
});
|
|
1900
|
+
},
|
|
1901
|
+
[]
|
|
1902
|
+
);
|
|
1903
|
+
const whenQuiet = useCallback(
|
|
1904
|
+
(handle, delay) => {
|
|
1905
|
+
const run = handle.followUps;
|
|
1906
|
+
if (run === null) return;
|
|
1907
|
+
const wait = (ms) => {
|
|
1908
|
+
if (run.quiet !== null) clearTimeout(run.quiet);
|
|
1909
|
+
run.quiet = setTimeout(() => {
|
|
1910
|
+
run.quiet = null;
|
|
1911
|
+
if (sessionRef.current !== handle || handle.done || run.voice) {
|
|
1912
|
+
return;
|
|
1913
|
+
}
|
|
1914
|
+
if (run.owed) {
|
|
1915
|
+
run.owed = false;
|
|
1916
|
+
wait(OWED_VOICE_WAIT_MS);
|
|
1917
|
+
return;
|
|
1918
|
+
}
|
|
1919
|
+
handle.playedOut = true;
|
|
1920
|
+
showFollowUp(handle, { speaking: false });
|
|
1921
|
+
attend();
|
|
1922
|
+
sendDueRef.current(handle);
|
|
1923
|
+
}, ms);
|
|
1924
|
+
};
|
|
1925
|
+
wait(delay);
|
|
1926
|
+
},
|
|
1927
|
+
[attend, showFollowUp]
|
|
1928
|
+
);
|
|
1929
|
+
const heardVoice = useCallback(
|
|
1930
|
+
(handle, speaking) => {
|
|
1931
|
+
const run = handle.followUps;
|
|
1932
|
+
if (run === null) return;
|
|
1933
|
+
run.voice = speaking;
|
|
1934
|
+
if (!speaking) {
|
|
1935
|
+
whenQuiet(handle, QUIET_PLAYED_OUT_MS);
|
|
1936
|
+
return;
|
|
1937
|
+
}
|
|
1938
|
+
if (run.quiet !== null) clearTimeout(run.quiet);
|
|
1939
|
+
run.quiet = null;
|
|
1940
|
+
run.heard = true;
|
|
1941
|
+
run.starts += 1;
|
|
1942
|
+
run.owed = false;
|
|
1943
|
+
handle.playedOut = false;
|
|
1944
|
+
showFollowUp(handle, { speaking: true });
|
|
1945
|
+
},
|
|
1946
|
+
[showFollowUp, whenQuiet]
|
|
1947
|
+
);
|
|
1948
|
+
const sendDue = useCallback(
|
|
1949
|
+
(handle) => {
|
|
1950
|
+
const run = handle.followUps;
|
|
1951
|
+
const due = run?.due ?? null;
|
|
1952
|
+
if (run === null || due === null || due.sending || run.retry !== null || handle.done || sessionRef.current !== handle || run.heard && !handle.playedOut) {
|
|
1953
|
+
return;
|
|
1954
|
+
}
|
|
1955
|
+
due.sending = true;
|
|
1956
|
+
const starts = run.starts;
|
|
1957
|
+
const read = () => requestTurn({
|
|
1958
|
+
base: handle.base,
|
|
1959
|
+
headers: handle.headers,
|
|
1960
|
+
sessionId: handle.session.sessionId,
|
|
1961
|
+
secret: handle.session.endSecret,
|
|
1962
|
+
kind: "answer",
|
|
1963
|
+
messageId: due.messageId,
|
|
1964
|
+
idempotencyKey: due.idempotencyKey
|
|
1965
|
+
});
|
|
1966
|
+
const notRead = (unread, closed) => {
|
|
1967
|
+
run.due = null;
|
|
1968
|
+
showFollowUp(handle, {
|
|
1969
|
+
pending: null,
|
|
1970
|
+
unread: due.known ?? unread,
|
|
1971
|
+
...closed ? { closed } : {}
|
|
1972
|
+
});
|
|
1973
|
+
attend();
|
|
1974
|
+
};
|
|
1975
|
+
void (async () => {
|
|
1976
|
+
let result = await read();
|
|
1977
|
+
if (result.kind === "failed" && result.lost && !handle.done) {
|
|
1978
|
+
result = await read();
|
|
1979
|
+
}
|
|
1980
|
+
due.sending = false;
|
|
1981
|
+
if (sessionRef.current !== handle || handle.done || run.due !== due) {
|
|
1982
|
+
return;
|
|
1983
|
+
}
|
|
1984
|
+
if (result.kind === "refused" && result.reason === "busy" && due.busy < MAX_BUSY_RETRIES) {
|
|
1985
|
+
due.busy += 1;
|
|
1986
|
+
if (run.heard && !handle.playedOut) return;
|
|
1987
|
+
const delay = Math.max(
|
|
1988
|
+
result.retryAfterSeconds === void 0 ? BUSY_RETRY_MS : result.retryAfterSeconds * 1e3,
|
|
1989
|
+
Math.min(BUSY_RETRY_MAX_MS, BUSY_RETRY_MS * 2 ** (due.busy - 1))
|
|
1990
|
+
);
|
|
1991
|
+
if (Date.now() + delay >= handle.endsAt) {
|
|
1992
|
+
notRead("no_time", false);
|
|
1993
|
+
return;
|
|
1994
|
+
}
|
|
1995
|
+
run.retry = setTimeout(() => {
|
|
1996
|
+
run.retry = null;
|
|
1997
|
+
sendDueRef.current(handle);
|
|
1998
|
+
}, delay);
|
|
1999
|
+
return;
|
|
2000
|
+
}
|
|
2001
|
+
if (result.kind !== "accepted") {
|
|
2002
|
+
notRead(
|
|
2003
|
+
result.kind === "refused" ? result.reason : "failed",
|
|
2004
|
+
result.kind === "gone" || result.kind === "refused" && result.reason === "max_answers"
|
|
2005
|
+
);
|
|
2006
|
+
return;
|
|
2007
|
+
}
|
|
2008
|
+
run.due = null;
|
|
2009
|
+
run.answers += 1;
|
|
2010
|
+
const heardSince = run.starts !== starts;
|
|
2011
|
+
run.owed = !heardSince;
|
|
2012
|
+
const playing = !heardSince || run.voice || run.quiet !== null;
|
|
2013
|
+
if (playing) handle.playedOut = false;
|
|
2014
|
+
showFollowUp(
|
|
2015
|
+
handle,
|
|
2016
|
+
{
|
|
2017
|
+
speaking: playing,
|
|
2018
|
+
pending: null,
|
|
2019
|
+
unread: null,
|
|
2020
|
+
closed: run.answers >= run.limits.maxAnswers
|
|
2021
|
+
},
|
|
2022
|
+
{ captions: result.captions, excerpt: result.excerpt }
|
|
2023
|
+
);
|
|
2024
|
+
if (!playing) {
|
|
2025
|
+
attend();
|
|
2026
|
+
return;
|
|
2027
|
+
}
|
|
2028
|
+
if (run.owed && run.heard && !run.voice) whenQuiet(handle, 0);
|
|
2029
|
+
})();
|
|
2030
|
+
},
|
|
2031
|
+
[attend, showFollowUp, whenQuiet]
|
|
2032
|
+
);
|
|
2033
|
+
sendDueRef.current = sendDue;
|
|
2034
|
+
const readFollowUp = useCallback(
|
|
2035
|
+
(handle, messageId, known) => {
|
|
2036
|
+
const run = handle.followUps;
|
|
2037
|
+
if (run === null) return;
|
|
2038
|
+
run.sent.add(messageId);
|
|
2039
|
+
const idempotencyKey = newIdempotencyKey();
|
|
2040
|
+
if (idempotencyKey === null) {
|
|
2041
|
+
showFollowUp(handle, { pending: null, unread: known ?? "failed" });
|
|
2042
|
+
attend();
|
|
2043
|
+
return;
|
|
2044
|
+
}
|
|
2045
|
+
run.due = { messageId, idempotencyKey, known, busy: 0, sending: false };
|
|
2046
|
+
showFollowUp(handle, { pending: "reading", unread: null });
|
|
2047
|
+
sendDue(handle);
|
|
2048
|
+
},
|
|
2049
|
+
[attend, sendDue, showFollowUp]
|
|
2050
|
+
);
|
|
1626
2051
|
const cancelStart = useCallback((reason) => {
|
|
1627
2052
|
const run = startRef.current;
|
|
1628
2053
|
if (!run) return;
|
|
@@ -1686,16 +2111,32 @@ function AvatarLiveView({
|
|
|
1686
2111
|
});
|
|
1687
2112
|
}, [applyAvailability, go]);
|
|
1688
2113
|
const begin = useCallback(
|
|
1689
|
-
(session,
|
|
2114
|
+
(session, context) => {
|
|
2115
|
+
const { offer } = context;
|
|
1690
2116
|
const received = Date.now();
|
|
1691
2117
|
const longest = offer.maxSessionSeconds * 1e3;
|
|
1692
2118
|
const ahead = session.endsAt - received;
|
|
1693
2119
|
const endsAt = ahead > 0 && ahead <= longest + CLOCK_TOLERANCE_MS ? session.endsAt : received + longest;
|
|
2120
|
+
const followUps = session.followUps !== void 0 && offer.copy.followUps === true && offer.questions === "any" ? {
|
|
2121
|
+
limits: session.followUps,
|
|
2122
|
+
token: context.conversationToken,
|
|
2123
|
+
answers: 1,
|
|
2124
|
+
voice: false,
|
|
2125
|
+
heard: false,
|
|
2126
|
+
starts: 0,
|
|
2127
|
+
owed: true,
|
|
2128
|
+
quiet: null,
|
|
2129
|
+
asked: null,
|
|
2130
|
+
due: null,
|
|
2131
|
+
retry: null,
|
|
2132
|
+
sent: /* @__PURE__ */ new Set([context.messageId]),
|
|
2133
|
+
seq: 0
|
|
2134
|
+
} : null;
|
|
1694
2135
|
sessionRef.current = {
|
|
1695
2136
|
session,
|
|
1696
|
-
base:
|
|
1697
|
-
headers:
|
|
1698
|
-
module,
|
|
2137
|
+
base: context.base,
|
|
2138
|
+
headers: context.headers,
|
|
2139
|
+
module: context.module,
|
|
1699
2140
|
room: null,
|
|
1700
2141
|
joined: null,
|
|
1701
2142
|
endsAt,
|
|
@@ -1705,6 +2146,7 @@ function AvatarLiveView({
|
|
|
1705
2146
|
playedOut: false,
|
|
1706
2147
|
unheard: null,
|
|
1707
2148
|
tail: null,
|
|
2149
|
+
followUps,
|
|
1708
2150
|
done: false
|
|
1709
2151
|
};
|
|
1710
2152
|
setBlocked(false);
|
|
@@ -1714,7 +2156,13 @@ function AvatarLiveView({
|
|
|
1714
2156
|
session: {
|
|
1715
2157
|
endsAt,
|
|
1716
2158
|
captions: session.captions,
|
|
1717
|
-
excerpt: session.excerpt
|
|
2159
|
+
excerpt: session.excerpt,
|
|
2160
|
+
followUp: followUps === null ? null : {
|
|
2161
|
+
speaking: true,
|
|
2162
|
+
pending: null,
|
|
2163
|
+
unread: null,
|
|
2164
|
+
closed: followUps.answers >= followUps.limits.maxAnswers
|
|
2165
|
+
}
|
|
1718
2166
|
}
|
|
1719
2167
|
});
|
|
1720
2168
|
},
|
|
@@ -1746,7 +2194,7 @@ function AvatarLiveView({
|
|
|
1746
2194
|
}
|
|
1747
2195
|
switch (result.kind) {
|
|
1748
2196
|
case "created":
|
|
1749
|
-
begin(result.session, context
|
|
2197
|
+
begin(result.session, context);
|
|
1750
2198
|
return;
|
|
1751
2199
|
case "unusable":
|
|
1752
2200
|
sendEnd({
|
|
@@ -1844,7 +2292,14 @@ function AvatarLiveView({
|
|
|
1844
2292
|
return;
|
|
1845
2293
|
}
|
|
1846
2294
|
if (turnstile !== null) go({ name: "creating" });
|
|
1847
|
-
const context = {
|
|
2295
|
+
const context = {
|
|
2296
|
+
module: loaded,
|
|
2297
|
+
offer,
|
|
2298
|
+
messageId,
|
|
2299
|
+
conversationToken,
|
|
2300
|
+
base: base2,
|
|
2301
|
+
headers: headers2
|
|
2302
|
+
};
|
|
1848
2303
|
const result = await requestCreate({
|
|
1849
2304
|
base: base2,
|
|
1850
2305
|
headers: headers2,
|
|
@@ -2149,6 +2604,9 @@ function AvatarLiveView({
|
|
|
2149
2604
|
attend();
|
|
2150
2605
|
}, PLAYOUT_TAIL_MS);
|
|
2151
2606
|
return;
|
|
2607
|
+
case "speaking":
|
|
2608
|
+
heardVoice(handle, event.speaking);
|
|
2609
|
+
return;
|
|
2152
2610
|
case "speaker-left":
|
|
2153
2611
|
finish(
|
|
2154
2612
|
wasLive ? "finished" : "failed",
|
|
@@ -2161,7 +2619,7 @@ function AvatarLiveView({
|
|
|
2161
2619
|
return;
|
|
2162
2620
|
}
|
|
2163
2621
|
},
|
|
2164
|
-
[attend, finish, goLive, inSight]
|
|
2622
|
+
[attend, finish, goLive, heardVoice, inSight]
|
|
2165
2623
|
);
|
|
2166
2624
|
useEffect(() => {
|
|
2167
2625
|
if (phase.name !== "pending") return;
|
|
@@ -2297,7 +2755,13 @@ function AvatarLiveView({
|
|
|
2297
2755
|
const textMode = any && (usedToday && (phase.name === "needs-answer" || phase.name === "consent" || phase.name === "declined" || phase.name === "ended") || phase.name === "refused" && phase.reason === "limits");
|
|
2298
2756
|
textBoxRef.current = textMode;
|
|
2299
2757
|
const askState = !any ? void 0 : textMode ? "text" : phase.name === "needs-answer" ? kind === "empty" ? "ready" : kind : phase.name;
|
|
2300
|
-
const
|
|
2758
|
+
const followUp = phase.name === "live" ? phase.session.followUp : null;
|
|
2759
|
+
const followUpAsks = followUpBox(
|
|
2760
|
+
phase,
|
|
2761
|
+
sessionRef.current?.followUps ?? null,
|
|
2762
|
+
token
|
|
2763
|
+
);
|
|
2764
|
+
const askReason = inFlight(conversation) || followUp !== null && followUp.pending !== null ? S.askBusy : conversation?.canSend ? null : S.askUnavailable;
|
|
2301
2765
|
const refreshMicOffer = useCallback(async () => {
|
|
2302
2766
|
const { live: live2, locale: locale2, base: base2, headers: headers2 } = latest.current;
|
|
2303
2767
|
if (base2 === null) return null;
|
|
@@ -2322,21 +2786,54 @@ function AvatarLiveView({
|
|
|
2322
2786
|
},
|
|
2323
2787
|
[askMaxLength, touchFirst]
|
|
2324
2788
|
);
|
|
2789
|
+
const onMicStart = useCallback(() => {
|
|
2790
|
+
const handle = sessionRef.current;
|
|
2791
|
+
const current = phaseRef.current;
|
|
2792
|
+
if (handle === null || handle.followUps === null || handle.done || current.name !== "live" || current.session.followUp?.speaking !== true) {
|
|
2793
|
+
return;
|
|
2794
|
+
}
|
|
2795
|
+
const run = handle.followUps;
|
|
2796
|
+
tell(handle, "interrupt");
|
|
2797
|
+
if (run.quiet !== null) clearTimeout(run.quiet);
|
|
2798
|
+
run.quiet = null;
|
|
2799
|
+
run.owed = false;
|
|
2800
|
+
handle.playedOut = true;
|
|
2801
|
+
showFollowUp(handle, { speaking: false });
|
|
2802
|
+
}, [showFollowUp, tell]);
|
|
2325
2803
|
const mic = useAvatarMic({
|
|
2326
2804
|
enabled: live.mic === true && micOffer !== null && !off && acceptsQuestion({
|
|
2327
2805
|
any,
|
|
2328
2806
|
phase: phase.name,
|
|
2329
2807
|
kind,
|
|
2330
2808
|
textMode,
|
|
2331
|
-
reason: askReason
|
|
2809
|
+
reason: askReason,
|
|
2810
|
+
followUp: followUpAsks
|
|
2332
2811
|
}),
|
|
2333
2812
|
locale,
|
|
2334
2813
|
base,
|
|
2335
2814
|
offer: micOffer,
|
|
2336
2815
|
refreshOffer: refreshMicOffer,
|
|
2337
|
-
onText: onMicText
|
|
2816
|
+
onText: onMicText,
|
|
2817
|
+
onStart: onMicStart
|
|
2338
2818
|
});
|
|
2339
2819
|
micCancelRef.current = mic.cancel;
|
|
2820
|
+
const micRecording = mic.recording;
|
|
2821
|
+
useEffect(() => {
|
|
2822
|
+
const handle = sessionRef.current;
|
|
2823
|
+
if (!micRecording || handle === null || handle.followUps === null || handle.done) {
|
|
2824
|
+
return;
|
|
2825
|
+
}
|
|
2826
|
+
tell(handle, "listening");
|
|
2827
|
+
const every = Math.min(
|
|
2828
|
+
LISTENING_MARK_MS,
|
|
2829
|
+
Math.max(1e3, handle.followUps.limits.idleSeconds * 1e3 / 3)
|
|
2830
|
+
);
|
|
2831
|
+
const timer = setInterval(() => tell(handle, "listening"), every);
|
|
2832
|
+
return () => {
|
|
2833
|
+
clearInterval(timer);
|
|
2834
|
+
if (sessionRef.current === handle) tell(handle, "listening");
|
|
2835
|
+
};
|
|
2836
|
+
}, [micRecording, tell]);
|
|
2340
2837
|
const notNow = useCallback(() => {
|
|
2341
2838
|
const current = phaseRef.current;
|
|
2342
2839
|
if ((current.name === "consent" || current.name === "needs-answer") && current.offer.questions === "any") {
|
|
@@ -2345,6 +2842,43 @@ function AvatarLiveView({
|
|
|
2345
2842
|
}
|
|
2346
2843
|
onContinueInChat();
|
|
2347
2844
|
}, [go, onContinueInChat]);
|
|
2845
|
+
const askFollowUp = useCallback(
|
|
2846
|
+
(handle, conversation2, question) => {
|
|
2847
|
+
const run = handle.followUps;
|
|
2848
|
+
const current = phaseRef.current;
|
|
2849
|
+
if (run === null || handle.done || current.name !== "live" || current.session.followUp?.pending !== null || !followUpBox(current, run, conversation2.getConversationToken())) {
|
|
2850
|
+
return;
|
|
2851
|
+
}
|
|
2852
|
+
sendingRef.current = true;
|
|
2853
|
+
run.seq += 1;
|
|
2854
|
+
const seq = run.seq;
|
|
2855
|
+
setDraft("");
|
|
2856
|
+
tell(handle, "asking");
|
|
2857
|
+
showFollowUp(handle, { pending: "asking", unread: null });
|
|
2858
|
+
void conversation2.send(question, [], { surface: "AVATAR" }).then((added) => {
|
|
2859
|
+
if (added === null) {
|
|
2860
|
+
setDraft((current2) => current2 === "" ? question : current2);
|
|
2861
|
+
}
|
|
2862
|
+
if (sessionRef.current !== handle || handle.done || run.seq !== seq) {
|
|
2863
|
+
return;
|
|
2864
|
+
}
|
|
2865
|
+
if (added === null || added.conversationToken !== run.token) {
|
|
2866
|
+
showFollowUp(handle, { pending: null });
|
|
2867
|
+
attend();
|
|
2868
|
+
return;
|
|
2869
|
+
}
|
|
2870
|
+
run.asked = {
|
|
2871
|
+
messageId: added.userMessageId,
|
|
2872
|
+
token: added.conversationToken,
|
|
2873
|
+
answerId: null
|
|
2874
|
+
};
|
|
2875
|
+
showFollowUp(handle, { pending: "asking" });
|
|
2876
|
+
}).finally(() => {
|
|
2877
|
+
sendingRef.current = false;
|
|
2878
|
+
});
|
|
2879
|
+
},
|
|
2880
|
+
[attend, showFollowUp, tell]
|
|
2881
|
+
);
|
|
2348
2882
|
const ask = useCallback(
|
|
2349
2883
|
(text) => {
|
|
2350
2884
|
const conversation2 = conversationRef.current;
|
|
@@ -2353,6 +2887,11 @@ function AvatarLiveView({
|
|
|
2353
2887
|
return;
|
|
2354
2888
|
}
|
|
2355
2889
|
const spoken = !textBoxRef.current;
|
|
2890
|
+
const handle = sessionRef.current;
|
|
2891
|
+
if (spoken && handle !== null && handle.followUps !== null) {
|
|
2892
|
+
askFollowUp(handle, conversation2, question);
|
|
2893
|
+
return;
|
|
2894
|
+
}
|
|
2356
2895
|
if (spoken && conversation2.messages.length > 0) return;
|
|
2357
2896
|
sendingRef.current = true;
|
|
2358
2897
|
setAskedHere(null);
|
|
@@ -2374,8 +2913,64 @@ function AvatarLiveView({
|
|
|
2374
2913
|
sendingRef.current = false;
|
|
2375
2914
|
});
|
|
2376
2915
|
},
|
|
2377
|
-
[setAskedHere]
|
|
2916
|
+
[askFollowUp, setAskedHere]
|
|
2378
2917
|
);
|
|
2918
|
+
useEffect(() => {
|
|
2919
|
+
const handle = sessionRef.current;
|
|
2920
|
+
const run = handle?.followUps ?? null;
|
|
2921
|
+
if (handle === null || run === null || handle.done || run.asked === null) {
|
|
2922
|
+
return;
|
|
2923
|
+
}
|
|
2924
|
+
const asked = run.asked;
|
|
2925
|
+
const chat = conversationRef.current;
|
|
2926
|
+
const messages = chat?.messages ?? [];
|
|
2927
|
+
const at = messages.findIndex((message) => message.id === asked.messageId);
|
|
2928
|
+
const question = at === -1 ? void 0 : messages[at];
|
|
2929
|
+
const answer = at === -1 ? void 0 : messages[at + 1];
|
|
2930
|
+
const drop = (unread2) => {
|
|
2931
|
+
run.asked = null;
|
|
2932
|
+
showFollowUp(handle, { pending: null, unread: unread2 });
|
|
2933
|
+
attend();
|
|
2934
|
+
};
|
|
2935
|
+
const unread = (id, reason) => {
|
|
2936
|
+
if (id === null || run.sent.has(id) || !isAvatarMessageId(id)) {
|
|
2937
|
+
drop(reason);
|
|
2938
|
+
return;
|
|
2939
|
+
}
|
|
2940
|
+
run.asked = null;
|
|
2941
|
+
readFollowUp(handle, id, reason);
|
|
2942
|
+
};
|
|
2943
|
+
if (question === void 0 || (chat?.getConversationToken() ?? null) !== run.token) {
|
|
2944
|
+
drop(null);
|
|
2945
|
+
return;
|
|
2946
|
+
}
|
|
2947
|
+
if (answer === void 0) {
|
|
2948
|
+
if (!inFlight(chat)) unread(asked.answerId, "answer_failed");
|
|
2949
|
+
return;
|
|
2950
|
+
}
|
|
2951
|
+
if (answer.status === "PENDING" || answer.status === "RUNNING") {
|
|
2952
|
+
if (answer.role === "ASSISTANT") asked.answerId = answer.id;
|
|
2953
|
+
return;
|
|
2954
|
+
}
|
|
2955
|
+
if (answer.role !== "ASSISTANT") {
|
|
2956
|
+
unread(asked.answerId, "answer_failed");
|
|
2957
|
+
return;
|
|
2958
|
+
}
|
|
2959
|
+
if (answer.status !== "COMPLETED" || answer.content.trim() === "") {
|
|
2960
|
+
unread(answer.id, "answer_failed");
|
|
2961
|
+
return;
|
|
2962
|
+
}
|
|
2963
|
+
if (run.sent.has(answer.id) || !isAvatarMessageId(answer.id)) {
|
|
2964
|
+
drop("not_eligible");
|
|
2965
|
+
return;
|
|
2966
|
+
}
|
|
2967
|
+
if (at + 2 !== messages.length || !readable(question, answer)) {
|
|
2968
|
+
unread(answer.id, "not_eligible");
|
|
2969
|
+
return;
|
|
2970
|
+
}
|
|
2971
|
+
run.asked = null;
|
|
2972
|
+
readFollowUp(handle, answer.id, null);
|
|
2973
|
+
});
|
|
2379
2974
|
const newChatForAvatar = useCallback(() => {
|
|
2380
2975
|
const conversation2 = conversationRef.current;
|
|
2381
2976
|
if (conversation2 === null) return;
|
|
@@ -2399,7 +2994,14 @@ function AvatarLiveView({
|
|
|
2399
2994
|
const focused = document.activeElement;
|
|
2400
2995
|
if (focused && focused !== document.body && focused.isConnected) return;
|
|
2401
2996
|
rootRef.current?.querySelector(PRIMARY)?.focus();
|
|
2402
|
-
}, [
|
|
2997
|
+
}, [
|
|
2998
|
+
active,
|
|
2999
|
+
phase.name,
|
|
3000
|
+
askState,
|
|
3001
|
+
shown.pendingAnswerId,
|
|
3002
|
+
blocked,
|
|
3003
|
+
followUpAsks
|
|
3004
|
+
]);
|
|
2403
3005
|
const onPlaying = goLive;
|
|
2404
3006
|
const enablePlayback = useCallback(() => {
|
|
2405
3007
|
void sessionRef.current?.joined?.enablePlayback().catch(() => void 0);
|
|
@@ -2799,13 +3401,32 @@ function AvatarLiveView({
|
|
|
2799
3401
|
actions2 = stopButton;
|
|
2800
3402
|
break;
|
|
2801
3403
|
case "pending":
|
|
2802
|
-
case "live":
|
|
2803
|
-
status = phase.name === "live" ? speakingLine(phase.session) : S.connecting;
|
|
3404
|
+
case "live": {
|
|
2804
3405
|
top2 = badge;
|
|
2805
3406
|
media2 = liveMedia(phase.name === "live");
|
|
2806
3407
|
body2 = liveBody(phase.session);
|
|
2807
3408
|
actions2 = liveActions(readInChatButton(false));
|
|
3409
|
+
if (followUp === null) {
|
|
3410
|
+
status = phase.name === "live" ? speakingLine(phase.session) : S.connecting;
|
|
3411
|
+
break;
|
|
3412
|
+
}
|
|
3413
|
+
status = followUp.speaking ? speakingLine(phase.session) : followUp.pending !== null ? (followUp.pending === "asking" ? activity : null) ?? S.gettingAnswer : followUp.unread !== null ? S[FOLLOW_UP_TEXT[followUp.unread]] : followUp.closed ? S.followUpLast : S.followUpIdle;
|
|
3414
|
+
if (!followUp.speaking && followUp.pending === null && followUp.unread !== null && !followUp.closed) {
|
|
3415
|
+
body2 = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3416
|
+
body2,
|
|
3417
|
+
/* @__PURE__ */ jsx(
|
|
3418
|
+
"p",
|
|
3419
|
+
{
|
|
3420
|
+
"data-boff-explore": "avatar-live-idle",
|
|
3421
|
+
className: "text-xs text-muted-foreground",
|
|
3422
|
+
children: S.followUpIdle
|
|
3423
|
+
}
|
|
3424
|
+
)
|
|
3425
|
+
] });
|
|
3426
|
+
}
|
|
3427
|
+
if (followUpAsks) box = "spoken";
|
|
2808
3428
|
break;
|
|
3429
|
+
}
|
|
2809
3430
|
case "ended":
|
|
2810
3431
|
status = S[phase.how];
|
|
2811
3432
|
outcome2 = true;
|
|
@@ -2853,7 +3474,7 @@ function AvatarLiveView({
|
|
|
2853
3474
|
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: S.newChatNote })
|
|
2854
3475
|
] }) : null,
|
|
2855
3476
|
chips,
|
|
2856
|
-
box !== null && usedToday ? /* @__PURE__ */ jsx(
|
|
3477
|
+
box !== null && usedToday && phase.name !== "live" ? /* @__PURE__ */ jsx(
|
|
2857
3478
|
"p",
|
|
2858
3479
|
{
|
|
2859
3480
|
"data-boff-explore": "avatar-live-used-today",
|