@crestapps/ai-chat-ui 2.0.0-preview.193 → 2.0.0-preview.197
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai-chat.js +77 -20
- package/dist/ai-chat.js.map +1 -1
- package/dist/ai-chat.min.js +1 -1
- package/dist/ai-chat.min.js.map +1 -1
- package/dist/chat-interaction.js +109 -17
- package/dist/chat-interaction.js.map +1 -1
- package/dist/chat-interaction.min.js +1 -1
- package/dist/chat-interaction.min.js.map +1 -1
- package/dist/realtime-audio.js +16 -2
- package/dist/realtime-audio.js.map +1 -1
- package/dist/realtime-audio.min.js +1 -1
- package/dist/realtime-audio.min.js.map +1 -1
- package/package.json +1 -1
package/dist/ai-chat.js
CHANGED
|
@@ -811,8 +811,10 @@ window.coreAIChatManager = function (_window$CoreAIChatMar, _window$CoreAIChatMa
|
|
|
811
811
|
mediaRecorder: null,
|
|
812
812
|
preRecordingPrompt: '',
|
|
813
813
|
micButton: null,
|
|
814
|
-
|
|
815
|
-
|
|
814
|
+
// Conversation mode is carried either by a realtime session or by the speech-to-text plus
|
|
815
|
+
// text-to-speech cascade, never both. Dictation and spoken playback belong to the cascade.
|
|
816
|
+
speechToTextEnabled: !config.realtimeEnabled && (config.chatMode === 'AudioInput' || config.chatMode === 'Conversation'),
|
|
817
|
+
textToSpeechEnabled: !config.realtimeEnabled && config.chatMode === 'Conversation' || !!config.textToSpeechEnabled,
|
|
816
818
|
ttsVoiceName: config.ttsVoiceName || null,
|
|
817
819
|
audioChunks: [],
|
|
818
820
|
audioPlayQueue: [],
|
|
@@ -835,6 +837,7 @@ window.coreAIChatManager = function (_window$CoreAIChatMar, _window$CoreAIChatMa
|
|
|
835
837
|
realtimeWebRtcIceServers: Array.isArray(config.realtimeWebRtcIceServers) && config.realtimeWebRtcIceServers.length ? config.realtimeWebRtcIceServers : null,
|
|
836
838
|
realtimeVoiceName: config.realtimeVoiceName || null,
|
|
837
839
|
conversationButton: null,
|
|
840
|
+
realtimeHintElement: config.realtimeHintElementSelector ? document.querySelector(config.realtimeHintElementSelector) : null,
|
|
838
841
|
isConversationMode: false,
|
|
839
842
|
notificationDismissTimers: {},
|
|
840
843
|
pendingSessionPromise: null,
|
|
@@ -1827,6 +1830,11 @@ window.coreAIChatManager = function (_window$CoreAIChatMar, _window$CoreAIChatMa
|
|
|
1827
1830
|
return;
|
|
1828
1831
|
}
|
|
1829
1832
|
|
|
1833
|
+
// A live voice session and a typed turn are two writers into one chat session, and they
|
|
1834
|
+
// would interleave. End the session first; the turns it already produced are persisted, so
|
|
1835
|
+
// the typed message simply continues the same thread.
|
|
1836
|
+
this.forceStopActiveVoice();
|
|
1837
|
+
|
|
1830
1838
|
// Stop any active recording before sending.
|
|
1831
1839
|
if (this.isRecording) {
|
|
1832
1840
|
this.stopRecording();
|
|
@@ -2399,6 +2407,45 @@ window.coreAIChatManager = function (_window$CoreAIChatMar, _window$CoreAIChatMa
|
|
|
2399
2407
|
return _this16.updateTtsPlaybackButtons();
|
|
2400
2408
|
});
|
|
2401
2409
|
},
|
|
2410
|
+
// A live voice session takes the message box away and puts the audio settings in its place; ending
|
|
2411
|
+
// the session gives it back. Sending a typed message already force-stopped the session, so the box
|
|
2412
|
+
// was never a way to say something *during* one -- hiding it only makes that honest, and frees the
|
|
2413
|
+
// row for the gear. Both transports land here: realtime through the module's onActivate, the
|
|
2414
|
+
// speech-to-text cascade through startConversationMode.
|
|
2415
|
+
// The realtime module inserts its settings popover directly after the button it was handed, and
|
|
2416
|
+
// hard-codes the element id. A page can host two chat clients at once -- this one and the admin
|
|
2417
|
+
// widget -- so that id is not unique and getElementById would hand the widget the page's gear.
|
|
2418
|
+
// Each client finds its own next to its own button.
|
|
2419
|
+
voiceSettingsElement: function voiceSettingsElement() {
|
|
2420
|
+
var next = this.conversationButton && this.conversationButton.nextElementSibling;
|
|
2421
|
+
return next && next.id === 'realtime-audio-settings' ? next : null;
|
|
2422
|
+
},
|
|
2423
|
+
setVoiceSessionLive: function setVoiceSessionLive(live) {
|
|
2424
|
+
if (this.inputElement) {
|
|
2425
|
+
this.inputElement.hidden = live;
|
|
2426
|
+
}
|
|
2427
|
+
if (this.buttonElement) {
|
|
2428
|
+
this.buttonElement.hidden = live;
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2431
|
+
// With the message box gone the button would otherwise sit at its natural width in an empty
|
|
2432
|
+
// row, so it takes the space the box left behind and reads as the thing now in charge. The
|
|
2433
|
+
// settings popover does not grow, so it stays at the right-hand end.
|
|
2434
|
+
if (this.conversationButton) {
|
|
2435
|
+
this.conversationButton.classList.toggle('flex-grow-1', live);
|
|
2436
|
+
}
|
|
2437
|
+
|
|
2438
|
+
// The gear is built by the realtime module next to its button, and only in realtime mode, so
|
|
2439
|
+
// it is absent on the cascade. It belongs to a live session rather than to the surface.
|
|
2440
|
+
var audioSettings = this.voiceSettingsElement();
|
|
2441
|
+
if (audioSettings) {
|
|
2442
|
+
audioSettings.hidden = !live;
|
|
2443
|
+
}
|
|
2444
|
+
var hint = this.realtimeHintElement;
|
|
2445
|
+
if (hint) {
|
|
2446
|
+
hint.classList.toggle('d-none', !live);
|
|
2447
|
+
}
|
|
2448
|
+
},
|
|
2402
2449
|
toggleConversationMode: function toggleConversationMode() {
|
|
2403
2450
|
if (this.realtimeEnabled) {
|
|
2404
2451
|
// Realtime is driven by the shared module, which owns the button; this only exists for
|
|
@@ -2474,19 +2521,25 @@ window.coreAIChatManager = function (_window$CoreAIChatMar, _window$CoreAIChatMa
|
|
|
2474
2521
|
},
|
|
2475
2522
|
realtimeEnabled: true,
|
|
2476
2523
|
// The conversation button doubles as the realtime button on this host; the module owns its
|
|
2477
|
-
// click, label and state from here on.
|
|
2478
|
-
//
|
|
2479
|
-
//
|
|
2524
|
+
// click, label and state from here on.
|
|
2525
|
+
//
|
|
2526
|
+
// input and sendButton are deliberately not handed over. The module hides every control it
|
|
2527
|
+
// is given when realtime takes over, and typing has to stay available during a voice
|
|
2528
|
+
// conversation -- that is the whole feature.
|
|
2480
2529
|
//
|
|
2481
|
-
// conversationButton is
|
|
2530
|
+
// conversationButton is not handed over either. It is the same element as the realtime
|
|
2482
2531
|
// button here, and the module hides the conversation button before showing the realtime
|
|
2483
2532
|
// one -- naming it twice would ask it to hide the control it then has to show.
|
|
2484
2533
|
selectors: {
|
|
2485
2534
|
realtimeButton: config.conversationButtonElementSelector,
|
|
2486
|
-
input: config.inputElementSelector,
|
|
2487
|
-
sendButton: config.sendButtonElementSelector,
|
|
2488
2535
|
micButton: config.micButtonElementSelector
|
|
2489
2536
|
},
|
|
2537
|
+
// The module owns whether a session is live, so the message box follows its flag rather
|
|
2538
|
+
// than this app's copy of it. Losing one of these events used to leave the box hidden
|
|
2539
|
+
// under a button that had already gone back to "Start speaking".
|
|
2540
|
+
onSessionStateChanged: function onSessionStateChanged(active) {
|
|
2541
|
+
self.setVoiceSessionLive(active);
|
|
2542
|
+
},
|
|
2490
2543
|
onActivate: function onActivate() {
|
|
2491
2544
|
self.isConversationMode = true;
|
|
2492
2545
|
self._conversationAssistantMessage = null;
|
|
@@ -3129,6 +3182,11 @@ window.coreAIChatManager = function (_window$CoreAIChatMar, _window$CoreAIChatMa
|
|
|
3129
3182
|
// The shared realtime module owns the button (click, label, state) and adds the
|
|
3130
3183
|
// voice settings popover next to it.
|
|
3131
3184
|
this.setupRealtimeController(config);
|
|
3185
|
+
|
|
3186
|
+
// The module reveals the gear as soon as the surface enters realtime mode, but it
|
|
3187
|
+
// belongs to a live session. The watcher that would hide it only runs on a change,
|
|
3188
|
+
// so the idle state has to be stated once here.
|
|
3189
|
+
this.setVoiceSessionLive(false);
|
|
3132
3190
|
} else {
|
|
3133
3191
|
this.conversationButton.addEventListener('click', function () {
|
|
3134
3192
|
_this23.toggleConversationMode();
|
|
@@ -3322,22 +3380,20 @@ window.coreAIChatManager = function (_window$CoreAIChatMar, _window$CoreAIChatMa
|
|
|
3322
3380
|
});
|
|
3323
3381
|
},
|
|
3324
3382
|
isConversationMode: function isConversationMode(active) {
|
|
3325
|
-
//
|
|
3383
|
+
// The dictation microphone is hidden while a voice conversation runs: the conversation
|
|
3384
|
+
// already owns the microphone, and a second one would mean something different.
|
|
3326
3385
|
if (this.micButton) {
|
|
3327
3386
|
this.micButton.style.display = active ? 'none' : this.speechToTextEnabled ? '' : 'none';
|
|
3328
3387
|
}
|
|
3329
3388
|
|
|
3330
|
-
//
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
//
|
|
3336
|
-
if (this.
|
|
3337
|
-
this.
|
|
3338
|
-
if (active) {
|
|
3339
|
-
this.inputElement.placeholder = '';
|
|
3340
|
-
}
|
|
3389
|
+
// The message box and the send button give way to the voice settings while the conversation
|
|
3390
|
+
// runs, and come back when it ends. Both kinds of turn still land in the same thread; what
|
|
3391
|
+
// they cannot do is overlap.
|
|
3392
|
+
//
|
|
3393
|
+
// Only the cascade is driven from here. Realtime follows the module's own session flag
|
|
3394
|
+
// (onSessionStateChanged), so the two never disagree about whether a session is live.
|
|
3395
|
+
if (!this.realtimeEnabled) {
|
|
3396
|
+
this.setVoiceSessionLive(active);
|
|
3341
3397
|
}
|
|
3342
3398
|
}
|
|
3343
3399
|
},
|
|
@@ -3450,6 +3506,7 @@ window.coreAIChatManager = function (_window$CoreAIChatMar, _window$CoreAIChatMa
|
|
|
3450
3506
|
chatMode: getAttributeValue(element, 'data-coreai-chat-mode'),
|
|
3451
3507
|
micButtonElementSelector: getAttributeValue(element, 'data-coreai-chat-mic-button-element-selector'),
|
|
3452
3508
|
conversationButtonElementSelector: getAttributeValue(element, 'data-coreai-chat-conversation-button-element-selector'),
|
|
3509
|
+
realtimeHintElementSelector: getAttributeValue(element, 'data-coreai-chat-realtime-hint-element-selector'),
|
|
3453
3510
|
ttsVoiceName: getAttributeValue(element, 'data-coreai-chat-tts-voice-name'),
|
|
3454
3511
|
realtimeVoiceName: getAttributeValue(element, 'data-coreai-chat-realtime-voice-name'),
|
|
3455
3512
|
documentBarSelector: getAttributeValue(element, 'data-coreai-chat-document-bar-selector'),
|