@crestapps/ai-chat-ui 2.0.0-preview.154 → 2.0.0-preview.162

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.
@@ -588,6 +588,8 @@ window.chatInteractionManager = function () {
588
588
  conversationModeEnabled: config.chatMode === 'Conversation',
589
589
  conversationButton: null,
590
590
  isConversationMode: false,
591
+ // Realtime (speech-to-speech) controller from the shared CoreAIRealtime module.
592
+ realtimeController: null,
591
593
  notifications: [],
592
594
  notificationDismissTimers: {},
593
595
  copyTitle: config.copyTitle,
@@ -692,19 +694,28 @@ window.chatInteractionManager = function () {
692
694
  }
693
695
  }
694
696
  });
695
- _this.connection.on("ReceiveConversationUserMessage", function (itemId, text) {
696
- if (text) {
697
+ _this.connection.on("ReceiveConversationUserMessage", function (itemId, turnId, text) {
698
+ // Realtime: a placeholder for this turn was already inserted in the right position when
699
+ // the utterance was captured (see onUserTurnPending), so just fill in its text.
700
+ if (turnId && _this._realtimePendingTurns && _this._realtimePendingTurns[turnId]) {
701
+ var pending = _this._realtimePendingTurns[turnId];
702
+ delete _this._realtimePendingTurns[turnId];
697
703
  _this.stopAudio();
698
-
699
- // If there's an interrupted assistant message still streaming,
700
- // mark it as done to stop the spinner animation.
701
- if (_this._conversationAssistantMessage) {
702
- var oldMsg = _this.messages[_this._conversationAssistantMessage.index];
703
- if (oldMsg) {
704
- oldMsg.isStreaming = false;
704
+ if (text) {
705
+ pending.content = text;
706
+ pending.rawContent = text;
707
+ pending.isPartial = false;
708
+ updateMessagePresentation(pending, pending.references);
709
+ } else {
710
+ var emptyIndex = _this.messages.indexOf(pending);
711
+ if (emptyIndex >= 0) {
712
+ _this.messages.splice(emptyIndex, 1);
705
713
  }
706
- _this._conversationAssistantMessage = null;
707
714
  }
715
+ return;
716
+ }
717
+ if (text) {
718
+ _this.stopAudio();
708
719
 
709
720
  // Replace the partial transcript message with the final one.
710
721
  if (_this._conversationPartialMessage) {
@@ -713,6 +724,21 @@ window.chatInteractionManager = function () {
713
724
  _this._conversationPartialMessage.htmlContent = '<p>' + escaped + '</p>';
714
725
  _this._conversationPartialMessage.isPartial = false;
715
726
  _this._conversationPartialMessage = null;
727
+ } else if (_this._conversationAssistantMessage) {
728
+ // Realtime: the user's transcript lags the assistant's reply for the SAME turn (the
729
+ // model answers the audio before speech-to-text finishes). Insert the user message
730
+ // just before the streaming assistant message so the order stays You -> Assistant,
731
+ // and keep that message streaming — ending it here split one reply into two bubbles.
732
+ var at = _this._conversationAssistantMessage.index;
733
+ var userMsg = {
734
+ role: 'user',
735
+ content: text,
736
+ rawContent: text,
737
+ references: {}
738
+ };
739
+ updateMessagePresentation(userMsg, userMsg.references);
740
+ _this.messages.splice(at, 0, userMsg);
741
+ _this._conversationAssistantMessage.index = at + 1;
716
742
  } else {
717
743
  _this.addMessage({
718
744
  role: 'user',
@@ -723,6 +749,15 @@ window.chatInteractionManager = function () {
723
749
  }
724
750
  });
725
751
  _this.connection.on("ReceiveConversationAssistantToken", function (itemId, messageId, token, responseId, references, appearance) {
752
+ // A new response id means a new turn — finalize the previous assistant message so two replies
753
+ // never merge into one bubble (also covers barge-in, which starts a fresh response).
754
+ if (_this._conversationAssistantMessage && _this._conversationAssistantResponseId && responseId && _this._conversationAssistantResponseId !== responseId) {
755
+ var prev = _this.messages[_this._conversationAssistantMessage.index];
756
+ if (prev) {
757
+ prev.isStreaming = false;
758
+ }
759
+ _this._conversationAssistantMessage = null;
760
+ }
726
761
  if (!_this._conversationAssistantMessage) {
727
762
  _this.stopAudio();
728
763
  _this.hideTypingIndicator();
@@ -748,6 +783,7 @@ window.chatInteractionManager = function () {
748
783
  index: msgIndex,
749
784
  content: ''
750
785
  };
786
+ _this._conversationAssistantResponseId = responseId;
751
787
  }
752
788
  _this._conversationAssistantMessage.content += token;
753
789
  var msg = _this.messages[_this._conversationAssistantMessage.index];
@@ -773,6 +809,7 @@ window.chatInteractionManager = function () {
773
809
  updateMessagePresentation(msg, msg.references);
774
810
  }
775
811
  _this._conversationAssistantMessage = null;
812
+ _this._conversationAssistantResponseId = null;
776
813
  }
777
814
  });
778
815
  _this.connection.on("ReceiveAudioChunk", function (itemId, base64Audio, contentType) {
@@ -782,7 +819,12 @@ window.chatInteractionManager = function () {
782
819
  for (var i = 0; i < binaryString.length; i++) {
783
820
  bytes[i] = binaryString.charCodeAt(i);
784
821
  }
785
- _this.audioChunks.push(bytes);
822
+ // Realtime PCM streams straight to the low-latency player; other formats (TTS) are buffered.
823
+ if (contentType === 'audio/pcm' && _this.realtimeController) {
824
+ _this.realtimeController.receivePcm(bytes);
825
+ } else {
826
+ _this.audioChunks.push(bytes);
827
+ }
786
828
  }
787
829
  });
788
830
  _this.connection.on("ReceiveAudioComplete", function (itemId) {
@@ -1982,6 +2024,205 @@ window.chatInteractionManager = function () {
1982
2024
  });
1983
2025
  }
1984
2026
  }
2027
+
2028
+ // Initialize realtime (speech-to-speech) mode via the shared CoreAIRealtime module. The
2029
+ // module owns the mic capture, playback, echo guard, push-to-talk and audio settings; the
2030
+ // callbacks below plug it into this app's connection and conversation-transcript display.
2031
+ if (window.CoreAIRealtime && config.realtimeButtonElementSelector) {
2032
+ this.realtimeController = window.CoreAIRealtime.attach({
2033
+ connection: this.connection,
2034
+ ensureConnected: function ensureConnected() {
2035
+ return Promise.resolve(_this18.connection);
2036
+ },
2037
+ sendStart: function sendStart(subject, voice, language, silenceMs, vadThreshold, allowInterruption) {
2038
+ _this18.connection.send('StartRealtimeConversation', _this18.getItemId(), subject, voice, language, silenceMs, vadThreshold, allowInterruption);
2039
+ },
2040
+ // Prefer WebRTC (server-relay) when the server advertises it; the shared module falls back
2041
+ // to the WebSocket sendStart above if the peer cannot connect.
2042
+ webRtcEnabled: config.realtimeWebRtcEnabled === true,
2043
+ sendStartWebRtc: function sendStartWebRtc(offerSdp, voice, language, silenceMs, vadThreshold, allowInterruption) {
2044
+ _this18.connection.send('StartRealtimeWebRtc', _this18.getItemId(), offerSdp, voice, language, silenceMs, vadThreshold, allowInterruption);
2045
+ },
2046
+ webRtcIceServers: Array.isArray(config.realtimeWebRtcIceServers) ? config.realtimeWebRtcIceServers : undefined,
2047
+ voiceName: config.realtimeVoiceName || '',
2048
+ getVoiceName: function getVoiceName() {
2049
+ var el = config.realtimeVoiceSelectElementSelector ? document.querySelector(config.realtimeVoiceSelectElementSelector) : null;
2050
+ return el ? el.value : '';
2051
+ },
2052
+ capableDeployments: config.realtimeCapableDeployments || [],
2053
+ realtimeEnabled: config.realtimeEnabled === true,
2054
+ selectors: {
2055
+ realtimeButton: config.realtimeButtonElementSelector,
2056
+ input: config.inputElementSelector,
2057
+ sendButton: config.sendButtonElementSelector,
2058
+ micButton: config.micButtonElementSelector,
2059
+ conversationButton: config.conversationButtonElementSelector,
2060
+ deploymentSelect: config.deploymentSelectElementSelector
2061
+ },
2062
+ onActivate: function onActivate() {
2063
+ _this18.isConversationMode = true;
2064
+ _this18._conversationPartialMessage = null;
2065
+ _this18._conversationAssistantMessage = null;
2066
+ },
2067
+ onDeactivate: function onDeactivate() {
2068
+ _this18.isConversationMode = false;
2069
+ if (_this18._conversationAssistantMessage) {
2070
+ var m = _this18.messages[_this18._conversationAssistantMessage.index];
2071
+ if (m) {
2072
+ m.isStreaming = false;
2073
+ }
2074
+ _this18._conversationAssistantMessage = null;
2075
+ }
2076
+ },
2077
+ onEnterRealtimeMode: function onEnterRealtimeMode() {
2078
+ if (_this18.isRecording) {
2079
+ _this18.stopRecording();
2080
+ }
2081
+ if (_this18.isConversationMode && (!_this18.realtimeController || !_this18.realtimeController.isActive())) {
2082
+ _this18.stopConversationMode();
2083
+ }
2084
+ },
2085
+ // The utterance has been captured but not transcribed yet. Showing a placeholder now
2086
+ // puts the prompt above the reply it produces: transcription lags the spoken answer, so
2087
+ // a bubble added only when the text arrives lands underneath its own reply.
2088
+ onUserTurnPending: function onUserTurnPending(turnId) {
2089
+ if (!turnId) {
2090
+ return;
2091
+ }
2092
+ var placeholder = {
2093
+ role: 'user',
2094
+ content: '',
2095
+ rawContent: '',
2096
+ references: {},
2097
+ isPartial: true
2098
+ };
2099
+ updateMessagePresentation(placeholder, placeholder.references);
2100
+ _this18._realtimePendingTurns = _this18._realtimePendingTurns || {};
2101
+ _this18._realtimePendingTurns[turnId] = placeholder;
2102
+ _this18.messages.push(placeholder);
2103
+ _this18.scrollToBottom();
2104
+ },
2105
+ onUserTurnDropped: function onUserTurnDropped(turnId) {
2106
+ if (!turnId || !_this18._realtimePendingTurns) {
2107
+ return;
2108
+ }
2109
+ var dropped = _this18._realtimePendingTurns[turnId];
2110
+ if (!dropped) {
2111
+ return;
2112
+ }
2113
+ delete _this18._realtimePendingTurns[turnId];
2114
+ var at = _this18.messages.indexOf(dropped);
2115
+ if (at >= 0) {
2116
+ _this18.messages.splice(at, 1);
2117
+ }
2118
+ }
2119
+ });
2120
+ this.setupRealtimeVoicePicker(config);
2121
+ }
2122
+ },
2123
+ // Populates the per-interaction realtime voice picker from the selected realtime deployment's
2124
+ // voices (via the realtime-voices endpoint), and shows it only for realtime-capable deployments.
2125
+ setupRealtimeVoicePicker: function setupRealtimeVoicePicker(config) {
2126
+ if (!config.realtimeVoiceSelectElementSelector || !config.realtimeVoicesUrl) {
2127
+ return;
2128
+ }
2129
+ var voiceSelect = document.querySelector(config.realtimeVoiceSelectElementSelector);
2130
+ if (!voiceSelect) {
2131
+ return;
2132
+ }
2133
+ var voiceGroup = config.realtimeVoiceGroupElementSelector ? document.querySelector(config.realtimeVoiceGroupElementSelector) : null;
2134
+ var deploymentSelect = config.deploymentSelectElementSelector ? document.querySelector(config.deploymentSelectElementSelector) : null;
2135
+ var capable = (config.realtimeCapableDeployments || []).map(function (n) {
2136
+ return (n || '').toLowerCase();
2137
+ });
2138
+ var savedVoiceId = config.realtimeVoiceName || '';
2139
+ function isRealtimeDeployment(name) {
2140
+ return name && capable.indexOf(name.toLowerCase()) !== -1;
2141
+ }
2142
+ function loadVoices() {
2143
+ return _loadVoices.apply(this, arguments);
2144
+ }
2145
+ function _loadVoices() {
2146
+ _loadVoices = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4() {
2147
+ var deploymentName, realtime, response, result, grouped, _iterator7, _step7, voice, groupName, _t2;
2148
+ return _regenerator().w(function (_context4) {
2149
+ while (1) switch (_context4.p = _context4.n) {
2150
+ case 0:
2151
+ deploymentName = deploymentSelect ? deploymentSelect.value : '';
2152
+ realtime = isRealtimeDeployment(deploymentName);
2153
+ if (voiceGroup) {
2154
+ voiceGroup.classList.toggle('d-none', !realtime);
2155
+ }
2156
+ if (realtime) {
2157
+ _context4.n = 1;
2158
+ break;
2159
+ }
2160
+ return _context4.a(2);
2161
+ case 1:
2162
+ voiceSelect.innerHTML = '<option value="">Default voice</option>';
2163
+ _context4.p = 2;
2164
+ _context4.n = 3;
2165
+ return fetch(config.realtimeVoicesUrl + '?deploymentName=' + encodeURIComponent(deploymentName), {
2166
+ credentials: 'same-origin'
2167
+ });
2168
+ case 3:
2169
+ response = _context4.v;
2170
+ _context4.n = 4;
2171
+ return response.json();
2172
+ case 4:
2173
+ result = _context4.v;
2174
+ if (!(!result || !Array.isArray(result.voices))) {
2175
+ _context4.n = 5;
2176
+ break;
2177
+ }
2178
+ return _context4.a(2);
2179
+ case 5:
2180
+ grouped = new Map();
2181
+ _iterator7 = _createForOfIteratorHelper(result.voices);
2182
+ try {
2183
+ for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
2184
+ voice = _step7.value;
2185
+ groupName = voice.gender || 'Voices';
2186
+ if (!grouped.has(groupName)) {
2187
+ grouped.set(groupName, []);
2188
+ }
2189
+ grouped.get(groupName).push(voice);
2190
+ }
2191
+ } catch (err) {
2192
+ _iterator7.e(err);
2193
+ } finally {
2194
+ _iterator7.f();
2195
+ }
2196
+ Array.from(grouped.keys()).sort(function (a, b) {
2197
+ return a.localeCompare(b);
2198
+ }).forEach(function (groupName) {
2199
+ var optgroup = document.createElement('optgroup');
2200
+ optgroup.label = groupName;
2201
+ grouped.get(groupName).forEach(function (voice) {
2202
+ var option = document.createElement('option');
2203
+ option.value = voice.id;
2204
+ option.textContent = voice.name;
2205
+ option.selected = voice.id === savedVoiceId;
2206
+ optgroup.appendChild(option);
2207
+ });
2208
+ voiceSelect.appendChild(optgroup);
2209
+ });
2210
+ _context4.n = 7;
2211
+ break;
2212
+ case 6:
2213
+ _context4.p = 6;
2214
+ _t2 = _context4.v;
2215
+ case 7:
2216
+ return _context4.a(2);
2217
+ }
2218
+ }, _callee4, null, [[2, 6]]);
2219
+ }));
2220
+ return _loadVoices.apply(this, arguments);
2221
+ }
2222
+ if (deploymentSelect) {
2223
+ deploymentSelect.addEventListener('change', loadVoices);
2224
+ }
2225
+ loadVoices();
1985
2226
  },
1986
2227
  loadInteraction: function loadInteraction(itemId) {
1987
2228
  this.connection.invoke("LoadInteraction", itemId)["catch"](function (err) {
@@ -1997,6 +2238,11 @@ window.chatInteractionManager = function () {
1997
2238
  clearHistory: function clearHistory(itemId) {
1998
2239
  var self = this;
1999
2240
  var clearHistoryConfirmed = function clearHistoryConfirmed() {
2241
+ // Force-stop any live realtime voice session before clearing history.
2242
+ if (self.realtimeController && self.realtimeController.isActive()) {
2243
+ self.realtimeController.stop();
2244
+ }
2245
+
2000
2246
  // Cancel any active stream before clearing history.
2001
2247
  if (self.stream) {
2002
2248
  self.stream.dispose();
@@ -2193,15 +2439,15 @@ window.chatInteractionManager = function () {
2193
2439
  var pendingChunk = Promise.resolve();
2194
2440
  _this22.mediaRecorder.addEventListener('dataavailable', function (e) {
2195
2441
  if (e.data && e.data.size > 0) {
2196
- pendingChunk = pendingChunk.then(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4() {
2442
+ pendingChunk = pendingChunk.then(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee5() {
2197
2443
  var data, uint8Array, binaryString, base64;
2198
- return _regenerator().w(function (_context4) {
2199
- while (1) switch (_context4.n) {
2444
+ return _regenerator().w(function (_context5) {
2445
+ while (1) switch (_context5.n) {
2200
2446
  case 0:
2201
- _context4.n = 1;
2447
+ _context5.n = 1;
2202
2448
  return e.data.arrayBuffer();
2203
2449
  case 1:
2204
- data = _context4.v;
2450
+ data = _context5.v;
2205
2451
  uint8Array = new Uint8Array(data);
2206
2452
  binaryString = uint8Array.reduce(function (str, _byte2) {
2207
2453
  return str + String.fromCharCode(_byte2);
@@ -2209,9 +2455,9 @@ window.chatInteractionManager = function () {
2209
2455
  base64 = btoa(binaryString);
2210
2456
  subject.next(base64);
2211
2457
  case 2:
2212
- return _context4.a(2);
2458
+ return _context5.a(2);
2213
2459
  }
2214
- }, _callee4);
2460
+ }, _callee5);
2215
2461
  })));
2216
2462
  }
2217
2463
  });
@@ -2288,11 +2534,11 @@ window.chatInteractionManager = function () {
2288
2534
  },
2289
2535
  mounted: function mounted() {
2290
2536
  var _this24 = this;
2291
- _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee5() {
2292
- return _regenerator().w(function (_context5) {
2293
- while (1) switch (_context5.n) {
2537
+ _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6() {
2538
+ return _regenerator().w(function (_context6) {
2539
+ while (1) switch (_context6.n) {
2294
2540
  case 0:
2295
- _context5.n = 1;
2541
+ _context6.n = 1;
2296
2542
  return _this24.startConnection();
2297
2543
  case 1:
2298
2544
  _this24.initializeApp();
@@ -2302,9 +2548,9 @@ window.chatInteractionManager = function () {
2302
2548
  _this24.fontAwesomeObserver = observeFontAwesomeIcons(_this24.$el);
2303
2549
  });
2304
2550
  case 2:
2305
- return _context5.a(2);
2551
+ return _context6.a(2);
2306
2552
  }
2307
- }, _callee5);
2553
+ }, _callee6);
2308
2554
  }))();
2309
2555
  window.addEventListener('beforeunload', this.handleBeforeUnload);
2310
2556
  window.addEventListener('crestapps-ai-chat-stop-tts', this.handleExternalTtsStop);
@@ -2668,23 +2914,23 @@ window.chatInteractionDocumentManager = function () {
2668
2914
  return _uploadDocuments.apply(this, arguments);
2669
2915
  }
2670
2916
  function _uploadDocuments() {
2671
- _uploadDocuments = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6(files) {
2672
- var filesToUpload, duplicateItems, knownDocumentKeys, pendingItems, uploadedCount, failedUploads, i, file, pendingItem, result, uploaded, failed, missingUploadMessage, failedMessage, errorMessage, _t2, _t3;
2673
- return _regenerator().w(function (_context6) {
2674
- while (1) switch (_context6.p = _context6.n) {
2917
+ _uploadDocuments = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee7(files) {
2918
+ var filesToUpload, duplicateItems, knownDocumentKeys, pendingItems, uploadedCount, failedUploads, i, file, pendingItem, result, uploaded, failed, missingUploadMessage, failedMessage, errorMessage, _t3, _t4;
2919
+ return _regenerator().w(function (_context7) {
2920
+ while (1) switch (_context7.p = _context7.n) {
2675
2921
  case 0:
2676
2922
  if (!(!config.uploadDocumentUrl || !files || files.length === 0)) {
2677
- _context6.n = 1;
2923
+ _context7.n = 1;
2678
2924
  break;
2679
2925
  }
2680
- return _context6.a(2);
2926
+ return _context7.a(2);
2681
2927
  case 1:
2682
2928
  if (!isUploadingDocuments) {
2683
- _context6.n = 2;
2929
+ _context7.n = 2;
2684
2930
  break;
2685
2931
  }
2686
2932
  showUploadStatus('A document upload is already in progress.', 'text-warning');
2687
- return _context6.a(2);
2933
+ return _context7.a(2);
2688
2934
  case 2:
2689
2935
  isUploadingDocuments = true;
2690
2936
  filesToUpload = [];
@@ -2711,7 +2957,7 @@ window.chatInteractionDocumentManager = function () {
2711
2957
  renderUploadQueue();
2712
2958
  }
2713
2959
  if (!(filesToUpload.length === 0)) {
2714
- _context6.n = 3;
2960
+ _context7.n = 3;
2715
2961
  break;
2716
2962
  }
2717
2963
  isUploadingDocuments = false;
@@ -2719,14 +2965,14 @@ window.chatInteractionDocumentManager = function () {
2719
2965
  return file.name + ': This document is already attached.';
2720
2966
  }).join(' | '), 'text-warning');
2721
2967
  showUploadProgress(null);
2722
- return _context6.a(2);
2968
+ return _context7.a(2);
2723
2969
  case 3:
2724
2970
  pendingItems = filesToUpload.map(createUploadItem);
2725
2971
  uploadItems = uploadItems.concat(pendingItems);
2726
2972
  renderUploadQueue();
2727
2973
  showUploadProgress(0, 'Preparing upload...', 'progress-bar-striped progress-bar-animated');
2728
2974
  fileInput.disabled = true;
2729
- _context6.p = 4;
2975
+ _context7.p = 4;
2730
2976
  uploadedCount = 0;
2731
2977
  failedUploads = duplicateItems.map(function (file) {
2732
2978
  return file.name + ': This document is already attached.';
@@ -2734,7 +2980,7 @@ window.chatInteractionDocumentManager = function () {
2734
2980
  i = 0;
2735
2981
  case 5:
2736
2982
  if (!(i < filesToUpload.length)) {
2737
- _context6.n = 10;
2983
+ _context7.n = 10;
2738
2984
  break;
2739
2985
  }
2740
2986
  file = filesToUpload[i];
@@ -2745,11 +2991,11 @@ window.chatInteractionDocumentManager = function () {
2745
2991
  error: null
2746
2992
  });
2747
2993
  showUploadStatus('Uploading ' + (i + 1) + ' of ' + filesToUpload.length + ' document(s)...', 'text-warning');
2748
- _context6.p = 6;
2749
- _context6.n = 7;
2994
+ _context7.p = 6;
2995
+ _context7.n = 7;
2750
2996
  return uploadSingleDocument(file, pendingItem.id, i, filesToUpload.length);
2751
2997
  case 7:
2752
- result = _context6.v;
2998
+ result = _context7.v;
2753
2999
  uploaded = (Array.isArray(result.uploaded) ? result.uploaded : []).map(normalizeDocumentInfo).filter(function (document) {
2754
3000
  return document && document.documentId;
2755
3001
  });
@@ -2786,13 +3032,13 @@ window.chatInteractionDocumentManager = function () {
2786
3032
  error: failedMessage
2787
3033
  });
2788
3034
  }
2789
- _context6.n = 9;
3035
+ _context7.n = 9;
2790
3036
  break;
2791
3037
  case 8:
2792
- _context6.p = 8;
2793
- _t2 = _context6.v;
2794
- errorMessage = _t2 && _t2.message ? _t2.message : 'Upload failed. Please try again.';
2795
- console.error('Upload failed:', _t2);
3038
+ _context7.p = 8;
3039
+ _t3 = _context7.v;
3040
+ errorMessage = _t3 && _t3.message ? _t3.message : 'Upload failed. Please try again.';
3041
+ console.error('Upload failed:', _t3);
2796
3042
  failedUploads.push(file.name + ': ' + errorMessage);
2797
3043
  updateUploadItem(pendingItem.id, {
2798
3044
  status: 'failed',
@@ -2801,12 +3047,12 @@ window.chatInteractionDocumentManager = function () {
2801
3047
  });
2802
3048
  case 9:
2803
3049
  i++;
2804
- _context6.n = 5;
3050
+ _context7.n = 5;
2805
3051
  break;
2806
3052
  case 10:
2807
3053
  renderDocuments();
2808
3054
  if (!(failedUploads.length > 0)) {
2809
- _context6.n = 11;
3055
+ _context7.n = 11;
2810
3056
  break;
2811
3057
  }
2812
3058
  removeUploadItems(function (item) {
@@ -2814,31 +3060,31 @@ window.chatInteractionDocumentManager = function () {
2814
3060
  });
2815
3061
  showUploadStatus((uploadedCount > 0 ? 'Uploaded ' + uploadedCount + ' document(s). ' : '') + failedUploads.join(' | '), uploadedCount > 0 ? 'text-warning' : 'text-danger');
2816
3062
  showUploadProgress(null);
2817
- return _context6.a(2);
3063
+ return _context7.a(2);
2818
3064
  case 11:
2819
3065
  removeUploadItems(function () {
2820
3066
  return true;
2821
3067
  });
2822
3068
  showUploadStatus('Uploaded ' + uploadedCount + ' document(s).', 'text-success');
2823
3069
  showUploadProgress(null);
2824
- _context6.n = 13;
3070
+ _context7.n = 13;
2825
3071
  break;
2826
3072
  case 12:
2827
- _context6.p = 12;
2828
- _t3 = _context6.v;
2829
- console.error('Upload failed:', _t3);
3073
+ _context7.p = 12;
3074
+ _t4 = _context7.v;
3075
+ console.error('Upload failed:', _t4);
2830
3076
  showUploadStatus('Upload failed. Please try again.', 'text-danger');
2831
3077
  showUploadProgress(null);
2832
3078
  case 13:
2833
- _context6.p = 13;
3079
+ _context7.p = 13;
2834
3080
  isUploadingDocuments = false;
2835
3081
  fileInput.disabled = false;
2836
3082
  fileInput.value = '';
2837
- return _context6.f(13);
3083
+ return _context7.f(13);
2838
3084
  case 14:
2839
- return _context6.a(2);
3085
+ return _context7.a(2);
2840
3086
  }
2841
- }, _callee6, null, [[6, 8], [4, 12, 13, 14]]);
3087
+ }, _callee7, null, [[6, 8], [4, 12, 13, 14]]);
2842
3088
  }));
2843
3089
  return _uploadDocuments.apply(this, arguments);
2844
3090
  }
@@ -2846,19 +3092,19 @@ window.chatInteractionDocumentManager = function () {
2846
3092
  return _removeDocument.apply(this, arguments);
2847
3093
  }
2848
3094
  function _removeDocument() {
2849
- _removeDocument = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee7(documentId) {
2850
- var response, result, serverDocuments, _t4, _t5;
2851
- return _regenerator().w(function (_context7) {
2852
- while (1) switch (_context7.p = _context7.n) {
3095
+ _removeDocument = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee8(documentId) {
3096
+ var response, result, serverDocuments, _t5, _t6;
3097
+ return _regenerator().w(function (_context8) {
3098
+ while (1) switch (_context8.p = _context8.n) {
2853
3099
  case 0:
2854
3100
  if (!(!config.removeDocumentUrl || !documentId || !window.confirm('Remove this document?'))) {
2855
- _context7.n = 1;
3101
+ _context8.n = 1;
2856
3102
  break;
2857
3103
  }
2858
- return _context7.a(2);
3104
+ return _context8.a(2);
2859
3105
  case 1:
2860
- _context7.p = 1;
2861
- _context7.n = 2;
3106
+ _context8.p = 1;
3107
+ _context8.n = 2;
2862
3108
  return fetch(config.removeDocumentUrl, {
2863
3109
  method: 'POST',
2864
3110
  headers: {
@@ -2870,23 +3116,23 @@ window.chatInteractionDocumentManager = function () {
2870
3116
  })
2871
3117
  });
2872
3118
  case 2:
2873
- response = _context7.v;
3119
+ response = _context8.v;
2874
3120
  if (response.ok) {
2875
- _context7.n = 4;
3121
+ _context8.n = 4;
2876
3122
  break;
2877
3123
  }
2878
- _t4 = console;
2879
- _context7.n = 3;
3124
+ _t5 = console;
3125
+ _context8.n = 3;
2880
3126
  return response.text();
2881
3127
  case 3:
2882
- _t4.error.call(_t4, 'Failed to remove document:', _context7.v);
3128
+ _t5.error.call(_t5, 'Failed to remove document:', _context8.v);
2883
3129
  showUploadStatus('Failed to remove document.', 'text-danger');
2884
- return _context7.a(2);
3130
+ return _context8.a(2);
2885
3131
  case 4:
2886
- _context7.n = 5;
3132
+ _context8.n = 5;
2887
3133
  return response.json();
2888
3134
  case 5:
2889
- result = _context7.v;
3135
+ result = _context8.v;
2890
3136
  serverDocuments = (Array.isArray(result.documents) ? result.documents : []).map(normalizeDocumentInfo).filter(function (document) {
2891
3137
  return document && document.documentId;
2892
3138
  });
@@ -2895,17 +3141,17 @@ window.chatInteractionDocumentManager = function () {
2895
3141
  });
2896
3142
  renderDocuments();
2897
3143
  showUploadStatus('Document removed.', 'text-success');
2898
- _context7.n = 7;
3144
+ _context8.n = 7;
2899
3145
  break;
2900
3146
  case 6:
2901
- _context7.p = 6;
2902
- _t5 = _context7.v;
2903
- console.error('Remove failed:', _t5);
3147
+ _context8.p = 6;
3148
+ _t6 = _context8.v;
3149
+ console.error('Remove failed:', _t6);
2904
3150
  showUploadStatus('Failed to remove document.', 'text-danger');
2905
3151
  case 7:
2906
- return _context7.a(2);
3152
+ return _context8.a(2);
2907
3153
  }
2908
- }, _callee7, null, [[1, 6]]);
3154
+ }, _callee8, null, [[1, 6]]);
2909
3155
  }));
2910
3156
  return _removeDocument.apply(this, arguments);
2911
3157
  }