@crestapps/ai-chat-ui 1.0.0-preview.8 → 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.js +143 -111
- 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 +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/package.json +1 -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
|
|
@@ -1010,7 +1010,7 @@ window.openAIChatManager = function () {
|
|
|
1010
1010
|
var name = doc.fileName || 'Document';
|
|
1011
1011
|
if (name.length > 20) name = name.substring(0, 17) + '...';
|
|
1012
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 || '') + '">';
|
|
1013
|
-
html += '<
|
|
1013
|
+
html += '<span class="fa-solid fa-file-lines" style="font-size: 0.7rem;"></span> ';
|
|
1014
1014
|
html += this.escapeHtml(name);
|
|
1015
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>';
|
|
1016
1016
|
html += '</span>';
|
|
@@ -1021,7 +1021,7 @@ window.openAIChatManager = function () {
|
|
|
1021
1021
|
var errorMsg = failedItem.error || 'Upload failed';
|
|
1022
1022
|
if (failedName.length > 15) failedName = failedName.substring(0, 12) + '...';
|
|
1023
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) + '">';
|
|
1024
|
-
html += '<
|
|
1024
|
+
html += '<span class="fa-solid fa-circle-exclamation" style="font-size: 0.7rem;"></span> ';
|
|
1025
1025
|
html += this.escapeHtml(failedName);
|
|
1026
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>';
|
|
1027
1027
|
html += '</span>';
|
|
@@ -1032,7 +1032,7 @@ window.openAIChatManager = function () {
|
|
|
1032
1032
|
html += '</span>';
|
|
1033
1033
|
}
|
|
1034
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">';
|
|
1035
|
-
html += '<
|
|
1035
|
+
html += '<span class="fa-solid fa-paperclip"></span>';
|
|
1036
1036
|
if (this.documents.length === 0 && !this.isUploading) {
|
|
1037
1037
|
html += ' <span>Attach files</span>';
|
|
1038
1038
|
}
|
|
@@ -1664,10 +1664,10 @@ window.openAIChatManager = function () {
|
|
|
1664
1664
|
}
|
|
1665
1665
|
if (this.isRecording) {
|
|
1666
1666
|
this.micButton.classList.add('stt-recording');
|
|
1667
|
-
this.micButton.innerHTML = '<
|
|
1667
|
+
this.micButton.innerHTML = '<span class="fa-solid fa-stop"></span>';
|
|
1668
1668
|
} else {
|
|
1669
1669
|
this.micButton.classList.remove('stt-recording');
|
|
1670
|
-
this.micButton.innerHTML = '<
|
|
1670
|
+
this.micButton.innerHTML = '<span class="fa-solid fa-microphone"></span>';
|
|
1671
1671
|
}
|
|
1672
1672
|
},
|
|
1673
1673
|
streamMessage: function streamMessage(profileId, trimmedPrompt, sessionProfileId) {
|
|
@@ -1933,8 +1933,25 @@ window.openAIChatManager = function () {
|
|
|
1933
1933
|
}
|
|
1934
1934
|
this.stopAudio(false);
|
|
1935
1935
|
},
|
|
1936
|
-
|
|
1936
|
+
updateTtsPlaybackButtons: function updateTtsPlaybackButtons() {
|
|
1937
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;
|
|
1938
1955
|
if (!this.textToSpeechEnabled || !text || !this.connection) {
|
|
1939
1956
|
return;
|
|
1940
1957
|
}
|
|
@@ -1943,12 +1960,16 @@ window.openAIChatManager = function () {
|
|
|
1943
1960
|
this._ttsCacheIndex = cacheIndex !== undefined ? cacheIndex : -1;
|
|
1944
1961
|
this.connection.invoke("SynthesizeSpeech", this.getProfileId(), this.getSessionId(), text, this.ttsVoiceName)["catch"](function (err) {
|
|
1945
1962
|
console.error("TTS synthesis error:", err);
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1963
|
+
_this10.isPlayingAudio = false;
|
|
1964
|
+
_this10.ttsPlayingMessageIndex = -1;
|
|
1965
|
+
_this10._ttsCacheIndex = -1;
|
|
1966
|
+
_this10.$nextTick(function () {
|
|
1967
|
+
return _this10.updateTtsPlaybackButtons();
|
|
1968
|
+
});
|
|
1949
1969
|
});
|
|
1950
1970
|
},
|
|
1951
1971
|
toggleMessageTts: function toggleMessageTts(message, index) {
|
|
1972
|
+
var _this11 = this;
|
|
1952
1973
|
if (this.ttsPlayingMessageIndex === index) {
|
|
1953
1974
|
this.stopAudio();
|
|
1954
1975
|
return;
|
|
@@ -1960,6 +1981,9 @@ window.openAIChatManager = function () {
|
|
|
1960
1981
|
}
|
|
1961
1982
|
}));
|
|
1962
1983
|
this.ttsPlayingMessageIndex = index;
|
|
1984
|
+
this.$nextTick(function () {
|
|
1985
|
+
return _this11.updateTtsPlaybackButtons();
|
|
1986
|
+
});
|
|
1963
1987
|
if (this.ttsAudioCache[index]) {
|
|
1964
1988
|
this.playAudioBlob(this.ttsAudioCache[index]);
|
|
1965
1989
|
return;
|
|
@@ -1967,10 +1991,14 @@ window.openAIChatManager = function () {
|
|
|
1967
1991
|
this.synthesizeSpeech(message.content, index);
|
|
1968
1992
|
},
|
|
1969
1993
|
playCollectedAudio: function playCollectedAudio() {
|
|
1994
|
+
var _this12 = this;
|
|
1970
1995
|
if (this.audioChunks.length === 0) {
|
|
1971
1996
|
if (!this.currentAudioElement && this.audioPlayQueue.length === 0) {
|
|
1972
1997
|
this.isPlayingAudio = false;
|
|
1973
1998
|
this.ttsPlayingMessageIndex = -1;
|
|
1999
|
+
this.$nextTick(function () {
|
|
2000
|
+
return _this12.updateTtsPlaybackButtons();
|
|
2001
|
+
});
|
|
1974
2002
|
}
|
|
1975
2003
|
return;
|
|
1976
2004
|
}
|
|
@@ -2009,45 +2037,53 @@ window.openAIChatManager = function () {
|
|
|
2009
2037
|
this.playAudioBlob(blob);
|
|
2010
2038
|
},
|
|
2011
2039
|
playAudioBlob: function playAudioBlob(blob) {
|
|
2012
|
-
var
|
|
2040
|
+
var _this13 = this;
|
|
2013
2041
|
var url = URL.createObjectURL(blob);
|
|
2014
2042
|
var audio = new Audio(url);
|
|
2015
2043
|
this.currentAudioUrl = url;
|
|
2016
2044
|
this.currentAudioElement = audio;
|
|
2017
2045
|
this.isPlayingAudio = true;
|
|
2018
2046
|
audio.addEventListener('ended', function () {
|
|
2019
|
-
|
|
2020
|
-
|
|
2047
|
+
_this13.currentAudioElement = null;
|
|
2048
|
+
_this13.currentAudioUrl = null;
|
|
2021
2049
|
URL.revokeObjectURL(url);
|
|
2022
|
-
|
|
2050
|
+
_this13.playNextInQueue();
|
|
2023
2051
|
});
|
|
2024
2052
|
audio.addEventListener('error', function () {
|
|
2025
|
-
|
|
2026
|
-
|
|
2053
|
+
_this13.currentAudioElement = null;
|
|
2054
|
+
_this13.currentAudioUrl = null;
|
|
2027
2055
|
URL.revokeObjectURL(url);
|
|
2028
|
-
|
|
2056
|
+
_this13.playNextInQueue();
|
|
2029
2057
|
});
|
|
2030
2058
|
audio.play()["catch"](function (err) {
|
|
2031
2059
|
console.error("Audio playback error:", err);
|
|
2032
|
-
|
|
2033
|
-
|
|
2060
|
+
_this13.currentAudioElement = null;
|
|
2061
|
+
_this13.currentAudioUrl = null;
|
|
2034
2062
|
URL.revokeObjectURL(url);
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2063
|
+
_this13.audioPlayQueue = [];
|
|
2064
|
+
_this13.isPlayingAudio = false;
|
|
2065
|
+
_this13.ttsPlayingMessageIndex = -1;
|
|
2066
|
+
_this13.$nextTick(function () {
|
|
2067
|
+
return _this13.updateTtsPlaybackButtons();
|
|
2068
|
+
});
|
|
2038
2069
|
});
|
|
2039
2070
|
},
|
|
2040
2071
|
playNextInQueue: function playNextInQueue() {
|
|
2072
|
+
var _this14 = this;
|
|
2041
2073
|
if (this.audioPlayQueue.length > 0) {
|
|
2042
2074
|
var nextBlob = this.audioPlayQueue.shift();
|
|
2043
2075
|
this.playAudioBlob(nextBlob);
|
|
2044
2076
|
} else {
|
|
2045
2077
|
this.isPlayingAudio = false;
|
|
2046
2078
|
this.ttsPlayingMessageIndex = -1;
|
|
2079
|
+
this.$nextTick(function () {
|
|
2080
|
+
return _this14.updateTtsPlaybackButtons();
|
|
2081
|
+
});
|
|
2047
2082
|
this.conversationModeOnAudioEnded();
|
|
2048
2083
|
}
|
|
2049
2084
|
},
|
|
2050
2085
|
stopAudio: function stopAudio() {
|
|
2086
|
+
var _this15 = this;
|
|
2051
2087
|
if (this.currentAudioElement) {
|
|
2052
2088
|
this.currentAudioElement.pause();
|
|
2053
2089
|
this.currentAudioElement.currentTime = 0;
|
|
@@ -2061,6 +2097,9 @@ window.openAIChatManager = function () {
|
|
|
2061
2097
|
this.audioPlayQueue = [];
|
|
2062
2098
|
this.isPlayingAudio = false;
|
|
2063
2099
|
this.ttsPlayingMessageIndex = -1;
|
|
2100
|
+
this.$nextTick(function () {
|
|
2101
|
+
return _this15.updateTtsPlaybackButtons();
|
|
2102
|
+
});
|
|
2064
2103
|
},
|
|
2065
2104
|
toggleConversationMode: function toggleConversationMode() {
|
|
2066
2105
|
if (this.isConversationMode) {
|
|
@@ -2070,7 +2109,7 @@ window.openAIChatManager = function () {
|
|
|
2070
2109
|
}
|
|
2071
2110
|
},
|
|
2072
2111
|
startConversationMode: function startConversationMode() {
|
|
2073
|
-
var
|
|
2112
|
+
var _this16 = this;
|
|
2074
2113
|
if (!this.conversationModeEnabled || this.isConversationMode || !this.connection) {
|
|
2075
2114
|
return;
|
|
2076
2115
|
}
|
|
@@ -2090,12 +2129,12 @@ window.openAIChatManager = function () {
|
|
|
2090
2129
|
}
|
|
2091
2130
|
}).then(function (stream) {
|
|
2092
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';
|
|
2093
|
-
|
|
2132
|
+
_this16.mediaRecorder = new MediaRecorder(stream, {
|
|
2094
2133
|
mimeType: mimeType,
|
|
2095
2134
|
audioBitsPerSecond: 128000
|
|
2096
2135
|
});
|
|
2097
|
-
|
|
2098
|
-
|
|
2136
|
+
_this16._conversationSubject = new signalR.Subject();
|
|
2137
|
+
_this16._conversationStream = stream;
|
|
2099
2138
|
|
|
2100
2139
|
// Create an AnalyserNode for volume-based interrupt detection.
|
|
2101
2140
|
// During TTS playback, detect when the user speaks above
|
|
@@ -2104,20 +2143,20 @@ window.openAIChatManager = function () {
|
|
|
2104
2143
|
// speaker echo so the STT stream has no gaps.
|
|
2105
2144
|
var AudioCtx = window.AudioContext || window.webkitAudioContext;
|
|
2106
2145
|
if (AudioCtx) {
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
var micSource =
|
|
2111
|
-
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);
|
|
2112
2151
|
}
|
|
2113
2152
|
var pendingChunk = Promise.resolve();
|
|
2114
|
-
var analyser =
|
|
2153
|
+
var analyser = _this16._conversationAnalyser;
|
|
2115
2154
|
var interruptVolumeThreshold = 30;
|
|
2116
|
-
|
|
2155
|
+
_this16.mediaRecorder.addEventListener('dataavailable', function (e) {
|
|
2117
2156
|
if (e.data && e.data.size > 0) {
|
|
2118
2157
|
// During TTS playback, check mic volume to detect
|
|
2119
2158
|
// user interruption (speaking above threshold).
|
|
2120
|
-
if (
|
|
2159
|
+
if (_this16.isPlayingAudio && analyser) {
|
|
2121
2160
|
var freqData = new Uint8Array(analyser.frequencyBinCount);
|
|
2122
2161
|
analyser.getByteFrequencyData(freqData);
|
|
2123
2162
|
var sum = 0;
|
|
@@ -2127,7 +2166,7 @@ window.openAIChatManager = function () {
|
|
|
2127
2166
|
var avg = sum / freqData.length;
|
|
2128
2167
|
if (avg >= interruptVolumeThreshold) {
|
|
2129
2168
|
// User is speaking — interrupt TTS playback.
|
|
2130
|
-
|
|
2169
|
+
_this16.stopAudio();
|
|
2131
2170
|
}
|
|
2132
2171
|
}
|
|
2133
2172
|
|
|
@@ -2149,7 +2188,7 @@ window.openAIChatManager = function () {
|
|
|
2149
2188
|
}, '');
|
|
2150
2189
|
base64 = btoa(binaryString);
|
|
2151
2190
|
try {
|
|
2152
|
-
|
|
2191
|
+
_this16._conversationSubject.next(base64);
|
|
2153
2192
|
} catch (err) {
|
|
2154
2193
|
// Subject may have been completed already.
|
|
2155
2194
|
}
|
|
@@ -2160,28 +2199,28 @@ window.openAIChatManager = function () {
|
|
|
2160
2199
|
})));
|
|
2161
2200
|
}
|
|
2162
2201
|
});
|
|
2163
|
-
|
|
2202
|
+
_this16.mediaRecorder.addEventListener('stop', function () {
|
|
2164
2203
|
stream.getTracks().forEach(function (track) {
|
|
2165
2204
|
return track.stop();
|
|
2166
2205
|
});
|
|
2167
2206
|
pendingChunk.then(function () {
|
|
2168
2207
|
try {
|
|
2169
|
-
|
|
2208
|
+
_this16._conversationSubject.complete();
|
|
2170
2209
|
} catch (err) {
|
|
2171
2210
|
// Already completed.
|
|
2172
2211
|
}
|
|
2173
2212
|
});
|
|
2174
2213
|
});
|
|
2175
|
-
var profileId =
|
|
2176
|
-
var sessionId =
|
|
2214
|
+
var profileId = _this16.getProfileId();
|
|
2215
|
+
var sessionId = _this16.getSessionId() || '';
|
|
2177
2216
|
var language = navigator.language || document.documentElement.lang || 'en-US';
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2217
|
+
_this16.connection.send("StartConversation", profileId, sessionId, _this16._conversationSubject, mimeType, language);
|
|
2218
|
+
_this16.mediaRecorder.start(250);
|
|
2219
|
+
_this16.isRecording = true;
|
|
2181
2220
|
})["catch"](function (err) {
|
|
2182
2221
|
console.error('Microphone access denied:', err);
|
|
2183
|
-
|
|
2184
|
-
|
|
2222
|
+
_this16.isConversationMode = false;
|
|
2223
|
+
_this16.updateConversationButton();
|
|
2185
2224
|
});
|
|
2186
2225
|
},
|
|
2187
2226
|
stopConversationMode: function stopConversationMode() {
|
|
@@ -2308,7 +2347,7 @@ window.openAIChatManager = function () {
|
|
|
2308
2347
|
return removedCount;
|
|
2309
2348
|
},
|
|
2310
2349
|
receiveNotification: function receiveNotification(notification) {
|
|
2311
|
-
var
|
|
2350
|
+
var _this17 = this;
|
|
2312
2351
|
if (!notification || !notification.type) {
|
|
2313
2352
|
return;
|
|
2314
2353
|
}
|
|
@@ -2323,7 +2362,7 @@ window.openAIChatManager = function () {
|
|
|
2323
2362
|
}
|
|
2324
2363
|
this.scheduleNotificationDismiss(notification);
|
|
2325
2364
|
this.$nextTick(function () {
|
|
2326
|
-
|
|
2365
|
+
_this17.scrollToBottom();
|
|
2327
2366
|
});
|
|
2328
2367
|
},
|
|
2329
2368
|
updateNotification: function updateNotification(notification) {
|
|
@@ -2340,12 +2379,12 @@ window.openAIChatManager = function () {
|
|
|
2340
2379
|
}
|
|
2341
2380
|
},
|
|
2342
2381
|
scheduleNotificationDismiss: function scheduleNotificationDismiss(notification) {
|
|
2343
|
-
var
|
|
2382
|
+
var _this18 = this;
|
|
2344
2383
|
if (!notification || !notification.type || !notification.autoDismissMs || notification.autoDismissMs <= 0) {
|
|
2345
2384
|
return;
|
|
2346
2385
|
}
|
|
2347
2386
|
this.notificationDismissTimers[notification.type] = setTimeout(function () {
|
|
2348
|
-
|
|
2387
|
+
_this18.removeNotification(notification.type);
|
|
2349
2388
|
}, notification.autoDismissMs);
|
|
2350
2389
|
},
|
|
2351
2390
|
clearNotificationDismiss: function clearNotificationDismiss(notificationType) {
|
|
@@ -2375,12 +2414,12 @@ window.openAIChatManager = function () {
|
|
|
2375
2414
|
});
|
|
2376
2415
|
},
|
|
2377
2416
|
scrollToBottom: function scrollToBottom() {
|
|
2378
|
-
var
|
|
2417
|
+
var _this19 = this;
|
|
2379
2418
|
if (!this.autoScroll) {
|
|
2380
2419
|
return;
|
|
2381
2420
|
}
|
|
2382
2421
|
setTimeout(function () {
|
|
2383
|
-
|
|
2422
|
+
_this19.chatContainer.scrollTop = _this19.chatContainer.scrollHeight - _this19.chatContainer.clientHeight;
|
|
2384
2423
|
}, 50);
|
|
2385
2424
|
},
|
|
2386
2425
|
handleUserInput: function handleUserInput(event) {
|
|
@@ -2422,7 +2461,7 @@ window.openAIChatManager = function () {
|
|
|
2422
2461
|
});
|
|
2423
2462
|
},
|
|
2424
2463
|
initializeApp: function initializeApp() {
|
|
2425
|
-
var
|
|
2464
|
+
var _this20 = this;
|
|
2426
2465
|
this.inputElement = document.querySelector(config.inputElementSelector);
|
|
2427
2466
|
this.buttonElement = document.querySelector(config.sendButtonElementSelector);
|
|
2428
2467
|
this.chatContainer = document.querySelector(config.chatContainerElementSelector);
|
|
@@ -2451,7 +2490,7 @@ window.openAIChatManager = function () {
|
|
|
2451
2490
|
fileInput.accept = config.allowedExtensions;
|
|
2452
2491
|
}
|
|
2453
2492
|
fileInput.addEventListener('change', function (e) {
|
|
2454
|
-
return
|
|
2493
|
+
return _this20.handleFileInputChange(e);
|
|
2455
2494
|
});
|
|
2456
2495
|
this.documentBar.parentElement.appendChild(fileInput);
|
|
2457
2496
|
|
|
@@ -2459,13 +2498,13 @@ window.openAIChatManager = function () {
|
|
|
2459
2498
|
var inputArea = this.inputElement ? this.inputElement.closest('.ai-admin-widget-input, .text-bg-light') : null;
|
|
2460
2499
|
if (inputArea) {
|
|
2461
2500
|
inputArea.addEventListener('dragover', function (e) {
|
|
2462
|
-
return
|
|
2501
|
+
return _this20.handleDragOver(e);
|
|
2463
2502
|
});
|
|
2464
2503
|
inputArea.addEventListener('dragleave', function (e) {
|
|
2465
|
-
return
|
|
2504
|
+
return _this20.handleDragLeave(e);
|
|
2466
2505
|
});
|
|
2467
2506
|
inputArea.addEventListener('drop', function (e) {
|
|
2468
|
-
return
|
|
2507
|
+
return _this20.handleDrop(e);
|
|
2469
2508
|
});
|
|
2470
2509
|
}
|
|
2471
2510
|
}
|
|
@@ -2473,55 +2512,55 @@ window.openAIChatManager = function () {
|
|
|
2473
2512
|
|
|
2474
2513
|
// Pause auto-scroll when the user manually scrolls up during streaming.
|
|
2475
2514
|
this.chatContainer.addEventListener('scroll', function () {
|
|
2476
|
-
if (!
|
|
2515
|
+
if (!_this20.stream) {
|
|
2477
2516
|
return;
|
|
2478
2517
|
}
|
|
2479
2518
|
var threshold = 30;
|
|
2480
|
-
var atBottom =
|
|
2481
|
-
|
|
2519
|
+
var atBottom = _this20.chatContainer.scrollHeight - _this20.chatContainer.clientHeight - _this20.chatContainer.scrollTop <= threshold;
|
|
2520
|
+
_this20.autoScroll = atBottom;
|
|
2482
2521
|
});
|
|
2483
2522
|
this.inputElement.addEventListener('keydown', function (event) {
|
|
2484
|
-
if (
|
|
2523
|
+
if (_this20.stream != null) {
|
|
2485
2524
|
return;
|
|
2486
2525
|
}
|
|
2487
2526
|
if (event.key === "Enter" && !event.shiftKey) {
|
|
2488
2527
|
event.preventDefault();
|
|
2489
|
-
|
|
2528
|
+
_this20.buttonElement.click();
|
|
2490
2529
|
}
|
|
2491
2530
|
});
|
|
2492
2531
|
this.inputElement.addEventListener('input', function (e) {
|
|
2493
|
-
|
|
2532
|
+
_this20.handleUserInput(e);
|
|
2494
2533
|
if (e.target.value.trim()) {
|
|
2495
|
-
|
|
2534
|
+
_this20.buttonElement.removeAttribute('disabled');
|
|
2496
2535
|
} else {
|
|
2497
|
-
|
|
2536
|
+
_this20.buttonElement.setAttribute('disabled', true);
|
|
2498
2537
|
}
|
|
2499
2538
|
});
|
|
2500
2539
|
this.buttonElement.addEventListener('click', function () {
|
|
2501
|
-
if (
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2540
|
+
if (_this20.stream != null) {
|
|
2541
|
+
_this20.stream.dispose();
|
|
2542
|
+
_this20.stream = null;
|
|
2543
|
+
_this20.streamingFinished();
|
|
2544
|
+
_this20.hideTypingIndicator();
|
|
2506
2545
|
|
|
2507
2546
|
// Clean up: remove empty assistant message or stop streaming animation.
|
|
2508
|
-
if (
|
|
2509
|
-
var lastMsg =
|
|
2547
|
+
if (_this20.messages.length > 0) {
|
|
2548
|
+
var lastMsg = _this20.messages[_this20.messages.length - 1];
|
|
2510
2549
|
if (lastMsg.role === 'assistant' && !lastMsg.content) {
|
|
2511
|
-
|
|
2550
|
+
_this20.messages.pop();
|
|
2512
2551
|
} else if (lastMsg.isStreaming) {
|
|
2513
2552
|
lastMsg.isStreaming = false;
|
|
2514
2553
|
}
|
|
2515
2554
|
}
|
|
2516
2555
|
return;
|
|
2517
2556
|
}
|
|
2518
|
-
|
|
2557
|
+
_this20.sendMessage();
|
|
2519
2558
|
});
|
|
2520
2559
|
var promptGenerators = document.getElementsByClassName('profile-generated-prompt');
|
|
2521
2560
|
for (var i = 0; i < promptGenerators.length; i++) {
|
|
2522
2561
|
promptGenerators[i].addEventListener('click', function (e) {
|
|
2523
2562
|
e.preventDefault();
|
|
2524
|
-
|
|
2563
|
+
_this20.generatePrompt(e.target);
|
|
2525
2564
|
});
|
|
2526
2565
|
}
|
|
2527
2566
|
var chatSessions = document.getElementsByClassName('chat-session-history-item');
|
|
@@ -2533,8 +2572,8 @@ window.openAIChatManager = function () {
|
|
|
2533
2572
|
console.error('an element with the class chat-session-history-item with no data-session-id set.');
|
|
2534
2573
|
return;
|
|
2535
2574
|
}
|
|
2536
|
-
|
|
2537
|
-
|
|
2575
|
+
_this20.loadSession(sessionId);
|
|
2576
|
+
_this20.showChatScreen();
|
|
2538
2577
|
});
|
|
2539
2578
|
}
|
|
2540
2579
|
for (var _i5 = 0; _i5 < config.messages.length; _i5++) {
|
|
@@ -2543,7 +2582,7 @@ window.openAIChatManager = function () {
|
|
|
2543
2582
|
|
|
2544
2583
|
// Update feedback icons in the DOM after initial messages have rendered.
|
|
2545
2584
|
this.$nextTick(function () {
|
|
2546
|
-
|
|
2585
|
+
_this20.refreshAllFeedbackIcons();
|
|
2547
2586
|
});
|
|
2548
2587
|
|
|
2549
2588
|
// Delegate click for code block copy buttons.
|
|
@@ -2561,9 +2600,9 @@ window.openAIChatManager = function () {
|
|
|
2561
2600
|
if (codeEl) {
|
|
2562
2601
|
navigator.clipboard.writeText(codeEl.textContent);
|
|
2563
2602
|
var copiedText = config.codeCopiedText || 'Copied!';
|
|
2564
|
-
btn.innerHTML = '<
|
|
2603
|
+
btn.innerHTML = '<span class="fa-solid fa-check"></span> ' + copiedText;
|
|
2565
2604
|
setTimeout(function () {
|
|
2566
|
-
btn.innerHTML = '<
|
|
2605
|
+
btn.innerHTML = '<span class="fa-regular fa-copy"></span>';
|
|
2567
2606
|
}, 2000);
|
|
2568
2607
|
}
|
|
2569
2608
|
});
|
|
@@ -2575,7 +2614,7 @@ window.openAIChatManager = function () {
|
|
|
2575
2614
|
if (this.micButton) {
|
|
2576
2615
|
this.micButton.style.display = '';
|
|
2577
2616
|
this.micButton.addEventListener('click', function () {
|
|
2578
|
-
|
|
2617
|
+
_this20.toggleRecording();
|
|
2579
2618
|
});
|
|
2580
2619
|
}
|
|
2581
2620
|
}
|
|
@@ -2585,7 +2624,7 @@ window.openAIChatManager = function () {
|
|
|
2585
2624
|
this.conversationButton = document.querySelector(config.conversationButtonElementSelector);
|
|
2586
2625
|
if (this.conversationButton) {
|
|
2587
2626
|
this.conversationButton.addEventListener('click', function () {
|
|
2588
|
-
|
|
2627
|
+
_this20.toggleConversationMode();
|
|
2589
2628
|
});
|
|
2590
2629
|
}
|
|
2591
2630
|
}
|
|
@@ -2617,7 +2656,7 @@ window.openAIChatManager = function () {
|
|
|
2617
2656
|
}
|
|
2618
2657
|
},
|
|
2619
2658
|
initializeWidget: function initializeWidget() {
|
|
2620
|
-
var
|
|
2659
|
+
var _this21 = this;
|
|
2621
2660
|
if (!config.widget.chatWidgetContainer) {
|
|
2622
2661
|
console.error('The widget chatWidgetContainer is required.');
|
|
2623
2662
|
return;
|
|
@@ -2648,9 +2687,9 @@ window.openAIChatManager = function () {
|
|
|
2648
2687
|
chatWidgetContainer.style.minHeight = (parsePixelValue(config.widget.minHeight) || 420) + 'px';
|
|
2649
2688
|
if (typeof ResizeObserver !== 'undefined') {
|
|
2650
2689
|
this.widgetResizeObserver = new ResizeObserver(function () {
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2690
|
+
_this21.persistWidgetPanelSize();
|
|
2691
|
+
_this21.constrainWidgetElementsToViewport();
|
|
2692
|
+
_this21.updateWidgetResetSizeButtonVisibility();
|
|
2654
2693
|
});
|
|
2655
2694
|
this.widgetResizeObserver.observe(chatWidgetContainer);
|
|
2656
2695
|
}
|
|
@@ -2669,14 +2708,14 @@ window.openAIChatManager = function () {
|
|
|
2669
2708
|
if (this.widgetResetSizeButtonElement) {
|
|
2670
2709
|
this.widgetResetSizeButtonElement.addEventListener('click', function (event) {
|
|
2671
2710
|
event.preventDefault();
|
|
2672
|
-
|
|
2711
|
+
_this21.resetWidgetSize();
|
|
2673
2712
|
});
|
|
2674
2713
|
}
|
|
2675
2714
|
this.restoreWidgetLayout();
|
|
2676
2715
|
if (!this.widgetViewportResizeHandler) {
|
|
2677
2716
|
this.widgetViewportResizeHandler = function () {
|
|
2678
|
-
|
|
2679
|
-
|
|
2717
|
+
_this21.constrainWidgetElementsToViewport();
|
|
2718
|
+
_this21.updateWidgetResetSizeButtonVisibility();
|
|
2680
2719
|
};
|
|
2681
2720
|
window.addEventListener('resize', this.widgetViewportResizeHandler);
|
|
2682
2721
|
}
|
|
@@ -2690,14 +2729,14 @@ window.openAIChatManager = function () {
|
|
|
2690
2729
|
var showHistoryButton = document.querySelector(config.widget.showHistoryButton);
|
|
2691
2730
|
if (showHistoryButton) {
|
|
2692
2731
|
showHistoryButton.addEventListener('click', function () {
|
|
2693
|
-
|
|
2732
|
+
_this21.chatHistorySection.classList.toggle('show');
|
|
2694
2733
|
});
|
|
2695
2734
|
}
|
|
2696
2735
|
if (config.widget.closeHistoryButton) {
|
|
2697
2736
|
var closeHistoryButton = document.querySelector(config.widget.closeHistoryButton);
|
|
2698
2737
|
if (closeHistoryButton) {
|
|
2699
2738
|
closeHistoryButton.addEventListener('click', function () {
|
|
2700
|
-
|
|
2739
|
+
_this21.showChatScreen();
|
|
2701
2740
|
});
|
|
2702
2741
|
}
|
|
2703
2742
|
}
|
|
@@ -2706,8 +2745,8 @@ window.openAIChatManager = function () {
|
|
|
2706
2745
|
var newChatButton = document.querySelector(config.widget.newChatButton);
|
|
2707
2746
|
if (newChatButton) {
|
|
2708
2747
|
newChatButton.addEventListener('click', function () {
|
|
2709
|
-
|
|
2710
|
-
|
|
2748
|
+
_this21.resetSession();
|
|
2749
|
+
_this21.showChatScreen();
|
|
2711
2750
|
});
|
|
2712
2751
|
}
|
|
2713
2752
|
}
|
|
@@ -2735,11 +2774,11 @@ window.openAIChatManager = function () {
|
|
|
2735
2774
|
var upBtn = container.querySelector('.rate-up-btn');
|
|
2736
2775
|
var downBtn = container.querySelector('.rate-down-btn');
|
|
2737
2776
|
|
|
2738
|
-
//
|
|
2739
|
-
//
|
|
2777
|
+
// Keep feedback icons as simple span-based Font Awesome markup so
|
|
2778
|
+
// later state updates do not depend on i2svg replacement.
|
|
2740
2779
|
if (upBtn) {
|
|
2741
2780
|
var upClass = userRating === true ? 'fa-solid fa-thumbs-up' : 'fa-regular fa-thumbs-up';
|
|
2742
|
-
var upIcon = document.createElement('
|
|
2781
|
+
var upIcon = document.createElement('span');
|
|
2743
2782
|
upIcon.className = upClass;
|
|
2744
2783
|
upIcon.style.fontSize = '0.9rem';
|
|
2745
2784
|
upBtn.textContent = '';
|
|
@@ -2747,19 +2786,12 @@ window.openAIChatManager = function () {
|
|
|
2747
2786
|
}
|
|
2748
2787
|
if (downBtn) {
|
|
2749
2788
|
var downClass = userRating === false ? 'fa-solid fa-thumbs-down' : 'fa-regular fa-thumbs-down';
|
|
2750
|
-
var downIcon = document.createElement('
|
|
2789
|
+
var downIcon = document.createElement('span');
|
|
2751
2790
|
downIcon.className = downClass;
|
|
2752
2791
|
downIcon.style.fontSize = '0.9rem';
|
|
2753
2792
|
downBtn.textContent = '';
|
|
2754
2793
|
downBtn.appendChild(downIcon);
|
|
2755
2794
|
}
|
|
2756
|
-
|
|
2757
|
-
// Trigger Font Awesome SVG+JS to convert the new <i> elements.
|
|
2758
|
-
if (window.FontAwesome && FontAwesome.dom && FontAwesome.dom.i2svg) {
|
|
2759
|
-
FontAwesome.dom.i2svg({
|
|
2760
|
-
node: container
|
|
2761
|
-
});
|
|
2762
|
-
}
|
|
2763
2795
|
},
|
|
2764
2796
|
refreshAllFeedbackIcons: function refreshAllFeedbackIcons() {
|
|
2765
2797
|
var containers = this.$el.querySelectorAll('.ai-chat-message-assistant-feedback');
|
|
@@ -2843,17 +2875,17 @@ window.openAIChatManager = function () {
|
|
|
2843
2875
|
}
|
|
2844
2876
|
},
|
|
2845
2877
|
mounted: function mounted() {
|
|
2846
|
-
var
|
|
2878
|
+
var _this22 = this;
|
|
2847
2879
|
_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6() {
|
|
2848
2880
|
return _regenerator().w(function (_context6) {
|
|
2849
2881
|
while (1) switch (_context6.n) {
|
|
2850
2882
|
case 0:
|
|
2851
2883
|
_context6.n = 1;
|
|
2852
|
-
return
|
|
2884
|
+
return _this22.startConnection();
|
|
2853
2885
|
case 1:
|
|
2854
|
-
|
|
2886
|
+
_this22.initializeApp();
|
|
2855
2887
|
if (hasWidgetConfig) {
|
|
2856
|
-
|
|
2888
|
+
_this22.initializeWidget();
|
|
2857
2889
|
}
|
|
2858
2890
|
case 2:
|
|
2859
2891
|
return _context6.a(2);
|