@burdenoff/website-sdk 2026.1104.2 → 2026.1104.4
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 -4
- package/dist/avatar-live-view/index.js +124 -46
- package/dist/avatar-live-view/index.js.map +1 -1
- package/dist/avatar-live-view/index.mjs +123 -45
- package/dist/avatar-live-view/index.mjs.map +1 -1
- package/dist/{chunk-5JQGE3XI.mjs → chunk-7HE33NBS.mjs} +4 -111
- package/dist/chunk-7HE33NBS.mjs.map +1 -0
- package/dist/chunk-JZS6FQT6.mjs +127 -0
- package/dist/chunk-JZS6FQT6.mjs.map +1 -0
- package/dist/{chunk-22OT6E26.js → chunk-MBVXDFVC.js} +18 -127
- package/dist/chunk-MBVXDFVC.js.map +1 -0
- package/dist/chunk-N7E6Z2GF.js +132 -0
- package/dist/chunk-N7E6Z2GF.js.map +1 -0
- package/dist/components/explore.d.mts +1 -1
- package/dist/components/explore.d.ts +1 -1
- package/dist/components/explore.js +20 -20
- package/dist/components/explore.mjs +2 -2
- package/dist/{explore-BV4dRwoC.d.ts → explore-Dfru4j4m.d.ts} +45 -31
- package/dist/{explore-BgEeGPvY.d.mts → explore-ei8uoko9.d.mts} +45 -31
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +61 -61
- package/dist/index.mjs +4 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-22OT6E26.js.map +0 -1
- package/dist/chunk-5JQGE3XI.mjs.map +0 -1
- package/dist/chunk-O4GS3XPZ.js +0 -10
- package/dist/chunk-O4GS3XPZ.js.map +0 -1
- package/dist/chunk-TT3MHN42.mjs +0 -8
- package/dist/chunk-TT3MHN42.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -387,9 +387,14 @@ publishes audio, video or data, and it sends the avatar nothing to say.
|
|
|
387
387
|
browser's own note of a session today, kept in `localStorage` as
|
|
388
388
|
`boff.explore.avatarUsedOn`), the box asks ordinary questions, without
|
|
389
389
|
`surface`, and the answer shows in the tab as text, with "Read the answer and
|
|
390
|
-
sources in Chat".
|
|
391
|
-
`
|
|
392
|
-
|
|
390
|
+
sources in Chat". The text is the answer's words, not its markdown: the form
|
|
391
|
+
the chat's read-aloud says (`answerSpeechText`), so a link is its label, a
|
|
392
|
+
table its rows, and the marks of emphasis, headings and quotes go, and on
|
|
393
|
+
this screen list markers as well (each item keeps its own line); citation
|
|
394
|
+
markers such as `[1]` stay, as in the chat. Pass `currentPath` to
|
|
395
|
+
`ExplorePanel` (as `SiteAssistantDock` does) so a page change calls off a
|
|
396
|
+
"Start when ready" at once; without it, the window's path is checked before
|
|
397
|
+
the create.
|
|
393
398
|
- **One answer: the first, to a suggested question.** The avatar service
|
|
394
399
|
accepts a conversation only when it holds exactly two messages: the first user
|
|
395
400
|
message (a suggested question) and the first assistant answer, completed. The
|
|
@@ -421,7 +426,22 @@ publishes audio, video or data, and it sends the avatar nothing to say.
|
|
|
421
426
|
back (Safari, iOS), a "Tap to turn on sound" button appears. A refusal (busy,
|
|
422
427
|
limits, region, language, paused, a question the avatar cannot read) is one
|
|
423
428
|
short sentence and "Continue in Chat". A network or CORS failure, or a route
|
|
424
|
-
that is not there, shows the view as it was before
|
|
429
|
+
that is not there, shows the view as it was before, until the create request
|
|
430
|
+
has been sent: from then on the server may have made the session, so a create
|
|
431
|
+
that gets no answer (its request failing on the way, its body cut off, or
|
|
432
|
+
nothing within 30 s) says "The live avatar couldn't start." with the way back
|
|
433
|
+
to Chat, never "Live avatar coming soon". The 30 s are a timer raced against
|
|
434
|
+
the request, so the view leaves "Connecting…" by then whatever the network
|
|
435
|
+
does. A create is never sent again by itself (the bot check's token is good
|
|
436
|
+
for one, and a second create could be paid twice), and a 201 that arrives
|
|
437
|
+
after the 30 s is never joined: its session is ended at once with its own
|
|
438
|
+
secret (reason `client_error`, or the visitor's own where they had stopped it
|
|
439
|
+
first). For that, only a request with no answer yet is aborted at 30 s: an
|
|
440
|
+
answer whose status is in by then is read to its end, so a 201 whose body is
|
|
441
|
+
still on its way keeps its secret. A request aborted with no answer at all
|
|
442
|
+
brings nothing back where the browser honours the abort, so a session the
|
|
443
|
+
server made for it is ended by the server's own deadlines (`no_show`). A 401,
|
|
444
|
+
403, 404 or 405 answer is still the view as it was before.
|
|
425
445
|
- **Ending.** Stop, closing the panel, leaving the page (`pagehide`), and the
|
|
426
446
|
live avatar going off under a session (the panel's locale changing to one
|
|
427
447
|
whose strings have not been reviewed) all end the session with a `keepalive`
|
|
@@ -494,6 +514,27 @@ publishes audio, video or data, and it sends the avatar nothing to say.
|
|
|
494
514
|
chat started in the Avatar tab, provided it passes the speech checks, whether
|
|
495
515
|
you chose a suggested question or typed your own", and the visitor is told
|
|
496
516
|
not to put personal details in a typed question.
|
|
517
|
+
`web-consent-2026-11-12-b` (bot check `turnstile`, 1,010 bytes, SHA-256
|
|
518
|
+
`e8f4495d1e7f179b16de86c1eba0d2528623afb088f904f100e54523ad350c8c`) and
|
|
519
|
+
`web-consent-2026-11-13-b` (bot check `off`, 966 bytes, SHA-256
|
|
520
|
+
`4c88c229da1331ebe0f7e6e32f425612071efb2e4cf01ece813ed827ea8fc174`) are the
|
|
521
|
+
same two with only the timing sentence changed, for the server's Stage B
|
|
522
|
+
sessions of up to three minutes: "It reads for up to three minutes; if an
|
|
523
|
+
answer is longer, it reads the first part, says so, and the full answer stays
|
|
524
|
+
in Chat."
|
|
525
|
+
- **A part-read answer.** Where the server speaks only the first part of an
|
|
526
|
+
answer because the whole of it does not fit the session (the create
|
|
527
|
+
answer's `excerpt: true`, web API contract v1.4, only under the server's
|
|
528
|
+
`AVATAR_WEB_SIZE_BY_AUDIO`), the status line says "The avatar reads the
|
|
529
|
+
first part of this answer. The full answer is in Chat." (key `excerpt`) while
|
|
530
|
+
the avatar speaks, in place of "The avatar is speaking.". The layout is the
|
|
531
|
+
same. Without the field, or with any value but `true`, nothing changes.
|
|
532
|
+
- **Session length.** The countdown and the room's timers follow the server's
|
|
533
|
+
`endsAt` for each session, up to the availability answer's
|
|
534
|
+
`maxSessionSeconds` (three minutes under Stage B); an `endsAt` this
|
|
535
|
+
browser's clock cannot place within that is counted down from
|
|
536
|
+
`maxSessionSeconds` on the browser's own clock. Nothing in the view assumes a
|
|
537
|
+
minute.
|
|
497
538
|
- **How a session ended.** When the worker leaves, the server closes the room,
|
|
498
539
|
or the session's time runs out with the room still open, the view says only
|
|
499
540
|
"The live avatar has ended." (key `finished`). The browser
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunkWSEQ2I6I_js = require('../chunk-WSEQ2I6I.js');
|
|
4
|
-
var
|
|
4
|
+
var chunkN7E6Z2GF_js = require('../chunk-N7E6Z2GF.js');
|
|
5
5
|
var chunkC6OJIHNO_js = require('../chunk-C6OJIHNO.js');
|
|
6
6
|
require('../chunk-ZSTFX7FV.js');
|
|
7
7
|
var react = require('react');
|
|
@@ -121,7 +121,8 @@ function readCreated(body) {
|
|
|
121
121
|
endSecret,
|
|
122
122
|
endsAt,
|
|
123
123
|
join: { livekitUrl, participantToken, workerIdentity },
|
|
124
|
-
captions: { locale, text }
|
|
124
|
+
captions: { locale, text },
|
|
125
|
+
excerpt: body.excerpt === true
|
|
125
126
|
}
|
|
126
127
|
};
|
|
127
128
|
}
|
|
@@ -181,7 +182,7 @@ async function requestAvailability(target) {
|
|
|
181
182
|
timer.done();
|
|
182
183
|
}
|
|
183
184
|
}
|
|
184
|
-
|
|
185
|
+
function requestCreate(target) {
|
|
185
186
|
const { body } = target;
|
|
186
187
|
const payload = JSON.stringify({
|
|
187
188
|
site: body.site,
|
|
@@ -191,27 +192,45 @@ async function requestCreate(target) {
|
|
|
191
192
|
consentVersion: body.consentVersion,
|
|
192
193
|
manifestVersion: body.manifestVersion
|
|
193
194
|
});
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
195
|
+
const controller = new AbortController();
|
|
196
|
+
let answered = false;
|
|
197
|
+
const answer = (async () => {
|
|
198
|
+
try {
|
|
199
|
+
const response = await fetch(`${target.base}/sessions`, {
|
|
200
|
+
method: "POST",
|
|
201
|
+
credentials: "omit",
|
|
202
|
+
cache: "no-store",
|
|
203
|
+
headers: {
|
|
204
|
+
...target.headers,
|
|
205
|
+
"Content-Type": "application/json",
|
|
206
|
+
"Idempotency-Key": target.idempotencyKey,
|
|
207
|
+
...target.botToken === void 0 ? {} : { "x-web-avatar-bot-token": target.botToken }
|
|
208
|
+
},
|
|
209
|
+
body: payload,
|
|
210
|
+
signal: controller.signal
|
|
211
|
+
});
|
|
212
|
+
answered = true;
|
|
213
|
+
return readCreate(response.status, await readJson(response));
|
|
214
|
+
} catch {
|
|
215
|
+
return FAILED;
|
|
216
|
+
}
|
|
217
|
+
})();
|
|
218
|
+
return new Promise((resolve) => {
|
|
219
|
+
let late = false;
|
|
220
|
+
const timer = setTimeout(() => {
|
|
221
|
+
late = true;
|
|
222
|
+
if (!answered) controller.abort();
|
|
223
|
+
resolve(FAILED);
|
|
224
|
+
}, CREATE_TIMEOUT_MS);
|
|
225
|
+
void answer.then((result) => {
|
|
226
|
+
if (late) {
|
|
227
|
+
target.onLate?.(result);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
clearTimeout(timer);
|
|
231
|
+
resolve(result);
|
|
208
232
|
});
|
|
209
|
-
|
|
210
|
-
} catch {
|
|
211
|
-
return INERT;
|
|
212
|
-
} finally {
|
|
213
|
-
timer.done();
|
|
214
|
-
}
|
|
233
|
+
});
|
|
215
234
|
}
|
|
216
235
|
function sendEnd(target) {
|
|
217
236
|
try {
|
|
@@ -294,6 +313,7 @@ var EN = {
|
|
|
294
313
|
failed: "The live avatar couldn't start.",
|
|
295
314
|
interrupted: "The live avatar stopped early.",
|
|
296
315
|
answerInChat: "The full answer is in Chat.",
|
|
316
|
+
excerpt: "The avatar reads the first part of this answer. The full answer is in Chat.",
|
|
297
317
|
backToChat: "Back to Chat",
|
|
298
318
|
busy: "The live avatar is busy right now. Please try again in a few minutes.",
|
|
299
319
|
limits: "The live avatar has reached its limit for now. Please try again later.",
|
|
@@ -351,6 +371,8 @@ var ZH = {
|
|
|
351
371
|
failed: "\u5B9E\u65F6\u865A\u62DF\u5F62\u8C61\u65E0\u6CD5\u542F\u52A8\u3002",
|
|
352
372
|
interrupted: "\u5B9E\u65F6\u865A\u62DF\u5F62\u8C61\u63D0\u524D\u505C\u6B62\u4E86\u3002",
|
|
353
373
|
answerInChat: "\u5B8C\u6574\u56DE\u7B54\u5728\u804A\u5929\u4E2D\u3002",
|
|
374
|
+
// TRANSLATION REVIEW PENDING (BOFF-9797): draft, the note for a part-read answer (Stage B).
|
|
375
|
+
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",
|
|
354
376
|
backToChat: "\u8FD4\u56DE\u804A\u5929",
|
|
355
377
|
busy: "\u5B9E\u65F6\u865A\u62DF\u5F62\u8C61\u76EE\u524D\u7E41\u5FD9\uFF0C\u8BF7\u51E0\u5206\u949F\u540E\u518D\u8BD5\u3002",
|
|
356
378
|
limits: "\u5B9E\u65F6\u865A\u62DF\u5F62\u8C61\u6682\u65F6\u5DF2\u8FBE\u5230\u4F7F\u7528\u4E0A\u9650\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5\u3002",
|
|
@@ -410,6 +432,8 @@ var HI = {
|
|
|
410
432
|
failed: "\u0932\u093E\u0907\u0935 \u0905\u0935\u0924\u093E\u0930 \u0936\u0941\u0930\u0942 \u0928\u0939\u0940\u0902 \u0939\u094B \u0938\u0915\u093E\u0964",
|
|
411
433
|
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",
|
|
412
434
|
answerInChat: "\u092A\u0942\u0930\u093E \u0909\u0924\u094D\u0924\u0930 \u091A\u0948\u091F \u092E\u0947\u0902 \u0939\u0948\u0964",
|
|
435
|
+
// TRANSLATION REVIEW PENDING (BOFF-9797): draft, the note for a part-read answer (Stage B).
|
|
436
|
+
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",
|
|
413
437
|
backToChat: "\u091A\u0948\u091F \u092A\u0930 \u0935\u093E\u092A\u0938 \u091C\u093E\u090F\u0901",
|
|
414
438
|
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",
|
|
415
439
|
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",
|
|
@@ -469,6 +493,8 @@ var ES = {
|
|
|
469
493
|
failed: "No se pudo iniciar el avatar en vivo.",
|
|
470
494
|
interrupted: "El avatar en vivo se detuvo antes de tiempo.",
|
|
471
495
|
answerInChat: "La respuesta completa est\xE1 en el chat.",
|
|
496
|
+
// TRANSLATION REVIEW PENDING (BOFF-9797): draft, the note for a part-read answer (Stage B).
|
|
497
|
+
excerpt: "El avatar lee la primera parte de esta respuesta. La respuesta completa est\xE1 en el chat.",
|
|
472
498
|
backToChat: "Volver al chat",
|
|
473
499
|
busy: "El avatar en vivo est\xE1 ocupado en este momento. Vuelve a intentarlo en unos minutos.",
|
|
474
500
|
limits: "El avatar en vivo ha alcanzado su l\xEDmite por ahora. Vuelve a intentarlo m\xE1s tarde.",
|
|
@@ -528,6 +554,8 @@ var AR = {
|
|
|
528
554
|
failed: "\u062A\u0639\u0630\u0651\u0631 \u0628\u062F\u0621 \u0627\u0644\u0623\u0641\u0627\u062A\u0627\u0631 \u0627\u0644\u0645\u0628\u0627\u0634\u0631.",
|
|
529
555
|
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.",
|
|
530
556
|
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.",
|
|
557
|
+
// TRANSLATION REVIEW PENDING (BOFF-9797): draft, the note for a part-read answer (Stage B).
|
|
558
|
+
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.",
|
|
531
559
|
backToChat: "\u0627\u0644\u0639\u0648\u062F\u0629 \u0625\u0644\u0649 \u0627\u0644\u062F\u0631\u062F\u0634\u0629",
|
|
532
560
|
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.",
|
|
533
561
|
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.",
|
|
@@ -587,6 +615,8 @@ var TA = {
|
|
|
587
615
|
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.",
|
|
588
616
|
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.",
|
|
589
617
|
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.",
|
|
618
|
+
// TRANSLATION REVIEW PENDING (BOFF-9797): draft, the note for a part-read answer (Stage B).
|
|
619
|
+
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.",
|
|
590
620
|
backToChat: "\u0B85\u0BB0\u0B9F\u0BCD\u0B9F\u0BC8\u0B95\u0BCD\u0B95\u0BC1\u0BA4\u0BCD \u0BA4\u0BBF\u0BB0\u0BC1\u0BAE\u0BCD\u0BAA\u0BC1",
|
|
591
621
|
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.",
|
|
592
622
|
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.",
|
|
@@ -734,6 +764,42 @@ var CONSENT = /* @__PURE__ */ new Map([
|
|
|
734
764
|
questions: "any"
|
|
735
765
|
}
|
|
736
766
|
}
|
|
767
|
+
],
|
|
768
|
+
[
|
|
769
|
+
// Stage B (operator decision 2026-11-04): web-consent-2026-11-05 with only its timing sentence changed. A session
|
|
770
|
+
// lasts up to three minutes, sized by the server to the answer's audio; an answer longer than that is read in part,
|
|
771
|
+
// which the avatar says and the Avatar tab notes (`excerpt`), and the full answer stays in Chat. A cap still
|
|
772
|
+
// applies, so the words never say every answer is read whole (gitops docs/avatar-web/en-web-consent-2026-11-12-b.txt).
|
|
773
|
+
"web-consent-2026-11-12-b",
|
|
774
|
+
{
|
|
775
|
+
en: {
|
|
776
|
+
title: "Live AI avatar (beta)",
|
|
777
|
+
introProduct: null,
|
|
778
|
+
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.",
|
|
779
|
+
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.",
|
|
780
|
+
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.",
|
|
781
|
+
privacyLink: "How we handle this",
|
|
782
|
+
botCheck: "turnstile",
|
|
783
|
+
questions: "any"
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
],
|
|
787
|
+
[
|
|
788
|
+
// The words of web-consent-2026-11-12-b without "When you start, Cloudflare checks for bots.", for a server that runs
|
|
789
|
+
// no bot check (gitops docs/avatar-web/en-web-consent-2026-11-13-b.txt).
|
|
790
|
+
"web-consent-2026-11-13-b",
|
|
791
|
+
{
|
|
792
|
+
en: {
|
|
793
|
+
title: "Live AI avatar (beta)",
|
|
794
|
+
introProduct: null,
|
|
795
|
+
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.",
|
|
796
|
+
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.",
|
|
797
|
+
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.",
|
|
798
|
+
privacyLink: "How we handle this",
|
|
799
|
+
botCheck: "off",
|
|
800
|
+
questions: "any"
|
|
801
|
+
}
|
|
802
|
+
}
|
|
737
803
|
]
|
|
738
804
|
]);
|
|
739
805
|
function avatarConsentCopy(version, locale) {
|
|
@@ -1303,27 +1369,31 @@ function AvatarLiveView({
|
|
|
1303
1369
|
setNow(received);
|
|
1304
1370
|
go({
|
|
1305
1371
|
name: "pending",
|
|
1306
|
-
session: {
|
|
1372
|
+
session: {
|
|
1373
|
+
endsAt,
|
|
1374
|
+
captions: session.captions,
|
|
1375
|
+
excerpt: session.excerpt
|
|
1376
|
+
}
|
|
1307
1377
|
});
|
|
1308
1378
|
},
|
|
1309
1379
|
[go]
|
|
1310
1380
|
);
|
|
1311
1381
|
const settle = react.useCallback(
|
|
1312
|
-
(result,
|
|
1382
|
+
(result, givenUp, context) => {
|
|
1313
1383
|
const created = result.kind === "created" ? {
|
|
1314
1384
|
sessionId: result.session.sessionId,
|
|
1315
1385
|
secret: result.session.endSecret
|
|
1316
1386
|
} : result.kind === "unusable" ? { sessionId: result.sessionId, secret: result.endSecret } : null;
|
|
1317
1387
|
const claimed = created !== null || result.kind === "refused" && result.reason === "answer_claimed";
|
|
1318
1388
|
if (claimed) claimedRef.current.add(context.messageId);
|
|
1319
|
-
if (
|
|
1389
|
+
if (givenUp !== null) {
|
|
1320
1390
|
if (created !== null) {
|
|
1321
1391
|
sendEnd({
|
|
1322
1392
|
base: context.base,
|
|
1323
1393
|
headers: context.headers,
|
|
1324
1394
|
sessionId: created.sessionId,
|
|
1325
1395
|
secret: created.secret,
|
|
1326
|
-
reason:
|
|
1396
|
+
reason: givenUp
|
|
1327
1397
|
});
|
|
1328
1398
|
}
|
|
1329
1399
|
const shown2 = phaseRef.current;
|
|
@@ -1432,21 +1502,21 @@ function AvatarLiveView({
|
|
|
1432
1502
|
return;
|
|
1433
1503
|
}
|
|
1434
1504
|
if (turnstile !== null) go({ name: "creating" });
|
|
1505
|
+
const context = { module: loaded, offer, messageId, base: base2, headers: headers2 };
|
|
1435
1506
|
const result = await requestCreate({
|
|
1436
1507
|
base: base2,
|
|
1437
1508
|
headers: headers2,
|
|
1438
1509
|
idempotencyKey,
|
|
1439
1510
|
botToken,
|
|
1440
|
-
body: body2
|
|
1511
|
+
body: body2,
|
|
1512
|
+
// An answer past the deadline, after the view has said the live avatar couldn't start: a session it made is
|
|
1513
|
+
// ended at once with its own secret, and never joined. The reason is the visitor's own where they gave the
|
|
1514
|
+
// start up first, else `client_error`. It reads `run` and never writes it, so the deadline's `failed` below is
|
|
1515
|
+
// shown whichever of the two is handled first.
|
|
1516
|
+
onLate: (late) => settle(late, run.cancelled ?? "client_error", context)
|
|
1441
1517
|
});
|
|
1442
1518
|
if (startRef.current === run) startRef.current = null;
|
|
1443
|
-
settle(result, run,
|
|
1444
|
-
module: loaded,
|
|
1445
|
-
offer,
|
|
1446
|
-
messageId,
|
|
1447
|
-
base: base2,
|
|
1448
|
-
headers: headers2
|
|
1449
|
-
});
|
|
1519
|
+
settle(result, run.cancelled, context);
|
|
1450
1520
|
})();
|
|
1451
1521
|
},
|
|
1452
1522
|
[exchangeNow, go, reoffer, settle]
|
|
@@ -2045,7 +2115,7 @@ function AvatarLiveView({
|
|
|
2045
2115
|
className: "w-full max-w-sm rounded-lg border border-border p-4 text-start",
|
|
2046
2116
|
children: [
|
|
2047
2117
|
/* @__PURE__ */ jsxRuntime.jsx("h2", { id: consentTitleId, className: "text-base font-semibold", children: copy.title }),
|
|
2048
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm", children: productName === null || copy.introProduct === null ? copy.intro :
|
|
2118
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm", children: productName === null || copy.introProduct === null ? copy.intro : chunkN7E6Z2GF_js.fill(copy.introProduct, { product: productName }) }),
|
|
2049
2119
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: copy.processing }),
|
|
2050
2120
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: copy.storage }),
|
|
2051
2121
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -2125,6 +2195,7 @@ function AvatarLiveView({
|
|
|
2125
2195
|
]
|
|
2126
2196
|
}
|
|
2127
2197
|
);
|
|
2198
|
+
const speakingLine = (session) => session.excerpt ? S.excerpt : S.speaking;
|
|
2128
2199
|
const liveBody = (session) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2129
2200
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2130
2201
|
"section",
|
|
@@ -2224,14 +2295,21 @@ function AvatarLiveView({
|
|
|
2224
2295
|
children: lastQuestion.content
|
|
2225
2296
|
}
|
|
2226
2297
|
),
|
|
2227
|
-
lastAnswer === void 0 ? unanswered === "waiting" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: activity ?? S.gettingAnswer }) : unanswered === "failed" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: S.answerFailed }) : null : lastAnswer.status === "PENDING" || lastAnswer.status === "RUNNING" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: activity ?? S.gettingAnswer }) : lastAnswer.status === "FAILED" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: S.answerFailed }) :
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2298
|
+
lastAnswer === void 0 ? unanswered === "waiting" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: activity ?? S.gettingAnswer }) : unanswered === "failed" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: S.answerFailed }) : null : lastAnswer.status === "PENDING" || lastAnswer.status === "RUNNING" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: activity ?? S.gettingAnswer }) : lastAnswer.status === "FAILED" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: S.answerFailed }) : (
|
|
2299
|
+
// The answer's words, not its markdown: `content` is written for the chat's renderer, and shown as it is
|
|
2300
|
+
// here a link reads `[label](https://…)`. In its spoken form, as the chat's read-aloud says it: a link is its
|
|
2301
|
+
// label (the address is in Chat, one tap away), a table its rows, and the markers of emphasis, headings,
|
|
2302
|
+
// quotes and list items go (`answerDisplayText`). The words are the ones the chat shows, citation markers
|
|
2303
|
+
// included, which the sources in Chat answer to.
|
|
2304
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2305
|
+
"p",
|
|
2306
|
+
{
|
|
2307
|
+
"data-boff-explore": "avatar-live-text-answer",
|
|
2308
|
+
dir: "auto",
|
|
2309
|
+
className: "line-clamp-6 w-full max-w-sm whitespace-pre-wrap break-words text-start text-sm",
|
|
2310
|
+
children: chunkN7E6Z2GF_js.answerDisplayText(lastAnswer.content)
|
|
2311
|
+
}
|
|
2312
|
+
)
|
|
2235
2313
|
)
|
|
2236
2314
|
] });
|
|
2237
2315
|
const ended = phase.name === "ended";
|
|
@@ -2338,7 +2416,7 @@ function AvatarLiveView({
|
|
|
2338
2416
|
break;
|
|
2339
2417
|
case "pending":
|
|
2340
2418
|
case "live":
|
|
2341
|
-
status = phase.name === "live" ?
|
|
2419
|
+
status = phase.name === "live" ? speakingLine(phase.session) : S.connecting;
|
|
2342
2420
|
top2 = badge;
|
|
2343
2421
|
media2 = liveMedia(phase.name === "live");
|
|
2344
2422
|
body2 = liveBody(phase.session);
|
|
@@ -2464,7 +2542,7 @@ function AvatarLiveView({
|
|
|
2464
2542
|
"bot-check": S.botCheck,
|
|
2465
2543
|
creating: S.connecting,
|
|
2466
2544
|
pending: S.connecting,
|
|
2467
|
-
live:
|
|
2545
|
+
live: phase.name === "live" ? speakingLine(phase.session) : "",
|
|
2468
2546
|
ended: phase.name === "ended" ? S[phase.how] : ""
|
|
2469
2547
|
};
|
|
2470
2548
|
const outcome = phase.name === "needs-answer" || phase.name === "refused" || phase.name === "ended";
|