@crestapps/ai-chat-ui 1.0.0-preview-22.6 → 1.0.0-preview.7
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 +604 -242
- 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 +33 -5
- 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/chat-widget.css +59 -6
- package/dist/chat-widget.css.map +1 -1
- package/dist/chat-widget.min.css +1 -1
- package/dist/document-drop-zone.js.map +1 -1
- package/dist/technical-name-generator.js.map +1 -1
- package/package.json +1 -1
package/dist/ai-chat.js
CHANGED
|
@@ -34,7 +34,25 @@ window.openAIChatManager = function () {
|
|
|
34
34
|
thumbsDownTitle: 'Thumbs down',
|
|
35
35
|
copyTitle: 'Click here to copy response to clipboard.',
|
|
36
36
|
codeCopiedText: 'Copied!',
|
|
37
|
-
|
|
37
|
+
widget: {
|
|
38
|
+
chatWidgetContainer: null,
|
|
39
|
+
chatWidgetStateName: null,
|
|
40
|
+
chatHistorySection: null,
|
|
41
|
+
showHistoryButton: null,
|
|
42
|
+
closeHistoryButton: null,
|
|
43
|
+
newChatButton: null,
|
|
44
|
+
toggleButtonSelector: null,
|
|
45
|
+
resetSizeButtonSelector: null,
|
|
46
|
+
dragHandleSelector: '.ai-chat-widget-header',
|
|
47
|
+
enableDragging: true,
|
|
48
|
+
enableResizing: true,
|
|
49
|
+
persistLayout: true,
|
|
50
|
+
defaultWidth: null,
|
|
51
|
+
defaultHeight: null,
|
|
52
|
+
minWidth: 320,
|
|
53
|
+
minHeight: 420
|
|
54
|
+
},
|
|
55
|
+
messageTemplate: "\n <div class=\"ai-chat-messages\">\n <div v-for=\"(message, index) in messages\" :key=\"'msg-' + index\" class=\"ai-chat-message-item\">\n <div>\n <div v-if=\"message.role === 'user'\" class=\"ai-chat-msg-role ai-chat-msg-role-user\">{{ userLabel }}</div>\n <div v-else-if=\"message.role !== 'indicator'\" :class=\"getAssistantRoleClasses(message)\">\n <span :class=\"getAssistantIconClasses(message, index)\"><i :class=\"getAssistantIcon(message)\"></i></span>\n {{ getAssistantLabel(message) }}\n </div>\n <div class=\"ai-chat-message-body lh-base\">\n <h4 v-if=\"message.title\">{{ message.title }}</h4>\n <div v-html=\"message.htmlContent\"></div>\n <span class=\"message-buttons-container\" v-if=\"!isIndicator(message)\">\n <template v-if=\"metricsEnabled && message.role === 'assistant'\">\n <span class=\"ai-chat-message-assistant-feedback\" :data-message-id=\"message.id\">\n <button class=\"btn btn-sm btn-link text-success p-0 me-2 button-message-toolbox rate-up-btn\" @click=\"rateMessage(message, true, $event)\" :title=\"thumbsUpTitle\">\n <i class=\"fa-regular fa-thumbs-up\"></i>\n </button>\n <button class=\"btn btn-sm btn-link text-danger p-0 me-2 button-message-toolbox rate-down-btn\" @click=\"rateMessage(message, false, $event)\" :title=\"thumbsDownTitle\">\n <i class=\"fa-regular fa-thumbs-down\"></i>\n </button>\n </span>\n </template>\n <button v-if=\"textToSpeechEnabled && !isConversationMode && message.role === 'assistant' && !message.isStreaming\" class=\"btn btn-sm btn-link text-secondary p-0 me-1 button-message-toolbox\" :class=\"{ 'tts-playing': ttsPlayingMessageIndex === index }\" @click=\"toggleMessageTts(message, index)\" :title=\"ttsPlayingMessageIndex === index ? 'Pause audio' : 'Read aloud'\">\n <i :class=\"ttsPlayingMessageIndex === index ? 'fa-solid fa-circle-pause' : 'fa-solid fa-circle-play'\"></i>\n </button>\n <button class=\"btn btn-sm btn-link text-secondary p-0 button-message-toolbox\" @click=\"copyResponse(message.content)\" :title=\"copyTitle\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n </span>\n </div>\n </div>\n </div>\n <div v-for=\"notification in notifications\" :key=\"'notif-' + notification.type\" class=\"ai-chat-notification\" :class=\"'ai-chat-notification-' + (notification.type || 'info') + ' ' + (notification.cssClass || '')\">\n <div class=\"ai-chat-notification-content\">\n <i v-if=\"notification.icon\" :class=\"notification.icon\" class=\"ai-chat-notification-icon\"></i>\n <span class=\"ai-chat-notification-text\">{{ notification.content }}</span>\n <button v-if=\"notification.dismissible\" class=\"btn btn-sm btn-link p-0 ms-2 ai-chat-notification-dismiss\" @click=\"dismissNotification(notification.type)\" title=\"Dismiss\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n <div v-if=\"notification.actions && notification.actions.length\" class=\"ai-chat-notification-actions\">\n <button v-for=\"action in notification.actions\" :key=\"action.name\" class=\"btn btn-sm\" :class=\"action.cssClass || 'btn-outline-secondary'\" @click=\"handleNotificationAction(notification.type, action.name)\">\n <i v-if=\"action.icon\" :class=\"action.icon\" class=\"me-1\"></i>\n {{ action.label }}\n </button>\n </div>\n </div>\n </div>\n ",
|
|
38
56
|
indicatorTemplate: "\n <div class=\"ai-chat-msg-role ai-chat-msg-role-assistant\">\n <span class=\"ai-streaming-icon\"><i class=\"fa fa-robot\" style=\"display: inline-block;\"></i></span>\n Assistant\n </div>\n "
|
|
39
57
|
};
|
|
40
58
|
|
|
@@ -54,6 +72,19 @@ window.openAIChatManager = function () {
|
|
|
54
72
|
span.textContent = text;
|
|
55
73
|
return span.innerHTML;
|
|
56
74
|
}
|
|
75
|
+
function parsePixelValue(value) {
|
|
76
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
77
|
+
return value;
|
|
78
|
+
}
|
|
79
|
+
if (typeof value !== 'string') {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
var parsed = parseFloat(value);
|
|
83
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
84
|
+
}
|
|
85
|
+
function clamp(value, min, max) {
|
|
86
|
+
return Math.min(Math.max(value, min), max);
|
|
87
|
+
}
|
|
57
88
|
function normalizeReference(reference) {
|
|
58
89
|
var _ref, _normalized$index, _ref2, _normalized$text, _ref3, _normalized$link;
|
|
59
90
|
if (!reference || _typeof(reference) !== 'object') {
|
|
@@ -330,6 +361,8 @@ window.openAIChatManager = function () {
|
|
|
330
361
|
}
|
|
331
362
|
var initialize = function initialize(instanceConfig) {
|
|
332
363
|
var config = Object.assign({}, defaultConfig, instanceConfig);
|
|
364
|
+
config.widget = Object.assign({}, defaultConfig.widget || {}, instanceConfig && instanceConfig.widget ? instanceConfig.widget : {});
|
|
365
|
+
var hasWidgetConfig = !!(instanceConfig && instanceConfig.widget && instanceConfig.widget.chatWidgetContainer && instanceConfig.widget.chatWidgetStateName);
|
|
333
366
|
// Keep defaultConfig in sync so renderers use overridden values
|
|
334
367
|
defaultConfig = config;
|
|
335
368
|
if (!config.signalRHubUrl) {
|
|
@@ -363,7 +396,15 @@ window.openAIChatManager = function () {
|
|
|
363
396
|
isPlaceholderVisible: true,
|
|
364
397
|
chatWidgetStateName: null,
|
|
365
398
|
chatWidgetStateSession: null,
|
|
399
|
+
chatWidgetLayoutKey: null,
|
|
366
400
|
chatHistorySection: null,
|
|
401
|
+
widgetContainerElement: null,
|
|
402
|
+
widgetToggleButtonElement: null,
|
|
403
|
+
widgetResetSizeButtonElement: null,
|
|
404
|
+
widgetResizeObserver: null,
|
|
405
|
+
widgetViewportResizeHandler: null,
|
|
406
|
+
widgetDefaultWidth: null,
|
|
407
|
+
widgetDefaultHeight: null,
|
|
367
408
|
widgetIsInitialized: false,
|
|
368
409
|
isStreaming: false,
|
|
369
410
|
isNavigatingAway: false,
|
|
@@ -394,9 +435,11 @@ window.openAIChatManager = function () {
|
|
|
394
435
|
audioPlayQueue: [],
|
|
395
436
|
isPlayingAudio: false,
|
|
396
437
|
currentAudioElement: null,
|
|
438
|
+
currentAudioUrl: null,
|
|
397
439
|
ttsButton: null,
|
|
398
440
|
ttsPlayingMessageIndex: -1,
|
|
399
441
|
ttsAudioCache: {},
|
|
442
|
+
ttsInstanceId: 'ai-chat-' + Math.random().toString(36).slice(2),
|
|
400
443
|
singleResponseMode: !!config.singleResponseMode,
|
|
401
444
|
conversationModeEnabled: config.chatMode === 'Conversation',
|
|
402
445
|
conversationButton: null,
|
|
@@ -418,6 +461,255 @@ window.openAIChatManager = function () {
|
|
|
418
461
|
handleBeforeUnload: function handleBeforeUnload() {
|
|
419
462
|
this.isNavigatingAway = true;
|
|
420
463
|
},
|
|
464
|
+
getStoredWidgetLayout: function getStoredWidgetLayout() {
|
|
465
|
+
if (!this.chatWidgetLayoutKey || !config.widget.persistLayout) {
|
|
466
|
+
return {};
|
|
467
|
+
}
|
|
468
|
+
try {
|
|
469
|
+
var storedLayout = localStorage.getItem(this.chatWidgetLayoutKey);
|
|
470
|
+
return storedLayout ? JSON.parse(storedLayout) || {} : {};
|
|
471
|
+
} catch (error) {
|
|
472
|
+
console.warn('Failed to read widget layout state.', error);
|
|
473
|
+
return {};
|
|
474
|
+
}
|
|
475
|
+
},
|
|
476
|
+
saveStoredWidgetLayout: function saveStoredWidgetLayout(partialLayout) {
|
|
477
|
+
if (!this.chatWidgetLayoutKey || !config.widget.persistLayout) {
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
var currentLayout = this.getStoredWidgetLayout();
|
|
481
|
+
var nextLayout = Object.assign({}, currentLayout);
|
|
482
|
+
if (partialLayout.panel !== undefined) {
|
|
483
|
+
nextLayout.panel = Object.assign({}, currentLayout.panel || {}, partialLayout.panel || {});
|
|
484
|
+
}
|
|
485
|
+
if (partialLayout.toggle !== undefined) {
|
|
486
|
+
nextLayout.toggle = Object.assign({}, currentLayout.toggle || {}, partialLayout.toggle || {});
|
|
487
|
+
}
|
|
488
|
+
localStorage.setItem(this.chatWidgetLayoutKey, JSON.stringify(nextLayout));
|
|
489
|
+
},
|
|
490
|
+
getElementSize: function getElementSize(element, fallbackWidth, fallbackHeight) {
|
|
491
|
+
if (!element) {
|
|
492
|
+
return {
|
|
493
|
+
width: fallbackWidth || 0,
|
|
494
|
+
height: fallbackHeight || 0
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
var rect = element.getBoundingClientRect();
|
|
498
|
+
var computed = window.getComputedStyle(element);
|
|
499
|
+
return {
|
|
500
|
+
width: Math.round(rect.width || parsePixelValue(computed.width) || fallbackWidth || 0),
|
|
501
|
+
height: Math.round(rect.height || parsePixelValue(computed.height) || fallbackHeight || 0)
|
|
502
|
+
};
|
|
503
|
+
},
|
|
504
|
+
clampWidgetPosition: function clampWidgetPosition(left, top, width, height) {
|
|
505
|
+
var viewportPadding = 8;
|
|
506
|
+
var maxLeft = Math.max(viewportPadding, window.innerWidth - width - viewportPadding);
|
|
507
|
+
var maxTop = Math.max(viewportPadding, window.innerHeight - height - viewportPadding);
|
|
508
|
+
return {
|
|
509
|
+
left: Math.round(clamp(left, viewportPadding, maxLeft)),
|
|
510
|
+
top: Math.round(clamp(top, viewportPadding, maxTop))
|
|
511
|
+
};
|
|
512
|
+
},
|
|
513
|
+
applyAbsolutePosition: function applyAbsolutePosition(element, left, top) {
|
|
514
|
+
if (!element) {
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
element.style.left = left + 'px';
|
|
518
|
+
element.style.top = top + 'px';
|
|
519
|
+
element.style.right = 'auto';
|
|
520
|
+
element.style.bottom = 'auto';
|
|
521
|
+
},
|
|
522
|
+
getWidgetDefaultSize: function getWidgetDefaultSize() {
|
|
523
|
+
return {
|
|
524
|
+
width: this.widgetDefaultWidth || parsePixelValue(config.widget.defaultWidth) || 380,
|
|
525
|
+
height: this.widgetDefaultHeight || parsePixelValue(config.widget.defaultHeight) || 520
|
|
526
|
+
};
|
|
527
|
+
},
|
|
528
|
+
persistWidgetPanelPosition: function persistWidgetPanelPosition() {
|
|
529
|
+
if (!this.widgetContainerElement || !config.widget.persistLayout) {
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
var panelRect = this.widgetContainerElement.getBoundingClientRect();
|
|
533
|
+
this.saveStoredWidgetLayout({
|
|
534
|
+
panel: {
|
|
535
|
+
left: Math.round(panelRect.left),
|
|
536
|
+
top: Math.round(panelRect.top)
|
|
537
|
+
}
|
|
538
|
+
});
|
|
539
|
+
},
|
|
540
|
+
persistWidgetTogglePosition: function persistWidgetTogglePosition() {
|
|
541
|
+
if (!this.widgetToggleButtonElement || !config.widget.persistLayout) {
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
var toggleRect = this.widgetToggleButtonElement.getBoundingClientRect();
|
|
545
|
+
this.saveStoredWidgetLayout({
|
|
546
|
+
toggle: {
|
|
547
|
+
left: Math.round(toggleRect.left),
|
|
548
|
+
top: Math.round(toggleRect.top)
|
|
549
|
+
}
|
|
550
|
+
});
|
|
551
|
+
},
|
|
552
|
+
persistWidgetPanelSize: function persistWidgetPanelSize() {
|
|
553
|
+
if (!this.widgetContainerElement || !config.widget.enableResizing || !config.widget.persistLayout) {
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
var defaultSize = this.getWidgetDefaultSize();
|
|
557
|
+
var currentSize = this.getElementSize(this.widgetContainerElement, defaultSize.width, defaultSize.height);
|
|
558
|
+
this.saveStoredWidgetLayout({
|
|
559
|
+
panel: {
|
|
560
|
+
width: Math.abs(currentSize.width - defaultSize.width) <= 1 ? null : currentSize.width,
|
|
561
|
+
height: Math.abs(currentSize.height - defaultSize.height) <= 1 ? null : currentSize.height
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
},
|
|
565
|
+
updateWidgetResetSizeButtonVisibility: function updateWidgetResetSizeButtonVisibility() {
|
|
566
|
+
if (!this.widgetResetSizeButtonElement) {
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
569
|
+
if (!config.widget.enableResizing || !this.widgetContainerElement) {
|
|
570
|
+
this.widgetResetSizeButtonElement.classList.add('d-none');
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
var defaultSize = this.getWidgetDefaultSize();
|
|
574
|
+
var currentSize = this.getElementSize(this.widgetContainerElement, defaultSize.width, defaultSize.height);
|
|
575
|
+
var isResized = Math.abs(currentSize.width - defaultSize.width) > 1 || Math.abs(currentSize.height - defaultSize.height) > 1 || !!this.widgetContainerElement.style.width || !!this.widgetContainerElement.style.height;
|
|
576
|
+
this.widgetResetSizeButtonElement.classList.toggle('d-none', !isResized);
|
|
577
|
+
},
|
|
578
|
+
resetWidgetSize: function resetWidgetSize() {
|
|
579
|
+
if (!this.widgetContainerElement || !config.widget.enableResizing) {
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
this.widgetContainerElement.style.removeProperty('width');
|
|
583
|
+
this.widgetContainerElement.style.removeProperty('height');
|
|
584
|
+
this.persistWidgetPanelSize();
|
|
585
|
+
this.constrainWidgetElementsToViewport();
|
|
586
|
+
this.updateWidgetResetSizeButtonVisibility();
|
|
587
|
+
},
|
|
588
|
+
restoreWidgetLayout: function restoreWidgetLayout() {
|
|
589
|
+
var storedLayout = this.getStoredWidgetLayout();
|
|
590
|
+
if (this.widgetContainerElement && config.widget.enableResizing) {
|
|
591
|
+
if (Number.isFinite(storedLayout.panel && storedLayout.panel.width)) {
|
|
592
|
+
this.widgetContainerElement.style.width = storedLayout.panel.width + 'px';
|
|
593
|
+
} else {
|
|
594
|
+
this.widgetContainerElement.style.removeProperty('width');
|
|
595
|
+
}
|
|
596
|
+
if (Number.isFinite(storedLayout.panel && storedLayout.panel.height)) {
|
|
597
|
+
this.widgetContainerElement.style.height = storedLayout.panel.height + 'px';
|
|
598
|
+
} else {
|
|
599
|
+
this.widgetContainerElement.style.removeProperty('height');
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
if (this.widgetContainerElement && config.widget.enableDragging && Number.isFinite(storedLayout.panel && storedLayout.panel.left) && Number.isFinite(storedLayout.panel && storedLayout.panel.top)) {
|
|
603
|
+
this.applyAbsolutePosition(this.widgetContainerElement, storedLayout.panel.left, storedLayout.panel.top);
|
|
604
|
+
}
|
|
605
|
+
if (this.widgetToggleButtonElement && config.widget.enableDragging && Number.isFinite(storedLayout.toggle && storedLayout.toggle.left) && Number.isFinite(storedLayout.toggle && storedLayout.toggle.top)) {
|
|
606
|
+
this.applyAbsolutePosition(this.widgetToggleButtonElement, storedLayout.toggle.left, storedLayout.toggle.top);
|
|
607
|
+
}
|
|
608
|
+
this.constrainWidgetElementsToViewport();
|
|
609
|
+
this.updateWidgetResetSizeButtonVisibility();
|
|
610
|
+
},
|
|
611
|
+
attachDraggableWidgetElement: function attachDraggableWidgetElement(element, handle, layoutKey, suppressClickOnDrag) {
|
|
612
|
+
var _this = this;
|
|
613
|
+
if (!element || !handle || !config.widget.enableDragging) {
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
var activePointerId = null;
|
|
617
|
+
var startX = 0;
|
|
618
|
+
var startY = 0;
|
|
619
|
+
var startLeft = 0;
|
|
620
|
+
var startTop = 0;
|
|
621
|
+
var dragged = false;
|
|
622
|
+
var dragThreshold = 4;
|
|
623
|
+
var interactiveSelector = 'button, a, input, textarea, select, option, label';
|
|
624
|
+
var _stopDragging = function stopDragging(event) {
|
|
625
|
+
if (activePointerId === null) {
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
if (event && event.pointerId !== undefined && event.pointerId !== activePointerId) {
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
document.removeEventListener('pointermove', onPointerMove);
|
|
632
|
+
document.removeEventListener('pointerup', _stopDragging);
|
|
633
|
+
document.removeEventListener('pointercancel', _stopDragging);
|
|
634
|
+
element.classList.remove('ai-chat-widget-dragging');
|
|
635
|
+
activePointerId = null;
|
|
636
|
+
if (!dragged) {
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
if (layoutKey === 'panel') {
|
|
640
|
+
_this.persistWidgetPanelPosition();
|
|
641
|
+
} else if (layoutKey === 'toggle') {
|
|
642
|
+
_this.persistWidgetTogglePosition();
|
|
643
|
+
}
|
|
644
|
+
if (suppressClickOnDrag) {
|
|
645
|
+
element.dataset.dragSuppressClick = 'true';
|
|
646
|
+
window.setTimeout(function () {
|
|
647
|
+
if (element.dataset.dragSuppressClick === 'true') {
|
|
648
|
+
element.dataset.dragSuppressClick = 'false';
|
|
649
|
+
}
|
|
650
|
+
}, 0);
|
|
651
|
+
}
|
|
652
|
+
};
|
|
653
|
+
var onPointerMove = function onPointerMove(event) {
|
|
654
|
+
if (activePointerId === null || event.pointerId !== activePointerId) {
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
657
|
+
var deltaX = event.clientX - startX;
|
|
658
|
+
var deltaY = event.clientY - startY;
|
|
659
|
+
if (!dragged && Math.hypot(deltaX, deltaY) < dragThreshold) {
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
dragged = true;
|
|
663
|
+
var defaultSize = _this.getWidgetDefaultSize();
|
|
664
|
+
var currentSize = _this.getElementSize(element, layoutKey === 'panel' ? defaultSize.width : 52, layoutKey === 'panel' ? defaultSize.height : 52);
|
|
665
|
+
var nextPosition = _this.clampWidgetPosition(startLeft + deltaX, startTop + deltaY, currentSize.width, currentSize.height);
|
|
666
|
+
_this.applyAbsolutePosition(element, nextPosition.left, nextPosition.top);
|
|
667
|
+
};
|
|
668
|
+
handle.addEventListener('pointerdown', function (event) {
|
|
669
|
+
if (event.button !== 0) {
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
if (layoutKey === 'panel' && event.target.closest(interactiveSelector)) {
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
675
|
+
var rect = element.getBoundingClientRect();
|
|
676
|
+
startX = event.clientX;
|
|
677
|
+
startY = event.clientY;
|
|
678
|
+
startLeft = rect.left;
|
|
679
|
+
startTop = rect.top;
|
|
680
|
+
dragged = false;
|
|
681
|
+
activePointerId = event.pointerId;
|
|
682
|
+
element.classList.add('ai-chat-widget-dragging');
|
|
683
|
+
if (handle.setPointerCapture) {
|
|
684
|
+
handle.setPointerCapture(event.pointerId);
|
|
685
|
+
}
|
|
686
|
+
document.addEventListener('pointermove', onPointerMove);
|
|
687
|
+
document.addEventListener('pointerup', _stopDragging);
|
|
688
|
+
document.addEventListener('pointercancel', _stopDragging);
|
|
689
|
+
event.preventDefault();
|
|
690
|
+
});
|
|
691
|
+
},
|
|
692
|
+
constrainWidgetElementsToViewport: function constrainWidgetElementsToViewport() {
|
|
693
|
+
if (this.widgetContainerElement && this.widgetContainerElement.style.left) {
|
|
694
|
+
var panelDefaultSize = this.getWidgetDefaultSize();
|
|
695
|
+
var panelSize = this.getElementSize(this.widgetContainerElement, panelDefaultSize.width, panelDefaultSize.height);
|
|
696
|
+
var panelRect = this.widgetContainerElement.getBoundingClientRect();
|
|
697
|
+
var clampedPanel = this.clampWidgetPosition(panelRect.left, panelRect.top, panelSize.width, panelSize.height);
|
|
698
|
+
this.applyAbsolutePosition(this.widgetContainerElement, clampedPanel.left, clampedPanel.top);
|
|
699
|
+
if (config.widget.persistLayout) {
|
|
700
|
+
this.persistWidgetPanelPosition();
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
if (this.widgetToggleButtonElement && this.widgetToggleButtonElement.style.left) {
|
|
704
|
+
var toggleSize = this.getElementSize(this.widgetToggleButtonElement, 52, 52);
|
|
705
|
+
var toggleRect = this.widgetToggleButtonElement.getBoundingClientRect();
|
|
706
|
+
var clampedToggle = this.clampWidgetPosition(toggleRect.left, toggleRect.top, toggleSize.width, toggleSize.height);
|
|
707
|
+
this.applyAbsolutePosition(this.widgetToggleButtonElement, clampedToggle.left, clampedToggle.top);
|
|
708
|
+
if (config.widget.persistLayout) {
|
|
709
|
+
this.persistWidgetTogglePosition();
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
},
|
|
421
713
|
handleDragOver: function handleDragOver(e) {
|
|
422
714
|
if (!config.sessionDocumentsEnabled) return;
|
|
423
715
|
e.preventDefault();
|
|
@@ -458,7 +750,7 @@ window.openAIChatManager = function () {
|
|
|
458
750
|
e.target.value = '';
|
|
459
751
|
},
|
|
460
752
|
uploadFiles: function uploadFiles(files) {
|
|
461
|
-
var
|
|
753
|
+
var _this2 = this;
|
|
462
754
|
return _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
|
|
463
755
|
var sessionId, profileId, formData, i, response, errorText, uploadError, result, j, _t;
|
|
464
756
|
return _regenerator().w(function (_context) {
|
|
@@ -470,8 +762,8 @@ window.openAIChatManager = function () {
|
|
|
470
762
|
}
|
|
471
763
|
return _context.a(2);
|
|
472
764
|
case 1:
|
|
473
|
-
sessionId =
|
|
474
|
-
profileId =
|
|
765
|
+
sessionId = _this2.getSessionId();
|
|
766
|
+
profileId = _this2.getProfileId();
|
|
475
767
|
if (!(!sessionId && !profileId)) {
|
|
476
768
|
_context.n = 2;
|
|
477
769
|
break;
|
|
@@ -479,9 +771,9 @@ window.openAIChatManager = function () {
|
|
|
479
771
|
console.warn('Cannot upload documents without a session or profile.');
|
|
480
772
|
return _context.a(2);
|
|
481
773
|
case 2:
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
774
|
+
_this2.isUploading = true;
|
|
775
|
+
_this2.uploadErrors = [];
|
|
776
|
+
_this2.renderDocumentBar();
|
|
485
777
|
_context.p = 3;
|
|
486
778
|
formData = new FormData();
|
|
487
779
|
if (sessionId) {
|
|
@@ -507,9 +799,9 @@ window.openAIChatManager = function () {
|
|
|
507
799
|
return response.text();
|
|
508
800
|
case 5:
|
|
509
801
|
errorText = _context.v;
|
|
510
|
-
uploadError =
|
|
802
|
+
uploadError = _this2.extractReadableErrorMessage(errorText, 'Upload failed. Please try again.');
|
|
511
803
|
console.error('Upload failed:', errorText);
|
|
512
|
-
|
|
804
|
+
_this2.uploadErrors = [{
|
|
513
805
|
fileName: '',
|
|
514
806
|
error: uploadError
|
|
515
807
|
}];
|
|
@@ -521,15 +813,15 @@ window.openAIChatManager = function () {
|
|
|
521
813
|
result = _context.v;
|
|
522
814
|
// If the server created a new session, initialize it.
|
|
523
815
|
if (result.sessionId && !sessionId) {
|
|
524
|
-
|
|
816
|
+
_this2.initializeSession(result.sessionId);
|
|
525
817
|
}
|
|
526
818
|
if (result.uploaded && result.uploaded.length > 0) {
|
|
527
819
|
for (j = 0; j < result.uploaded.length; j++) {
|
|
528
|
-
|
|
820
|
+
_this2.documents.push(result.uploaded[j]);
|
|
529
821
|
}
|
|
530
822
|
}
|
|
531
823
|
if (result.failed && result.failed.length > 0) {
|
|
532
|
-
|
|
824
|
+
_this2.uploadErrors = result.failed;
|
|
533
825
|
}
|
|
534
826
|
_context.n = 9;
|
|
535
827
|
break;
|
|
@@ -537,14 +829,14 @@ window.openAIChatManager = function () {
|
|
|
537
829
|
_context.p = 8;
|
|
538
830
|
_t = _context.v;
|
|
539
831
|
console.error('Upload error:', _t);
|
|
540
|
-
|
|
832
|
+
_this2.uploadErrors = [{
|
|
541
833
|
fileName: '',
|
|
542
834
|
error: 'Upload failed. Please try again.'
|
|
543
835
|
}];
|
|
544
836
|
case 9:
|
|
545
837
|
_context.p = 9;
|
|
546
|
-
|
|
547
|
-
|
|
838
|
+
_this2.isUploading = false;
|
|
839
|
+
_this2.renderDocumentBar();
|
|
548
840
|
return _context.f(9);
|
|
549
841
|
case 10:
|
|
550
842
|
return _context.a(2);
|
|
@@ -553,7 +845,7 @@ window.openAIChatManager = function () {
|
|
|
553
845
|
}))();
|
|
554
846
|
},
|
|
555
847
|
removeDocument: function removeDocument(doc) {
|
|
556
|
-
var
|
|
848
|
+
var _this3 = this;
|
|
557
849
|
return _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2() {
|
|
558
850
|
var sessionId, response, idx, errorText, removeError, _t2;
|
|
559
851
|
return _regenerator().w(function (_context2) {
|
|
@@ -566,7 +858,7 @@ window.openAIChatManager = function () {
|
|
|
566
858
|
return _context2.a(2);
|
|
567
859
|
case 1:
|
|
568
860
|
_context2.p = 1;
|
|
569
|
-
sessionId =
|
|
861
|
+
sessionId = _this3.getSessionId();
|
|
570
862
|
_context2.n = 2;
|
|
571
863
|
return fetch(config.removeDocumentUrl, {
|
|
572
864
|
method: 'POST',
|
|
@@ -584,8 +876,8 @@ window.openAIChatManager = function () {
|
|
|
584
876
|
_context2.n = 3;
|
|
585
877
|
break;
|
|
586
878
|
}
|
|
587
|
-
idx =
|
|
588
|
-
if (idx > -1)
|
|
879
|
+
idx = _this3.documents.indexOf(doc);
|
|
880
|
+
if (idx > -1) _this3.documents.splice(idx, 1);
|
|
589
881
|
_context2.n = 5;
|
|
590
882
|
break;
|
|
591
883
|
case 3:
|
|
@@ -593,13 +885,13 @@ window.openAIChatManager = function () {
|
|
|
593
885
|
return response.text();
|
|
594
886
|
case 4:
|
|
595
887
|
errorText = _context2.v;
|
|
596
|
-
removeError =
|
|
888
|
+
removeError = _this3.extractReadableErrorMessage(errorText, 'Failed to remove document. Please try again.');
|
|
597
889
|
console.error('Failed to remove document:', response.status, errorText);
|
|
598
|
-
|
|
890
|
+
_this3.uploadErrors = [{
|
|
599
891
|
fileName: doc.fileName || '',
|
|
600
892
|
error: removeError
|
|
601
893
|
}];
|
|
602
|
-
|
|
894
|
+
_this3.renderDocumentBar();
|
|
603
895
|
case 5:
|
|
604
896
|
_context2.n = 7;
|
|
605
897
|
break;
|
|
@@ -607,11 +899,11 @@ window.openAIChatManager = function () {
|
|
|
607
899
|
_context2.p = 6;
|
|
608
900
|
_t2 = _context2.v;
|
|
609
901
|
console.error('Remove document error:', _t2);
|
|
610
|
-
|
|
902
|
+
_this3.uploadErrors = [{
|
|
611
903
|
fileName: doc.fileName || '',
|
|
612
904
|
error: 'Failed to remove document. Please try again.'
|
|
613
905
|
}];
|
|
614
|
-
|
|
906
|
+
_this3.renderDocumentBar();
|
|
615
907
|
case 7:
|
|
616
908
|
return _context2.a(2);
|
|
617
909
|
}
|
|
@@ -781,139 +1073,139 @@ window.openAIChatManager = function () {
|
|
|
781
1073
|
return !!message && message.isStreaming && index === this.lastAssistantIndex && !(appearance && appearance.disableStreamingAnimation);
|
|
782
1074
|
},
|
|
783
1075
|
startConnection: function startConnection() {
|
|
784
|
-
var
|
|
1076
|
+
var _this4 = this;
|
|
785
1077
|
return _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3() {
|
|
786
1078
|
var _t3;
|
|
787
1079
|
return _regenerator().w(function (_context3) {
|
|
788
1080
|
while (1) switch (_context3.p = _context3.n) {
|
|
789
1081
|
case 0:
|
|
790
|
-
|
|
1082
|
+
_this4.connection = new signalR.HubConnectionBuilder().withUrl(config.signalRHubUrl).withAutomaticReconnect().build();
|
|
791
1083
|
|
|
792
1084
|
// Allow long-running operations (e.g., multi-step MCP tool calls)
|
|
793
1085
|
// without the client disconnecting prematurely.
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
1086
|
+
_this4.connection.serverTimeoutInMilliseconds = 600000;
|
|
1087
|
+
_this4.connection.keepAliveIntervalInMilliseconds = 15000;
|
|
1088
|
+
_this4.connection.on("LoadSession", function (data) {
|
|
797
1089
|
var _data$messages;
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
1090
|
+
_this4.initializeSession(data.sessionId, true);
|
|
1091
|
+
_this4.messages = [];
|
|
1092
|
+
_this4.documents = data.documents || [];
|
|
801
1093
|
((_data$messages = data.messages) !== null && _data$messages !== void 0 ? _data$messages : []).forEach(function (msg) {
|
|
802
|
-
|
|
803
|
-
|
|
1094
|
+
_this4.addMessage(msg);
|
|
1095
|
+
_this4.$nextTick(function () {
|
|
804
1096
|
renderChartsInMessage(msg);
|
|
805
1097
|
});
|
|
806
1098
|
});
|
|
807
1099
|
|
|
808
1100
|
// Update feedback icons in the DOM after all messages have rendered.
|
|
809
|
-
|
|
810
|
-
|
|
1101
|
+
_this4.$nextTick(function () {
|
|
1102
|
+
_this4.refreshAllFeedbackIcons();
|
|
811
1103
|
});
|
|
812
1104
|
|
|
813
1105
|
// When the session is new (no messages) and an initial prompt is configured,
|
|
814
1106
|
// automatically send it as the first user message to trigger an AI response.
|
|
815
|
-
if (
|
|
816
|
-
|
|
817
|
-
|
|
1107
|
+
if (_this4.messages.length === 0 && config.initialPrompt) {
|
|
1108
|
+
_this4.prompt = config.initialPrompt;
|
|
1109
|
+
_this4.sendMessage();
|
|
818
1110
|
}
|
|
819
1111
|
});
|
|
820
|
-
|
|
1112
|
+
_this4.connection.on("ReceiveError", function (error) {
|
|
821
1113
|
console.error("SignalR Error: ", error);
|
|
822
|
-
if (
|
|
823
|
-
|
|
1114
|
+
if (_this4.isRecording) {
|
|
1115
|
+
_this4.stopRecording();
|
|
824
1116
|
}
|
|
825
1117
|
|
|
826
1118
|
// If this is a widget with a stale cached session (e.g., profile was deleted),
|
|
827
1119
|
// clear the cached session and start fresh with the current profile.
|
|
828
|
-
if (
|
|
829
|
-
|
|
830
|
-
localStorage.removeItem(
|
|
831
|
-
|
|
1120
|
+
if (_this4.widgetIsInitialized && !_this4.isSessionStarted && !_this4._attemptedSessionRecovery) {
|
|
1121
|
+
_this4._attemptedSessionRecovery = true;
|
|
1122
|
+
localStorage.removeItem(_this4.chatWidgetStateSession);
|
|
1123
|
+
_this4.startNewSession();
|
|
832
1124
|
}
|
|
833
1125
|
});
|
|
834
|
-
|
|
835
|
-
var msg =
|
|
1126
|
+
_this4.connection.on("MessageRated", function (messageId, userRating) {
|
|
1127
|
+
var msg = _this4.messages.find(function (m) {
|
|
836
1128
|
return m.id === messageId;
|
|
837
1129
|
});
|
|
838
1130
|
if (msg) {
|
|
839
1131
|
msg.userRating = userRating;
|
|
840
1132
|
}
|
|
841
1133
|
});
|
|
842
|
-
|
|
843
|
-
if (
|
|
1134
|
+
_this4.connection.on("ReceiveTranscript", function (sessionId, text, isFinal) {
|
|
1135
|
+
if (_this4.isConversationMode) {
|
|
844
1136
|
if (!isFinal && text) {
|
|
845
|
-
|
|
1137
|
+
_this4._conversationPartialTranscript = text;
|
|
846
1138
|
var escaped = text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
847
1139
|
var html = '<p class="ai-partial-transcript">' + escaped + '</p>';
|
|
848
1140
|
|
|
849
1141
|
// Show partial transcript as a live user message.
|
|
850
|
-
if (!
|
|
851
|
-
|
|
852
|
-
|
|
1142
|
+
if (!_this4._conversationPartialMessage) {
|
|
1143
|
+
_this4.hidePlaceholder();
|
|
1144
|
+
_this4._conversationPartialMessage = {
|
|
853
1145
|
role: 'user',
|
|
854
1146
|
content: text,
|
|
855
1147
|
htmlContent: html,
|
|
856
1148
|
isPartial: true
|
|
857
1149
|
};
|
|
858
|
-
|
|
1150
|
+
_this4.messages.push(_this4._conversationPartialMessage);
|
|
859
1151
|
} else {
|
|
860
|
-
|
|
861
|
-
|
|
1152
|
+
_this4._conversationPartialMessage.content = text;
|
|
1153
|
+
_this4._conversationPartialMessage.htmlContent = html;
|
|
862
1154
|
}
|
|
863
|
-
|
|
1155
|
+
_this4.scrollToBottom();
|
|
864
1156
|
}
|
|
865
1157
|
return;
|
|
866
1158
|
}
|
|
867
|
-
if (text && !
|
|
868
|
-
|
|
869
|
-
if (
|
|
870
|
-
|
|
871
|
-
|
|
1159
|
+
if (text && !_this4._audioInputSent) {
|
|
1160
|
+
_this4.prompt = _this4.preRecordingPrompt + text;
|
|
1161
|
+
if (_this4.inputElement) {
|
|
1162
|
+
_this4.inputElement.value = _this4.prompt;
|
|
1163
|
+
_this4.inputElement.dispatchEvent(new Event('input'));
|
|
872
1164
|
}
|
|
873
1165
|
}
|
|
874
1166
|
});
|
|
875
|
-
|
|
1167
|
+
_this4.connection.on("ReceiveConversationUserMessage", function (sessionId, text) {
|
|
876
1168
|
if (text) {
|
|
877
|
-
|
|
1169
|
+
_this4.stopAudio();
|
|
878
1170
|
|
|
879
1171
|
// If there's an interrupted assistant message still streaming,
|
|
880
1172
|
// mark it as done to stop the spinner animation.
|
|
881
|
-
if (
|
|
882
|
-
var oldMsg =
|
|
1173
|
+
if (_this4._conversationAssistantMessage) {
|
|
1174
|
+
var oldMsg = _this4.messages[_this4._conversationAssistantMessage.index];
|
|
883
1175
|
if (oldMsg) {
|
|
884
1176
|
oldMsg.isStreaming = false;
|
|
885
1177
|
}
|
|
886
|
-
|
|
1178
|
+
_this4._conversationAssistantMessage = null;
|
|
887
1179
|
}
|
|
888
1180
|
|
|
889
1181
|
// Replace the partial transcript message with the final one.
|
|
890
|
-
if (
|
|
1182
|
+
if (_this4._conversationPartialMessage) {
|
|
891
1183
|
var escaped = text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
1184
|
+
_this4._conversationPartialMessage.content = text;
|
|
1185
|
+
_this4._conversationPartialMessage.htmlContent = '<p>' + escaped + '</p>';
|
|
1186
|
+
_this4._conversationPartialMessage.isPartial = false;
|
|
1187
|
+
_this4._conversationPartialMessage = null;
|
|
896
1188
|
} else {
|
|
897
|
-
|
|
1189
|
+
_this4.addMessage({
|
|
898
1190
|
role: 'user',
|
|
899
1191
|
content: text
|
|
900
1192
|
});
|
|
901
1193
|
}
|
|
902
|
-
|
|
1194
|
+
_this4.scrollToBottom();
|
|
903
1195
|
}
|
|
904
1196
|
});
|
|
905
|
-
|
|
906
|
-
if (!
|
|
907
|
-
|
|
908
|
-
|
|
1197
|
+
_this4.connection.on("ReceiveConversationAssistantToken", function (sessionId, messageId, token, responseId, appearance) {
|
|
1198
|
+
if (!_this4._conversationAssistantMessage) {
|
|
1199
|
+
_this4.stopAudio();
|
|
1200
|
+
_this4.hideTypingIndicator();
|
|
909
1201
|
|
|
910
1202
|
// Ensure no stale streaming indicators remain from prior messages.
|
|
911
|
-
for (var j = 0; j <
|
|
912
|
-
if (
|
|
913
|
-
|
|
1203
|
+
for (var j = 0; j < _this4.messages.length; j++) {
|
|
1204
|
+
if (_this4.messages[j].isStreaming) {
|
|
1205
|
+
_this4.messages[j].isStreaming = false;
|
|
914
1206
|
}
|
|
915
1207
|
}
|
|
916
|
-
var msgIndex =
|
|
1208
|
+
var msgIndex = _this4.messages.length;
|
|
917
1209
|
var newMessage = {
|
|
918
1210
|
id: messageId,
|
|
919
1211
|
role: "assistant",
|
|
@@ -921,72 +1213,72 @@ window.openAIChatManager = function () {
|
|
|
921
1213
|
htmlContent: "",
|
|
922
1214
|
isStreaming: true,
|
|
923
1215
|
userRating: null,
|
|
924
|
-
appearance:
|
|
1216
|
+
appearance: _this4.normalizeAssistantAppearance(appearance)
|
|
925
1217
|
};
|
|
926
|
-
|
|
927
|
-
|
|
1218
|
+
_this4.messages.push(newMessage);
|
|
1219
|
+
_this4._conversationAssistantMessage = {
|
|
928
1220
|
index: msgIndex,
|
|
929
1221
|
content: ''
|
|
930
1222
|
};
|
|
931
1223
|
}
|
|
932
|
-
|
|
933
|
-
var msg =
|
|
1224
|
+
_this4._conversationAssistantMessage.content += token;
|
|
1225
|
+
var msg = _this4.messages[_this4._conversationAssistantMessage.index];
|
|
934
1226
|
if (msg) {
|
|
935
1227
|
if (!msg.appearance) {
|
|
936
|
-
msg.appearance =
|
|
1228
|
+
msg.appearance = _this4.normalizeAssistantAppearance(appearance);
|
|
937
1229
|
}
|
|
938
|
-
msg.content =
|
|
1230
|
+
msg.content = _this4._conversationAssistantMessage.content;
|
|
939
1231
|
msg.htmlContent = parseMarkdownContent(msg.content, msg);
|
|
940
|
-
|
|
1232
|
+
_this4.$nextTick(function () {
|
|
941
1233
|
renderChartsInMessage(msg);
|
|
942
|
-
|
|
1234
|
+
_this4.scrollToBottom();
|
|
943
1235
|
});
|
|
944
1236
|
}
|
|
945
1237
|
});
|
|
946
|
-
|
|
947
|
-
if (
|
|
948
|
-
var msg =
|
|
1238
|
+
_this4.connection.on("ReceiveConversationAssistantComplete", function (sessionId, messageId) {
|
|
1239
|
+
if (_this4._conversationAssistantMessage) {
|
|
1240
|
+
var msg = _this4.messages[_this4._conversationAssistantMessage.index];
|
|
949
1241
|
if (msg) {
|
|
950
1242
|
msg.isStreaming = false;
|
|
951
1243
|
}
|
|
952
|
-
|
|
1244
|
+
_this4._conversationAssistantMessage = null;
|
|
953
1245
|
}
|
|
954
1246
|
});
|
|
955
|
-
|
|
1247
|
+
_this4.connection.on("ReceiveAudioChunk", function (sessionId, base64Audio, contentType) {
|
|
956
1248
|
if (base64Audio) {
|
|
957
1249
|
var binaryString = atob(base64Audio);
|
|
958
1250
|
var bytes = new Uint8Array(binaryString.length);
|
|
959
1251
|
for (var i = 0; i < binaryString.length; i++) {
|
|
960
1252
|
bytes[i] = binaryString.charCodeAt(i);
|
|
961
1253
|
}
|
|
962
|
-
|
|
1254
|
+
_this4.audioChunks.push(bytes);
|
|
963
1255
|
}
|
|
964
1256
|
});
|
|
965
|
-
|
|
966
|
-
|
|
1257
|
+
_this4.connection.on("ReceiveAudioComplete", function (sessionId) {
|
|
1258
|
+
_this4.playCollectedAudio();
|
|
967
1259
|
});
|
|
968
|
-
|
|
969
|
-
|
|
1260
|
+
_this4.connection.on("ReceiveNotification", function (notification) {
|
|
1261
|
+
_this4.receiveNotification(notification);
|
|
970
1262
|
});
|
|
971
|
-
|
|
972
|
-
|
|
1263
|
+
_this4.connection.on("UpdateNotification", function (notification) {
|
|
1264
|
+
_this4.updateNotification(notification);
|
|
973
1265
|
});
|
|
974
|
-
|
|
975
|
-
|
|
1266
|
+
_this4.connection.on("RemoveNotification", function (notificationType) {
|
|
1267
|
+
_this4.removeNotification(notificationType);
|
|
976
1268
|
});
|
|
977
|
-
|
|
1269
|
+
_this4.connection.onreconnecting(function () {
|
|
978
1270
|
console.warn("SignalR: reconnecting...");
|
|
979
1271
|
});
|
|
980
|
-
|
|
1272
|
+
_this4.connection.onreconnected(function () {
|
|
981
1273
|
console.info("SignalR: reconnected.");
|
|
982
|
-
if (
|
|
983
|
-
|
|
1274
|
+
if (_this4.isSessionStarted) {
|
|
1275
|
+
_this4.reloadCurrentSession();
|
|
984
1276
|
} else if (config.autoCreateSession) {
|
|
985
|
-
|
|
1277
|
+
_this4.startNewSession();
|
|
986
1278
|
}
|
|
987
1279
|
});
|
|
988
|
-
|
|
989
|
-
if (
|
|
1280
|
+
_this4.connection.onclose(function (error) {
|
|
1281
|
+
if (_this4.isNavigatingAway) {
|
|
990
1282
|
return;
|
|
991
1283
|
}
|
|
992
1284
|
if (error) {
|
|
@@ -995,7 +1287,7 @@ window.openAIChatManager = function () {
|
|
|
995
1287
|
});
|
|
996
1288
|
_context3.p = 1;
|
|
997
1289
|
_context3.n = 2;
|
|
998
|
-
return
|
|
1290
|
+
return _this4.connection.start();
|
|
999
1291
|
case 2:
|
|
1000
1292
|
_context3.n = 4;
|
|
1001
1293
|
break;
|
|
@@ -1010,7 +1302,7 @@ window.openAIChatManager = function () {
|
|
|
1010
1302
|
}))();
|
|
1011
1303
|
},
|
|
1012
1304
|
addMessageInternal: function addMessageInternal(message) {
|
|
1013
|
-
var
|
|
1305
|
+
var _this5 = this;
|
|
1014
1306
|
if (message.role === 'assistant') {
|
|
1015
1307
|
message.appearance = this.normalizeAssistantAppearance(message.appearance);
|
|
1016
1308
|
}
|
|
@@ -1024,7 +1316,7 @@ window.openAIChatManager = function () {
|
|
|
1024
1316
|
}));
|
|
1025
1317
|
this.messages.push(message);
|
|
1026
1318
|
this.$nextTick(function () {
|
|
1027
|
-
|
|
1319
|
+
_this5.fireEvent(new CustomEvent("addedOpenAIPromotMessage", {
|
|
1028
1320
|
detail: {
|
|
1029
1321
|
message: message
|
|
1030
1322
|
}
|
|
@@ -1032,7 +1324,7 @@ window.openAIChatManager = function () {
|
|
|
1032
1324
|
});
|
|
1033
1325
|
},
|
|
1034
1326
|
addMessage: function addMessage(message) {
|
|
1035
|
-
var
|
|
1327
|
+
var _this6 = this;
|
|
1036
1328
|
// Ensure userRating is always defined for Vue reactivity.
|
|
1037
1329
|
if (message.userRating === undefined) {
|
|
1038
1330
|
message.userRating = null;
|
|
@@ -1120,17 +1412,17 @@ window.openAIChatManager = function () {
|
|
|
1120
1412
|
this.$nextTick(function () {
|
|
1121
1413
|
// Render any pending charts once the DOM is updated
|
|
1122
1414
|
renderChartsInMessage(message);
|
|
1123
|
-
|
|
1415
|
+
_this6.scrollToBottom();
|
|
1124
1416
|
});
|
|
1125
1417
|
},
|
|
1126
1418
|
addMessages: function addMessages(messages) {
|
|
1127
|
-
var
|
|
1419
|
+
var _this7 = this;
|
|
1128
1420
|
for (var i = 0; i < messages.length; i++) {
|
|
1129
1421
|
this.addMessageInternal(messages[i]);
|
|
1130
1422
|
}
|
|
1131
1423
|
this.hidePlaceholder();
|
|
1132
1424
|
this.$nextTick(function () {
|
|
1133
|
-
|
|
1425
|
+
_this7.scrollToBottom();
|
|
1134
1426
|
});
|
|
1135
1427
|
},
|
|
1136
1428
|
hidePlaceholder: function hidePlaceholder() {
|
|
@@ -1207,7 +1499,7 @@ window.openAIChatManager = function () {
|
|
|
1207
1499
|
this.prompt = '';
|
|
1208
1500
|
},
|
|
1209
1501
|
startRecording: function startRecording() {
|
|
1210
|
-
var
|
|
1502
|
+
var _this8 = this;
|
|
1211
1503
|
if (this.isRecording || !this.connection) {
|
|
1212
1504
|
return;
|
|
1213
1505
|
}
|
|
@@ -1219,17 +1511,17 @@ window.openAIChatManager = function () {
|
|
|
1219
1511
|
}
|
|
1220
1512
|
}).then(function (stream) {
|
|
1221
1513
|
var mimeType = MediaRecorder.isTypeSupported('audio/ogg;codecs=opus') ? 'audio/ogg;codecs=opus' : MediaRecorder.isTypeSupported('audio/webm;codecs=opus') ? 'audio/webm;codecs=opus' : 'audio/webm';
|
|
1222
|
-
|
|
1514
|
+
_this8.mediaRecorder = new MediaRecorder(stream, {
|
|
1223
1515
|
mimeType: mimeType,
|
|
1224
1516
|
audioBitsPerSecond: 128000
|
|
1225
1517
|
});
|
|
1226
|
-
|
|
1227
|
-
|
|
1518
|
+
_this8.preRecordingPrompt = _this8.prompt;
|
|
1519
|
+
_this8._audioInputSent = false;
|
|
1228
1520
|
var subject = new signalR.Subject();
|
|
1229
|
-
var profileId =
|
|
1230
|
-
var sessionId =
|
|
1521
|
+
var profileId = _this8.getProfileId();
|
|
1522
|
+
var sessionId = _this8.getSessionId() || '';
|
|
1231
1523
|
var pendingChunk = Promise.resolve();
|
|
1232
|
-
|
|
1524
|
+
_this8.mediaRecorder.addEventListener('dataavailable', function (e) {
|
|
1233
1525
|
if (e.data && e.data.size > 0) {
|
|
1234
1526
|
pendingChunk = pendingChunk.then(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4() {
|
|
1235
1527
|
var data, uint8Array, binaryString, base64;
|
|
@@ -1253,7 +1545,7 @@ window.openAIChatManager = function () {
|
|
|
1253
1545
|
})));
|
|
1254
1546
|
}
|
|
1255
1547
|
});
|
|
1256
|
-
|
|
1548
|
+
_this8.mediaRecorder.addEventListener('stop', function () {
|
|
1257
1549
|
stream.getTracks().forEach(function (track) {
|
|
1258
1550
|
return track.stop();
|
|
1259
1551
|
});
|
|
@@ -1262,10 +1554,10 @@ window.openAIChatManager = function () {
|
|
|
1262
1554
|
});
|
|
1263
1555
|
});
|
|
1264
1556
|
var language = navigator.language || document.documentElement.lang || 'en-US';
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1557
|
+
_this8.connection.send("SendAudioStream", profileId, sessionId, subject, mimeType, language);
|
|
1558
|
+
_this8.mediaRecorder.start(250);
|
|
1559
|
+
_this8.isRecording = true;
|
|
1560
|
+
_this8.updateMicButton();
|
|
1269
1561
|
})["catch"](function (err) {
|
|
1270
1562
|
console.error('Microphone access denied:', err);
|
|
1271
1563
|
});
|
|
@@ -1298,7 +1590,7 @@ window.openAIChatManager = function () {
|
|
|
1298
1590
|
}
|
|
1299
1591
|
},
|
|
1300
1592
|
streamMessage: function streamMessage(profileId, trimmedPrompt, sessionProfileId) {
|
|
1301
|
-
var
|
|
1593
|
+
var _this9 = this;
|
|
1302
1594
|
if (this.stream) {
|
|
1303
1595
|
this.stream.dispose();
|
|
1304
1596
|
this.stream = null;
|
|
@@ -1315,14 +1607,14 @@ window.openAIChatManager = function () {
|
|
|
1315
1607
|
var currentSessionId = this.getSessionId();
|
|
1316
1608
|
this.stream = this.connection.stream("SendMessage", profileId, trimmedPrompt, currentSessionId, sessionProfileId).subscribe({
|
|
1317
1609
|
next: function next(chunk) {
|
|
1318
|
-
var message =
|
|
1610
|
+
var message = _this9.messages[messageIndex];
|
|
1319
1611
|
if (!message) {
|
|
1320
1612
|
if (chunk.sessionId && !currentSessionId) {
|
|
1321
|
-
|
|
1613
|
+
_this9.initializeSession(chunk.sessionId);
|
|
1322
1614
|
}
|
|
1323
|
-
|
|
1615
|
+
_this9.hideTypingIndicator();
|
|
1324
1616
|
// Re-assign the index after hiding the typing indicator.
|
|
1325
|
-
messageIndex =
|
|
1617
|
+
messageIndex = _this9.messages.length;
|
|
1326
1618
|
var newMessage = {
|
|
1327
1619
|
id: chunk.messageId,
|
|
1328
1620
|
role: "assistant",
|
|
@@ -1332,7 +1624,7 @@ window.openAIChatManager = function () {
|
|
|
1332
1624
|
isStreaming: true,
|
|
1333
1625
|
userRating: null
|
|
1334
1626
|
};
|
|
1335
|
-
|
|
1627
|
+
_this9.messages.push(newMessage);
|
|
1336
1628
|
message = newMessage;
|
|
1337
1629
|
}
|
|
1338
1630
|
if (chunk.title && (!message.title || message.title !== chunk.title)) {
|
|
@@ -1372,46 +1664,46 @@ window.openAIChatManager = function () {
|
|
|
1372
1664
|
// Update the existing message
|
|
1373
1665
|
message.content = content;
|
|
1374
1666
|
message.htmlContent = parseMarkdownContent(content, message);
|
|
1375
|
-
|
|
1376
|
-
|
|
1667
|
+
_this9.messages[messageIndex] = message;
|
|
1668
|
+
_this9.$nextTick(function () {
|
|
1377
1669
|
renderChartsInMessage(message);
|
|
1378
|
-
|
|
1670
|
+
_this9.scrollToBottom();
|
|
1379
1671
|
});
|
|
1380
1672
|
},
|
|
1381
1673
|
complete: function complete() {
|
|
1382
|
-
var
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
var msg =
|
|
1674
|
+
var _this9$stream;
|
|
1675
|
+
_this9.processReferences(references, messageIndex);
|
|
1676
|
+
_this9.streamingFinished();
|
|
1677
|
+
var msg = _this9.messages[messageIndex];
|
|
1386
1678
|
if (msg) {
|
|
1387
1679
|
msg.isStreaming = false;
|
|
1388
1680
|
}
|
|
1389
1681
|
if (!msg || !msg.content) {
|
|
1390
1682
|
// No content received at all.
|
|
1391
|
-
|
|
1683
|
+
_this9.hideTypingIndicator();
|
|
1392
1684
|
}
|
|
1393
1685
|
|
|
1394
1686
|
// Trigger text-to-speech only in conversation mode.
|
|
1395
|
-
if (
|
|
1396
|
-
|
|
1687
|
+
if (_this9.isConversationMode && _this9.textToSpeechEnabled && msg && msg.content) {
|
|
1688
|
+
_this9.synthesizeSpeech(msg.content);
|
|
1397
1689
|
}
|
|
1398
|
-
(
|
|
1399
|
-
|
|
1690
|
+
(_this9$stream = _this9.stream) === null || _this9$stream === void 0 || _this9$stream.dispose();
|
|
1691
|
+
_this9.stream = null;
|
|
1400
1692
|
},
|
|
1401
1693
|
error: function error(err) {
|
|
1402
|
-
var
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
var msg =
|
|
1694
|
+
var _this9$stream2;
|
|
1695
|
+
_this9.processReferences(references, messageIndex);
|
|
1696
|
+
_this9.streamingFinished();
|
|
1697
|
+
var msg = _this9.messages[messageIndex];
|
|
1406
1698
|
if (msg) {
|
|
1407
1699
|
msg.isStreaming = false;
|
|
1408
1700
|
}
|
|
1409
|
-
|
|
1410
|
-
if (!
|
|
1411
|
-
|
|
1701
|
+
_this9.hideTypingIndicator();
|
|
1702
|
+
if (!_this9.isNavigatingAway) {
|
|
1703
|
+
_this9.addMessage(_this9.getServiceDownMessage());
|
|
1412
1704
|
}
|
|
1413
|
-
(
|
|
1414
|
-
|
|
1705
|
+
(_this9$stream2 = _this9.stream) === null || _this9$stream2 === void 0 || _this9$stream2.dispose();
|
|
1706
|
+
_this9.stream = null;
|
|
1415
1707
|
console.error("Stream error:", err);
|
|
1416
1708
|
}
|
|
1417
1709
|
});
|
|
@@ -1425,7 +1717,7 @@ window.openAIChatManager = function () {
|
|
|
1425
1717
|
return newMessage;
|
|
1426
1718
|
},
|
|
1427
1719
|
processReferences: function processReferences(references, messageIndex) {
|
|
1428
|
-
var
|
|
1720
|
+
var _this0 = this;
|
|
1429
1721
|
references = normalizeReferences(references);
|
|
1430
1722
|
if (Object.keys(references).length) {
|
|
1431
1723
|
var message = this.messages[messageIndex];
|
|
@@ -1510,7 +1802,7 @@ window.openAIChatManager = function () {
|
|
|
1510
1802
|
this.messages[messageIndex] = message;
|
|
1511
1803
|
this.$nextTick(function () {
|
|
1512
1804
|
renderChartsInMessage(message);
|
|
1513
|
-
|
|
1805
|
+
_this0.scrollToBottom();
|
|
1514
1806
|
});
|
|
1515
1807
|
}
|
|
1516
1808
|
},
|
|
@@ -1553,8 +1845,15 @@ window.openAIChatManager = function () {
|
|
|
1553
1845
|
}
|
|
1554
1846
|
}
|
|
1555
1847
|
},
|
|
1848
|
+
handleExternalTtsStop: function handleExternalTtsStop(e) {
|
|
1849
|
+
var _e$detail;
|
|
1850
|
+
if ((e === null || e === void 0 || (_e$detail = e.detail) === null || _e$detail === void 0 ? void 0 : _e$detail.sourceId) === this.ttsInstanceId) {
|
|
1851
|
+
return;
|
|
1852
|
+
}
|
|
1853
|
+
this.stopAudio(false);
|
|
1854
|
+
},
|
|
1556
1855
|
synthesizeSpeech: function synthesizeSpeech(text, cacheIndex) {
|
|
1557
|
-
var
|
|
1856
|
+
var _this1 = this;
|
|
1558
1857
|
if (!this.textToSpeechEnabled || !text || !this.connection) {
|
|
1559
1858
|
return;
|
|
1560
1859
|
}
|
|
@@ -1563,9 +1862,9 @@ window.openAIChatManager = function () {
|
|
|
1563
1862
|
this._ttsCacheIndex = cacheIndex !== undefined ? cacheIndex : -1;
|
|
1564
1863
|
this.connection.invoke("SynthesizeSpeech", this.getProfileId(), this.getSessionId(), text, this.ttsVoiceName)["catch"](function (err) {
|
|
1565
1864
|
console.error("TTS synthesis error:", err);
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1865
|
+
_this1.isPlayingAudio = false;
|
|
1866
|
+
_this1.ttsPlayingMessageIndex = -1;
|
|
1867
|
+
_this1._ttsCacheIndex = -1;
|
|
1569
1868
|
});
|
|
1570
1869
|
},
|
|
1571
1870
|
toggleMessageTts: function toggleMessageTts(message, index) {
|
|
@@ -1573,7 +1872,12 @@ window.openAIChatManager = function () {
|
|
|
1573
1872
|
this.stopAudio();
|
|
1574
1873
|
return;
|
|
1575
1874
|
}
|
|
1576
|
-
this.stopAudio();
|
|
1875
|
+
this.stopAudio(false);
|
|
1876
|
+
window.dispatchEvent(new CustomEvent('crestapps-ai-chat-stop-tts', {
|
|
1877
|
+
detail: {
|
|
1878
|
+
sourceId: this.ttsInstanceId
|
|
1879
|
+
}
|
|
1880
|
+
}));
|
|
1577
1881
|
this.ttsPlayingMessageIndex = index;
|
|
1578
1882
|
if (this.ttsAudioCache[index]) {
|
|
1579
1883
|
this.playAudioBlob(this.ttsAudioCache[index]);
|
|
@@ -1585,6 +1889,7 @@ window.openAIChatManager = function () {
|
|
|
1585
1889
|
if (this.audioChunks.length === 0) {
|
|
1586
1890
|
if (!this.currentAudioElement && this.audioPlayQueue.length === 0) {
|
|
1587
1891
|
this.isPlayingAudio = false;
|
|
1892
|
+
this.ttsPlayingMessageIndex = -1;
|
|
1588
1893
|
}
|
|
1589
1894
|
return;
|
|
1590
1895
|
}
|
|
@@ -1623,26 +1928,32 @@ window.openAIChatManager = function () {
|
|
|
1623
1928
|
this.playAudioBlob(blob);
|
|
1624
1929
|
},
|
|
1625
1930
|
playAudioBlob: function playAudioBlob(blob) {
|
|
1626
|
-
var
|
|
1931
|
+
var _this10 = this;
|
|
1627
1932
|
var url = URL.createObjectURL(blob);
|
|
1628
1933
|
var audio = new Audio(url);
|
|
1934
|
+
this.currentAudioUrl = url;
|
|
1629
1935
|
this.currentAudioElement = audio;
|
|
1630
1936
|
this.isPlayingAudio = true;
|
|
1631
1937
|
audio.addEventListener('ended', function () {
|
|
1938
|
+
_this10.currentAudioElement = null;
|
|
1939
|
+
_this10.currentAudioUrl = null;
|
|
1632
1940
|
URL.revokeObjectURL(url);
|
|
1633
|
-
|
|
1634
|
-
_this1.playNextInQueue();
|
|
1941
|
+
_this10.playNextInQueue();
|
|
1635
1942
|
});
|
|
1636
1943
|
audio.addEventListener('error', function () {
|
|
1944
|
+
_this10.currentAudioElement = null;
|
|
1945
|
+
_this10.currentAudioUrl = null;
|
|
1637
1946
|
URL.revokeObjectURL(url);
|
|
1638
|
-
|
|
1639
|
-
_this1.playNextInQueue();
|
|
1947
|
+
_this10.playNextInQueue();
|
|
1640
1948
|
});
|
|
1641
1949
|
audio.play()["catch"](function (err) {
|
|
1642
1950
|
console.error("Audio playback error:", err);
|
|
1951
|
+
_this10.currentAudioElement = null;
|
|
1952
|
+
_this10.currentAudioUrl = null;
|
|
1643
1953
|
URL.revokeObjectURL(url);
|
|
1644
|
-
|
|
1645
|
-
|
|
1954
|
+
_this10.audioPlayQueue = [];
|
|
1955
|
+
_this10.isPlayingAudio = false;
|
|
1956
|
+
_this10.ttsPlayingMessageIndex = -1;
|
|
1646
1957
|
});
|
|
1647
1958
|
},
|
|
1648
1959
|
playNextInQueue: function playNextInQueue() {
|
|
@@ -1661,6 +1972,10 @@ window.openAIChatManager = function () {
|
|
|
1661
1972
|
this.currentAudioElement.currentTime = 0;
|
|
1662
1973
|
this.currentAudioElement = null;
|
|
1663
1974
|
}
|
|
1975
|
+
if (this.currentAudioUrl) {
|
|
1976
|
+
URL.revokeObjectURL(this.currentAudioUrl);
|
|
1977
|
+
this.currentAudioUrl = null;
|
|
1978
|
+
}
|
|
1664
1979
|
this.audioChunks = [];
|
|
1665
1980
|
this.audioPlayQueue = [];
|
|
1666
1981
|
this.isPlayingAudio = false;
|
|
@@ -1674,7 +1989,7 @@ window.openAIChatManager = function () {
|
|
|
1674
1989
|
}
|
|
1675
1990
|
},
|
|
1676
1991
|
startConversationMode: function startConversationMode() {
|
|
1677
|
-
var
|
|
1992
|
+
var _this11 = this;
|
|
1678
1993
|
if (!this.conversationModeEnabled || this.isConversationMode || !this.connection) {
|
|
1679
1994
|
return;
|
|
1680
1995
|
}
|
|
@@ -1694,12 +2009,12 @@ window.openAIChatManager = function () {
|
|
|
1694
2009
|
}
|
|
1695
2010
|
}).then(function (stream) {
|
|
1696
2011
|
var mimeType = MediaRecorder.isTypeSupported('audio/ogg;codecs=opus') ? 'audio/ogg;codecs=opus' : MediaRecorder.isTypeSupported('audio/webm;codecs=opus') ? 'audio/webm;codecs=opus' : 'audio/webm';
|
|
1697
|
-
|
|
2012
|
+
_this11.mediaRecorder = new MediaRecorder(stream, {
|
|
1698
2013
|
mimeType: mimeType,
|
|
1699
2014
|
audioBitsPerSecond: 128000
|
|
1700
2015
|
});
|
|
1701
|
-
|
|
1702
|
-
|
|
2016
|
+
_this11._conversationSubject = new signalR.Subject();
|
|
2017
|
+
_this11._conversationStream = stream;
|
|
1703
2018
|
|
|
1704
2019
|
// Create an AnalyserNode for volume-based interrupt detection.
|
|
1705
2020
|
// During TTS playback, detect when the user speaks above
|
|
@@ -1708,20 +2023,20 @@ window.openAIChatManager = function () {
|
|
|
1708
2023
|
// speaker echo so the STT stream has no gaps.
|
|
1709
2024
|
var AudioCtx = window.AudioContext || window.webkitAudioContext;
|
|
1710
2025
|
if (AudioCtx) {
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
var micSource =
|
|
1715
|
-
micSource.connect(
|
|
2026
|
+
_this11._conversationAudioCtx = new AudioCtx();
|
|
2027
|
+
_this11._conversationAnalyser = _this11._conversationAudioCtx.createAnalyser();
|
|
2028
|
+
_this11._conversationAnalyser.fftSize = 256;
|
|
2029
|
+
var micSource = _this11._conversationAudioCtx.createMediaStreamSource(stream);
|
|
2030
|
+
micSource.connect(_this11._conversationAnalyser);
|
|
1716
2031
|
}
|
|
1717
2032
|
var pendingChunk = Promise.resolve();
|
|
1718
|
-
var analyser =
|
|
2033
|
+
var analyser = _this11._conversationAnalyser;
|
|
1719
2034
|
var interruptVolumeThreshold = 30;
|
|
1720
|
-
|
|
2035
|
+
_this11.mediaRecorder.addEventListener('dataavailable', function (e) {
|
|
1721
2036
|
if (e.data && e.data.size > 0) {
|
|
1722
2037
|
// During TTS playback, check mic volume to detect
|
|
1723
2038
|
// user interruption (speaking above threshold).
|
|
1724
|
-
if (
|
|
2039
|
+
if (_this11.isPlayingAudio && analyser) {
|
|
1725
2040
|
var freqData = new Uint8Array(analyser.frequencyBinCount);
|
|
1726
2041
|
analyser.getByteFrequencyData(freqData);
|
|
1727
2042
|
var sum = 0;
|
|
@@ -1731,7 +2046,7 @@ window.openAIChatManager = function () {
|
|
|
1731
2046
|
var avg = sum / freqData.length;
|
|
1732
2047
|
if (avg >= interruptVolumeThreshold) {
|
|
1733
2048
|
// User is speaking — interrupt TTS playback.
|
|
1734
|
-
|
|
2049
|
+
_this11.stopAudio();
|
|
1735
2050
|
}
|
|
1736
2051
|
}
|
|
1737
2052
|
|
|
@@ -1753,7 +2068,7 @@ window.openAIChatManager = function () {
|
|
|
1753
2068
|
}, '');
|
|
1754
2069
|
base64 = btoa(binaryString);
|
|
1755
2070
|
try {
|
|
1756
|
-
|
|
2071
|
+
_this11._conversationSubject.next(base64);
|
|
1757
2072
|
} catch (err) {
|
|
1758
2073
|
// Subject may have been completed already.
|
|
1759
2074
|
}
|
|
@@ -1764,28 +2079,28 @@ window.openAIChatManager = function () {
|
|
|
1764
2079
|
})));
|
|
1765
2080
|
}
|
|
1766
2081
|
});
|
|
1767
|
-
|
|
2082
|
+
_this11.mediaRecorder.addEventListener('stop', function () {
|
|
1768
2083
|
stream.getTracks().forEach(function (track) {
|
|
1769
2084
|
return track.stop();
|
|
1770
2085
|
});
|
|
1771
2086
|
pendingChunk.then(function () {
|
|
1772
2087
|
try {
|
|
1773
|
-
|
|
2088
|
+
_this11._conversationSubject.complete();
|
|
1774
2089
|
} catch (err) {
|
|
1775
2090
|
// Already completed.
|
|
1776
2091
|
}
|
|
1777
2092
|
});
|
|
1778
2093
|
});
|
|
1779
|
-
var profileId =
|
|
1780
|
-
var sessionId =
|
|
2094
|
+
var profileId = _this11.getProfileId();
|
|
2095
|
+
var sessionId = _this11.getSessionId() || '';
|
|
1781
2096
|
var language = navigator.language || document.documentElement.lang || 'en-US';
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
2097
|
+
_this11.connection.send("StartConversation", profileId, sessionId, _this11._conversationSubject, mimeType, language);
|
|
2098
|
+
_this11.mediaRecorder.start(250);
|
|
2099
|
+
_this11.isRecording = true;
|
|
1785
2100
|
})["catch"](function (err) {
|
|
1786
2101
|
console.error('Microphone access denied:', err);
|
|
1787
|
-
|
|
1788
|
-
|
|
2102
|
+
_this11.isConversationMode = false;
|
|
2103
|
+
_this11.updateConversationButton();
|
|
1789
2104
|
});
|
|
1790
2105
|
},
|
|
1791
2106
|
stopConversationMode: function stopConversationMode() {
|
|
@@ -1912,7 +2227,7 @@ window.openAIChatManager = function () {
|
|
|
1912
2227
|
return removedCount;
|
|
1913
2228
|
},
|
|
1914
2229
|
receiveNotification: function receiveNotification(notification) {
|
|
1915
|
-
var
|
|
2230
|
+
var _this12 = this;
|
|
1916
2231
|
if (!notification || !notification.type) {
|
|
1917
2232
|
return;
|
|
1918
2233
|
}
|
|
@@ -1927,7 +2242,7 @@ window.openAIChatManager = function () {
|
|
|
1927
2242
|
}
|
|
1928
2243
|
this.scheduleNotificationDismiss(notification);
|
|
1929
2244
|
this.$nextTick(function () {
|
|
1930
|
-
|
|
2245
|
+
_this12.scrollToBottom();
|
|
1931
2246
|
});
|
|
1932
2247
|
},
|
|
1933
2248
|
updateNotification: function updateNotification(notification) {
|
|
@@ -1944,12 +2259,12 @@ window.openAIChatManager = function () {
|
|
|
1944
2259
|
}
|
|
1945
2260
|
},
|
|
1946
2261
|
scheduleNotificationDismiss: function scheduleNotificationDismiss(notification) {
|
|
1947
|
-
var
|
|
2262
|
+
var _this13 = this;
|
|
1948
2263
|
if (!notification || !notification.type || !notification.autoDismissMs || notification.autoDismissMs <= 0) {
|
|
1949
2264
|
return;
|
|
1950
2265
|
}
|
|
1951
2266
|
this.notificationDismissTimers[notification.type] = setTimeout(function () {
|
|
1952
|
-
|
|
2267
|
+
_this13.removeNotification(notification.type);
|
|
1953
2268
|
}, notification.autoDismissMs);
|
|
1954
2269
|
},
|
|
1955
2270
|
clearNotificationDismiss: function clearNotificationDismiss(notificationType) {
|
|
@@ -1979,12 +2294,12 @@ window.openAIChatManager = function () {
|
|
|
1979
2294
|
});
|
|
1980
2295
|
},
|
|
1981
2296
|
scrollToBottom: function scrollToBottom() {
|
|
1982
|
-
var
|
|
2297
|
+
var _this14 = this;
|
|
1983
2298
|
if (!this.autoScroll) {
|
|
1984
2299
|
return;
|
|
1985
2300
|
}
|
|
1986
2301
|
setTimeout(function () {
|
|
1987
|
-
|
|
2302
|
+
_this14.chatContainer.scrollTop = _this14.chatContainer.scrollHeight - _this14.chatContainer.clientHeight;
|
|
1988
2303
|
}, 50);
|
|
1989
2304
|
},
|
|
1990
2305
|
handleUserInput: function handleUserInput(event) {
|
|
@@ -2026,16 +2341,16 @@ window.openAIChatManager = function () {
|
|
|
2026
2341
|
});
|
|
2027
2342
|
},
|
|
2028
2343
|
initializeApp: function initializeApp() {
|
|
2029
|
-
var
|
|
2344
|
+
var _this15 = this;
|
|
2030
2345
|
this.inputElement = document.querySelector(config.inputElementSelector);
|
|
2031
2346
|
this.buttonElement = document.querySelector(config.sendButtonElementSelector);
|
|
2032
2347
|
this.chatContainer = document.querySelector(config.chatContainerElementSelector);
|
|
2033
2348
|
this.placeholder = document.querySelector(config.placeholderElementSelector);
|
|
2034
2349
|
this.applyOrchestratorAvailability();
|
|
2035
2350
|
var sessionId = this.getSessionId();
|
|
2036
|
-
if (!
|
|
2351
|
+
if (!hasWidgetConfig && sessionId) {
|
|
2037
2352
|
this.loadSession(sessionId);
|
|
2038
|
-
} else if (this.isOrchestratorAvailable() && config.autoCreateSession && !
|
|
2353
|
+
} else if (this.isOrchestratorAvailable() && config.autoCreateSession && !hasWidgetConfig && !sessionId) {
|
|
2039
2354
|
this.startNewSession();
|
|
2040
2355
|
}
|
|
2041
2356
|
|
|
@@ -2055,7 +2370,7 @@ window.openAIChatManager = function () {
|
|
|
2055
2370
|
fileInput.accept = config.allowedExtensions;
|
|
2056
2371
|
}
|
|
2057
2372
|
fileInput.addEventListener('change', function (e) {
|
|
2058
|
-
return
|
|
2373
|
+
return _this15.handleFileInputChange(e);
|
|
2059
2374
|
});
|
|
2060
2375
|
this.documentBar.parentElement.appendChild(fileInput);
|
|
2061
2376
|
|
|
@@ -2063,13 +2378,13 @@ window.openAIChatManager = function () {
|
|
|
2063
2378
|
var inputArea = this.inputElement ? this.inputElement.closest('.ai-admin-widget-input, .text-bg-light') : null;
|
|
2064
2379
|
if (inputArea) {
|
|
2065
2380
|
inputArea.addEventListener('dragover', function (e) {
|
|
2066
|
-
return
|
|
2381
|
+
return _this15.handleDragOver(e);
|
|
2067
2382
|
});
|
|
2068
2383
|
inputArea.addEventListener('dragleave', function (e) {
|
|
2069
|
-
return
|
|
2384
|
+
return _this15.handleDragLeave(e);
|
|
2070
2385
|
});
|
|
2071
2386
|
inputArea.addEventListener('drop', function (e) {
|
|
2072
|
-
return
|
|
2387
|
+
return _this15.handleDrop(e);
|
|
2073
2388
|
});
|
|
2074
2389
|
}
|
|
2075
2390
|
}
|
|
@@ -2077,55 +2392,55 @@ window.openAIChatManager = function () {
|
|
|
2077
2392
|
|
|
2078
2393
|
// Pause auto-scroll when the user manually scrolls up during streaming.
|
|
2079
2394
|
this.chatContainer.addEventListener('scroll', function () {
|
|
2080
|
-
if (!
|
|
2395
|
+
if (!_this15.stream) {
|
|
2081
2396
|
return;
|
|
2082
2397
|
}
|
|
2083
2398
|
var threshold = 30;
|
|
2084
|
-
var atBottom =
|
|
2085
|
-
|
|
2399
|
+
var atBottom = _this15.chatContainer.scrollHeight - _this15.chatContainer.clientHeight - _this15.chatContainer.scrollTop <= threshold;
|
|
2400
|
+
_this15.autoScroll = atBottom;
|
|
2086
2401
|
});
|
|
2087
2402
|
this.inputElement.addEventListener('keydown', function (event) {
|
|
2088
|
-
if (
|
|
2403
|
+
if (_this15.stream != null) {
|
|
2089
2404
|
return;
|
|
2090
2405
|
}
|
|
2091
2406
|
if (event.key === "Enter" && !event.shiftKey) {
|
|
2092
2407
|
event.preventDefault();
|
|
2093
|
-
|
|
2408
|
+
_this15.buttonElement.click();
|
|
2094
2409
|
}
|
|
2095
2410
|
});
|
|
2096
2411
|
this.inputElement.addEventListener('input', function (e) {
|
|
2097
|
-
|
|
2412
|
+
_this15.handleUserInput(e);
|
|
2098
2413
|
if (e.target.value.trim()) {
|
|
2099
|
-
|
|
2414
|
+
_this15.buttonElement.removeAttribute('disabled');
|
|
2100
2415
|
} else {
|
|
2101
|
-
|
|
2416
|
+
_this15.buttonElement.setAttribute('disabled', true);
|
|
2102
2417
|
}
|
|
2103
2418
|
});
|
|
2104
2419
|
this.buttonElement.addEventListener('click', function () {
|
|
2105
|
-
if (
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2420
|
+
if (_this15.stream != null) {
|
|
2421
|
+
_this15.stream.dispose();
|
|
2422
|
+
_this15.stream = null;
|
|
2423
|
+
_this15.streamingFinished();
|
|
2424
|
+
_this15.hideTypingIndicator();
|
|
2110
2425
|
|
|
2111
2426
|
// Clean up: remove empty assistant message or stop streaming animation.
|
|
2112
|
-
if (
|
|
2113
|
-
var lastMsg =
|
|
2427
|
+
if (_this15.messages.length > 0) {
|
|
2428
|
+
var lastMsg = _this15.messages[_this15.messages.length - 1];
|
|
2114
2429
|
if (lastMsg.role === 'assistant' && !lastMsg.content) {
|
|
2115
|
-
|
|
2430
|
+
_this15.messages.pop();
|
|
2116
2431
|
} else if (lastMsg.isStreaming) {
|
|
2117
2432
|
lastMsg.isStreaming = false;
|
|
2118
2433
|
}
|
|
2119
2434
|
}
|
|
2120
2435
|
return;
|
|
2121
2436
|
}
|
|
2122
|
-
|
|
2437
|
+
_this15.sendMessage();
|
|
2123
2438
|
});
|
|
2124
2439
|
var promptGenerators = document.getElementsByClassName('profile-generated-prompt');
|
|
2125
2440
|
for (var i = 0; i < promptGenerators.length; i++) {
|
|
2126
2441
|
promptGenerators[i].addEventListener('click', function (e) {
|
|
2127
2442
|
e.preventDefault();
|
|
2128
|
-
|
|
2443
|
+
_this15.generatePrompt(e.target);
|
|
2129
2444
|
});
|
|
2130
2445
|
}
|
|
2131
2446
|
var chatSessions = document.getElementsByClassName('chat-session-history-item');
|
|
@@ -2137,8 +2452,8 @@ window.openAIChatManager = function () {
|
|
|
2137
2452
|
console.error('an element with the class chat-session-history-item with no data-session-id set.');
|
|
2138
2453
|
return;
|
|
2139
2454
|
}
|
|
2140
|
-
|
|
2141
|
-
|
|
2455
|
+
_this15.loadSession(sessionId);
|
|
2456
|
+
_this15.showChatScreen();
|
|
2142
2457
|
});
|
|
2143
2458
|
}
|
|
2144
2459
|
for (var _i5 = 0; _i5 < config.messages.length; _i5++) {
|
|
@@ -2147,7 +2462,7 @@ window.openAIChatManager = function () {
|
|
|
2147
2462
|
|
|
2148
2463
|
// Update feedback icons in the DOM after initial messages have rendered.
|
|
2149
2464
|
this.$nextTick(function () {
|
|
2150
|
-
|
|
2465
|
+
_this15.refreshAllFeedbackIcons();
|
|
2151
2466
|
});
|
|
2152
2467
|
|
|
2153
2468
|
// Delegate click for code block copy buttons.
|
|
@@ -2179,7 +2494,7 @@ window.openAIChatManager = function () {
|
|
|
2179
2494
|
if (this.micButton) {
|
|
2180
2495
|
this.micButton.style.display = '';
|
|
2181
2496
|
this.micButton.addEventListener('click', function () {
|
|
2182
|
-
|
|
2497
|
+
_this15.toggleRecording();
|
|
2183
2498
|
});
|
|
2184
2499
|
}
|
|
2185
2500
|
}
|
|
@@ -2189,7 +2504,7 @@ window.openAIChatManager = function () {
|
|
|
2189
2504
|
this.conversationButton = document.querySelector(config.conversationButtonElementSelector);
|
|
2190
2505
|
if (this.conversationButton) {
|
|
2191
2506
|
this.conversationButton.addEventListener('click', function () {
|
|
2192
|
-
|
|
2507
|
+
_this15.toggleConversationMode();
|
|
2193
2508
|
});
|
|
2194
2509
|
}
|
|
2195
2510
|
}
|
|
@@ -2221,7 +2536,7 @@ window.openAIChatManager = function () {
|
|
|
2221
2536
|
}
|
|
2222
2537
|
},
|
|
2223
2538
|
initializeWidget: function initializeWidget() {
|
|
2224
|
-
var
|
|
2539
|
+
var _this16 = this;
|
|
2225
2540
|
if (!config.widget.chatWidgetContainer) {
|
|
2226
2541
|
console.error('The widget chatWidgetContainer is required.');
|
|
2227
2542
|
return;
|
|
@@ -2239,7 +2554,51 @@ window.openAIChatManager = function () {
|
|
|
2239
2554
|
}
|
|
2240
2555
|
this.chatWidgetStateName = config.widget.chatWidgetStateName;
|
|
2241
2556
|
this.chatWidgetStateSession = config.widget.chatWidgetStateName + 'Session';
|
|
2557
|
+
this.chatWidgetLayoutKey = config.widget.chatWidgetStateName + 'Layout';
|
|
2558
|
+
this.widgetContainerElement = chatWidgetContainer;
|
|
2559
|
+
this.widgetToggleButtonElement = config.widget.toggleButtonSelector ? document.querySelector(config.widget.toggleButtonSelector) : null;
|
|
2560
|
+
this.widgetResetSizeButtonElement = config.widget.resetSizeButtonSelector ? document.querySelector(config.widget.resetSizeButtonSelector) : null;
|
|
2561
|
+
this.widgetDefaultWidth = parsePixelValue(config.widget.defaultWidth) || parsePixelValue(window.getComputedStyle(chatWidgetContainer).width) || 380;
|
|
2562
|
+
this.widgetDefaultHeight = parsePixelValue(config.widget.defaultHeight) || parsePixelValue(window.getComputedStyle(chatWidgetContainer).height) || 520;
|
|
2242
2563
|
this.widgetIsInitialized = true;
|
|
2564
|
+
if (config.widget.enableResizing) {
|
|
2565
|
+
chatWidgetContainer.classList.add('ai-chat-widget-resizable');
|
|
2566
|
+
chatWidgetContainer.style.minWidth = (parsePixelValue(config.widget.minWidth) || 320) + 'px';
|
|
2567
|
+
chatWidgetContainer.style.minHeight = (parsePixelValue(config.widget.minHeight) || 420) + 'px';
|
|
2568
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
2569
|
+
this.widgetResizeObserver = new ResizeObserver(function () {
|
|
2570
|
+
_this16.persistWidgetPanelSize();
|
|
2571
|
+
_this16.constrainWidgetElementsToViewport();
|
|
2572
|
+
_this16.updateWidgetResetSizeButtonVisibility();
|
|
2573
|
+
});
|
|
2574
|
+
this.widgetResizeObserver.observe(chatWidgetContainer);
|
|
2575
|
+
}
|
|
2576
|
+
}
|
|
2577
|
+
var dragHandleSelector = config.widget.dragHandleSelector || '.ai-chat-widget-header';
|
|
2578
|
+
var dragHandle = chatWidgetContainer.querySelector(dragHandleSelector);
|
|
2579
|
+
if (config.widget.enableDragging && dragHandle) {
|
|
2580
|
+
dragHandle.classList.add('ai-chat-widget-drag-handle');
|
|
2581
|
+
chatWidgetContainer.classList.add('ai-chat-widget-draggable');
|
|
2582
|
+
this.attachDraggableWidgetElement(chatWidgetContainer, dragHandle, 'panel', false);
|
|
2583
|
+
}
|
|
2584
|
+
if (config.widget.enableDragging && this.widgetToggleButtonElement) {
|
|
2585
|
+
this.widgetToggleButtonElement.classList.add('ai-chat-widget-draggable');
|
|
2586
|
+
this.attachDraggableWidgetElement(this.widgetToggleButtonElement, this.widgetToggleButtonElement, 'toggle', true);
|
|
2587
|
+
}
|
|
2588
|
+
if (this.widgetResetSizeButtonElement) {
|
|
2589
|
+
this.widgetResetSizeButtonElement.addEventListener('click', function (event) {
|
|
2590
|
+
event.preventDefault();
|
|
2591
|
+
_this16.resetWidgetSize();
|
|
2592
|
+
});
|
|
2593
|
+
}
|
|
2594
|
+
this.restoreWidgetLayout();
|
|
2595
|
+
if (!this.widgetViewportResizeHandler) {
|
|
2596
|
+
this.widgetViewportResizeHandler = function () {
|
|
2597
|
+
_this16.constrainWidgetElementsToViewport();
|
|
2598
|
+
_this16.updateWidgetResetSizeButtonVisibility();
|
|
2599
|
+
};
|
|
2600
|
+
window.addEventListener('resize', this.widgetViewportResizeHandler);
|
|
2601
|
+
}
|
|
2243
2602
|
|
|
2244
2603
|
// Auto-load the last session so the user always sees previous chat history.
|
|
2245
2604
|
this.reloadCurrentSession();
|
|
@@ -2250,14 +2609,14 @@ window.openAIChatManager = function () {
|
|
|
2250
2609
|
var showHistoryButton = document.querySelector(config.widget.showHistoryButton);
|
|
2251
2610
|
if (showHistoryButton) {
|
|
2252
2611
|
showHistoryButton.addEventListener('click', function () {
|
|
2253
|
-
|
|
2612
|
+
_this16.chatHistorySection.classList.toggle('show');
|
|
2254
2613
|
});
|
|
2255
2614
|
}
|
|
2256
2615
|
if (config.widget.closeHistoryButton) {
|
|
2257
2616
|
var closeHistoryButton = document.querySelector(config.widget.closeHistoryButton);
|
|
2258
2617
|
if (closeHistoryButton) {
|
|
2259
2618
|
closeHistoryButton.addEventListener('click', function () {
|
|
2260
|
-
|
|
2619
|
+
_this16.showChatScreen();
|
|
2261
2620
|
});
|
|
2262
2621
|
}
|
|
2263
2622
|
}
|
|
@@ -2266,8 +2625,8 @@ window.openAIChatManager = function () {
|
|
|
2266
2625
|
var newChatButton = document.querySelector(config.widget.newChatButton);
|
|
2267
2626
|
if (newChatButton) {
|
|
2268
2627
|
newChatButton.addEventListener('click', function () {
|
|
2269
|
-
|
|
2270
|
-
|
|
2628
|
+
_this16.resetSession();
|
|
2629
|
+
_this16.showChatScreen();
|
|
2271
2630
|
});
|
|
2272
2631
|
}
|
|
2273
2632
|
}
|
|
@@ -2403,17 +2762,17 @@ window.openAIChatManager = function () {
|
|
|
2403
2762
|
}
|
|
2404
2763
|
},
|
|
2405
2764
|
mounted: function mounted() {
|
|
2406
|
-
var
|
|
2765
|
+
var _this17 = this;
|
|
2407
2766
|
_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6() {
|
|
2408
2767
|
return _regenerator().w(function (_context6) {
|
|
2409
2768
|
while (1) switch (_context6.n) {
|
|
2410
2769
|
case 0:
|
|
2411
2770
|
_context6.n = 1;
|
|
2412
|
-
return
|
|
2771
|
+
return _this17.startConnection();
|
|
2413
2772
|
case 1:
|
|
2414
|
-
|
|
2415
|
-
if (
|
|
2416
|
-
|
|
2773
|
+
_this17.initializeApp();
|
|
2774
|
+
if (hasWidgetConfig) {
|
|
2775
|
+
_this17.initializeWidget();
|
|
2417
2776
|
}
|
|
2418
2777
|
case 2:
|
|
2419
2778
|
return _context6.a(2);
|
|
@@ -2421,9 +2780,12 @@ window.openAIChatManager = function () {
|
|
|
2421
2780
|
}, _callee6);
|
|
2422
2781
|
}))();
|
|
2423
2782
|
window.addEventListener('beforeunload', this.handleBeforeUnload);
|
|
2783
|
+
window.addEventListener('crestapps-ai-chat-stop-tts', this.handleExternalTtsStop);
|
|
2424
2784
|
},
|
|
2425
2785
|
beforeUnmount: function beforeUnmount() {
|
|
2426
2786
|
window.removeEventListener('beforeunload', this.handleBeforeUnload);
|
|
2787
|
+
window.removeEventListener('crestapps-ai-chat-stop-tts', this.handleExternalTtsStop);
|
|
2788
|
+
this.stopAudio(false);
|
|
2427
2789
|
if (this.stream) {
|
|
2428
2790
|
this.stream.dispose();
|
|
2429
2791
|
this.stream = null;
|