@crestapps/ai-chat-ui 1.0.0-preview.7 → 1.0.0-preview.9
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.css +362 -0
- package/dist/ai-chat.css.map +1 -0
- package/dist/ai-chat.js +244 -131
- package/dist/ai-chat.js.map +1 -1
- package/dist/ai-chat.min.css +1 -0
- package/dist/ai-chat.min.js +1 -1
- package/dist/ai-chat.min.js.map +1 -1
- package/dist/chat-interaction.js +9 -9
- 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 +104 -3
- package/dist/chat-widget.css.map +1 -1
- package/dist/chat-widget.min.css +1 -1
- package/package.json +4 -1
package/dist/ai-chat.js
CHANGED
|
@@ -52,8 +52,8 @@ window.openAIChatManager = function () {
|
|
|
52
52
|
minWidth: 320,
|
|
53
53
|
minHeight: 420
|
|
54
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)\"><
|
|
56
|
-
indicatorTemplate: "\n <div class=\"ai-chat-msg-role ai-chat-msg-role-assistant\">\n <span class=\"ai-streaming-icon\"><
|
|
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)\"><span :class=\"getAssistantIcon(message)\"></span></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 <span class=\"fa-regular fa-thumbs-up\"></span>\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 <span class=\"fa-regular fa-thumbs-down\"></span>\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 }\" :data-tts-message-index=\"index\" @click=\"toggleMessageTts(message, index)\" :title=\"ttsPlayingMessageIndex === index ? 'Pause audio' : 'Read aloud'\">\n <span :class=\"ttsPlayingMessageIndex === index ? 'fa-solid fa-circle-pause' : 'fa-solid fa-circle-play'\"></span>\n </button>\n <button class=\"btn btn-sm btn-link text-secondary p-0 button-message-toolbox\" @click=\"copyResponse(message.content)\" :title=\"copyTitle\">\n <span class=\"fa-solid fa-copy\"></span>\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 <span v-if=\"notification.icon\" :class=\"notification.icon\" class=\"ai-chat-notification-icon\"></span>\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 <span class=\"fa-solid fa-xmark\"></span>\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 <span v-if=\"action.icon\" :class=\"action.icon\" class=\"me-1\"></span>\n {{ action.label }}\n </button>\n </div>\n </div>\n </div>\n ",
|
|
56
|
+
indicatorTemplate: "\n <div class=\"ai-chat-msg-role ai-chat-msg-role-assistant\">\n <span class=\"ai-streaming-icon\"><span class=\"fa fa-robot\" style=\"display: inline-block;\"></span></span>\n Assistant\n </div>\n "
|
|
57
57
|
};
|
|
58
58
|
|
|
59
59
|
// Sanitize URLs to prevent javascript: protocol injection.
|
|
@@ -140,7 +140,7 @@ window.openAIChatManager = function () {
|
|
|
140
140
|
highlighted = escapeHtmlEntities(code);
|
|
141
141
|
}
|
|
142
142
|
var langDisplay = lang ? escapeHtmlEntities(lang) : 'code';
|
|
143
|
-
return "<div class=\"ai-code-block\"><div class=\"ai-code-header\"><span class=\"ai-code-lang\"><
|
|
143
|
+
return "<div class=\"ai-code-block\"><div class=\"ai-code-header\"><span class=\"ai-code-lang\"><span class=\"fa-solid fa-code\"></span> ".concat(langDisplay, "</span><button type=\"button\" class=\"ai-code-copy-btn\" title=\"Copy code\"><span class=\"fa-regular fa-copy\"></span></button></div><pre><code class=\"hljs").concat(lang ? ' language-' + lang : '', "\">").concat(highlighted, "</code></pre></div>");
|
|
144
144
|
};
|
|
145
145
|
|
|
146
146
|
// Custom image renderer for generated images with thumbnail styling and download button.
|
|
@@ -150,7 +150,7 @@ window.openAIChatManager = function () {
|
|
|
150
150
|
if (!src) return '';
|
|
151
151
|
var alt = data.text || defaultConfig.generatedImageAltText;
|
|
152
152
|
var maxWidth = defaultConfig.generatedImageMaxWidth;
|
|
153
|
-
return "<div class=\"generated-image-container\">\n <img src=\"".concat(src, "\" alt=\"").concat(alt, "\" class=\"img-thumbnail\" style=\"max-width: ").concat(maxWidth, "px; height: auto;\" />\n <div class=\"mt-2\">\n <a href=\"").concat(src, "\" target=\"_blank\" download=\"").concat(alt, "\" title=\"").concat(defaultConfig.downloadImageTitle, "\" class=\"btn btn-sm btn-outline-secondary ai-download-image\">\n <
|
|
153
|
+
return "<div class=\"generated-image-container\">\n <img src=\"".concat(src, "\" alt=\"").concat(alt, "\" class=\"img-thumbnail\" style=\"max-width: ").concat(maxWidth, "px; height: auto;\" />\n <div class=\"mt-2\">\n <a href=\"").concat(src, "\" target=\"_blank\" download=\"").concat(alt, "\" title=\"").concat(defaultConfig.downloadImageTitle, "\" class=\"btn btn-sm btn-outline-secondary ai-download-image\">\n <span class=\"fa-solid fa-download\"></span>\n </a>\n </div>\n </div>");
|
|
154
154
|
};
|
|
155
155
|
|
|
156
156
|
// Chart counter for unique IDs
|
|
@@ -164,7 +164,7 @@ window.openAIChatManager = function () {
|
|
|
164
164
|
// its DOM update to render charts it didn't create itself.
|
|
165
165
|
window.__chartConfigs = window.__chartConfigs || {};
|
|
166
166
|
function createChartHtml(chartId) {
|
|
167
|
-
return "<div class=\"chart-container\" style=\"position: relative; width: 100%; max-width: 560px; min-height: 420px;\">" + "<canvas id=\"".concat(chartId, "\"></canvas>") + "</div>" + "<div class=\"mt-2\">" + "<button type=\"button\" class=\"btn btn-sm btn-outline-secondary download-chart-btn\" data-chart-id=\"".concat(chartId, "\" title=\"").concat(defaultConfig.downloadChartTitle, "\">") + "<
|
|
167
|
+
return "<div class=\"chart-container\" style=\"position: relative; width: 100%; max-width: 560px; min-height: 420px;\">" + "<canvas id=\"".concat(chartId, "\"></canvas>") + "</div>" + "<div class=\"mt-2\">" + "<button type=\"button\" class=\"btn btn-sm btn-outline-secondary download-chart-btn\" data-chart-id=\"".concat(chartId, "\" title=\"").concat(defaultConfig.downloadChartTitle, "\">") + "<span class=\"fa-solid fa-download\"></span> ".concat(defaultConfig.downloadChartButtonText) + "</button>" + "</div>";
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
// Register [chart:{...json...}] as a native marked block extension so the
|
|
@@ -482,8 +482,8 @@ window.openAIChatManager = function () {
|
|
|
482
482
|
if (partialLayout.panel !== undefined) {
|
|
483
483
|
nextLayout.panel = Object.assign({}, currentLayout.panel || {}, partialLayout.panel || {});
|
|
484
484
|
}
|
|
485
|
-
if (partialLayout.
|
|
486
|
-
nextLayout.
|
|
485
|
+
if (partialLayout.position !== undefined) {
|
|
486
|
+
nextLayout.position = Object.assign({}, currentLayout.position || {}, partialLayout.position || {});
|
|
487
487
|
}
|
|
488
488
|
localStorage.setItem(this.chatWidgetLayoutKey, JSON.stringify(nextLayout));
|
|
489
489
|
},
|
|
@@ -501,6 +501,25 @@ window.openAIChatManager = function () {
|
|
|
501
501
|
height: Math.round(rect.height || parsePixelValue(computed.height) || fallbackHeight || 0)
|
|
502
502
|
};
|
|
503
503
|
},
|
|
504
|
+
getElementPosition: function getElementPosition(element) {
|
|
505
|
+
if (!element) {
|
|
506
|
+
return {
|
|
507
|
+
left: 0,
|
|
508
|
+
top: 0
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
var rect = element.getBoundingClientRect();
|
|
512
|
+
var computed = window.getComputedStyle(element);
|
|
513
|
+
var inlineLeft = parsePixelValue(element.style.left);
|
|
514
|
+
var inlineTop = parsePixelValue(element.style.top);
|
|
515
|
+
var computedLeft = parsePixelValue(computed.left);
|
|
516
|
+
var computedTop = parsePixelValue(computed.top);
|
|
517
|
+
var isHidden = computed.display === 'none';
|
|
518
|
+
return {
|
|
519
|
+
left: Math.round(isHidden && Number.isFinite(inlineLeft) ? inlineLeft : rect.left || inlineLeft || computedLeft || 0),
|
|
520
|
+
top: Math.round(isHidden && Number.isFinite(inlineTop) ? inlineTop : rect.top || inlineTop || computedTop || 0)
|
|
521
|
+
};
|
|
522
|
+
},
|
|
504
523
|
clampWidgetPosition: function clampWidgetPosition(left, top, width, height) {
|
|
505
524
|
var viewportPadding = 8;
|
|
506
525
|
var maxLeft = Math.max(viewportPadding, window.innerWidth - width - viewportPadding);
|
|
@@ -525,15 +544,29 @@ window.openAIChatManager = function () {
|
|
|
525
544
|
height: this.widgetDefaultHeight || parsePixelValue(config.widget.defaultHeight) || 520
|
|
526
545
|
};
|
|
527
546
|
},
|
|
547
|
+
getWidgetToggleGap: function getWidgetToggleGap() {
|
|
548
|
+
return 8;
|
|
549
|
+
},
|
|
550
|
+
isWidgetPanelVisible: function isWidgetPanelVisible() {
|
|
551
|
+
if (!this.widgetContainerElement) {
|
|
552
|
+
return false;
|
|
553
|
+
}
|
|
554
|
+
var computed = window.getComputedStyle(this.widgetContainerElement);
|
|
555
|
+
return this.widgetContainerElement.classList.contains('open') && computed.display !== 'none';
|
|
556
|
+
},
|
|
528
557
|
persistWidgetPanelPosition: function persistWidgetPanelPosition() {
|
|
529
558
|
if (!this.widgetContainerElement || !config.widget.persistLayout) {
|
|
530
559
|
return;
|
|
531
560
|
}
|
|
532
|
-
var
|
|
561
|
+
var panelDefaultSize = this.getWidgetDefaultSize();
|
|
562
|
+
var panelPosition = this.getElementPosition(this.widgetContainerElement);
|
|
563
|
+
var panelSize = this.getElementSize(this.widgetContainerElement, panelDefaultSize.width, panelDefaultSize.height);
|
|
564
|
+
var toggleSize = this.getElementSize(this.widgetToggleButtonElement, 52, 52);
|
|
565
|
+
var linkedPosition = this.clampWidgetPosition(panelPosition.left + panelSize.width - toggleSize.width, panelPosition.top + panelSize.height + this.getWidgetToggleGap(), toggleSize.width, toggleSize.height);
|
|
533
566
|
this.saveStoredWidgetLayout({
|
|
534
|
-
|
|
535
|
-
left:
|
|
536
|
-
top:
|
|
567
|
+
position: {
|
|
568
|
+
left: linkedPosition.left,
|
|
569
|
+
top: linkedPosition.top
|
|
537
570
|
}
|
|
538
571
|
});
|
|
539
572
|
},
|
|
@@ -543,9 +576,9 @@ window.openAIChatManager = function () {
|
|
|
543
576
|
}
|
|
544
577
|
var toggleRect = this.widgetToggleButtonElement.getBoundingClientRect();
|
|
545
578
|
this.saveStoredWidgetLayout({
|
|
546
|
-
|
|
547
|
-
left:
|
|
548
|
-
top:
|
|
579
|
+
position: {
|
|
580
|
+
left: this.getElementPosition(this.widgetToggleButtonElement).left,
|
|
581
|
+
top: this.getElementPosition(this.widgetToggleButtonElement).top
|
|
549
582
|
}
|
|
550
583
|
});
|
|
551
584
|
},
|
|
@@ -562,6 +595,36 @@ window.openAIChatManager = function () {
|
|
|
562
595
|
}
|
|
563
596
|
});
|
|
564
597
|
},
|
|
598
|
+
syncTogglePositionToPanel: function syncTogglePositionToPanel() {
|
|
599
|
+
var persistLayout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
|
600
|
+
if (!this.widgetContainerElement || !this.widgetToggleButtonElement) {
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
var panelDefaultSize = this.getWidgetDefaultSize();
|
|
604
|
+
var panelSize = this.getElementSize(this.widgetContainerElement, panelDefaultSize.width, panelDefaultSize.height);
|
|
605
|
+
var toggleSize = this.getElementSize(this.widgetToggleButtonElement, 52, 52);
|
|
606
|
+
var panelPosition = this.getElementPosition(this.widgetContainerElement);
|
|
607
|
+
var linkedPosition = this.clampWidgetPosition(panelPosition.left + panelSize.width - toggleSize.width, panelPosition.top + panelSize.height + this.getWidgetToggleGap(), toggleSize.width, toggleSize.height);
|
|
608
|
+
this.applyAbsolutePosition(this.widgetToggleButtonElement, linkedPosition.left, linkedPosition.top);
|
|
609
|
+
if (persistLayout && config.widget.persistLayout) {
|
|
610
|
+
this.persistWidgetTogglePosition();
|
|
611
|
+
}
|
|
612
|
+
},
|
|
613
|
+
syncPanelPositionToToggle: function syncPanelPositionToToggle() {
|
|
614
|
+
var persistLayout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
|
615
|
+
if (!this.widgetContainerElement || !this.widgetToggleButtonElement) {
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
var panelDefaultSize = this.getWidgetDefaultSize();
|
|
619
|
+
var panelSize = this.getElementSize(this.widgetContainerElement, panelDefaultSize.width, panelDefaultSize.height);
|
|
620
|
+
var toggleSize = this.getElementSize(this.widgetToggleButtonElement, 52, 52);
|
|
621
|
+
var togglePosition = this.getElementPosition(this.widgetToggleButtonElement);
|
|
622
|
+
var linkedPosition = this.clampWidgetPosition(togglePosition.left + toggleSize.width - panelSize.width, togglePosition.top - panelSize.height - this.getWidgetToggleGap(), panelSize.width, panelSize.height);
|
|
623
|
+
this.applyAbsolutePosition(this.widgetContainerElement, linkedPosition.left, linkedPosition.top);
|
|
624
|
+
if (persistLayout && config.widget.persistLayout) {
|
|
625
|
+
this.persistWidgetPanelPosition();
|
|
626
|
+
}
|
|
627
|
+
},
|
|
565
628
|
updateWidgetResetSizeButtonVisibility: function updateWidgetResetSizeButtonVisibility() {
|
|
566
629
|
if (!this.widgetResetSizeButtonElement) {
|
|
567
630
|
return;
|
|
@@ -599,11 +662,15 @@ window.openAIChatManager = function () {
|
|
|
599
662
|
this.widgetContainerElement.style.removeProperty('height');
|
|
600
663
|
}
|
|
601
664
|
}
|
|
602
|
-
if (this.
|
|
603
|
-
this.applyAbsolutePosition(this.
|
|
604
|
-
|
|
605
|
-
if (this.widgetToggleButtonElement && config.widget.enableDragging && Number.isFinite(storedLayout.toggle && storedLayout.toggle.left) && Number.isFinite(storedLayout.toggle && storedLayout.toggle.top)) {
|
|
665
|
+
if (this.widgetToggleButtonElement && config.widget.enableDragging && Number.isFinite(storedLayout.position && storedLayout.position.left) && Number.isFinite(storedLayout.position && storedLayout.position.top)) {
|
|
666
|
+
this.applyAbsolutePosition(this.widgetToggleButtonElement, storedLayout.position.left, storedLayout.position.top);
|
|
667
|
+
this.syncPanelPositionToToggle(false);
|
|
668
|
+
} else if (this.widgetToggleButtonElement && config.widget.enableDragging && Number.isFinite(storedLayout.toggle && storedLayout.toggle.left) && Number.isFinite(storedLayout.toggle && storedLayout.toggle.top)) {
|
|
606
669
|
this.applyAbsolutePosition(this.widgetToggleButtonElement, storedLayout.toggle.left, storedLayout.toggle.top);
|
|
670
|
+
this.syncPanelPositionToToggle(false);
|
|
671
|
+
} else if (this.widgetContainerElement && config.widget.enableDragging && Number.isFinite(storedLayout.panel && storedLayout.panel.left) && Number.isFinite(storedLayout.panel && storedLayout.panel.top)) {
|
|
672
|
+
this.applyAbsolutePosition(this.widgetContainerElement, storedLayout.panel.left, storedLayout.panel.top);
|
|
673
|
+
this.syncTogglePositionToPanel(false);
|
|
607
674
|
}
|
|
608
675
|
this.constrainWidgetElementsToViewport();
|
|
609
676
|
this.updateWidgetResetSizeButtonVisibility();
|
|
@@ -637,8 +704,14 @@ window.openAIChatManager = function () {
|
|
|
637
704
|
return;
|
|
638
705
|
}
|
|
639
706
|
if (layoutKey === 'panel') {
|
|
707
|
+
_this.syncTogglePositionToPanel(false);
|
|
640
708
|
_this.persistWidgetPanelPosition();
|
|
641
709
|
} else if (layoutKey === 'toggle') {
|
|
710
|
+
_this.syncPanelPositionToToggle(false);
|
|
711
|
+
_this.persistWidgetTogglePosition();
|
|
712
|
+
}
|
|
713
|
+
if (config.widget.persistLayout) {
|
|
714
|
+
_this.persistWidgetPanelPosition();
|
|
642
715
|
_this.persistWidgetTogglePosition();
|
|
643
716
|
}
|
|
644
717
|
if (suppressClickOnDrag) {
|
|
@@ -664,6 +737,11 @@ window.openAIChatManager = function () {
|
|
|
664
737
|
var currentSize = _this.getElementSize(element, layoutKey === 'panel' ? defaultSize.width : 52, layoutKey === 'panel' ? defaultSize.height : 52);
|
|
665
738
|
var nextPosition = _this.clampWidgetPosition(startLeft + deltaX, startTop + deltaY, currentSize.width, currentSize.height);
|
|
666
739
|
_this.applyAbsolutePosition(element, nextPosition.left, nextPosition.top);
|
|
740
|
+
if (layoutKey === 'panel') {
|
|
741
|
+
_this.syncTogglePositionToPanel(false);
|
|
742
|
+
} else if (layoutKey === 'toggle') {
|
|
743
|
+
_this.syncPanelPositionToToggle(false);
|
|
744
|
+
}
|
|
667
745
|
};
|
|
668
746
|
handle.addEventListener('pointerdown', function (event) {
|
|
669
747
|
if (event.button !== 0) {
|
|
@@ -690,23 +768,26 @@ window.openAIChatManager = function () {
|
|
|
690
768
|
});
|
|
691
769
|
},
|
|
692
770
|
constrainWidgetElementsToViewport: function constrainWidgetElementsToViewport() {
|
|
693
|
-
if (this.widgetContainerElement && this.widgetContainerElement.style.left) {
|
|
771
|
+
if (this.widgetContainerElement && this.widgetContainerElement.style.left && this.isWidgetPanelVisible()) {
|
|
694
772
|
var panelDefaultSize = this.getWidgetDefaultSize();
|
|
695
773
|
var panelSize = this.getElementSize(this.widgetContainerElement, panelDefaultSize.width, panelDefaultSize.height);
|
|
696
|
-
var
|
|
697
|
-
var clampedPanel = this.clampWidgetPosition(
|
|
774
|
+
var panelPosition = this.getElementPosition(this.widgetContainerElement);
|
|
775
|
+
var clampedPanel = this.clampWidgetPosition(panelPosition.left, panelPosition.top, panelSize.width, panelSize.height);
|
|
698
776
|
this.applyAbsolutePosition(this.widgetContainerElement, clampedPanel.left, clampedPanel.top);
|
|
777
|
+
this.syncTogglePositionToPanel(false);
|
|
699
778
|
if (config.widget.persistLayout) {
|
|
700
779
|
this.persistWidgetPanelPosition();
|
|
780
|
+
this.persistWidgetTogglePosition();
|
|
701
781
|
}
|
|
702
|
-
}
|
|
703
|
-
if (this.widgetToggleButtonElement && this.widgetToggleButtonElement.style.left) {
|
|
782
|
+
} else if (this.widgetToggleButtonElement && this.widgetToggleButtonElement.style.left) {
|
|
704
783
|
var toggleSize = this.getElementSize(this.widgetToggleButtonElement, 52, 52);
|
|
705
|
-
var
|
|
706
|
-
var clampedToggle = this.clampWidgetPosition(
|
|
784
|
+
var togglePosition = this.getElementPosition(this.widgetToggleButtonElement);
|
|
785
|
+
var clampedToggle = this.clampWidgetPosition(togglePosition.left, togglePosition.top, toggleSize.width, toggleSize.height);
|
|
707
786
|
this.applyAbsolutePosition(this.widgetToggleButtonElement, clampedToggle.left, clampedToggle.top);
|
|
787
|
+
this.syncPanelPositionToToggle(false);
|
|
708
788
|
if (config.widget.persistLayout) {
|
|
709
789
|
this.persistWidgetTogglePosition();
|
|
790
|
+
this.persistWidgetPanelPosition();
|
|
710
791
|
}
|
|
711
792
|
}
|
|
712
793
|
},
|
|
@@ -929,7 +1010,7 @@ window.openAIChatManager = function () {
|
|
|
929
1010
|
var name = doc.fileName || 'Document';
|
|
930
1011
|
if (name.length > 20) name = name.substring(0, 17) + '...';
|
|
931
1012
|
html += '<span class="badge bg-secondary bg-opacity-25 text-dark d-inline-flex align-items-center gap-1 px-2 py-1" style="font-size: 0.8rem;" title="' + this.escapeHtml(doc.fileName || '') + '">';
|
|
932
|
-
html += '<
|
|
1013
|
+
html += '<span class="fa-solid fa-file-lines" style="font-size: 0.7rem;"></span> ';
|
|
933
1014
|
html += this.escapeHtml(name);
|
|
934
1015
|
html += ' <button type="button" class="btn-close btn-close-sm ms-1" style="font-size: 0.5rem;" data-doc-index="' + i + '" aria-label="Remove"></button>';
|
|
935
1016
|
html += '</span>';
|
|
@@ -940,7 +1021,7 @@ window.openAIChatManager = function () {
|
|
|
940
1021
|
var errorMsg = failedItem.error || 'Upload failed';
|
|
941
1022
|
if (failedName.length > 15) failedName = failedName.substring(0, 12) + '...';
|
|
942
1023
|
html += '<span class="badge bg-danger bg-opacity-25 text-danger d-inline-flex align-items-center gap-1 px-2 py-1" style="font-size: 0.8rem;" title="' + this.escapeHtml((failedItem.fileName || '') + ': ' + errorMsg) + '">';
|
|
943
|
-
html += '<
|
|
1024
|
+
html += '<span class="fa-solid fa-circle-exclamation" style="font-size: 0.7rem;"></span> ';
|
|
944
1025
|
html += this.escapeHtml(failedName);
|
|
945
1026
|
html += ' <button type="button" class="btn-close btn-close-sm ms-1" style="font-size: 0.5rem;" data-error-index="' + m + '" aria-label="Dismiss"></button>';
|
|
946
1027
|
html += '</span>';
|
|
@@ -951,7 +1032,7 @@ window.openAIChatManager = function () {
|
|
|
951
1032
|
html += '</span>';
|
|
952
1033
|
}
|
|
953
1034
|
html += '<button type="button" class="btn btn-sm btn-outline-secondary rounded-pill ai-chat-doc-add-btn d-inline-flex align-items-center gap-1" style="font-size: 0.75rem; padding: 0.15rem 0.5rem;" title="Attach documents">';
|
|
954
|
-
html += '<
|
|
1035
|
+
html += '<span class="fa-solid fa-paperclip"></span>';
|
|
955
1036
|
if (this.documents.length === 0 && !this.isUploading) {
|
|
956
1037
|
html += ' <span>Attach files</span>';
|
|
957
1038
|
}
|
|
@@ -1583,10 +1664,10 @@ window.openAIChatManager = function () {
|
|
|
1583
1664
|
}
|
|
1584
1665
|
if (this.isRecording) {
|
|
1585
1666
|
this.micButton.classList.add('stt-recording');
|
|
1586
|
-
this.micButton.innerHTML = '<
|
|
1667
|
+
this.micButton.innerHTML = '<span class="fa-solid fa-stop"></span>';
|
|
1587
1668
|
} else {
|
|
1588
1669
|
this.micButton.classList.remove('stt-recording');
|
|
1589
|
-
this.micButton.innerHTML = '<
|
|
1670
|
+
this.micButton.innerHTML = '<span class="fa-solid fa-microphone"></span>';
|
|
1590
1671
|
}
|
|
1591
1672
|
},
|
|
1592
1673
|
streamMessage: function streamMessage(profileId, trimmedPrompt, sessionProfileId) {
|
|
@@ -1852,8 +1933,25 @@ window.openAIChatManager = function () {
|
|
|
1852
1933
|
}
|
|
1853
1934
|
this.stopAudio(false);
|
|
1854
1935
|
},
|
|
1855
|
-
|
|
1936
|
+
updateTtsPlaybackButtons: function updateTtsPlaybackButtons() {
|
|
1856
1937
|
var _this1 = this;
|
|
1938
|
+
if (!this.chatContainer) {
|
|
1939
|
+
return;
|
|
1940
|
+
}
|
|
1941
|
+
var buttons = this.chatContainer.querySelectorAll('[data-tts-message-index]');
|
|
1942
|
+
buttons.forEach(function (button) {
|
|
1943
|
+
var buttonIndex = Number(button.getAttribute('data-tts-message-index'));
|
|
1944
|
+
var isPlaying = buttonIndex === _this1.ttsPlayingMessageIndex;
|
|
1945
|
+
var iconHtml = isPlaying ? '<span class="fa-solid fa-circle-pause"></span>' : '<span class="fa-solid fa-circle-play"></span>';
|
|
1946
|
+
button.classList.toggle('tts-playing', isPlaying);
|
|
1947
|
+
button.setAttribute('title', isPlaying ? 'Pause audio' : 'Read aloud');
|
|
1948
|
+
button.replaceChildren(DOMPurify.sanitize(iconHtml, {
|
|
1949
|
+
RETURN_DOM_FRAGMENT: true
|
|
1950
|
+
}));
|
|
1951
|
+
});
|
|
1952
|
+
},
|
|
1953
|
+
synthesizeSpeech: function synthesizeSpeech(text, cacheIndex) {
|
|
1954
|
+
var _this10 = this;
|
|
1857
1955
|
if (!this.textToSpeechEnabled || !text || !this.connection) {
|
|
1858
1956
|
return;
|
|
1859
1957
|
}
|
|
@@ -1862,12 +1960,16 @@ window.openAIChatManager = function () {
|
|
|
1862
1960
|
this._ttsCacheIndex = cacheIndex !== undefined ? cacheIndex : -1;
|
|
1863
1961
|
this.connection.invoke("SynthesizeSpeech", this.getProfileId(), this.getSessionId(), text, this.ttsVoiceName)["catch"](function (err) {
|
|
1864
1962
|
console.error("TTS synthesis error:", err);
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1963
|
+
_this10.isPlayingAudio = false;
|
|
1964
|
+
_this10.ttsPlayingMessageIndex = -1;
|
|
1965
|
+
_this10._ttsCacheIndex = -1;
|
|
1966
|
+
_this10.$nextTick(function () {
|
|
1967
|
+
return _this10.updateTtsPlaybackButtons();
|
|
1968
|
+
});
|
|
1868
1969
|
});
|
|
1869
1970
|
},
|
|
1870
1971
|
toggleMessageTts: function toggleMessageTts(message, index) {
|
|
1972
|
+
var _this11 = this;
|
|
1871
1973
|
if (this.ttsPlayingMessageIndex === index) {
|
|
1872
1974
|
this.stopAudio();
|
|
1873
1975
|
return;
|
|
@@ -1879,6 +1981,9 @@ window.openAIChatManager = function () {
|
|
|
1879
1981
|
}
|
|
1880
1982
|
}));
|
|
1881
1983
|
this.ttsPlayingMessageIndex = index;
|
|
1984
|
+
this.$nextTick(function () {
|
|
1985
|
+
return _this11.updateTtsPlaybackButtons();
|
|
1986
|
+
});
|
|
1882
1987
|
if (this.ttsAudioCache[index]) {
|
|
1883
1988
|
this.playAudioBlob(this.ttsAudioCache[index]);
|
|
1884
1989
|
return;
|
|
@@ -1886,10 +1991,14 @@ window.openAIChatManager = function () {
|
|
|
1886
1991
|
this.synthesizeSpeech(message.content, index);
|
|
1887
1992
|
},
|
|
1888
1993
|
playCollectedAudio: function playCollectedAudio() {
|
|
1994
|
+
var _this12 = this;
|
|
1889
1995
|
if (this.audioChunks.length === 0) {
|
|
1890
1996
|
if (!this.currentAudioElement && this.audioPlayQueue.length === 0) {
|
|
1891
1997
|
this.isPlayingAudio = false;
|
|
1892
1998
|
this.ttsPlayingMessageIndex = -1;
|
|
1999
|
+
this.$nextTick(function () {
|
|
2000
|
+
return _this12.updateTtsPlaybackButtons();
|
|
2001
|
+
});
|
|
1893
2002
|
}
|
|
1894
2003
|
return;
|
|
1895
2004
|
}
|
|
@@ -1928,45 +2037,53 @@ window.openAIChatManager = function () {
|
|
|
1928
2037
|
this.playAudioBlob(blob);
|
|
1929
2038
|
},
|
|
1930
2039
|
playAudioBlob: function playAudioBlob(blob) {
|
|
1931
|
-
var
|
|
2040
|
+
var _this13 = this;
|
|
1932
2041
|
var url = URL.createObjectURL(blob);
|
|
1933
2042
|
var audio = new Audio(url);
|
|
1934
2043
|
this.currentAudioUrl = url;
|
|
1935
2044
|
this.currentAudioElement = audio;
|
|
1936
2045
|
this.isPlayingAudio = true;
|
|
1937
2046
|
audio.addEventListener('ended', function () {
|
|
1938
|
-
|
|
1939
|
-
|
|
2047
|
+
_this13.currentAudioElement = null;
|
|
2048
|
+
_this13.currentAudioUrl = null;
|
|
1940
2049
|
URL.revokeObjectURL(url);
|
|
1941
|
-
|
|
2050
|
+
_this13.playNextInQueue();
|
|
1942
2051
|
});
|
|
1943
2052
|
audio.addEventListener('error', function () {
|
|
1944
|
-
|
|
1945
|
-
|
|
2053
|
+
_this13.currentAudioElement = null;
|
|
2054
|
+
_this13.currentAudioUrl = null;
|
|
1946
2055
|
URL.revokeObjectURL(url);
|
|
1947
|
-
|
|
2056
|
+
_this13.playNextInQueue();
|
|
1948
2057
|
});
|
|
1949
2058
|
audio.play()["catch"](function (err) {
|
|
1950
2059
|
console.error("Audio playback error:", err);
|
|
1951
|
-
|
|
1952
|
-
|
|
2060
|
+
_this13.currentAudioElement = null;
|
|
2061
|
+
_this13.currentAudioUrl = null;
|
|
1953
2062
|
URL.revokeObjectURL(url);
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
2063
|
+
_this13.audioPlayQueue = [];
|
|
2064
|
+
_this13.isPlayingAudio = false;
|
|
2065
|
+
_this13.ttsPlayingMessageIndex = -1;
|
|
2066
|
+
_this13.$nextTick(function () {
|
|
2067
|
+
return _this13.updateTtsPlaybackButtons();
|
|
2068
|
+
});
|
|
1957
2069
|
});
|
|
1958
2070
|
},
|
|
1959
2071
|
playNextInQueue: function playNextInQueue() {
|
|
2072
|
+
var _this14 = this;
|
|
1960
2073
|
if (this.audioPlayQueue.length > 0) {
|
|
1961
2074
|
var nextBlob = this.audioPlayQueue.shift();
|
|
1962
2075
|
this.playAudioBlob(nextBlob);
|
|
1963
2076
|
} else {
|
|
1964
2077
|
this.isPlayingAudio = false;
|
|
1965
2078
|
this.ttsPlayingMessageIndex = -1;
|
|
2079
|
+
this.$nextTick(function () {
|
|
2080
|
+
return _this14.updateTtsPlaybackButtons();
|
|
2081
|
+
});
|
|
1966
2082
|
this.conversationModeOnAudioEnded();
|
|
1967
2083
|
}
|
|
1968
2084
|
},
|
|
1969
2085
|
stopAudio: function stopAudio() {
|
|
2086
|
+
var _this15 = this;
|
|
1970
2087
|
if (this.currentAudioElement) {
|
|
1971
2088
|
this.currentAudioElement.pause();
|
|
1972
2089
|
this.currentAudioElement.currentTime = 0;
|
|
@@ -1980,6 +2097,9 @@ window.openAIChatManager = function () {
|
|
|
1980
2097
|
this.audioPlayQueue = [];
|
|
1981
2098
|
this.isPlayingAudio = false;
|
|
1982
2099
|
this.ttsPlayingMessageIndex = -1;
|
|
2100
|
+
this.$nextTick(function () {
|
|
2101
|
+
return _this15.updateTtsPlaybackButtons();
|
|
2102
|
+
});
|
|
1983
2103
|
},
|
|
1984
2104
|
toggleConversationMode: function toggleConversationMode() {
|
|
1985
2105
|
if (this.isConversationMode) {
|
|
@@ -1989,7 +2109,7 @@ window.openAIChatManager = function () {
|
|
|
1989
2109
|
}
|
|
1990
2110
|
},
|
|
1991
2111
|
startConversationMode: function startConversationMode() {
|
|
1992
|
-
var
|
|
2112
|
+
var _this16 = this;
|
|
1993
2113
|
if (!this.conversationModeEnabled || this.isConversationMode || !this.connection) {
|
|
1994
2114
|
return;
|
|
1995
2115
|
}
|
|
@@ -2009,12 +2129,12 @@ window.openAIChatManager = function () {
|
|
|
2009
2129
|
}
|
|
2010
2130
|
}).then(function (stream) {
|
|
2011
2131
|
var mimeType = MediaRecorder.isTypeSupported('audio/ogg;codecs=opus') ? 'audio/ogg;codecs=opus' : MediaRecorder.isTypeSupported('audio/webm;codecs=opus') ? 'audio/webm;codecs=opus' : 'audio/webm';
|
|
2012
|
-
|
|
2132
|
+
_this16.mediaRecorder = new MediaRecorder(stream, {
|
|
2013
2133
|
mimeType: mimeType,
|
|
2014
2134
|
audioBitsPerSecond: 128000
|
|
2015
2135
|
});
|
|
2016
|
-
|
|
2017
|
-
|
|
2136
|
+
_this16._conversationSubject = new signalR.Subject();
|
|
2137
|
+
_this16._conversationStream = stream;
|
|
2018
2138
|
|
|
2019
2139
|
// Create an AnalyserNode for volume-based interrupt detection.
|
|
2020
2140
|
// During TTS playback, detect when the user speaks above
|
|
@@ -2023,20 +2143,20 @@ window.openAIChatManager = function () {
|
|
|
2023
2143
|
// speaker echo so the STT stream has no gaps.
|
|
2024
2144
|
var AudioCtx = window.AudioContext || window.webkitAudioContext;
|
|
2025
2145
|
if (AudioCtx) {
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
var micSource =
|
|
2030
|
-
micSource.connect(
|
|
2146
|
+
_this16._conversationAudioCtx = new AudioCtx();
|
|
2147
|
+
_this16._conversationAnalyser = _this16._conversationAudioCtx.createAnalyser();
|
|
2148
|
+
_this16._conversationAnalyser.fftSize = 256;
|
|
2149
|
+
var micSource = _this16._conversationAudioCtx.createMediaStreamSource(stream);
|
|
2150
|
+
micSource.connect(_this16._conversationAnalyser);
|
|
2031
2151
|
}
|
|
2032
2152
|
var pendingChunk = Promise.resolve();
|
|
2033
|
-
var analyser =
|
|
2153
|
+
var analyser = _this16._conversationAnalyser;
|
|
2034
2154
|
var interruptVolumeThreshold = 30;
|
|
2035
|
-
|
|
2155
|
+
_this16.mediaRecorder.addEventListener('dataavailable', function (e) {
|
|
2036
2156
|
if (e.data && e.data.size > 0) {
|
|
2037
2157
|
// During TTS playback, check mic volume to detect
|
|
2038
2158
|
// user interruption (speaking above threshold).
|
|
2039
|
-
if (
|
|
2159
|
+
if (_this16.isPlayingAudio && analyser) {
|
|
2040
2160
|
var freqData = new Uint8Array(analyser.frequencyBinCount);
|
|
2041
2161
|
analyser.getByteFrequencyData(freqData);
|
|
2042
2162
|
var sum = 0;
|
|
@@ -2046,7 +2166,7 @@ window.openAIChatManager = function () {
|
|
|
2046
2166
|
var avg = sum / freqData.length;
|
|
2047
2167
|
if (avg >= interruptVolumeThreshold) {
|
|
2048
2168
|
// User is speaking — interrupt TTS playback.
|
|
2049
|
-
|
|
2169
|
+
_this16.stopAudio();
|
|
2050
2170
|
}
|
|
2051
2171
|
}
|
|
2052
2172
|
|
|
@@ -2068,7 +2188,7 @@ window.openAIChatManager = function () {
|
|
|
2068
2188
|
}, '');
|
|
2069
2189
|
base64 = btoa(binaryString);
|
|
2070
2190
|
try {
|
|
2071
|
-
|
|
2191
|
+
_this16._conversationSubject.next(base64);
|
|
2072
2192
|
} catch (err) {
|
|
2073
2193
|
// Subject may have been completed already.
|
|
2074
2194
|
}
|
|
@@ -2079,28 +2199,28 @@ window.openAIChatManager = function () {
|
|
|
2079
2199
|
})));
|
|
2080
2200
|
}
|
|
2081
2201
|
});
|
|
2082
|
-
|
|
2202
|
+
_this16.mediaRecorder.addEventListener('stop', function () {
|
|
2083
2203
|
stream.getTracks().forEach(function (track) {
|
|
2084
2204
|
return track.stop();
|
|
2085
2205
|
});
|
|
2086
2206
|
pendingChunk.then(function () {
|
|
2087
2207
|
try {
|
|
2088
|
-
|
|
2208
|
+
_this16._conversationSubject.complete();
|
|
2089
2209
|
} catch (err) {
|
|
2090
2210
|
// Already completed.
|
|
2091
2211
|
}
|
|
2092
2212
|
});
|
|
2093
2213
|
});
|
|
2094
|
-
var profileId =
|
|
2095
|
-
var sessionId =
|
|
2214
|
+
var profileId = _this16.getProfileId();
|
|
2215
|
+
var sessionId = _this16.getSessionId() || '';
|
|
2096
2216
|
var language = navigator.language || document.documentElement.lang || 'en-US';
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2217
|
+
_this16.connection.send("StartConversation", profileId, sessionId, _this16._conversationSubject, mimeType, language);
|
|
2218
|
+
_this16.mediaRecorder.start(250);
|
|
2219
|
+
_this16.isRecording = true;
|
|
2100
2220
|
})["catch"](function (err) {
|
|
2101
2221
|
console.error('Microphone access denied:', err);
|
|
2102
|
-
|
|
2103
|
-
|
|
2222
|
+
_this16.isConversationMode = false;
|
|
2223
|
+
_this16.updateConversationButton();
|
|
2104
2224
|
});
|
|
2105
2225
|
},
|
|
2106
2226
|
stopConversationMode: function stopConversationMode() {
|
|
@@ -2227,7 +2347,7 @@ window.openAIChatManager = function () {
|
|
|
2227
2347
|
return removedCount;
|
|
2228
2348
|
},
|
|
2229
2349
|
receiveNotification: function receiveNotification(notification) {
|
|
2230
|
-
var
|
|
2350
|
+
var _this17 = this;
|
|
2231
2351
|
if (!notification || !notification.type) {
|
|
2232
2352
|
return;
|
|
2233
2353
|
}
|
|
@@ -2242,7 +2362,7 @@ window.openAIChatManager = function () {
|
|
|
2242
2362
|
}
|
|
2243
2363
|
this.scheduleNotificationDismiss(notification);
|
|
2244
2364
|
this.$nextTick(function () {
|
|
2245
|
-
|
|
2365
|
+
_this17.scrollToBottom();
|
|
2246
2366
|
});
|
|
2247
2367
|
},
|
|
2248
2368
|
updateNotification: function updateNotification(notification) {
|
|
@@ -2259,12 +2379,12 @@ window.openAIChatManager = function () {
|
|
|
2259
2379
|
}
|
|
2260
2380
|
},
|
|
2261
2381
|
scheduleNotificationDismiss: function scheduleNotificationDismiss(notification) {
|
|
2262
|
-
var
|
|
2382
|
+
var _this18 = this;
|
|
2263
2383
|
if (!notification || !notification.type || !notification.autoDismissMs || notification.autoDismissMs <= 0) {
|
|
2264
2384
|
return;
|
|
2265
2385
|
}
|
|
2266
2386
|
this.notificationDismissTimers[notification.type] = setTimeout(function () {
|
|
2267
|
-
|
|
2387
|
+
_this18.removeNotification(notification.type);
|
|
2268
2388
|
}, notification.autoDismissMs);
|
|
2269
2389
|
},
|
|
2270
2390
|
clearNotificationDismiss: function clearNotificationDismiss(notificationType) {
|
|
@@ -2294,12 +2414,12 @@ window.openAIChatManager = function () {
|
|
|
2294
2414
|
});
|
|
2295
2415
|
},
|
|
2296
2416
|
scrollToBottom: function scrollToBottom() {
|
|
2297
|
-
var
|
|
2417
|
+
var _this19 = this;
|
|
2298
2418
|
if (!this.autoScroll) {
|
|
2299
2419
|
return;
|
|
2300
2420
|
}
|
|
2301
2421
|
setTimeout(function () {
|
|
2302
|
-
|
|
2422
|
+
_this19.chatContainer.scrollTop = _this19.chatContainer.scrollHeight - _this19.chatContainer.clientHeight;
|
|
2303
2423
|
}, 50);
|
|
2304
2424
|
},
|
|
2305
2425
|
handleUserInput: function handleUserInput(event) {
|
|
@@ -2341,7 +2461,7 @@ window.openAIChatManager = function () {
|
|
|
2341
2461
|
});
|
|
2342
2462
|
},
|
|
2343
2463
|
initializeApp: function initializeApp() {
|
|
2344
|
-
var
|
|
2464
|
+
var _this20 = this;
|
|
2345
2465
|
this.inputElement = document.querySelector(config.inputElementSelector);
|
|
2346
2466
|
this.buttonElement = document.querySelector(config.sendButtonElementSelector);
|
|
2347
2467
|
this.chatContainer = document.querySelector(config.chatContainerElementSelector);
|
|
@@ -2370,7 +2490,7 @@ window.openAIChatManager = function () {
|
|
|
2370
2490
|
fileInput.accept = config.allowedExtensions;
|
|
2371
2491
|
}
|
|
2372
2492
|
fileInput.addEventListener('change', function (e) {
|
|
2373
|
-
return
|
|
2493
|
+
return _this20.handleFileInputChange(e);
|
|
2374
2494
|
});
|
|
2375
2495
|
this.documentBar.parentElement.appendChild(fileInput);
|
|
2376
2496
|
|
|
@@ -2378,13 +2498,13 @@ window.openAIChatManager = function () {
|
|
|
2378
2498
|
var inputArea = this.inputElement ? this.inputElement.closest('.ai-admin-widget-input, .text-bg-light') : null;
|
|
2379
2499
|
if (inputArea) {
|
|
2380
2500
|
inputArea.addEventListener('dragover', function (e) {
|
|
2381
|
-
return
|
|
2501
|
+
return _this20.handleDragOver(e);
|
|
2382
2502
|
});
|
|
2383
2503
|
inputArea.addEventListener('dragleave', function (e) {
|
|
2384
|
-
return
|
|
2504
|
+
return _this20.handleDragLeave(e);
|
|
2385
2505
|
});
|
|
2386
2506
|
inputArea.addEventListener('drop', function (e) {
|
|
2387
|
-
return
|
|
2507
|
+
return _this20.handleDrop(e);
|
|
2388
2508
|
});
|
|
2389
2509
|
}
|
|
2390
2510
|
}
|
|
@@ -2392,55 +2512,55 @@ window.openAIChatManager = function () {
|
|
|
2392
2512
|
|
|
2393
2513
|
// Pause auto-scroll when the user manually scrolls up during streaming.
|
|
2394
2514
|
this.chatContainer.addEventListener('scroll', function () {
|
|
2395
|
-
if (!
|
|
2515
|
+
if (!_this20.stream) {
|
|
2396
2516
|
return;
|
|
2397
2517
|
}
|
|
2398
2518
|
var threshold = 30;
|
|
2399
|
-
var atBottom =
|
|
2400
|
-
|
|
2519
|
+
var atBottom = _this20.chatContainer.scrollHeight - _this20.chatContainer.clientHeight - _this20.chatContainer.scrollTop <= threshold;
|
|
2520
|
+
_this20.autoScroll = atBottom;
|
|
2401
2521
|
});
|
|
2402
2522
|
this.inputElement.addEventListener('keydown', function (event) {
|
|
2403
|
-
if (
|
|
2523
|
+
if (_this20.stream != null) {
|
|
2404
2524
|
return;
|
|
2405
2525
|
}
|
|
2406
2526
|
if (event.key === "Enter" && !event.shiftKey) {
|
|
2407
2527
|
event.preventDefault();
|
|
2408
|
-
|
|
2528
|
+
_this20.buttonElement.click();
|
|
2409
2529
|
}
|
|
2410
2530
|
});
|
|
2411
2531
|
this.inputElement.addEventListener('input', function (e) {
|
|
2412
|
-
|
|
2532
|
+
_this20.handleUserInput(e);
|
|
2413
2533
|
if (e.target.value.trim()) {
|
|
2414
|
-
|
|
2534
|
+
_this20.buttonElement.removeAttribute('disabled');
|
|
2415
2535
|
} else {
|
|
2416
|
-
|
|
2536
|
+
_this20.buttonElement.setAttribute('disabled', true);
|
|
2417
2537
|
}
|
|
2418
2538
|
});
|
|
2419
2539
|
this.buttonElement.addEventListener('click', function () {
|
|
2420
|
-
if (
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2540
|
+
if (_this20.stream != null) {
|
|
2541
|
+
_this20.stream.dispose();
|
|
2542
|
+
_this20.stream = null;
|
|
2543
|
+
_this20.streamingFinished();
|
|
2544
|
+
_this20.hideTypingIndicator();
|
|
2425
2545
|
|
|
2426
2546
|
// Clean up: remove empty assistant message or stop streaming animation.
|
|
2427
|
-
if (
|
|
2428
|
-
var lastMsg =
|
|
2547
|
+
if (_this20.messages.length > 0) {
|
|
2548
|
+
var lastMsg = _this20.messages[_this20.messages.length - 1];
|
|
2429
2549
|
if (lastMsg.role === 'assistant' && !lastMsg.content) {
|
|
2430
|
-
|
|
2550
|
+
_this20.messages.pop();
|
|
2431
2551
|
} else if (lastMsg.isStreaming) {
|
|
2432
2552
|
lastMsg.isStreaming = false;
|
|
2433
2553
|
}
|
|
2434
2554
|
}
|
|
2435
2555
|
return;
|
|
2436
2556
|
}
|
|
2437
|
-
|
|
2557
|
+
_this20.sendMessage();
|
|
2438
2558
|
});
|
|
2439
2559
|
var promptGenerators = document.getElementsByClassName('profile-generated-prompt');
|
|
2440
2560
|
for (var i = 0; i < promptGenerators.length; i++) {
|
|
2441
2561
|
promptGenerators[i].addEventListener('click', function (e) {
|
|
2442
2562
|
e.preventDefault();
|
|
2443
|
-
|
|
2563
|
+
_this20.generatePrompt(e.target);
|
|
2444
2564
|
});
|
|
2445
2565
|
}
|
|
2446
2566
|
var chatSessions = document.getElementsByClassName('chat-session-history-item');
|
|
@@ -2452,8 +2572,8 @@ window.openAIChatManager = function () {
|
|
|
2452
2572
|
console.error('an element with the class chat-session-history-item with no data-session-id set.');
|
|
2453
2573
|
return;
|
|
2454
2574
|
}
|
|
2455
|
-
|
|
2456
|
-
|
|
2575
|
+
_this20.loadSession(sessionId);
|
|
2576
|
+
_this20.showChatScreen();
|
|
2457
2577
|
});
|
|
2458
2578
|
}
|
|
2459
2579
|
for (var _i5 = 0; _i5 < config.messages.length; _i5++) {
|
|
@@ -2462,7 +2582,7 @@ window.openAIChatManager = function () {
|
|
|
2462
2582
|
|
|
2463
2583
|
// Update feedback icons in the DOM after initial messages have rendered.
|
|
2464
2584
|
this.$nextTick(function () {
|
|
2465
|
-
|
|
2585
|
+
_this20.refreshAllFeedbackIcons();
|
|
2466
2586
|
});
|
|
2467
2587
|
|
|
2468
2588
|
// Delegate click for code block copy buttons.
|
|
@@ -2480,9 +2600,9 @@ window.openAIChatManager = function () {
|
|
|
2480
2600
|
if (codeEl) {
|
|
2481
2601
|
navigator.clipboard.writeText(codeEl.textContent);
|
|
2482
2602
|
var copiedText = config.codeCopiedText || 'Copied!';
|
|
2483
|
-
btn.innerHTML = '<
|
|
2603
|
+
btn.innerHTML = '<span class="fa-solid fa-check"></span> ' + copiedText;
|
|
2484
2604
|
setTimeout(function () {
|
|
2485
|
-
btn.innerHTML = '<
|
|
2605
|
+
btn.innerHTML = '<span class="fa-regular fa-copy"></span>';
|
|
2486
2606
|
}, 2000);
|
|
2487
2607
|
}
|
|
2488
2608
|
});
|
|
@@ -2494,7 +2614,7 @@ window.openAIChatManager = function () {
|
|
|
2494
2614
|
if (this.micButton) {
|
|
2495
2615
|
this.micButton.style.display = '';
|
|
2496
2616
|
this.micButton.addEventListener('click', function () {
|
|
2497
|
-
|
|
2617
|
+
_this20.toggleRecording();
|
|
2498
2618
|
});
|
|
2499
2619
|
}
|
|
2500
2620
|
}
|
|
@@ -2504,7 +2624,7 @@ window.openAIChatManager = function () {
|
|
|
2504
2624
|
this.conversationButton = document.querySelector(config.conversationButtonElementSelector);
|
|
2505
2625
|
if (this.conversationButton) {
|
|
2506
2626
|
this.conversationButton.addEventListener('click', function () {
|
|
2507
|
-
|
|
2627
|
+
_this20.toggleConversationMode();
|
|
2508
2628
|
});
|
|
2509
2629
|
}
|
|
2510
2630
|
}
|
|
@@ -2536,7 +2656,7 @@ window.openAIChatManager = function () {
|
|
|
2536
2656
|
}
|
|
2537
2657
|
},
|
|
2538
2658
|
initializeWidget: function initializeWidget() {
|
|
2539
|
-
var
|
|
2659
|
+
var _this21 = this;
|
|
2540
2660
|
if (!config.widget.chatWidgetContainer) {
|
|
2541
2661
|
console.error('The widget chatWidgetContainer is required.');
|
|
2542
2662
|
return;
|
|
@@ -2567,9 +2687,9 @@ window.openAIChatManager = function () {
|
|
|
2567
2687
|
chatWidgetContainer.style.minHeight = (parsePixelValue(config.widget.minHeight) || 420) + 'px';
|
|
2568
2688
|
if (typeof ResizeObserver !== 'undefined') {
|
|
2569
2689
|
this.widgetResizeObserver = new ResizeObserver(function () {
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2690
|
+
_this21.persistWidgetPanelSize();
|
|
2691
|
+
_this21.constrainWidgetElementsToViewport();
|
|
2692
|
+
_this21.updateWidgetResetSizeButtonVisibility();
|
|
2573
2693
|
});
|
|
2574
2694
|
this.widgetResizeObserver.observe(chatWidgetContainer);
|
|
2575
2695
|
}
|
|
@@ -2588,14 +2708,14 @@ window.openAIChatManager = function () {
|
|
|
2588
2708
|
if (this.widgetResetSizeButtonElement) {
|
|
2589
2709
|
this.widgetResetSizeButtonElement.addEventListener('click', function (event) {
|
|
2590
2710
|
event.preventDefault();
|
|
2591
|
-
|
|
2711
|
+
_this21.resetWidgetSize();
|
|
2592
2712
|
});
|
|
2593
2713
|
}
|
|
2594
2714
|
this.restoreWidgetLayout();
|
|
2595
2715
|
if (!this.widgetViewportResizeHandler) {
|
|
2596
2716
|
this.widgetViewportResizeHandler = function () {
|
|
2597
|
-
|
|
2598
|
-
|
|
2717
|
+
_this21.constrainWidgetElementsToViewport();
|
|
2718
|
+
_this21.updateWidgetResetSizeButtonVisibility();
|
|
2599
2719
|
};
|
|
2600
2720
|
window.addEventListener('resize', this.widgetViewportResizeHandler);
|
|
2601
2721
|
}
|
|
@@ -2609,14 +2729,14 @@ window.openAIChatManager = function () {
|
|
|
2609
2729
|
var showHistoryButton = document.querySelector(config.widget.showHistoryButton);
|
|
2610
2730
|
if (showHistoryButton) {
|
|
2611
2731
|
showHistoryButton.addEventListener('click', function () {
|
|
2612
|
-
|
|
2732
|
+
_this21.chatHistorySection.classList.toggle('show');
|
|
2613
2733
|
});
|
|
2614
2734
|
}
|
|
2615
2735
|
if (config.widget.closeHistoryButton) {
|
|
2616
2736
|
var closeHistoryButton = document.querySelector(config.widget.closeHistoryButton);
|
|
2617
2737
|
if (closeHistoryButton) {
|
|
2618
2738
|
closeHistoryButton.addEventListener('click', function () {
|
|
2619
|
-
|
|
2739
|
+
_this21.showChatScreen();
|
|
2620
2740
|
});
|
|
2621
2741
|
}
|
|
2622
2742
|
}
|
|
@@ -2625,8 +2745,8 @@ window.openAIChatManager = function () {
|
|
|
2625
2745
|
var newChatButton = document.querySelector(config.widget.newChatButton);
|
|
2626
2746
|
if (newChatButton) {
|
|
2627
2747
|
newChatButton.addEventListener('click', function () {
|
|
2628
|
-
|
|
2629
|
-
|
|
2748
|
+
_this21.resetSession();
|
|
2749
|
+
_this21.showChatScreen();
|
|
2630
2750
|
});
|
|
2631
2751
|
}
|
|
2632
2752
|
}
|
|
@@ -2654,11 +2774,11 @@ window.openAIChatManager = function () {
|
|
|
2654
2774
|
var upBtn = container.querySelector('.rate-up-btn');
|
|
2655
2775
|
var downBtn = container.querySelector('.rate-down-btn');
|
|
2656
2776
|
|
|
2657
|
-
//
|
|
2658
|
-
//
|
|
2777
|
+
// Keep feedback icons as simple span-based Font Awesome markup so
|
|
2778
|
+
// later state updates do not depend on i2svg replacement.
|
|
2659
2779
|
if (upBtn) {
|
|
2660
2780
|
var upClass = userRating === true ? 'fa-solid fa-thumbs-up' : 'fa-regular fa-thumbs-up';
|
|
2661
|
-
var upIcon = document.createElement('
|
|
2781
|
+
var upIcon = document.createElement('span');
|
|
2662
2782
|
upIcon.className = upClass;
|
|
2663
2783
|
upIcon.style.fontSize = '0.9rem';
|
|
2664
2784
|
upBtn.textContent = '';
|
|
@@ -2666,19 +2786,12 @@ window.openAIChatManager = function () {
|
|
|
2666
2786
|
}
|
|
2667
2787
|
if (downBtn) {
|
|
2668
2788
|
var downClass = userRating === false ? 'fa-solid fa-thumbs-down' : 'fa-regular fa-thumbs-down';
|
|
2669
|
-
var downIcon = document.createElement('
|
|
2789
|
+
var downIcon = document.createElement('span');
|
|
2670
2790
|
downIcon.className = downClass;
|
|
2671
2791
|
downIcon.style.fontSize = '0.9rem';
|
|
2672
2792
|
downBtn.textContent = '';
|
|
2673
2793
|
downBtn.appendChild(downIcon);
|
|
2674
2794
|
}
|
|
2675
|
-
|
|
2676
|
-
// Trigger Font Awesome SVG+JS to convert the new <i> elements.
|
|
2677
|
-
if (window.FontAwesome && FontAwesome.dom && FontAwesome.dom.i2svg) {
|
|
2678
|
-
FontAwesome.dom.i2svg({
|
|
2679
|
-
node: container
|
|
2680
|
-
});
|
|
2681
|
-
}
|
|
2682
2795
|
},
|
|
2683
2796
|
refreshAllFeedbackIcons: function refreshAllFeedbackIcons() {
|
|
2684
2797
|
var containers = this.$el.querySelectorAll('.ai-chat-message-assistant-feedback');
|
|
@@ -2762,17 +2875,17 @@ window.openAIChatManager = function () {
|
|
|
2762
2875
|
}
|
|
2763
2876
|
},
|
|
2764
2877
|
mounted: function mounted() {
|
|
2765
|
-
var
|
|
2878
|
+
var _this22 = this;
|
|
2766
2879
|
_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6() {
|
|
2767
2880
|
return _regenerator().w(function (_context6) {
|
|
2768
2881
|
while (1) switch (_context6.n) {
|
|
2769
2882
|
case 0:
|
|
2770
2883
|
_context6.n = 1;
|
|
2771
|
-
return
|
|
2884
|
+
return _this22.startConnection();
|
|
2772
2885
|
case 1:
|
|
2773
|
-
|
|
2886
|
+
_this22.initializeApp();
|
|
2774
2887
|
if (hasWidgetConfig) {
|
|
2775
|
-
|
|
2888
|
+
_this22.initializeWidget();
|
|
2776
2889
|
}
|
|
2777
2890
|
case 2:
|
|
2778
2891
|
return _context6.a(2);
|