@eshal-bot/chat-widget 0.1.28 → 0.1.29
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/chat-widget.esm.js +4 -4
- package/dist/chat-widget.js +79 -22
- package/dist/chat-widget.min.js +2 -2
- package/dist/chat-widget.umd.js +2 -2
- package/package.json +89 -89
package/dist/chat-widget.js
CHANGED
|
@@ -8594,20 +8594,20 @@
|
|
|
8594
8594
|
}
|
|
8595
8595
|
if (!apiBaseUrl) {
|
|
8596
8596
|
// Default fallback if no API base URL is provided
|
|
8597
|
-
return 'wss://dev.eshal.ai/ws
|
|
8597
|
+
return 'wss://dev.eshal.ai/knowledge-api/ws';
|
|
8598
8598
|
}
|
|
8599
8599
|
try {
|
|
8600
8600
|
const url = new URL(apiBaseUrl);
|
|
8601
8601
|
// Replace http/https with ws/wss
|
|
8602
8602
|
url.protocol = url.protocol.replace(/^http/, 'ws');
|
|
8603
|
-
// Append the
|
|
8604
|
-
url.pathname = '/ws
|
|
8603
|
+
// Append the WebSocket specific path
|
|
8604
|
+
url.pathname = '/knowledge-api/ws';
|
|
8605
8605
|
// Ensure it returns a clean URL without extra slashes
|
|
8606
8606
|
return url.toString().replace(/\/$/, '');
|
|
8607
8607
|
} catch (error) {
|
|
8608
8608
|
console.error("Invalid API base URL provided for WebSocket:", error);
|
|
8609
8609
|
// Fallback to default if URL parsing fails
|
|
8610
|
-
return 'wss://dev.eshal.ai/ws
|
|
8610
|
+
return 'wss://dev.eshal.ai/knowledge-api/ws';
|
|
8611
8611
|
}
|
|
8612
8612
|
};
|
|
8613
8613
|
|
|
@@ -8916,7 +8916,6 @@
|
|
|
8916
8916
|
openDelay,
|
|
8917
8917
|
darkMode,
|
|
8918
8918
|
enableVoiceInteraction = false,
|
|
8919
|
-
voiceGender = 'male',
|
|
8920
8919
|
onboardingQuestions = [],
|
|
8921
8920
|
onboardingEnabled = false,
|
|
8922
8921
|
collectionPrompt,
|
|
@@ -9002,14 +9001,14 @@
|
|
|
9002
9001
|
const userHasSpokenRef = reactExports.useRef(false); // Track if user has sent first message - prevents automatic greetings
|
|
9003
9002
|
const turnHasTranscriptionRef = reactExports.useRef(false); // True when outputTranscription received this turn — skip content.parts text
|
|
9004
9003
|
const stopVoiceSessionRef = reactExports.useRef(null); // Ref to avoid referencing stopVoiceSession before it is defined in handleBidiEvent
|
|
9004
|
+
const pendingVoiceSourcesRef = reactExports.useRef(null); // Hold sources until the assistant bubble for this turn exists
|
|
9005
9005
|
|
|
9006
9006
|
const websocketUrl = reactExports.useMemo(() => {
|
|
9007
9007
|
if (!organizationId) return null;
|
|
9008
9008
|
// Construct WebSocket URL from the API base URL
|
|
9009
9009
|
const resolvedWsBaseUrl = getWebSocketUrl(apiBaseUrl, wsBaseUrl);
|
|
9010
|
-
|
|
9011
|
-
|
|
9012
|
-
}, [apiBaseUrl, organizationId, bidiSessionId, voiceGender]);
|
|
9010
|
+
return "".concat(resolvedWsBaseUrl, "/").concat(organizationId, "/").concat(bidiSessionId);
|
|
9011
|
+
}, [apiBaseUrl, organizationId, bidiSessionId]);
|
|
9013
9012
|
const getNextMessageId = reactExports.useCallback(() => {
|
|
9014
9013
|
const id = "msg-".concat(messageIdRef.current);
|
|
9015
9014
|
messageIdRef.current += 1;
|
|
@@ -9719,6 +9718,10 @@
|
|
|
9719
9718
|
source: "bidi"
|
|
9720
9719
|
}
|
|
9721
9720
|
});
|
|
9721
|
+
if (Array.isArray(pendingVoiceSourcesRef.current) && pendingVoiceSourcesRef.current.length > 0) {
|
|
9722
|
+
assistantMessage.sources = pendingVoiceSourcesRef.current;
|
|
9723
|
+
pendingVoiceSourcesRef.current = null;
|
|
9724
|
+
}
|
|
9722
9725
|
|
|
9723
9726
|
// CRITICAL: Double-check message doesn't already exist
|
|
9724
9727
|
const messageExists = result.some(m => m.id === newId);
|
|
@@ -9735,7 +9738,12 @@
|
|
|
9735
9738
|
result = result.map(msg => msg.id === newId ? _objectSpread2(_objectSpread2({}, msg), {}, {
|
|
9736
9739
|
content: "".concat(msg.content || "").concat(text),
|
|
9737
9740
|
isProcessing: !finished
|
|
9738
|
-
})
|
|
9741
|
+
}, Array.isArray(pendingVoiceSourcesRef.current) && pendingVoiceSourcesRef.current.length > 0 ? {
|
|
9742
|
+
sources: pendingVoiceSourcesRef.current
|
|
9743
|
+
} : {}) : msg);
|
|
9744
|
+
if (Array.isArray(pendingVoiceSourcesRef.current) && pendingVoiceSourcesRef.current.length > 0) {
|
|
9745
|
+
pendingVoiceSourcesRef.current = null;
|
|
9746
|
+
}
|
|
9739
9747
|
// Set ref to the existing message
|
|
9740
9748
|
currentAssistantMessageIdRef.current = newId;
|
|
9741
9749
|
}
|
|
@@ -9760,8 +9768,13 @@
|
|
|
9760
9768
|
// CRITICAL: Don't update timestamp when appending content - preserve original timestamp for ordering
|
|
9761
9769
|
// timestamp: new Date(), // Removed - preserve original timestamp
|
|
9762
9770
|
isProcessing: !finished
|
|
9763
|
-
})
|
|
9771
|
+
}, Array.isArray(pendingVoiceSourcesRef.current) && pendingVoiceSourcesRef.current.length > 0 ? {
|
|
9772
|
+
sources: pendingVoiceSourcesRef.current
|
|
9773
|
+
} : {});
|
|
9764
9774
|
});
|
|
9775
|
+
if (Array.isArray(pendingVoiceSourcesRef.current) && pendingVoiceSourcesRef.current.length > 0) {
|
|
9776
|
+
pendingVoiceSourcesRef.current = null;
|
|
9777
|
+
}
|
|
9765
9778
|
} else {
|
|
9766
9779
|
console.error("[BIDI] appendAssistantContent: ERROR - assistant message not found!", {
|
|
9767
9780
|
expectedId: currentAssistantMessageIdRef.current,
|
|
@@ -9779,6 +9792,10 @@
|
|
|
9779
9792
|
source: "bidi"
|
|
9780
9793
|
}
|
|
9781
9794
|
});
|
|
9795
|
+
if (Array.isArray(pendingVoiceSourcesRef.current) && pendingVoiceSourcesRef.current.length > 0) {
|
|
9796
|
+
assistantMessage.sources = pendingVoiceSourcesRef.current;
|
|
9797
|
+
pendingVoiceSourcesRef.current = null;
|
|
9798
|
+
}
|
|
9782
9799
|
result = [...result, assistantMessage];
|
|
9783
9800
|
console.log("[BIDI] appendAssistantContent: recreated lost assistant message", {
|
|
9784
9801
|
messageId: newId
|
|
@@ -9909,6 +9926,7 @@
|
|
|
9909
9926
|
currentAssistantMessageIdRef.current = null;
|
|
9910
9927
|
currentInputMessageIdRef.current = null;
|
|
9911
9928
|
turnHasTranscriptionRef.current = false; // reset for next turn
|
|
9929
|
+
pendingVoiceSourcesRef.current = null;
|
|
9912
9930
|
}, []);
|
|
9913
9931
|
const handleInterrupted = reactExports.useCallback(() => {
|
|
9914
9932
|
setIsLoading(false);
|
|
@@ -9919,6 +9937,7 @@
|
|
|
9919
9937
|
}
|
|
9920
9938
|
currentAssistantMessageIdRef.current = null;
|
|
9921
9939
|
currentInputMessageIdRef.current = null;
|
|
9940
|
+
pendingVoiceSourcesRef.current = null;
|
|
9922
9941
|
setBidiMessages(prev => prev.map(message => {
|
|
9923
9942
|
var _message$metadata2;
|
|
9924
9943
|
return ((_message$metadata2 = message.metadata) === null || _message$metadata2 === void 0 ? void 0 : _message$metadata2.source) === "bidi" ? _objectSpread2(_objectSpread2({}, message), {}, {
|
|
@@ -9939,6 +9958,7 @@
|
|
|
9939
9958
|
|
|
9940
9959
|
// Reset userHasSpoken flag when stopping session
|
|
9941
9960
|
userHasSpokenRef.current = false;
|
|
9961
|
+
pendingVoiceSourcesRef.current = null;
|
|
9942
9962
|
if (websocketRef.current && websocketRef.current.readyState === WebSocket.OPEN) {
|
|
9943
9963
|
websocketRef.current.close();
|
|
9944
9964
|
}
|
|
@@ -9956,7 +9976,7 @@
|
|
|
9956
9976
|
isAudioReadyRef.current = false;
|
|
9957
9977
|
}, []);
|
|
9958
9978
|
const handleBidiEvent = reactExports.useCallback(event => {
|
|
9959
|
-
var _event$content, _event$conclusion_det, _event$outputTranscri2, _event$content3;
|
|
9979
|
+
var _event$content, _event$conclusion_det, _event$sources, _event$outputTranscri2, _event$content3;
|
|
9960
9980
|
console.log("[BIDI] handleBidiEvent called", {
|
|
9961
9981
|
event,
|
|
9962
9982
|
isVoiceSessionActive: isVoiceSessionActiveRef.current,
|
|
@@ -10028,20 +10048,43 @@
|
|
|
10028
10048
|
// Handle sources that arrive as a separate message after turnComplete.
|
|
10029
10049
|
// Must be checked before the !userHasSpokenRef gate so they are always
|
|
10030
10050
|
// attached regardless of session state.
|
|
10031
|
-
|
|
10051
|
+
//
|
|
10052
|
+
// NOTE: voice_chat.py emits each source with `sourceid` (no underscore)
|
|
10053
|
+
// to match the Milvus/MongoDB field name, but MessageSources /
|
|
10054
|
+
// handleFileDownload read `source.source_id`. Without normalization the
|
|
10055
|
+
// download button appears but the click is a silent no-op. The same
|
|
10056
|
+
// mapping is already applied on the history-load path above (~line 192)
|
|
10057
|
+
// — mirror it here so live and reloaded conversations produce the same
|
|
10058
|
+
// shape.
|
|
10059
|
+
const rawSources = (_event$sources = event.sources) !== null && _event$sources !== void 0 ? _event$sources : event.Sources;
|
|
10060
|
+
if (Array.isArray(rawSources) && rawSources.length > 0) {
|
|
10061
|
+
const normalizedSources = rawSources.map(s => {
|
|
10062
|
+
var _ref5, _s$source_type2, _ref6, _s$source_id2, _ref7, _s$source_name2;
|
|
10063
|
+
return {
|
|
10064
|
+
source_type: (_ref5 = (_s$source_type2 = s.source_type) !== null && _s$source_type2 !== void 0 ? _s$source_type2 : s.sourceType) !== null && _ref5 !== void 0 ? _ref5 : 'file',
|
|
10065
|
+
source_id: (_ref6 = (_s$source_id2 = s.source_id) !== null && _s$source_id2 !== void 0 ? _s$source_id2 : s.sourceid) !== null && _ref6 !== void 0 ? _ref6 : s.sourceId,
|
|
10066
|
+
source_name: (_ref7 = (_s$source_name2 = s.source_name) !== null && _s$source_name2 !== void 0 ? _s$source_name2 : s.sourceName) !== null && _ref7 !== void 0 ? _ref7 : '',
|
|
10067
|
+
url: s.url
|
|
10068
|
+
};
|
|
10069
|
+
}).filter(s => s.source_id || s.url);
|
|
10070
|
+
if (normalizedSources.length === 0) return;
|
|
10032
10071
|
setBidiMessages(prev => {
|
|
10033
10072
|
const updated = [...prev];
|
|
10073
|
+
let attached = false;
|
|
10034
10074
|
for (let i = updated.length - 1; i >= 0; i--) {
|
|
10035
10075
|
if (updated[i].role === 'assistant') {
|
|
10036
10076
|
updated[i] = _objectSpread2(_objectSpread2({}, updated[i]), {}, {
|
|
10037
|
-
sources:
|
|
10077
|
+
sources: normalizedSources
|
|
10038
10078
|
});
|
|
10079
|
+
attached = true;
|
|
10039
10080
|
break;
|
|
10040
10081
|
}
|
|
10041
10082
|
}
|
|
10083
|
+
if (!attached) {
|
|
10084
|
+
pendingVoiceSourcesRef.current = normalizedSources;
|
|
10085
|
+
}
|
|
10042
10086
|
return updated;
|
|
10043
10087
|
});
|
|
10044
|
-
return;
|
|
10045
10088
|
}
|
|
10046
10089
|
|
|
10047
10090
|
// CRITICAL: Ignore assistant responses until user has spoken
|
|
@@ -62846,6 +62889,7 @@
|
|
|
62846
62889
|
const hasUserMessages = messages === null || messages === void 0 || (_messages$some = messages.some) === null || _messages$some === void 0 ? void 0 : _messages$some.call(messages, msg => msg.role === "user");
|
|
62847
62890
|
const shouldShowQuickQuestions = !hasUserMessages && quickQuestions.length > 0 && quickQuestionsEnabled;
|
|
62848
62891
|
const hasOnboardingQuestions = onboardingQuestions && onboardingQuestions.length > 0;
|
|
62892
|
+
const isCsatEnabled = Boolean(csatEnabled);
|
|
62849
62893
|
const shouldHideResolveForOnboarding = onboardingEnabled && hasOnboardingQuestions && !onboardingCompleted;
|
|
62850
62894
|
const handleCsatRating = async (rating, format) => {
|
|
62851
62895
|
setCsatSubmitted(true); // optimistic UI
|
|
@@ -62883,6 +62927,7 @@
|
|
|
62883
62927
|
|
|
62884
62928
|
// Handle Resolve feedback submission
|
|
62885
62929
|
const handleResolveSubmission = reactExports.useCallback(async () => {
|
|
62930
|
+
if (!isCsatEnabled) return;
|
|
62886
62931
|
if (isSubmittingResolve || isConversationResolved) return;
|
|
62887
62932
|
if (resolveRating === 0) return;
|
|
62888
62933
|
setIsSubmittingResolve(true);
|
|
@@ -62932,10 +62977,14 @@
|
|
|
62932
62977
|
} finally {
|
|
62933
62978
|
setIsSubmittingResolve(false);
|
|
62934
62979
|
}
|
|
62935
|
-
}, [isSubmittingResolve, isConversationResolved, resolveRating, resolveFeedbackText, conversationId, organizationId, conciergeId, apiBaseUrl, csatFormat, onResetConversation]);
|
|
62980
|
+
}, [isCsatEnabled, isSubmittingResolve, isConversationResolved, resolveRating, resolveFeedbackText, conversationId, organizationId, conciergeId, apiBaseUrl, csatFormat, onResetConversation]);
|
|
62936
62981
|
|
|
62937
62982
|
// Handle X button: first click shows form, second click closes
|
|
62938
62983
|
const handleCloseClick = reactExports.useCallback(() => {
|
|
62984
|
+
if (!isCsatEnabled) {
|
|
62985
|
+
onClose === null || onClose === void 0 || onClose();
|
|
62986
|
+
return;
|
|
62987
|
+
}
|
|
62939
62988
|
if (showResolveForm) {
|
|
62940
62989
|
setShowResolveForm(false);
|
|
62941
62990
|
onClose === null || onClose === void 0 || onClose();
|
|
@@ -62944,7 +62993,14 @@
|
|
|
62944
62993
|
} else {
|
|
62945
62994
|
onClose === null || onClose === void 0 || onClose();
|
|
62946
62995
|
}
|
|
62947
|
-
}, [showResolveForm, isConversationResolved, onClose]);
|
|
62996
|
+
}, [isCsatEnabled, showResolveForm, isConversationResolved, onClose]);
|
|
62997
|
+
reactExports.useEffect(() => {
|
|
62998
|
+
if (isCsatEnabled) return;
|
|
62999
|
+
if (showResolveForm) setShowResolveForm(false);
|
|
63000
|
+
if (isConversationResolved) setIsConversationResolved(false);
|
|
63001
|
+
if (resolveRating !== 0) setResolveRating(0);
|
|
63002
|
+
if (resolveFeedbackText) setResolveFeedbackText("");
|
|
63003
|
+
}, [isCsatEnabled, showResolveForm, isConversationResolved, resolveRating, resolveFeedbackText]);
|
|
62948
63004
|
const latestPromptSuggestions = reactExports.useMemo(() => {
|
|
62949
63005
|
if (!messages || !Array.isArray(messages)) return [];
|
|
62950
63006
|
for (let i = messages.length - 1; i >= 0; i -= 1) {
|
|
@@ -63209,7 +63265,7 @@
|
|
|
63209
63265
|
userMessageBubbleFontSize: userMessageBubbleFontSize,
|
|
63210
63266
|
fontSize: fontSize,
|
|
63211
63267
|
isRtl: isRtlLanguage,
|
|
63212
|
-
csatVisible: showCsat && csatEnabled && !csatSubmitted || showResolveForm || isConversationResolved,
|
|
63268
|
+
csatVisible: showCsat && csatEnabled && !csatSubmitted || isCsatEnabled && (showResolveForm || isConversationResolved),
|
|
63213
63269
|
enableVoiceInteraction: enableVoiceInteraction,
|
|
63214
63270
|
isVoiceSessionActive: isVoiceSessionActive,
|
|
63215
63271
|
voiceStatus: voiceStatus,
|
|
@@ -63230,8 +63286,11 @@
|
|
|
63230
63286
|
userTextColor: userTextColor,
|
|
63231
63287
|
promptSuggestions: showResolveForm || isConversationResolved || autoPromptEnabled === false || isLoading ? [] : stablePromptSuggestions,
|
|
63232
63288
|
onPromptSuggestionClick: onPromptSuggestionClick !== null && onPromptSuggestionClick !== void 0 ? onPromptSuggestionClick : text => onDirectSend === null || onDirectSend === void 0 ? void 0 : onDirectSend(text),
|
|
63233
|
-
showResolveButton: hasUserMessages && !isConversationResolved && !showResolveForm && !showCsat && !shouldHideResolveForOnboarding,
|
|
63234
|
-
onResolve: () =>
|
|
63289
|
+
showResolveButton: isCsatEnabled && hasUserMessages && !isConversationResolved && !showResolveForm && !showCsat && !shouldHideResolveForOnboarding,
|
|
63290
|
+
onResolve: () => {
|
|
63291
|
+
if (!isCsatEnabled) return;
|
|
63292
|
+
setShowResolveForm(true);
|
|
63293
|
+
}
|
|
63235
63294
|
})]
|
|
63236
63295
|
})]
|
|
63237
63296
|
});
|
|
@@ -63350,7 +63409,7 @@
|
|
|
63350
63409
|
|
|
63351
63410
|
// Map API response to widget props (use props as overrides if provided)
|
|
63352
63411
|
const widgetConfig = reactExports.useMemo(() => {
|
|
63353
|
-
var _ref2, _ref3, _ref4, _ref5, _agentConfig$chatbotA, _agentConfig$chatbotA2, _ref6, _ref7, _ref8, _ref9, _ref0, _ref1, _ref10, _ref11, _ref12, _ref13, _ref14, _ref15, _ref16, _ref17, _ref18,
|
|
63412
|
+
var _ref2, _ref3, _ref4, _ref5, _agentConfig$chatbotA, _agentConfig$chatbotA2, _ref6, _ref7, _ref8, _ref9, _ref0, _ref1, _ref10, _ref11, _ref12, _ref13, _ref14, _ref15, _ref16, _ref17, _ref18, _ref19, _ref20, _ref21, _ref22, _ref23, _ref24, _ref25, _agentConfig$inactivi, _agentConfig$inactivi2, _ref26, _ref27, _ref28, _ref29, _ref30, _ref31, _ref32, _ref33, _ref34, _ref35, _ref36, _ref37, _agentConfig$csatEnab, _agentConfig$csatForm, _agentConfig$csatProm, _agentConfig$csatTrig, _agentConfig$csatIdle, _agentConfig$csatFoll, _agentConfig$csatFoll2, _agentConfig$autoProm, _agentConfig$allowFee;
|
|
63354
63413
|
if (!agentConfig) {
|
|
63355
63414
|
return null;
|
|
63356
63415
|
}
|
|
@@ -63378,7 +63437,6 @@
|
|
|
63378
63437
|
headerTextBold: (_ref16 = headerTextBold !== null && headerTextBold !== void 0 ? headerTextBold : agentConfig.headerTextBold) !== null && _ref16 !== void 0 ? _ref16 : false,
|
|
63379
63438
|
headerTextItalic: (_ref17 = headerTextItalic !== null && headerTextItalic !== void 0 ? headerTextItalic : agentConfig.headerTextItalic) !== null && _ref17 !== void 0 ? _ref17 : false,
|
|
63380
63439
|
enableVoiceInteraction: (_ref18 = enableVoiceInteraction !== null && enableVoiceInteraction !== void 0 ? enableVoiceInteraction : agentConfig.enableVoiceInteraction) !== null && _ref18 !== void 0 ? _ref18 : false,
|
|
63381
|
-
voiceGender: (_agentConfig$voiceGen = agentConfig.voiceGender) !== null && _agentConfig$voiceGen !== void 0 ? _agentConfig$voiceGen : 'male',
|
|
63382
63440
|
disclaimerEnabled: (_ref19 = disclaimerEnabled !== null && disclaimerEnabled !== void 0 ? disclaimerEnabled : agentConfig.disclaimerEnabled) !== null && _ref19 !== void 0 ? _ref19 : false,
|
|
63383
63441
|
disclaimerText: disclaimerText !== null && disclaimerText !== void 0 ? disclaimerText : agentConfig.disclaimerText,
|
|
63384
63442
|
disclaimerPosition: (_ref20 = disclaimerPosition !== null && disclaimerPosition !== void 0 ? disclaimerPosition : agentConfig.disclaimerPosition) !== null && _ref20 !== void 0 ? _ref20 : "top",
|
|
@@ -63480,7 +63538,6 @@
|
|
|
63480
63538
|
openDelay,
|
|
63481
63539
|
darkMode: widgetConfig.darkMode,
|
|
63482
63540
|
enableVoiceInteraction: widgetConfig.enableVoiceInteraction,
|
|
63483
|
-
voiceGender: widgetConfig.voiceGender,
|
|
63484
63541
|
onboardingQuestions: widgetConfig.onboardingQuestions,
|
|
63485
63542
|
onboardingEnabled: widgetConfig.onboardingEnabled,
|
|
63486
63543
|
collectionPrompt: widgetConfig.collectionPrompt,
|