@eshal-bot/chat-widget 0.1.3 → 0.1.4
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.css +1 -1
- package/dist/chat-widget.esm.css +1 -1
- package/dist/chat-widget.esm.js +4 -4
- package/dist/chat-widget.js +1457 -550
- package/dist/chat-widget.min.js +6 -6
- package/dist/chat-widget.standalone.css +1 -1
- package/dist/chat-widget.umd.js +4 -4
- package/dist/index.css +1 -1
- package/dist/index.d.ts +16 -0
- package/package.json +1 -1
package/dist/chat-widget.js
CHANGED
|
@@ -644,19 +644,145 @@
|
|
|
644
644
|
return null;
|
|
645
645
|
};
|
|
646
646
|
|
|
647
|
+
/**
|
|
648
|
+
* Initializes the PCM audio player worklet that streams inline PCM chunks
|
|
649
|
+
* coming from the ADK websocket events.
|
|
650
|
+
*/
|
|
651
|
+
async function startAudioPlayerWorklet() {
|
|
652
|
+
if (typeof window === 'undefined') {
|
|
653
|
+
throw new Error('Audio player can only be initialized in the browser');
|
|
654
|
+
}
|
|
655
|
+
const audioContext = new AudioContext({
|
|
656
|
+
sampleRate: 24000
|
|
657
|
+
});
|
|
658
|
+
|
|
659
|
+
// For webpack/vite, we need to use a different approach
|
|
660
|
+
// We'll inline the worklet code or use a blob URL
|
|
661
|
+
const workletCode = "\n class PCMPlayerProcessor extends AudioWorkletProcessor {\n constructor() {\n super();\n this.bufferSize = 24000 * 180;\n this.buffer = new Float32Array(this.bufferSize);\n this.writeIndex = 0;\n this.readIndex = 0;\n this.port.onmessage = (event) => {\n if (event.data?.command === 'endOfAudio') {\n this.readIndex = this.writeIndex;\n return;\n }\n const int16Samples = new Int16Array(event.data);\n this.enqueue(int16Samples);\n };\n }\n\n enqueue(samples) {\n for (let i = 0; i < samples.length; i += 1) {\n const floatVal = samples[i] / 32768;\n this.buffer[this.writeIndex] = floatVal;\n this.writeIndex = (this.writeIndex + 1) % this.bufferSize;\n if (this.writeIndex === this.readIndex) {\n this.readIndex = (this.readIndex + 1) % this.bufferSize;\n }\n }\n }\n\n process(inputs, outputs) {\n const output = outputs[0];\n const framesPerBlock = output[0].length;\n for (let frame = 0; frame < framesPerBlock; frame += 1) {\n output[0][frame] = this.buffer[this.readIndex];\n if (output.length > 1) {\n output[1][frame] = this.buffer[this.readIndex];\n }\n if (this.readIndex !== this.writeIndex) {\n this.readIndex = (this.readIndex + 1) % this.bufferSize;\n }\n }\n return true;\n }\n }\n\n registerProcessor('pcm-player-processor', PCMPlayerProcessor);\n ";
|
|
662
|
+
const blob = new Blob([workletCode], {
|
|
663
|
+
type: 'application/javascript'
|
|
664
|
+
});
|
|
665
|
+
const workletUrl = URL.createObjectURL(blob);
|
|
666
|
+
await audioContext.audioWorklet.addModule(workletUrl);
|
|
667
|
+
const audioPlayerNode = new AudioWorkletNode(audioContext, 'pcm-player-processor');
|
|
668
|
+
audioPlayerNode.connect(audioContext.destination);
|
|
669
|
+
URL.revokeObjectURL(workletUrl);
|
|
670
|
+
return [audioPlayerNode, audioContext];
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* Bootstraps the PCM recorder audio worklet, captures mic audio at 16kHz
|
|
675
|
+
* mono, and forwards buffers through the provided handler.
|
|
676
|
+
*/
|
|
677
|
+
async function startAudioRecorderWorklet(onPcmChunk) {
|
|
678
|
+
if (typeof window === 'undefined') {
|
|
679
|
+
throw new Error('Audio recorder can only run in the browser');
|
|
680
|
+
}
|
|
681
|
+
const audioRecorderContext = new AudioContext({
|
|
682
|
+
sampleRate: 16000
|
|
683
|
+
});
|
|
684
|
+
const workletCode = "\n class PCMRecorderProcessor extends AudioWorkletProcessor {\n process(inputs) {\n if (!inputs.length || !inputs[0].length) {\n return true;\n }\n const inputChannel = inputs[0][0];\n this.port.postMessage(new Float32Array(inputChannel));\n return true;\n }\n }\n\n registerProcessor('pcm-recorder-processor', PCMRecorderProcessor);\n ";
|
|
685
|
+
const blob = new Blob([workletCode], {
|
|
686
|
+
type: 'application/javascript'
|
|
687
|
+
});
|
|
688
|
+
const workletUrl = URL.createObjectURL(blob);
|
|
689
|
+
await audioRecorderContext.audioWorklet.addModule(workletUrl);
|
|
690
|
+
const micStream = await navigator.mediaDevices.getUserMedia({
|
|
691
|
+
audio: {
|
|
692
|
+
channelCount: 1
|
|
693
|
+
}
|
|
694
|
+
});
|
|
695
|
+
const source = audioRecorderContext.createMediaStreamSource(micStream);
|
|
696
|
+
const audioRecorderNode = new AudioWorkletNode(audioRecorderContext, 'pcm-recorder-processor');
|
|
697
|
+
audioRecorderNode.port.onmessage = event => {
|
|
698
|
+
const pcmData = convertFloat32ToPCM(event.data);
|
|
699
|
+
onPcmChunk(pcmData);
|
|
700
|
+
};
|
|
701
|
+
source.connect(audioRecorderNode);
|
|
702
|
+
URL.revokeObjectURL(workletUrl);
|
|
703
|
+
return [audioRecorderNode, audioRecorderContext, micStream];
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
/**
|
|
707
|
+
* Stops all microphone tracks.
|
|
708
|
+
*/
|
|
709
|
+
function stopMicrophone(stream) {
|
|
710
|
+
if (!stream) {
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
stream.getTracks().forEach(track => track.stop());
|
|
714
|
+
}
|
|
715
|
+
const INT16_MAX = 0x7fff;
|
|
716
|
+
function convertFloat32ToPCM(float32Array) {
|
|
717
|
+
const pcm16Array = new Int16Array(float32Array.length);
|
|
718
|
+
for (let i = 0; i < float32Array.length; i += 1) {
|
|
719
|
+
pcm16Array[i] = Math.max(-1, Math.min(1, float32Array[i])) * INT16_MAX;
|
|
720
|
+
}
|
|
721
|
+
return pcm16Array.buffer;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
var _process$env;
|
|
725
|
+
|
|
726
|
+
// BIDI WebSocket base URL - can be overridden via config
|
|
727
|
+
const BIDI_WS_BASE = typeof process !== 'undefined' && (_process$env = process.env) !== null && _process$env !== void 0 && _process$env.NEXT_PUBLIC_BIDI_WS_BASE ? process.env.NEXT_PUBLIC_BIDI_WS_BASE : 'wss://dev.eshal.ai/knowledge-api/ws';
|
|
728
|
+
|
|
729
|
+
/**
|
|
730
|
+
* Clean CJK (Chinese, Japanese, Korean) spaces
|
|
731
|
+
*/
|
|
732
|
+
const cleanCJKSpaces = value => {
|
|
733
|
+
return value.replace(/([\u3000-\u303f\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uff00-\uffef])\s+([\u3000-\u303f\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uff00-\uffef])/g, '$1$2');
|
|
734
|
+
};
|
|
735
|
+
|
|
736
|
+
/**
|
|
737
|
+
* Convert base64 to ArrayBuffer
|
|
738
|
+
*/
|
|
739
|
+
const base64ToArrayBuffer = base64 => {
|
|
740
|
+
if (typeof window === 'undefined') {
|
|
741
|
+
return new ArrayBuffer(0);
|
|
742
|
+
}
|
|
743
|
+
let normalized = base64.replace(/-/g, '+').replace(/_/g, '/');
|
|
744
|
+
while (normalized.length % 4 !== 0) {
|
|
745
|
+
normalized += '=';
|
|
746
|
+
}
|
|
747
|
+
const binary = window.atob(normalized);
|
|
748
|
+
const len = binary.length;
|
|
749
|
+
const bytes = new Uint8Array(len);
|
|
750
|
+
for (let i = 0; i < len; i += 1) {
|
|
751
|
+
bytes[i] = binary.charCodeAt(i);
|
|
752
|
+
}
|
|
753
|
+
return bytes.buffer;
|
|
754
|
+
};
|
|
755
|
+
|
|
756
|
+
/**
|
|
757
|
+
* Sanitize WebSocket base URL
|
|
758
|
+
*/
|
|
759
|
+
const sanitizeWsBase = value => value.replace(/\/$/, '');
|
|
760
|
+
|
|
761
|
+
/**
|
|
762
|
+
* CN utility for conditional class names
|
|
763
|
+
*/
|
|
764
|
+
const cn = function () {
|
|
765
|
+
for (var _len = arguments.length, classes = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
766
|
+
classes[_key] = arguments[_key];
|
|
767
|
+
}
|
|
768
|
+
return classes.filter(Boolean).join(' ');
|
|
769
|
+
};
|
|
770
|
+
|
|
647
771
|
const createMessage = _ref => {
|
|
648
772
|
let {
|
|
649
773
|
id,
|
|
650
774
|
role,
|
|
651
775
|
content,
|
|
652
|
-
isProcessing = false
|
|
776
|
+
isProcessing = false,
|
|
777
|
+
metadata
|
|
653
778
|
} = _ref;
|
|
654
779
|
return {
|
|
655
780
|
id,
|
|
656
781
|
role,
|
|
657
782
|
content,
|
|
658
783
|
timestamp: new Date(),
|
|
659
|
-
isProcessing
|
|
784
|
+
isProcessing,
|
|
785
|
+
metadata
|
|
660
786
|
};
|
|
661
787
|
};
|
|
662
788
|
const useChatState = _ref2 => {
|
|
@@ -668,7 +794,8 @@
|
|
|
668
794
|
organizationId,
|
|
669
795
|
autoOpen,
|
|
670
796
|
openDelay,
|
|
671
|
-
darkMode
|
|
797
|
+
darkMode,
|
|
798
|
+
enableVoiceInteraction = false
|
|
672
799
|
} = _ref2;
|
|
673
800
|
const [isOpen, setIsOpen] = reactExports.useState(autoOpen);
|
|
674
801
|
const [isMinimized, setIsMinimized] = reactExports.useState(false);
|
|
@@ -689,6 +816,31 @@
|
|
|
689
816
|
const [isLoading, setIsLoading] = reactExports.useState(false);
|
|
690
817
|
const widgetRef = reactExports.useRef(null);
|
|
691
818
|
const messageIdRef = reactExports.useRef(1);
|
|
819
|
+
|
|
820
|
+
// Bidi/Voice state
|
|
821
|
+
const [isVoiceSessionActive, setIsVoiceSessionActive] = reactExports.useState(false);
|
|
822
|
+
const [bidiMessages, setBidiMessages] = reactExports.useState([]);
|
|
823
|
+
const [voiceStatus, setVoiceStatus] = reactExports.useState("idle"); // 'idle' | 'connecting' | 'connected' | 'error'
|
|
824
|
+
const [voiceError, setVoiceError] = reactExports.useState(null);
|
|
825
|
+
const [bidiSessionId] = reactExports.useState(() => "widget-session-".concat(Math.random().toString(36).slice(2, 9)));
|
|
826
|
+
|
|
827
|
+
// Bidi refs
|
|
828
|
+
const websocketRef = reactExports.useRef(null);
|
|
829
|
+
const audioPlayerNodeRef = reactExports.useRef(null);
|
|
830
|
+
const audioPlayerContextRef = reactExports.useRef(null);
|
|
831
|
+
const audioRecorderNodeRef = reactExports.useRef(null);
|
|
832
|
+
const audioRecorderContextRef = reactExports.useRef(null);
|
|
833
|
+
const micStreamRef = reactExports.useRef(null);
|
|
834
|
+
const currentInputMessageIdRef = reactExports.useRef(null);
|
|
835
|
+
const currentAssistantMessageIdRef = reactExports.useRef(null);
|
|
836
|
+
const isAudioReadyRef = reactExports.useRef(false);
|
|
837
|
+
const isVoiceSessionActiveRef = reactExports.useRef(false);
|
|
838
|
+
reactExports.useRef(null);
|
|
839
|
+
const websocketUrl = reactExports.useMemo(() => {
|
|
840
|
+
if (!organizationId) return null;
|
|
841
|
+
const normalizedBase = sanitizeWsBase(BIDI_WS_BASE);
|
|
842
|
+
return "".concat(normalizedBase, "/").concat(organizationId, "/").concat(bidiSessionId);
|
|
843
|
+
}, [organizationId, bidiSessionId]);
|
|
692
844
|
const getNextMessageId = reactExports.useCallback(() => {
|
|
693
845
|
const id = "msg-".concat(messageIdRef.current);
|
|
694
846
|
messageIdRef.current += 1;
|
|
@@ -840,17 +992,386 @@
|
|
|
840
992
|
const handleQuickQuestion = question => {
|
|
841
993
|
void sendMessage(question);
|
|
842
994
|
};
|
|
995
|
+
|
|
996
|
+
/**
|
|
997
|
+
* Handle user decision for HITL (Human-in-the-Loop)
|
|
998
|
+
*/
|
|
999
|
+
const handleDecision = reactExports.useCallback(async (decisionId, optionId, optionValue) => {
|
|
1000
|
+
// Remove the decision message from the list
|
|
1001
|
+
setMessages(prev => prev.filter(msg => {
|
|
1002
|
+
var _msg$decisionData;
|
|
1003
|
+
return ((_msg$decisionData = msg.decisionData) === null || _msg$decisionData === void 0 ? void 0 : _msg$decisionData.decisionId) !== decisionId;
|
|
1004
|
+
}));
|
|
1005
|
+
|
|
1006
|
+
// Handle the decision based on the selected option
|
|
1007
|
+
if (optionValue === "connect_agent") {
|
|
1008
|
+
// User wants to connect with a human agent
|
|
1009
|
+
const responseMessage = createMessage({
|
|
1010
|
+
id: getNextMessageId(),
|
|
1011
|
+
role: "assistant",
|
|
1012
|
+
content: "Great! I'm setting up a connection with a live customer service agent. Please hold on for a moment while I transfer you."
|
|
1013
|
+
});
|
|
1014
|
+
setMessages(prev => [...prev, responseMessage]);
|
|
1015
|
+
} else if (optionValue === "decline") {
|
|
1016
|
+
// User declined to connect with a human agent
|
|
1017
|
+
const responseMessage = createMessage({
|
|
1018
|
+
id: getNextMessageId(),
|
|
1019
|
+
role: "assistant",
|
|
1020
|
+
content: "I understand. I apologize that I don't have specific information about your query in my knowledge base. Is there anything else I can help you with?"
|
|
1021
|
+
});
|
|
1022
|
+
setMessages(prev => [...prev, responseMessage]);
|
|
1023
|
+
}
|
|
1024
|
+
}, [getNextMessageId]);
|
|
1025
|
+
|
|
1026
|
+
// Bidi/Voice functions
|
|
1027
|
+
const finalizePendingInputMessage = reactExports.useCallback(() => {
|
|
1028
|
+
if (!currentInputMessageIdRef.current) {
|
|
1029
|
+
return;
|
|
1030
|
+
}
|
|
1031
|
+
setBidiMessages(prev => prev.map(message => message.id === currentInputMessageIdRef.current ? _objectSpread2(_objectSpread2({}, message), {}, {
|
|
1032
|
+
isProcessing: false
|
|
1033
|
+
}) : message));
|
|
1034
|
+
currentInputMessageIdRef.current = null;
|
|
1035
|
+
}, []);
|
|
1036
|
+
const appendUserTranscription = reactExports.useCallback(function (text) {
|
|
1037
|
+
let finished = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
1038
|
+
if (!text) {
|
|
1039
|
+
return;
|
|
1040
|
+
}
|
|
1041
|
+
const chunk = cleanCJKSpaces(text);
|
|
1042
|
+
setBidiMessages(prev => {
|
|
1043
|
+
if (!currentInputMessageIdRef.current) {
|
|
1044
|
+
const newId = "bidi-input-".concat(Date.now());
|
|
1045
|
+
currentInputMessageIdRef.current = newId;
|
|
1046
|
+
const userMessage = createMessage({
|
|
1047
|
+
id: newId,
|
|
1048
|
+
role: "user",
|
|
1049
|
+
content: chunk,
|
|
1050
|
+
isProcessing: !finished,
|
|
1051
|
+
metadata: {
|
|
1052
|
+
source: "bidi",
|
|
1053
|
+
transcriptionType: "input"
|
|
1054
|
+
}
|
|
1055
|
+
});
|
|
1056
|
+
return [...prev, userMessage];
|
|
1057
|
+
}
|
|
1058
|
+
return prev.map(message => {
|
|
1059
|
+
if (message.id !== currentInputMessageIdRef.current) {
|
|
1060
|
+
return message;
|
|
1061
|
+
}
|
|
1062
|
+
const combined = cleanCJKSpaces("".concat(message.content || "").concat(chunk));
|
|
1063
|
+
return _objectSpread2(_objectSpread2({}, message), {}, {
|
|
1064
|
+
content: combined,
|
|
1065
|
+
timestamp: new Date(),
|
|
1066
|
+
isProcessing: !finished,
|
|
1067
|
+
metadata: _objectSpread2(_objectSpread2({}, message.metadata), {}, {
|
|
1068
|
+
transcriptionType: "input"
|
|
1069
|
+
})
|
|
1070
|
+
});
|
|
1071
|
+
});
|
|
1072
|
+
});
|
|
1073
|
+
if (finished) {
|
|
1074
|
+
currentInputMessageIdRef.current = null;
|
|
1075
|
+
}
|
|
1076
|
+
}, []);
|
|
1077
|
+
const appendAssistantContent = reactExports.useCallback(function (text) {
|
|
1078
|
+
let finished = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
1079
|
+
if (!text) {
|
|
1080
|
+
return;
|
|
1081
|
+
}
|
|
1082
|
+
finalizePendingInputMessage();
|
|
1083
|
+
setBidiMessages(prev => {
|
|
1084
|
+
if (!currentAssistantMessageIdRef.current) {
|
|
1085
|
+
const newId = "bidi-assistant-".concat(Date.now());
|
|
1086
|
+
currentAssistantMessageIdRef.current = newId;
|
|
1087
|
+
const assistantMessage = createMessage({
|
|
1088
|
+
id: newId,
|
|
1089
|
+
role: "assistant",
|
|
1090
|
+
content: text,
|
|
1091
|
+
isProcessing: !finished,
|
|
1092
|
+
metadata: {
|
|
1093
|
+
source: "bidi"
|
|
1094
|
+
}
|
|
1095
|
+
});
|
|
1096
|
+
return [...prev, assistantMessage];
|
|
1097
|
+
}
|
|
1098
|
+
return prev.map(message => {
|
|
1099
|
+
if (message.id !== currentAssistantMessageIdRef.current) {
|
|
1100
|
+
return message;
|
|
1101
|
+
}
|
|
1102
|
+
return _objectSpread2(_objectSpread2({}, message), {}, {
|
|
1103
|
+
content: "".concat(message.content || "").concat(text),
|
|
1104
|
+
timestamp: new Date(),
|
|
1105
|
+
isProcessing: !finished
|
|
1106
|
+
});
|
|
1107
|
+
});
|
|
1108
|
+
});
|
|
1109
|
+
if (finished) {
|
|
1110
|
+
currentAssistantMessageIdRef.current = null;
|
|
1111
|
+
}
|
|
1112
|
+
}, [finalizePendingInputMessage]);
|
|
1113
|
+
const handleContentParts = reactExports.useCallback(parts => {
|
|
1114
|
+
parts.forEach(part => {
|
|
1115
|
+
var _part$inlineData, _part$inlineData$mime;
|
|
1116
|
+
if ((_part$inlineData = part.inlineData) !== null && _part$inlineData !== void 0 && _part$inlineData.data && (_part$inlineData$mime = part.inlineData.mimeType) !== null && _part$inlineData$mime !== void 0 && _part$inlineData$mime.startsWith("audio/pcm")) {
|
|
1117
|
+
if (audioPlayerNodeRef.current) {
|
|
1118
|
+
audioPlayerNodeRef.current.port.postMessage(base64ToArrayBuffer(part.inlineData.data));
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
if (part.text) {
|
|
1122
|
+
appendAssistantContent(part.text, false);
|
|
1123
|
+
}
|
|
1124
|
+
});
|
|
1125
|
+
}, [appendAssistantContent]);
|
|
1126
|
+
const handleTurnComplete = reactExports.useCallback(() => {
|
|
1127
|
+
currentAssistantMessageIdRef.current = null;
|
|
1128
|
+
currentInputMessageIdRef.current = null;
|
|
1129
|
+
setBidiMessages(prev => prev.map(message => {
|
|
1130
|
+
var _message$metadata;
|
|
1131
|
+
return ((_message$metadata = message.metadata) === null || _message$metadata === void 0 ? void 0 : _message$metadata.source) === "bidi" && message.isProcessing ? _objectSpread2(_objectSpread2({}, message), {}, {
|
|
1132
|
+
isProcessing: false
|
|
1133
|
+
}) : message;
|
|
1134
|
+
}));
|
|
1135
|
+
}, []);
|
|
1136
|
+
const handleInterrupted = reactExports.useCallback(() => {
|
|
1137
|
+
if (audioPlayerNodeRef.current) {
|
|
1138
|
+
audioPlayerNodeRef.current.port.postMessage({
|
|
1139
|
+
command: "endOfAudio"
|
|
1140
|
+
});
|
|
1141
|
+
}
|
|
1142
|
+
currentAssistantMessageIdRef.current = null;
|
|
1143
|
+
currentInputMessageIdRef.current = null;
|
|
1144
|
+
setBidiMessages(prev => prev.map(message => {
|
|
1145
|
+
var _message$metadata2;
|
|
1146
|
+
return ((_message$metadata2 = message.metadata) === null || _message$metadata2 === void 0 ? void 0 : _message$metadata2.source) === "bidi" ? _objectSpread2(_objectSpread2({}, message), {}, {
|
|
1147
|
+
isProcessing: false,
|
|
1148
|
+
metadata: _objectSpread2(_objectSpread2({}, message.metadata), {}, {
|
|
1149
|
+
interrupted: true
|
|
1150
|
+
})
|
|
1151
|
+
}) : message;
|
|
1152
|
+
}));
|
|
1153
|
+
}, []);
|
|
1154
|
+
const handleBidiEvent = reactExports.useCallback(event => {
|
|
1155
|
+
var _event$inputTranscrip, _event$outputTranscri, _event$content;
|
|
1156
|
+
if (!event) {
|
|
1157
|
+
return;
|
|
1158
|
+
}
|
|
1159
|
+
if (event.turnComplete) {
|
|
1160
|
+
handleTurnComplete();
|
|
1161
|
+
return;
|
|
1162
|
+
}
|
|
1163
|
+
if (event.interrupted) {
|
|
1164
|
+
handleInterrupted();
|
|
1165
|
+
return;
|
|
1166
|
+
}
|
|
1167
|
+
if ((_event$inputTranscrip = event.inputTranscription) !== null && _event$inputTranscrip !== void 0 && _event$inputTranscrip.text) {
|
|
1168
|
+
appendUserTranscription(event.inputTranscription.text, Boolean(event.inputTranscription.finished));
|
|
1169
|
+
}
|
|
1170
|
+
if ((_event$outputTranscri = event.outputTranscription) !== null && _event$outputTranscri !== void 0 && _event$outputTranscri.text) {
|
|
1171
|
+
appendAssistantContent(event.outputTranscription.text, Boolean(event.outputTranscription.finished));
|
|
1172
|
+
}
|
|
1173
|
+
if ((_event$content = event.content) !== null && _event$content !== void 0 && _event$content.parts) {
|
|
1174
|
+
handleContentParts(event.content.parts);
|
|
1175
|
+
}
|
|
1176
|
+
}, [appendAssistantContent, appendUserTranscription, handleContentParts, handleInterrupted, handleTurnComplete]);
|
|
1177
|
+
const handleRecorderAudio = reactExports.useCallback(pcmData => {
|
|
1178
|
+
const ws = websocketRef.current;
|
|
1179
|
+
if (!isVoiceSessionActiveRef.current || !ws || ws.readyState !== WebSocket.OPEN) {
|
|
1180
|
+
return;
|
|
1181
|
+
}
|
|
1182
|
+
ws.send(pcmData);
|
|
1183
|
+
}, []);
|
|
1184
|
+
const initializeAudioPipeline = reactExports.useCallback(async () => {
|
|
1185
|
+
if (isAudioReadyRef.current || typeof window === "undefined") {
|
|
1186
|
+
return;
|
|
1187
|
+
}
|
|
1188
|
+
try {
|
|
1189
|
+
const [playerNode, playerContext] = await startAudioPlayerWorklet();
|
|
1190
|
+
audioPlayerNodeRef.current = playerNode;
|
|
1191
|
+
audioPlayerContextRef.current = playerContext;
|
|
1192
|
+
await playerContext.resume();
|
|
1193
|
+
const [recorderNode, recorderContext, micStream] = await startAudioRecorderWorklet(handleRecorderAudio);
|
|
1194
|
+
audioRecorderNodeRef.current = recorderNode;
|
|
1195
|
+
audioRecorderContextRef.current = recorderContext;
|
|
1196
|
+
micStreamRef.current = micStream;
|
|
1197
|
+
await recorderContext.resume();
|
|
1198
|
+
isAudioReadyRef.current = true;
|
|
1199
|
+
} catch (error) {
|
|
1200
|
+
console.error("Failed to initialize audio pipeline", error);
|
|
1201
|
+
throw error;
|
|
1202
|
+
}
|
|
1203
|
+
}, [handleRecorderAudio]);
|
|
1204
|
+
const connectWebsocket = reactExports.useCallback(() => {
|
|
1205
|
+
if (typeof window === "undefined" || !websocketUrl) {
|
|
1206
|
+
return;
|
|
1207
|
+
}
|
|
1208
|
+
if (websocketRef.current && websocketRef.current.readyState === WebSocket.OPEN) {
|
|
1209
|
+
return;
|
|
1210
|
+
}
|
|
1211
|
+
setVoiceStatus("connecting");
|
|
1212
|
+
setVoiceError(null);
|
|
1213
|
+
try {
|
|
1214
|
+
const ws = new WebSocket(websocketUrl);
|
|
1215
|
+
websocketRef.current = ws;
|
|
1216
|
+
ws.onopen = () => {
|
|
1217
|
+
setVoiceStatus("connected");
|
|
1218
|
+
};
|
|
1219
|
+
ws.onmessage = event => {
|
|
1220
|
+
try {
|
|
1221
|
+
const payload = JSON.parse(event.data);
|
|
1222
|
+
handleBidiEvent(payload);
|
|
1223
|
+
} catch (error) {
|
|
1224
|
+
console.error("Failed to parse ADK event", error);
|
|
1225
|
+
}
|
|
1226
|
+
};
|
|
1227
|
+
ws.onerror = () => {
|
|
1228
|
+
setVoiceStatus("error");
|
|
1229
|
+
setVoiceError("Voice session connection error");
|
|
1230
|
+
};
|
|
1231
|
+
ws.onclose = () => {
|
|
1232
|
+
websocketRef.current = null;
|
|
1233
|
+
setVoiceStatus("idle");
|
|
1234
|
+
if (isVoiceSessionActiveRef.current) {
|
|
1235
|
+
setTimeout(() => {
|
|
1236
|
+
connectWebsocket();
|
|
1237
|
+
}, 5000);
|
|
1238
|
+
}
|
|
1239
|
+
};
|
|
1240
|
+
} catch (error) {
|
|
1241
|
+
console.error("Failed to open voice websocket", error);
|
|
1242
|
+
setVoiceStatus("error");
|
|
1243
|
+
setVoiceError(error instanceof Error ? error.message : "Unable to start voice session");
|
|
1244
|
+
}
|
|
1245
|
+
}, [handleBidiEvent, websocketUrl]);
|
|
1246
|
+
const startVoiceSession = reactExports.useCallback(async () => {
|
|
1247
|
+
if (!enableVoiceInteraction || !organizationId) {
|
|
1248
|
+
return;
|
|
1249
|
+
}
|
|
1250
|
+
setVoiceError(null);
|
|
1251
|
+
setVoiceStatus(prev => prev === "connected" ? prev : "connecting");
|
|
1252
|
+
setIsVoiceSessionActive(true);
|
|
1253
|
+
isVoiceSessionActiveRef.current = true;
|
|
1254
|
+
setBidiMessages(prev => {
|
|
1255
|
+
if (prev.length > 0) {
|
|
1256
|
+
return prev;
|
|
1257
|
+
}
|
|
1258
|
+
if (!welcomeMessage || welcomeMessage.trim() === "") {
|
|
1259
|
+
return [];
|
|
1260
|
+
}
|
|
1261
|
+
const welcomeMsg = createMessage({
|
|
1262
|
+
id: "bidi-welcome-".concat(Date.now()),
|
|
1263
|
+
role: "assistant",
|
|
1264
|
+
content: welcomeMessage,
|
|
1265
|
+
metadata: {
|
|
1266
|
+
source: "bidi"
|
|
1267
|
+
}
|
|
1268
|
+
});
|
|
1269
|
+
return [welcomeMsg];
|
|
1270
|
+
});
|
|
1271
|
+
connectWebsocket();
|
|
1272
|
+
try {
|
|
1273
|
+
await initializeAudioPipeline();
|
|
1274
|
+
} catch (error) {
|
|
1275
|
+
console.error("Failed to start audio pipeline", error);
|
|
1276
|
+
setVoiceError(error instanceof Error ? error.message : "Unable to access microphone");
|
|
1277
|
+
setVoiceStatus("error");
|
|
1278
|
+
}
|
|
1279
|
+
}, [enableVoiceInteraction, organizationId, welcomeMessage, connectWebsocket, initializeAudioPipeline]);
|
|
1280
|
+
const stopVoiceSession = reactExports.useCallback(() => {
|
|
1281
|
+
var _audioPlayerNodeRef$c, _audioPlayerContextRe, _audioRecorderNodeRef, _audioRecorderContext;
|
|
1282
|
+
setIsVoiceSessionActive(false);
|
|
1283
|
+
isVoiceSessionActiveRef.current = false;
|
|
1284
|
+
setVoiceStatus("idle");
|
|
1285
|
+
setVoiceError(null);
|
|
1286
|
+
if (websocketRef.current && websocketRef.current.readyState === WebSocket.OPEN) {
|
|
1287
|
+
websocketRef.current.close();
|
|
1288
|
+
}
|
|
1289
|
+
websocketRef.current = null;
|
|
1290
|
+
(_audioPlayerNodeRef$c = audioPlayerNodeRef.current) === null || _audioPlayerNodeRef$c === void 0 || _audioPlayerNodeRef$c.disconnect();
|
|
1291
|
+
(_audioPlayerContextRe = audioPlayerContextRef.current) === null || _audioPlayerContextRe === void 0 || _audioPlayerContextRe.close();
|
|
1292
|
+
audioPlayerNodeRef.current = null;
|
|
1293
|
+
audioPlayerContextRef.current = null;
|
|
1294
|
+
(_audioRecorderNodeRef = audioRecorderNodeRef.current) === null || _audioRecorderNodeRef === void 0 || _audioRecorderNodeRef.disconnect();
|
|
1295
|
+
(_audioRecorderContext = audioRecorderContextRef.current) === null || _audioRecorderContext === void 0 || _audioRecorderContext.close();
|
|
1296
|
+
audioRecorderNodeRef.current = null;
|
|
1297
|
+
audioRecorderContextRef.current = null;
|
|
1298
|
+
stopMicrophone(micStreamRef.current);
|
|
1299
|
+
micStreamRef.current = null;
|
|
1300
|
+
isAudioReadyRef.current = false;
|
|
1301
|
+
}, []);
|
|
1302
|
+
const handleVoiceToggle = reactExports.useCallback(() => {
|
|
1303
|
+
if (isVoiceSessionActive) {
|
|
1304
|
+
stopVoiceSession();
|
|
1305
|
+
return;
|
|
1306
|
+
}
|
|
1307
|
+
if (voiceStatus === "connecting") {
|
|
1308
|
+
return;
|
|
1309
|
+
}
|
|
1310
|
+
void startVoiceSession();
|
|
1311
|
+
}, [isVoiceSessionActive, startVoiceSession, stopVoiceSession, voiceStatus]);
|
|
1312
|
+
const sendBidiTextMessage = reactExports.useCallback(text => {
|
|
1313
|
+
const trimmed = text.trim();
|
|
1314
|
+
if (!trimmed) {
|
|
1315
|
+
return;
|
|
1316
|
+
}
|
|
1317
|
+
const ws = websocketRef.current;
|
|
1318
|
+
if (!ws || ws.readyState !== WebSocket.OPEN) {
|
|
1319
|
+
setVoiceError("Voice session is not connected yet");
|
|
1320
|
+
return;
|
|
1321
|
+
}
|
|
1322
|
+
ws.send(JSON.stringify({
|
|
1323
|
+
type: "text",
|
|
1324
|
+
text: trimmed
|
|
1325
|
+
}));
|
|
1326
|
+
const userMessage = createMessage({
|
|
1327
|
+
id: "bidi-user-".concat(Date.now()),
|
|
1328
|
+
role: "user",
|
|
1329
|
+
content: trimmed,
|
|
1330
|
+
metadata: {
|
|
1331
|
+
source: "bidi"
|
|
1332
|
+
}
|
|
1333
|
+
});
|
|
1334
|
+
setBidiMessages(prev => [...prev, userMessage]);
|
|
1335
|
+
setInputValue("");
|
|
1336
|
+
}, []);
|
|
1337
|
+
|
|
1338
|
+
// Cleanup on unmount
|
|
1339
|
+
reactExports.useEffect(() => {
|
|
1340
|
+
isVoiceSessionActiveRef.current = isVoiceSessionActive;
|
|
1341
|
+
}, [isVoiceSessionActive]);
|
|
1342
|
+
reactExports.useEffect(() => {
|
|
1343
|
+
return () => {
|
|
1344
|
+
var _audioPlayerNodeRef$c2, _audioPlayerContextRe2, _audioRecorderNodeRef2, _audioRecorderContext2;
|
|
1345
|
+
if (websocketRef.current && websocketRef.current.readyState === WebSocket.OPEN) {
|
|
1346
|
+
websocketRef.current.close();
|
|
1347
|
+
}
|
|
1348
|
+
(_audioPlayerNodeRef$c2 = audioPlayerNodeRef.current) === null || _audioPlayerNodeRef$c2 === void 0 || _audioPlayerNodeRef$c2.disconnect();
|
|
1349
|
+
(_audioPlayerContextRe2 = audioPlayerContextRef.current) === null || _audioPlayerContextRe2 === void 0 || _audioPlayerContextRe2.close();
|
|
1350
|
+
(_audioRecorderNodeRef2 = audioRecorderNodeRef.current) === null || _audioRecorderNodeRef2 === void 0 || _audioRecorderNodeRef2.disconnect();
|
|
1351
|
+
(_audioRecorderContext2 = audioRecorderContextRef.current) === null || _audioRecorderContext2 === void 0 || _audioRecorderContext2.close();
|
|
1352
|
+
stopMicrophone(micStreamRef.current);
|
|
1353
|
+
micStreamRef.current = null;
|
|
1354
|
+
isAudioReadyRef.current = false;
|
|
1355
|
+
};
|
|
1356
|
+
}, []);
|
|
843
1357
|
const memoizedQuickQuestions = reactExports.useMemo(() => quickQuestions, [quickQuestions]);
|
|
1358
|
+
|
|
1359
|
+
// Determine which messages to use
|
|
1360
|
+
const activeMessages = isVoiceSessionActive ? bidiMessages : messages;
|
|
844
1361
|
return {
|
|
845
1362
|
// State
|
|
846
1363
|
isOpen,
|
|
847
1364
|
isMinimized,
|
|
848
1365
|
isDark,
|
|
849
|
-
messages,
|
|
1366
|
+
messages: activeMessages,
|
|
850
1367
|
inputValue,
|
|
851
1368
|
isLoading,
|
|
852
1369
|
widgetRef,
|
|
853
1370
|
quickQuestions: memoizedQuickQuestions,
|
|
1371
|
+
// Bidi/Voice state
|
|
1372
|
+
isVoiceSessionActive,
|
|
1373
|
+
voiceStatus,
|
|
1374
|
+
voiceError,
|
|
854
1375
|
// Actions
|
|
855
1376
|
setInputValue,
|
|
856
1377
|
handleSend,
|
|
@@ -859,7 +1380,11 @@
|
|
|
859
1380
|
toggleChat,
|
|
860
1381
|
toggleTheme,
|
|
861
1382
|
toggleMinimize,
|
|
862
|
-
closeChat
|
|
1383
|
+
closeChat,
|
|
1384
|
+
handleDecision,
|
|
1385
|
+
// Bidi/Voice actions
|
|
1386
|
+
handleVoiceToggle,
|
|
1387
|
+
sendBidiTextMessage
|
|
863
1388
|
};
|
|
864
1389
|
};
|
|
865
1390
|
|
|
@@ -923,13 +1448,13 @@
|
|
|
923
1448
|
*/
|
|
924
1449
|
|
|
925
1450
|
|
|
926
|
-
const
|
|
927
|
-
["path", { d: "
|
|
928
|
-
["
|
|
929
|
-
["path", { d: "
|
|
930
|
-
["path", { d: "
|
|
931
|
-
["path", { d: "
|
|
932
|
-
["path", { d: "
|
|
1451
|
+
const AudioLines = createLucideIcon("AudioLines", [
|
|
1452
|
+
["path", { d: "M2 10v3", key: "1fnikh" }],
|
|
1453
|
+
["path", { d: "M6 6v11", key: "11sgs0" }],
|
|
1454
|
+
["path", { d: "M10 3v18", key: "yhl04a" }],
|
|
1455
|
+
["path", { d: "M14 8v7", key: "3a1oy3" }],
|
|
1456
|
+
["path", { d: "M18 5v13", key: "123xd1" }],
|
|
1457
|
+
["path", { d: "M22 10v3", key: "154ddg" }]
|
|
933
1458
|
]);
|
|
934
1459
|
|
|
935
1460
|
/**
|
|
@@ -940,11 +1465,8 @@
|
|
|
940
1465
|
*/
|
|
941
1466
|
|
|
942
1467
|
|
|
943
|
-
const
|
|
944
|
-
["
|
|
945
|
-
["polyline", { points: "9 21 3 21 3 15", key: "1avn1i" }],
|
|
946
|
-
["line", { x1: "21", x2: "14", y1: "3", y2: "10", key: "ota7mn" }],
|
|
947
|
-
["line", { x1: "3", x2: "10", y1: "21", y2: "14", key: "1atl0r" }]
|
|
1468
|
+
const Loader2 = createLucideIcon("Loader2", [
|
|
1469
|
+
["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]
|
|
948
1470
|
]);
|
|
949
1471
|
|
|
950
1472
|
/**
|
|
@@ -955,10 +1477,11 @@
|
|
|
955
1477
|
*/
|
|
956
1478
|
|
|
957
1479
|
|
|
958
|
-
const
|
|
959
|
-
["
|
|
960
|
-
["
|
|
961
|
-
["
|
|
1480
|
+
const Maximize2 = createLucideIcon("Maximize2", [
|
|
1481
|
+
["polyline", { points: "15 3 21 3 21 9", key: "mznyad" }],
|
|
1482
|
+
["polyline", { points: "9 21 3 21 3 15", key: "1avn1i" }],
|
|
1483
|
+
["line", { x1: "21", x2: "14", y1: "3", y2: "10", key: "ota7mn" }],
|
|
1484
|
+
["line", { x1: "3", x2: "10", y1: "21", y2: "14", key: "1atl0r" }]
|
|
962
1485
|
]);
|
|
963
1486
|
|
|
964
1487
|
/**
|
|
@@ -1059,323 +1582,6 @@
|
|
|
1059
1582
|
["path", { d: "m6 6 12 12", key: "d8bk6v" }]
|
|
1060
1583
|
]);
|
|
1061
1584
|
|
|
1062
|
-
var jsxRuntime = {exports: {}};
|
|
1063
|
-
|
|
1064
|
-
var reactJsxRuntime_production_min = {};
|
|
1065
|
-
|
|
1066
|
-
/**
|
|
1067
|
-
* @license React
|
|
1068
|
-
* react-jsx-runtime.production.min.js
|
|
1069
|
-
*
|
|
1070
|
-
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
1071
|
-
*
|
|
1072
|
-
* This source code is licensed under the MIT license found in the
|
|
1073
|
-
* LICENSE file in the root directory of this source tree.
|
|
1074
|
-
*/
|
|
1075
|
-
var f=reactExports,k=Symbol.for("react.element"),l=Symbol.for("react.fragment"),m=Object.prototype.hasOwnProperty,n=f.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,p={key:!0,ref:!0,__self:!0,__source:!0};
|
|
1076
|
-
function q(c,a,g){var b,d={},e=null,h=null;void 0!==g&&(e=""+g);void 0!==a.key&&(e=""+a.key);void 0!==a.ref&&(h=a.ref);for(b in a)m.call(a,b)&&!p.hasOwnProperty(b)&&(d[b]=a[b]);if(c&&c.defaultProps)for(b in a=c.defaultProps,a)void 0===d[b]&&(d[b]=a[b]);return {$$typeof:k,type:c,key:e,ref:h,props:d,_owner:n.current}}reactJsxRuntime_production_min.Fragment=l;reactJsxRuntime_production_min.jsx=q;reactJsxRuntime_production_min.jsxs=q;
|
|
1077
|
-
|
|
1078
|
-
{
|
|
1079
|
-
jsxRuntime.exports = reactJsxRuntime_production_min;
|
|
1080
|
-
}
|
|
1081
|
-
|
|
1082
|
-
var jsxRuntimeExports = jsxRuntime.exports;
|
|
1083
|
-
|
|
1084
|
-
const LOGO_MAX_HEIGHT = "3.5rem";
|
|
1085
|
-
const LOGO_MAX_HEIGHT_COMPACT = "2.5rem";
|
|
1086
|
-
const LOGO_MAX_WIDTH_DEFAULT = "4.5rem";
|
|
1087
|
-
const LOGO_MAX_WIDTH_DEFAULT_COMPACT = "3rem";
|
|
1088
|
-
const LOGO_MAX_WIDTH_WIDE = "9rem";
|
|
1089
|
-
const LOGO_MAX_WIDTH_WIDE_COMPACT = "5.5rem";
|
|
1090
|
-
const STATUS_DOT_SIZE = "0.8rem";
|
|
1091
|
-
const STATUS_DOT_SIZE_COMPACT = "0.65rem";
|
|
1092
|
-
const STATUS_DOT_BORDER_WIDTH = "2px";
|
|
1093
|
-
const STATUS_DOT_BORDER_WIDTH_COMPACT = "1.5px";
|
|
1094
|
-
const STATUS_DOT_DEFAULT_COLOR = "#34d399";
|
|
1095
|
-
const STATUS_DOT_OFFSET = "38%";
|
|
1096
|
-
const STATUS_DOT_OFFSET_COMPACT = "22%";
|
|
1097
|
-
const LogoImage = _ref => {
|
|
1098
|
-
let {
|
|
1099
|
-
src,
|
|
1100
|
-
showStatusDot = false,
|
|
1101
|
-
statusColor = STATUS_DOT_DEFAULT_COLOR,
|
|
1102
|
-
size = "default"
|
|
1103
|
-
} = _ref;
|
|
1104
|
-
const [aspect, setAspect] = reactExports.useState("square");
|
|
1105
|
-
const isCompact = size === "compact";
|
|
1106
|
-
reactExports.useEffect(() => {
|
|
1107
|
-
if (typeof window === "undefined" || !src) {
|
|
1108
|
-
return;
|
|
1109
|
-
}
|
|
1110
|
-
const img = new Image();
|
|
1111
|
-
img.src = src;
|
|
1112
|
-
img.onload = () => {
|
|
1113
|
-
if (img.width > img.height) {
|
|
1114
|
-
setAspect("wide");
|
|
1115
|
-
} else if (img.height > img.width) {
|
|
1116
|
-
setAspect("tall");
|
|
1117
|
-
} else {
|
|
1118
|
-
setAspect("square");
|
|
1119
|
-
}
|
|
1120
|
-
};
|
|
1121
|
-
}, [src]);
|
|
1122
|
-
const containerStyle = {
|
|
1123
|
-
position: "relative",
|
|
1124
|
-
display: "inline-flex"
|
|
1125
|
-
};
|
|
1126
|
-
const imageStyle = {
|
|
1127
|
-
display: "block",
|
|
1128
|
-
objectFit: "contain",
|
|
1129
|
-
height: "auto",
|
|
1130
|
-
width: "auto",
|
|
1131
|
-
maxHeight: isCompact ? LOGO_MAX_HEIGHT_COMPACT : LOGO_MAX_HEIGHT,
|
|
1132
|
-
maxWidth: isCompact ? LOGO_MAX_WIDTH_DEFAULT_COMPACT : LOGO_MAX_WIDTH_DEFAULT
|
|
1133
|
-
};
|
|
1134
|
-
if (aspect === "wide") {
|
|
1135
|
-
imageStyle.maxWidth = isCompact ? LOGO_MAX_WIDTH_WIDE_COMPACT : LOGO_MAX_WIDTH_WIDE;
|
|
1136
|
-
}
|
|
1137
|
-
if (aspect === "tall") {
|
|
1138
|
-
imageStyle.maxHeight = isCompact ? "3rem" : "4rem";
|
|
1139
|
-
imageStyle.maxWidth = isCompact ? "3rem" : "4rem";
|
|
1140
|
-
}
|
|
1141
|
-
return /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
|
|
1142
|
-
style: containerStyle,
|
|
1143
|
-
children: [/*#__PURE__*/jsxRuntimeExports.jsx("img", {
|
|
1144
|
-
src: src,
|
|
1145
|
-
alt: "Logo",
|
|
1146
|
-
style: imageStyle,
|
|
1147
|
-
loading: "lazy"
|
|
1148
|
-
}), showStatusDot && /*#__PURE__*/jsxRuntimeExports.jsx("span", {
|
|
1149
|
-
style: {
|
|
1150
|
-
position: "absolute",
|
|
1151
|
-
bottom: 0,
|
|
1152
|
-
right: 0,
|
|
1153
|
-
width: isCompact ? STATUS_DOT_SIZE_COMPACT : STATUS_DOT_SIZE,
|
|
1154
|
-
height: isCompact ? STATUS_DOT_SIZE_COMPACT : STATUS_DOT_SIZE,
|
|
1155
|
-
borderRadius: "9999px",
|
|
1156
|
-
backgroundColor: statusColor,
|
|
1157
|
-
border: "".concat(isCompact ? STATUS_DOT_BORDER_WIDTH_COMPACT : STATUS_DOT_BORDER_WIDTH, " solid #ffffff"),
|
|
1158
|
-
transform: "translate(".concat(isCompact ? STATUS_DOT_OFFSET_COMPACT : STATUS_DOT_OFFSET, ", ").concat(isCompact ? STATUS_DOT_OFFSET_COMPACT : STATUS_DOT_OFFSET, ")"),
|
|
1159
|
-
pointerEvents: "none"
|
|
1160
|
-
}
|
|
1161
|
-
})]
|
|
1162
|
-
});
|
|
1163
|
-
};
|
|
1164
|
-
|
|
1165
|
-
const IS_BROWSER = typeof window !== "undefined";
|
|
1166
|
-
const SYSTEM_FONT_FAMILIES = new Set(["Arial", "Helvetica", "Times New Roman", "Georgia", "Courier New", "Verdana", "Trebuchet MS", "Palatino", "Garamond", "Tahoma", "Lucida Sans", "Lucida Grande", "Lucida Console", "Gill Sans", "Impact", "Comic Sans MS", "system-ui"].map(font => font.toLowerCase()));
|
|
1167
|
-
const GENERIC_FONT_KEYWORDS = ["sans-serif", "serif", "monospace", "cursive", "fantasy"];
|
|
1168
|
-
const GOOGLE_FONT_WEIGHTS = "300,400,500,600,700";
|
|
1169
|
-
const loadedFonts = new Set();
|
|
1170
|
-
let webFontLoaderPromise = null;
|
|
1171
|
-
const shouldSkipLoading = fontFamily => {
|
|
1172
|
-
const normalized = fontFamily.trim().toLowerCase();
|
|
1173
|
-
if (!normalized) return true;
|
|
1174
|
-
if (SYSTEM_FONT_FAMILIES.has(normalized)) return true;
|
|
1175
|
-
return GENERIC_FONT_KEYWORDS.some(keyword => normalized.includes(keyword));
|
|
1176
|
-
};
|
|
1177
|
-
const toGoogleFontQuery = fontFamily => fontFamily.trim().replace(/\s+/g, "+");
|
|
1178
|
-
function useGoogleFont(fontFamily) {
|
|
1179
|
-
reactExports.useEffect(() => {
|
|
1180
|
-
var _fontFamily$split$;
|
|
1181
|
-
if (!IS_BROWSER || !fontFamily) {
|
|
1182
|
-
return;
|
|
1183
|
-
}
|
|
1184
|
-
const baseFont = (_fontFamily$split$ = fontFamily.split(",")[0]) === null || _fontFamily$split$ === void 0 ? void 0 : _fontFamily$split$.trim();
|
|
1185
|
-
if (!baseFont || loadedFonts.has(baseFont)) {
|
|
1186
|
-
return;
|
|
1187
|
-
}
|
|
1188
|
-
if (shouldSkipLoading(baseFont)) {
|
|
1189
|
-
loadedFonts.add(baseFont);
|
|
1190
|
-
return;
|
|
1191
|
-
}
|
|
1192
|
-
let isMounted = true;
|
|
1193
|
-
const loadFont = async () => {
|
|
1194
|
-
try {
|
|
1195
|
-
if (!webFontLoaderPromise) {
|
|
1196
|
-
webFontLoaderPromise = Promise.resolve().then(function () { return webfontloader; });
|
|
1197
|
-
}
|
|
1198
|
-
const webFontModule = await webFontLoaderPromise;
|
|
1199
|
-
const WebFont = webFontModule && "default" in webFontModule ? webFontModule.default : webFontModule;
|
|
1200
|
-
const googleQuery = toGoogleFontQuery(baseFont);
|
|
1201
|
-
WebFont.load({
|
|
1202
|
-
google: {
|
|
1203
|
-
families: ["".concat(googleQuery, ":").concat(GOOGLE_FONT_WEIGHTS)]
|
|
1204
|
-
},
|
|
1205
|
-
fontactive: family => {
|
|
1206
|
-
if (isMounted) {
|
|
1207
|
-
loadedFonts.add(family);
|
|
1208
|
-
}
|
|
1209
|
-
},
|
|
1210
|
-
fontinactive: family => {
|
|
1211
|
-
if (isMounted) {
|
|
1212
|
-
loadedFonts.add(family);
|
|
1213
|
-
}
|
|
1214
|
-
console.warn("Warning: failed to load Google Font: ".concat(family));
|
|
1215
|
-
}
|
|
1216
|
-
});
|
|
1217
|
-
} catch (error) {
|
|
1218
|
-
console.error("Warning: WebFont loader error:", error);
|
|
1219
|
-
}
|
|
1220
|
-
};
|
|
1221
|
-
void loadFont();
|
|
1222
|
-
return () => {
|
|
1223
|
-
isMounted = false;
|
|
1224
|
-
};
|
|
1225
|
-
}, [fontFamily]);
|
|
1226
|
-
}
|
|
1227
|
-
|
|
1228
|
-
const lightenColor = function (color) {
|
|
1229
|
-
let amount = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0.12;
|
|
1230
|
-
if (!color) {
|
|
1231
|
-
return color;
|
|
1232
|
-
}
|
|
1233
|
-
const hexMatch = color.trim().match(/^#([0-9a-f]{3,8})$/i);
|
|
1234
|
-
if (!hexMatch) {
|
|
1235
|
-
return color;
|
|
1236
|
-
}
|
|
1237
|
-
let hex = hexMatch[1];
|
|
1238
|
-
if (hex.length === 3) {
|
|
1239
|
-
hex = hex.split("").map(char => char + char).join("");
|
|
1240
|
-
}
|
|
1241
|
-
if (hex.length === 8) {
|
|
1242
|
-
hex = hex.slice(0, 6);
|
|
1243
|
-
}
|
|
1244
|
-
if (hex.length !== 6) {
|
|
1245
|
-
return color;
|
|
1246
|
-
}
|
|
1247
|
-
const num = parseInt(hex, 16);
|
|
1248
|
-
const r = num >> 16 & 255;
|
|
1249
|
-
const g = num >> 8 & 255;
|
|
1250
|
-
const b = num & 255;
|
|
1251
|
-
const mix = channel => {
|
|
1252
|
-
const mixed = Math.round(channel + (255 - channel) * amount);
|
|
1253
|
-
return Math.min(255, Math.max(0, mixed));
|
|
1254
|
-
};
|
|
1255
|
-
const [lr, lg, lb] = [mix(r), mix(g), mix(b)];
|
|
1256
|
-
const toHex = channel => channel.toString(16).padStart(2, "0");
|
|
1257
|
-
return "#".concat(toHex(lr)).concat(toHex(lg)).concat(toHex(lb));
|
|
1258
|
-
};
|
|
1259
|
-
const ChatHeader = _ref => {
|
|
1260
|
-
let {
|
|
1261
|
-
conciergeName,
|
|
1262
|
-
companyName,
|
|
1263
|
-
companyLogo,
|
|
1264
|
-
primaryColor,
|
|
1265
|
-
isDark,
|
|
1266
|
-
isMinimized = false,
|
|
1267
|
-
textColor,
|
|
1268
|
-
fontFamily,
|
|
1269
|
-
fontSize,
|
|
1270
|
-
onToggleTheme,
|
|
1271
|
-
onMinimize,
|
|
1272
|
-
onClose
|
|
1273
|
-
} = _ref;
|
|
1274
|
-
useGoogleFont(fontFamily);
|
|
1275
|
-
return /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
|
|
1276
|
-
className: "text-white ".concat(isMinimized ? "px-4 py-2.5" : "px-5 py-4", " flex items-center justify-between relative overflow-hidden rounded-t-2xl"),
|
|
1277
|
-
style: {
|
|
1278
|
-
background: "linear-gradient(135deg, ".concat(primaryColor, " 0%, ").concat(lightenColor(primaryColor, 0.2), " 100%)"),
|
|
1279
|
-
fontFamily
|
|
1280
|
-
},
|
|
1281
|
-
children: [/*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
1282
|
-
className: "absolute inset-0 pointer-events-none transition-opacity duration-200 ".concat(isMinimized ? "opacity-0" : "opacity-100", " bg-gradient-to-br from-white/10 to-transparent")
|
|
1283
|
-
}), /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
|
|
1284
|
-
className: "flex items-center ".concat(isMinimized ? "gap-1.5" : "gap-3", " relative z-10 min-w-0"),
|
|
1285
|
-
children: [companyLogo ? /*#__PURE__*/jsxRuntimeExports.jsx(LogoImage, {
|
|
1286
|
-
src: companyLogo,
|
|
1287
|
-
showStatusDot: true,
|
|
1288
|
-
statusColor: "#34d399",
|
|
1289
|
-
size: isMinimized ? "compact" : "default"
|
|
1290
|
-
}) : /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
|
|
1291
|
-
className: "relative",
|
|
1292
|
-
children: [/*#__PURE__*/jsxRuntimeExports.jsx(MessageCircle, {
|
|
1293
|
-
className: "transition-all ".concat(isMinimized ? "w-8 h-8" : "w-10 h-10")
|
|
1294
|
-
}), /*#__PURE__*/jsxRuntimeExports.jsx("span", {
|
|
1295
|
-
className: "absolute rounded-full",
|
|
1296
|
-
style: {
|
|
1297
|
-
bottom: 0,
|
|
1298
|
-
right: 0,
|
|
1299
|
-
width: isMinimized ? "0.65rem" : "0.8rem",
|
|
1300
|
-
height: isMinimized ? "0.65rem" : "0.8rem",
|
|
1301
|
-
backgroundColor: "#34d399",
|
|
1302
|
-
border: isMinimized ? "1.5px solid #ffffff" : "2px solid #ffffff",
|
|
1303
|
-
transform: "translate(".concat(isMinimized ? "22%" : "38%", ", ").concat(isMinimized ? "22%" : "38%", ")"),
|
|
1304
|
-
pointerEvents: "none"
|
|
1305
|
-
}
|
|
1306
|
-
})]
|
|
1307
|
-
}), /*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
1308
|
-
className: "flex items-center gap-2 min-w-0",
|
|
1309
|
-
children: /*#__PURE__*/jsxRuntimeExports.jsx("h3", {
|
|
1310
|
-
className: "font-semibold leading-tight truncate",
|
|
1311
|
-
style: {
|
|
1312
|
-
fontSize: fontSize ? "calc(".concat(fontSize, " + ").concat(isMinimized ? "6px" : "10px", ")") : isMinimized ? "13px" : "15px",
|
|
1313
|
-
color: textColor || "#FFFFFF"
|
|
1314
|
-
},
|
|
1315
|
-
children: conciergeName
|
|
1316
|
-
})
|
|
1317
|
-
})]
|
|
1318
|
-
}), /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
|
|
1319
|
-
className: "flex items-center ".concat(isMinimized ? "gap-3" : "gap-4", " relative z-10 text-white"),
|
|
1320
|
-
children: [/*#__PURE__*/jsxRuntimeExports.jsx("span", {
|
|
1321
|
-
role: "button",
|
|
1322
|
-
tabIndex: 0,
|
|
1323
|
-
"aria-label": "Toggle theme",
|
|
1324
|
-
onClick: onToggleTheme,
|
|
1325
|
-
onKeyDown: event => {
|
|
1326
|
-
if (event.key === "Enter" || event.key === " ") {
|
|
1327
|
-
event.preventDefault();
|
|
1328
|
-
onToggleTheme === null || onToggleTheme === void 0 || onToggleTheme(event);
|
|
1329
|
-
}
|
|
1330
|
-
},
|
|
1331
|
-
className: "inline-flex h-8 w-8 items-center justify-center cursor-pointer transition-opacity duration-200 hover:opacity-80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/40 rounded-full",
|
|
1332
|
-
children: isDark ? /*#__PURE__*/jsxRuntimeExports.jsx(Sun, {
|
|
1333
|
-
className: "w-4 h-4",
|
|
1334
|
-
strokeWidth: 1.6
|
|
1335
|
-
}) : /*#__PURE__*/jsxRuntimeExports.jsx(Moon, {
|
|
1336
|
-
className: "w-4 h-4",
|
|
1337
|
-
strokeWidth: 1.6
|
|
1338
|
-
})
|
|
1339
|
-
}), onMinimize && /*#__PURE__*/jsxRuntimeExports.jsx("span", {
|
|
1340
|
-
role: "button",
|
|
1341
|
-
tabIndex: 0,
|
|
1342
|
-
"aria-label": isMinimized ? "Expand" : "Minimize",
|
|
1343
|
-
onClick: onMinimize,
|
|
1344
|
-
onKeyDown: event => {
|
|
1345
|
-
if (event.key === "Enter" || event.key === " ") {
|
|
1346
|
-
event.preventDefault();
|
|
1347
|
-
onMinimize === null || onMinimize === void 0 || onMinimize(event);
|
|
1348
|
-
}
|
|
1349
|
-
},
|
|
1350
|
-
className: "inline-flex h-8 w-8 items-center justify-center cursor-pointer transition-opacity duration-200 hover:opacity-80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/40 rounded-full",
|
|
1351
|
-
children: isMinimized ? /*#__PURE__*/jsxRuntimeExports.jsx(Maximize2, {
|
|
1352
|
-
className: "w-4 h-4",
|
|
1353
|
-
strokeWidth: 1.6
|
|
1354
|
-
}) : /*#__PURE__*/jsxRuntimeExports.jsx(Minimize2, {
|
|
1355
|
-
className: "w-4 h-4",
|
|
1356
|
-
strokeWidth: 1.6
|
|
1357
|
-
})
|
|
1358
|
-
}), /*#__PURE__*/jsxRuntimeExports.jsx("span", {
|
|
1359
|
-
role: "button",
|
|
1360
|
-
tabIndex: 0,
|
|
1361
|
-
"aria-label": "Close",
|
|
1362
|
-
onClick: onClose,
|
|
1363
|
-
onKeyDown: event => {
|
|
1364
|
-
if (event.key === "Enter" || event.key === " ") {
|
|
1365
|
-
event.preventDefault();
|
|
1366
|
-
onClose === null || onClose === void 0 || onClose(event);
|
|
1367
|
-
}
|
|
1368
|
-
},
|
|
1369
|
-
className: "inline-flex h-8 w-8 items-center justify-center cursor-pointer transition-opacity duration-200 hover:opacity-80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/40 rounded-full",
|
|
1370
|
-
children: /*#__PURE__*/jsxRuntimeExports.jsx(X, {
|
|
1371
|
-
className: "w-4 h-4",
|
|
1372
|
-
strokeWidth: 1.6
|
|
1373
|
-
})
|
|
1374
|
-
})]
|
|
1375
|
-
})]
|
|
1376
|
-
});
|
|
1377
|
-
};
|
|
1378
|
-
|
|
1379
1585
|
function ok$2() {}
|
|
1380
1586
|
|
|
1381
1587
|
function unreachable() {}
|
|
@@ -4508,6 +4714,28 @@
|
|
|
4508
4714
|
]
|
|
4509
4715
|
};
|
|
4510
4716
|
|
|
4717
|
+
var jsxRuntime = {exports: {}};
|
|
4718
|
+
|
|
4719
|
+
var reactJsxRuntime_production_min = {};
|
|
4720
|
+
|
|
4721
|
+
/**
|
|
4722
|
+
* @license React
|
|
4723
|
+
* react-jsx-runtime.production.min.js
|
|
4724
|
+
*
|
|
4725
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
4726
|
+
*
|
|
4727
|
+
* This source code is licensed under the MIT license found in the
|
|
4728
|
+
* LICENSE file in the root directory of this source tree.
|
|
4729
|
+
*/
|
|
4730
|
+
var f=reactExports,k=Symbol.for("react.element"),l=Symbol.for("react.fragment"),m=Object.prototype.hasOwnProperty,n=f.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,p={key:!0,ref:!0,__self:!0,__source:!0};
|
|
4731
|
+
function q(c,a,g){var b,d={},e=null,h=null;void 0!==g&&(e=""+g);void 0!==a.key&&(e=""+a.key);void 0!==a.ref&&(h=a.ref);for(b in a)m.call(a,b)&&!p.hasOwnProperty(b)&&(d[b]=a[b]);if(c&&c.defaultProps)for(b in a=c.defaultProps,a)void 0===d[b]&&(d[b]=a[b]);return {$$typeof:k,type:c,key:e,ref:h,props:d,_owner:n.current}}reactJsxRuntime_production_min.Fragment=l;reactJsxRuntime_production_min.jsx=q;reactJsxRuntime_production_min.jsxs=q;
|
|
4732
|
+
|
|
4733
|
+
{
|
|
4734
|
+
jsxRuntime.exports = reactJsxRuntime_production_min;
|
|
4735
|
+
}
|
|
4736
|
+
|
|
4737
|
+
var jsxRuntimeExports = jsxRuntime.exports;
|
|
4738
|
+
|
|
4511
4739
|
/**
|
|
4512
4740
|
* @typedef {import('mdast').Nodes} Nodes
|
|
4513
4741
|
*
|
|
@@ -55074,24 +55302,91 @@
|
|
|
55074
55302
|
}
|
|
55075
55303
|
};
|
|
55076
55304
|
|
|
55305
|
+
const IS_BROWSER = typeof window !== "undefined";
|
|
55306
|
+
const SYSTEM_FONT_FAMILIES = new Set(["Arial", "Helvetica", "Times New Roman", "Georgia", "Courier New", "Verdana", "Trebuchet MS", "Palatino", "Garamond", "Tahoma", "Lucida Sans", "Lucida Grande", "Lucida Console", "Gill Sans", "Impact", "Comic Sans MS", "system-ui"].map(font => font.toLowerCase()));
|
|
55307
|
+
const GENERIC_FONT_KEYWORDS = ["sans-serif", "serif", "monospace", "cursive", "fantasy"];
|
|
55308
|
+
const GOOGLE_FONT_WEIGHTS = "300,400,500,600,700";
|
|
55309
|
+
const loadedFonts = new Set();
|
|
55310
|
+
let webFontLoaderPromise = null;
|
|
55311
|
+
const shouldSkipLoading = fontFamily => {
|
|
55312
|
+
const normalized = fontFamily.trim().toLowerCase();
|
|
55313
|
+
if (!normalized) return true;
|
|
55314
|
+
if (SYSTEM_FONT_FAMILIES.has(normalized)) return true;
|
|
55315
|
+
return GENERIC_FONT_KEYWORDS.some(keyword => normalized.includes(keyword));
|
|
55316
|
+
};
|
|
55317
|
+
const toGoogleFontQuery = fontFamily => fontFamily.trim().replace(/\s+/g, "+");
|
|
55318
|
+
function useGoogleFont(fontFamily) {
|
|
55319
|
+
reactExports.useEffect(() => {
|
|
55320
|
+
var _fontFamily$split$;
|
|
55321
|
+
if (!IS_BROWSER || !fontFamily) {
|
|
55322
|
+
return;
|
|
55323
|
+
}
|
|
55324
|
+
const baseFont = (_fontFamily$split$ = fontFamily.split(",")[0]) === null || _fontFamily$split$ === void 0 ? void 0 : _fontFamily$split$.trim();
|
|
55325
|
+
if (!baseFont || loadedFonts.has(baseFont)) {
|
|
55326
|
+
return;
|
|
55327
|
+
}
|
|
55328
|
+
if (shouldSkipLoading(baseFont)) {
|
|
55329
|
+
loadedFonts.add(baseFont);
|
|
55330
|
+
return;
|
|
55331
|
+
}
|
|
55332
|
+
let isMounted = true;
|
|
55333
|
+
const loadFont = async () => {
|
|
55334
|
+
try {
|
|
55335
|
+
if (!webFontLoaderPromise) {
|
|
55336
|
+
webFontLoaderPromise = Promise.resolve().then(function () { return webfontloader; });
|
|
55337
|
+
}
|
|
55338
|
+
const webFontModule = await webFontLoaderPromise;
|
|
55339
|
+
const WebFont = webFontModule && "default" in webFontModule ? webFontModule.default : webFontModule;
|
|
55340
|
+
const googleQuery = toGoogleFontQuery(baseFont);
|
|
55341
|
+
WebFont.load({
|
|
55342
|
+
google: {
|
|
55343
|
+
families: ["".concat(googleQuery, ":").concat(GOOGLE_FONT_WEIGHTS)]
|
|
55344
|
+
},
|
|
55345
|
+
fontactive: family => {
|
|
55346
|
+
if (isMounted) {
|
|
55347
|
+
loadedFonts.add(family);
|
|
55348
|
+
}
|
|
55349
|
+
},
|
|
55350
|
+
fontinactive: family => {
|
|
55351
|
+
if (isMounted) {
|
|
55352
|
+
loadedFonts.add(family);
|
|
55353
|
+
}
|
|
55354
|
+
console.warn("Warning: failed to load Google Font: ".concat(family));
|
|
55355
|
+
}
|
|
55356
|
+
});
|
|
55357
|
+
} catch (error) {
|
|
55358
|
+
console.error("Warning: WebFont loader error:", error);
|
|
55359
|
+
}
|
|
55360
|
+
};
|
|
55361
|
+
void loadFont();
|
|
55362
|
+
return () => {
|
|
55363
|
+
isMounted = false;
|
|
55364
|
+
};
|
|
55365
|
+
}, [fontFamily]);
|
|
55366
|
+
}
|
|
55367
|
+
|
|
55077
55368
|
const _excluded = ["node", "children"],
|
|
55078
55369
|
_excluded2 = ["node", "children"],
|
|
55079
55370
|
_excluded3 = ["node", "children"],
|
|
55080
55371
|
_excluded4 = ["node", "children"],
|
|
55081
|
-
_excluded5 = ["
|
|
55372
|
+
_excluded5 = ["node", "children"],
|
|
55082
55373
|
_excluded6 = ["node", "children"],
|
|
55083
55374
|
_excluded7 = ["node", "children"],
|
|
55084
55375
|
_excluded8 = ["node", "children"],
|
|
55085
55376
|
_excluded9 = ["node", "children"],
|
|
55086
55377
|
_excluded0 = ["node", "children"],
|
|
55087
55378
|
_excluded1 = ["node", "children"],
|
|
55088
|
-
_excluded10 = ["node", "children"]
|
|
55379
|
+
_excluded10 = ["node", "children"],
|
|
55380
|
+
_excluded11 = ["className", "children"];
|
|
55089
55381
|
const StreamingMarkdown = _ref => {
|
|
55090
55382
|
let {
|
|
55091
55383
|
content,
|
|
55092
55384
|
isStreaming,
|
|
55093
55385
|
isDark = false,
|
|
55094
|
-
isRtl = false
|
|
55386
|
+
isRtl = false,
|
|
55387
|
+
textColor,
|
|
55388
|
+
fontFamily,
|
|
55389
|
+
fontSize
|
|
55095
55390
|
} = _ref;
|
|
55096
55391
|
const [displayedContent, setDisplayedContent] = reactExports.useState("");
|
|
55097
55392
|
const [showCursor, setShowCursor] = reactExports.useState(false);
|
|
@@ -55100,19 +55395,23 @@
|
|
|
55100
55395
|
const animationFrameRef = reactExports.useRef(null);
|
|
55101
55396
|
const lastUpdateRef = reactExports.useRef(0);
|
|
55102
55397
|
reactExports.useEffect(() => {
|
|
55398
|
+
// Reset if content changes significantly
|
|
55103
55399
|
if (content !== contentRef.current) {
|
|
55104
55400
|
contentRef.current = content;
|
|
55401
|
+
// If we're already past the new content length, show it all
|
|
55105
55402
|
if (indexRef.current >= content.length) {
|
|
55106
55403
|
setDisplayedContent(content);
|
|
55107
55404
|
setShowCursor(false);
|
|
55108
55405
|
return;
|
|
55109
55406
|
}
|
|
55407
|
+
// If new content is shorter, reset
|
|
55110
55408
|
if (content.length < displayedContent.length) {
|
|
55111
55409
|
indexRef.current = 0;
|
|
55112
55410
|
setDisplayedContent("");
|
|
55113
55411
|
}
|
|
55114
55412
|
}
|
|
55115
55413
|
if (!isStreaming) {
|
|
55414
|
+
// Not streaming - show full content immediately
|
|
55116
55415
|
setDisplayedContent(content);
|
|
55117
55416
|
setShowCursor(false);
|
|
55118
55417
|
if (animationFrameRef.current) {
|
|
@@ -55120,20 +55419,25 @@
|
|
|
55120
55419
|
}
|
|
55121
55420
|
return;
|
|
55122
55421
|
}
|
|
55422
|
+
|
|
55423
|
+
// Streaming mode - animate character by character
|
|
55123
55424
|
setShowCursor(true);
|
|
55124
55425
|
const animate = timestamp => {
|
|
55426
|
+
// Throttle updates for smooth 60fps animation
|
|
55125
55427
|
if (timestamp - lastUpdateRef.current < 16) {
|
|
55126
55428
|
animationFrameRef.current = requestAnimationFrame(animate);
|
|
55127
55429
|
return;
|
|
55128
55430
|
}
|
|
55129
55431
|
lastUpdateRef.current = timestamp;
|
|
55130
55432
|
if (indexRef.current < content.length) {
|
|
55433
|
+
// Add 2-5 characters per frame for natural speed
|
|
55131
55434
|
const charsToAdd = Math.max(2, Math.floor(Math.random() * 4));
|
|
55132
55435
|
const newIndex = Math.min(indexRef.current + charsToAdd, content.length);
|
|
55133
55436
|
setDisplayedContent(content.slice(0, newIndex));
|
|
55134
55437
|
indexRef.current = newIndex;
|
|
55135
55438
|
animationFrameRef.current = requestAnimationFrame(animate);
|
|
55136
55439
|
} else {
|
|
55440
|
+
// Finished streaming
|
|
55137
55441
|
setShowCursor(false);
|
|
55138
55442
|
}
|
|
55139
55443
|
};
|
|
@@ -55143,7 +55447,7 @@
|
|
|
55143
55447
|
cancelAnimationFrame(animationFrameRef.current);
|
|
55144
55448
|
}
|
|
55145
55449
|
};
|
|
55146
|
-
}, [content,
|
|
55450
|
+
}, [content, isStreaming]);
|
|
55147
55451
|
return /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
|
|
55148
55452
|
className: "relative",
|
|
55149
55453
|
style: {
|
|
@@ -55152,126 +55456,142 @@
|
|
|
55152
55456
|
},
|
|
55153
55457
|
children: [/*#__PURE__*/jsxRuntimeExports.jsx(Markdown, {
|
|
55154
55458
|
remarkPlugins: [remarkGfm],
|
|
55155
|
-
className: "
|
|
55459
|
+
className: "prose prose-sm max-w-none [&>*:last-child]:!mb-0 [&>*:first-child]:!mt-0",
|
|
55460
|
+
style: {
|
|
55461
|
+
color: textColor || (isDark ? "#f3f4f6" : "#1A1A1A"),
|
|
55462
|
+
fontFamily: fontFamily || "Inter",
|
|
55463
|
+
fontSize: fontSize || "14px",
|
|
55464
|
+
margin: 0,
|
|
55465
|
+
padding: 0
|
|
55466
|
+
},
|
|
55156
55467
|
components: {
|
|
55157
|
-
|
|
55468
|
+
a(_ref2) {
|
|
55158
55469
|
let {
|
|
55159
55470
|
node,
|
|
55160
55471
|
children
|
|
55161
55472
|
} = _ref2,
|
|
55162
55473
|
props = _objectWithoutProperties$1(_ref2, _excluded);
|
|
55163
|
-
return /*#__PURE__*/jsxRuntimeExports.jsx("
|
|
55164
|
-
className:
|
|
55474
|
+
return /*#__PURE__*/jsxRuntimeExports.jsx("a", _objectSpread2(_objectSpread2({
|
|
55475
|
+
className: isDark ? "text-blue-400 hover:text-blue-300 hover:underline" : "text-blue-600 hover:underline",
|
|
55476
|
+
target: "_blank",
|
|
55477
|
+
rel: "noopener noreferrer"
|
|
55165
55478
|
}, props), {}, {
|
|
55166
55479
|
children: children
|
|
55167
55480
|
}));
|
|
55168
55481
|
},
|
|
55169
|
-
|
|
55482
|
+
p(_ref3) {
|
|
55170
55483
|
let {
|
|
55171
55484
|
node,
|
|
55172
55485
|
children
|
|
55173
55486
|
} = _ref3,
|
|
55174
55487
|
props = _objectWithoutProperties$1(_ref3, _excluded2);
|
|
55175
|
-
return /*#__PURE__*/jsxRuntimeExports.jsx("
|
|
55176
|
-
className: "
|
|
55488
|
+
return /*#__PURE__*/jsxRuntimeExports.jsx("p", _objectSpread2(_objectSpread2({
|
|
55489
|
+
className: "leading-relaxed [&:not(:last-child)]:mb-2 [&:first-child]:!mt-0",
|
|
55490
|
+
style: {
|
|
55491
|
+
color: textColor || (isDark ? "#f3f4f6" : "#1A1A1A"),
|
|
55492
|
+
fontFamily: fontFamily || "Inter",
|
|
55493
|
+
fontSize: fontSize || "14px",
|
|
55494
|
+
margin: 0,
|
|
55495
|
+
marginTop: 0,
|
|
55496
|
+
padding: 0
|
|
55497
|
+
}
|
|
55177
55498
|
}, props), {}, {
|
|
55178
55499
|
children: children
|
|
55179
55500
|
}));
|
|
55180
55501
|
},
|
|
55181
|
-
|
|
55502
|
+
ul(_ref4) {
|
|
55182
55503
|
let {
|
|
55183
55504
|
node,
|
|
55184
55505
|
children
|
|
55185
55506
|
} = _ref4,
|
|
55186
55507
|
props = _objectWithoutProperties$1(_ref4, _excluded3);
|
|
55187
|
-
return /*#__PURE__*/jsxRuntimeExports.jsx("
|
|
55188
|
-
className: "
|
|
55508
|
+
return /*#__PURE__*/jsxRuntimeExports.jsx("ul", _objectSpread2(_objectSpread2({
|
|
55509
|
+
className: "list-disc pl-5 space-y-1 [&:first-child]:!mt-0",
|
|
55510
|
+
style: {
|
|
55511
|
+
marginTop: 0
|
|
55512
|
+
}
|
|
55189
55513
|
}, props), {}, {
|
|
55190
55514
|
children: children
|
|
55191
55515
|
}));
|
|
55192
55516
|
},
|
|
55193
|
-
|
|
55517
|
+
ol(_ref5) {
|
|
55194
55518
|
let {
|
|
55195
55519
|
node,
|
|
55196
55520
|
children
|
|
55197
55521
|
} = _ref5,
|
|
55198
55522
|
props = _objectWithoutProperties$1(_ref5, _excluded4);
|
|
55199
|
-
return /*#__PURE__*/jsxRuntimeExports.jsx("
|
|
55200
|
-
className: "
|
|
55523
|
+
return /*#__PURE__*/jsxRuntimeExports.jsx("ol", _objectSpread2(_objectSpread2({
|
|
55524
|
+
className: "list-decimal pl-5 space-y-1 [&:first-child]:!mt-0",
|
|
55525
|
+
style: {
|
|
55526
|
+
marginTop: 0
|
|
55527
|
+
}
|
|
55201
55528
|
}, props), {}, {
|
|
55202
55529
|
children: children
|
|
55203
55530
|
}));
|
|
55204
55531
|
},
|
|
55205
|
-
|
|
55532
|
+
li(_ref6) {
|
|
55206
55533
|
let {
|
|
55207
|
-
|
|
55534
|
+
node,
|
|
55208
55535
|
children
|
|
55209
55536
|
} = _ref6,
|
|
55210
55537
|
props = _objectWithoutProperties$1(_ref6, _excluded5);
|
|
55211
|
-
|
|
55212
|
-
|
|
55213
|
-
|
|
55214
|
-
|
|
55215
|
-
|
|
55216
|
-
|
|
55217
|
-
|
|
55218
|
-
}, props), {}, {
|
|
55219
|
-
children: String(children).replace(/\n$/, "")
|
|
55220
|
-
}));
|
|
55221
|
-
}
|
|
55222
|
-
return /*#__PURE__*/jsxRuntimeExports.jsx("code", _objectSpread2(_objectSpread2({
|
|
55223
|
-
className: className
|
|
55538
|
+
return /*#__PURE__*/jsxRuntimeExports.jsx("li", _objectSpread2(_objectSpread2({
|
|
55539
|
+
className: "mb-1",
|
|
55540
|
+
style: {
|
|
55541
|
+
color: textColor || (isDark ? "#f3f4f6" : "#1A1A1A"),
|
|
55542
|
+
fontFamily: fontFamily || "Inter",
|
|
55543
|
+
fontSize: fontSize || "14px"
|
|
55544
|
+
}
|
|
55224
55545
|
}, props), {}, {
|
|
55225
55546
|
children: children
|
|
55226
55547
|
}));
|
|
55227
55548
|
},
|
|
55228
|
-
|
|
55549
|
+
h1(_ref7) {
|
|
55229
55550
|
let {
|
|
55230
55551
|
node,
|
|
55231
55552
|
children
|
|
55232
55553
|
} = _ref7,
|
|
55233
55554
|
props = _objectWithoutProperties$1(_ref7, _excluded6);
|
|
55234
|
-
return /*#__PURE__*/jsxRuntimeExports.jsx("
|
|
55235
|
-
className:
|
|
55236
|
-
|
|
55237
|
-
|
|
55555
|
+
return /*#__PURE__*/jsxRuntimeExports.jsx("h1", _objectSpread2(_objectSpread2({
|
|
55556
|
+
className: "text-xl font-bold mb-2 [&:first-child]:!mt-0",
|
|
55557
|
+
style: {
|
|
55558
|
+
color: textColor || (isDark ? "#f3f4f6" : "#1A1A1A"),
|
|
55559
|
+
fontFamily: fontFamily || "Inter",
|
|
55560
|
+
marginTop: "0.75rem"
|
|
55561
|
+
}
|
|
55238
55562
|
}, props), {}, {
|
|
55239
55563
|
children: children
|
|
55240
55564
|
}));
|
|
55241
55565
|
},
|
|
55242
|
-
|
|
55566
|
+
h2(_ref8) {
|
|
55243
55567
|
let {
|
|
55244
55568
|
node,
|
|
55245
55569
|
children
|
|
55246
55570
|
} = _ref8,
|
|
55247
55571
|
props = _objectWithoutProperties$1(_ref8, _excluded7);
|
|
55248
|
-
return /*#__PURE__*/jsxRuntimeExports.jsx("
|
|
55249
|
-
className: "
|
|
55572
|
+
return /*#__PURE__*/jsxRuntimeExports.jsx("h2", _objectSpread2(_objectSpread2({
|
|
55573
|
+
className: "text-lg font-semibold mb-2 [&:first-child]:!mt-0",
|
|
55250
55574
|
style: {
|
|
55251
|
-
|
|
55252
|
-
|
|
55253
|
-
|
|
55254
|
-
marginTop: "0.5rem",
|
|
55255
|
-
marginBottom: "0.5rem"
|
|
55575
|
+
color: textColor || (isDark ? "#f3f4f6" : "#1A1A1A"),
|
|
55576
|
+
fontFamily: fontFamily || "Inter",
|
|
55577
|
+
marginTop: "0.75rem"
|
|
55256
55578
|
}
|
|
55257
55579
|
}, props), {}, {
|
|
55258
55580
|
children: children
|
|
55259
55581
|
}));
|
|
55260
55582
|
},
|
|
55261
|
-
|
|
55583
|
+
h3(_ref9) {
|
|
55262
55584
|
let {
|
|
55263
55585
|
node,
|
|
55264
55586
|
children
|
|
55265
55587
|
} = _ref9,
|
|
55266
55588
|
props = _objectWithoutProperties$1(_ref9, _excluded8);
|
|
55267
|
-
return /*#__PURE__*/jsxRuntimeExports.jsx("
|
|
55268
|
-
className: "
|
|
55589
|
+
return /*#__PURE__*/jsxRuntimeExports.jsx("h3", _objectSpread2(_objectSpread2({
|
|
55590
|
+
className: "text-base font-semibold mb-2 [&:first-child]:!mt-0",
|
|
55269
55591
|
style: {
|
|
55270
|
-
|
|
55271
|
-
|
|
55272
|
-
|
|
55273
|
-
marginTop: "0.5rem",
|
|
55274
|
-
marginBottom: "0.5rem"
|
|
55592
|
+
color: textColor || (isDark ? "#f3f4f6" : "#1A1A1A"),
|
|
55593
|
+
fontFamily: fontFamily || "Inter",
|
|
55594
|
+
marginTop: "0.75rem"
|
|
55275
55595
|
}
|
|
55276
55596
|
}, props), {}, {
|
|
55277
55597
|
children: children
|
|
@@ -55327,6 +55647,29 @@
|
|
|
55327
55647
|
}, props), {}, {
|
|
55328
55648
|
children: children
|
|
55329
55649
|
}));
|
|
55650
|
+
},
|
|
55651
|
+
code(_ref12) {
|
|
55652
|
+
let {
|
|
55653
|
+
className,
|
|
55654
|
+
children
|
|
55655
|
+
} = _ref12,
|
|
55656
|
+
props = _objectWithoutProperties$1(_ref12, _excluded11);
|
|
55657
|
+
const match = /language-(\w+)/.exec(className || "");
|
|
55658
|
+
if (match) {
|
|
55659
|
+
return /*#__PURE__*/jsxRuntimeExports.jsx(SyntaxHighlighter, _objectSpread2(_objectSpread2({
|
|
55660
|
+
style: oneDark,
|
|
55661
|
+
language: match[1],
|
|
55662
|
+
PreTag: "div",
|
|
55663
|
+
wrapLines: true
|
|
55664
|
+
}, props), {}, {
|
|
55665
|
+
children: String(children).replace(/\n$/, "")
|
|
55666
|
+
}));
|
|
55667
|
+
}
|
|
55668
|
+
return /*#__PURE__*/jsxRuntimeExports.jsx("code", _objectSpread2(_objectSpread2({
|
|
55669
|
+
className: className
|
|
55670
|
+
}, props), {}, {
|
|
55671
|
+
children: children
|
|
55672
|
+
}));
|
|
55330
55673
|
}
|
|
55331
55674
|
},
|
|
55332
55675
|
children: displayedContent
|
|
@@ -55338,34 +55681,54 @@
|
|
|
55338
55681
|
})]
|
|
55339
55682
|
});
|
|
55340
55683
|
};
|
|
55341
|
-
const TypingIndicator =
|
|
55342
|
-
let {
|
|
55343
|
-
isDark
|
|
55344
|
-
} = _ref12;
|
|
55684
|
+
const TypingIndicator = _ref13 => {
|
|
55345
55685
|
return /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
|
|
55346
55686
|
className: "flex gap-1.5",
|
|
55347
55687
|
children: [/*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
55348
55688
|
className: "w-2 h-2 rounded-full bg-gray-400 animate-bounce",
|
|
55349
55689
|
style: {
|
|
55350
|
-
animationDelay: "0ms"
|
|
55351
|
-
backgroundColor: isDark ? "#9CA3AF" : "#9CA3AF"
|
|
55690
|
+
animationDelay: "0ms"
|
|
55352
55691
|
}
|
|
55353
55692
|
}), /*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
55354
55693
|
className: "w-2 h-2 rounded-full bg-gray-400 animate-bounce",
|
|
55355
55694
|
style: {
|
|
55356
|
-
animationDelay: "150ms"
|
|
55357
|
-
backgroundColor: isDark ? "#9CA3AF" : "#9CA3AF"
|
|
55695
|
+
animationDelay: "150ms"
|
|
55358
55696
|
}
|
|
55359
55697
|
}), /*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
55360
55698
|
className: "w-2 h-2 rounded-full bg-gray-400 animate-bounce",
|
|
55361
55699
|
style: {
|
|
55362
|
-
animationDelay: "300ms"
|
|
55363
|
-
backgroundColor: isDark ? "#9CA3AF" : "#9CA3AF"
|
|
55700
|
+
animationDelay: "300ms"
|
|
55364
55701
|
}
|
|
55365
55702
|
})]
|
|
55366
55703
|
});
|
|
55367
55704
|
};
|
|
55368
|
-
|
|
55705
|
+
|
|
55706
|
+
// Decision widget component for HITL (Human-in-the-Loop)
|
|
55707
|
+
const DecisionWidget = _ref14 => {
|
|
55708
|
+
let {
|
|
55709
|
+
question,
|
|
55710
|
+
options,
|
|
55711
|
+
onDecision,
|
|
55712
|
+
disabled,
|
|
55713
|
+
isDark = false
|
|
55714
|
+
} = _ref14;
|
|
55715
|
+
return /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
|
|
55716
|
+
className: "mt-3 p-3 rounded-lg border ".concat(isDark ? "bg-blue-900/30 border-blue-700/50" : "bg-blue-50 border-blue-200"),
|
|
55717
|
+
children: [/*#__PURE__*/jsxRuntimeExports.jsx("p", {
|
|
55718
|
+
className: "text-sm font-medium mb-2 ".concat(isDark ? "text-gray-100" : "text-gray-900"),
|
|
55719
|
+
children: question
|
|
55720
|
+
}), /*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
55721
|
+
className: "space-y-2",
|
|
55722
|
+
children: options.map(option => /*#__PURE__*/jsxRuntimeExports.jsx("button", {
|
|
55723
|
+
onClick: () => onDecision(option.id, option.label),
|
|
55724
|
+
disabled: disabled,
|
|
55725
|
+
className: "w-full text-left px-3 py-2 text-sm rounded transition-all ".concat(isDark ? "bg-gray-800 border border-gray-700 hover:bg-blue-900/50 hover:border-blue-600 disabled:opacity-50 disabled:cursor-not-allowed" : "bg-white border border-gray-300 hover:bg-blue-50 hover:border-blue-400 disabled:opacity-50 disabled:cursor-not-allowed"),
|
|
55726
|
+
children: option.label
|
|
55727
|
+
}, option.id))
|
|
55728
|
+
})]
|
|
55729
|
+
});
|
|
55730
|
+
};
|
|
55731
|
+
const AssistantMessage = _ref15 => {
|
|
55369
55732
|
let {
|
|
55370
55733
|
message,
|
|
55371
55734
|
formatTime,
|
|
@@ -55373,28 +55736,47 @@
|
|
|
55373
55736
|
primaryColor,
|
|
55374
55737
|
agentMessageBubbleColor,
|
|
55375
55738
|
textColor,
|
|
55739
|
+
assistantTextColor,
|
|
55376
55740
|
fontFamily,
|
|
55377
55741
|
fontSize,
|
|
55378
|
-
isRtl
|
|
55379
|
-
|
|
55742
|
+
isRtl,
|
|
55743
|
+
onDecision,
|
|
55744
|
+
companyLogo,
|
|
55745
|
+
conciergeName,
|
|
55746
|
+
companyName
|
|
55747
|
+
} = _ref15;
|
|
55380
55748
|
const displayContent = typeof message.content === "string" ? message.content : "";
|
|
55381
55749
|
const isTypingMessage = message.isProcessing && (!displayContent || displayContent.length === 0);
|
|
55382
|
-
const bubbleColor = agentMessageBubbleColor
|
|
55383
|
-
const messageTextColor = textColor
|
|
55384
|
-
const messageFontFamily = fontFamily
|
|
55385
|
-
const messageFontSize = fontSize
|
|
55750
|
+
const bubbleColor = agentMessageBubbleColor !== undefined && agentMessageBubbleColor !== null ? agentMessageBubbleColor : isDark ? "#1f2937" : "#FFFFFF";
|
|
55751
|
+
const messageTextColor = assistantTextColor !== undefined && assistantTextColor !== null ? assistantTextColor : textColor !== undefined && textColor !== null ? textColor : isDark ? "#f3f4f6" : "#1A1A1A";
|
|
55752
|
+
const messageFontFamily = fontFamily !== undefined && fontFamily !== null ? fontFamily : "Inter";
|
|
55753
|
+
const messageFontSize = fontSize !== undefined && fontSize !== null ? fontSize : "14px";
|
|
55386
55754
|
useGoogleFont(messageFontFamily);
|
|
55387
55755
|
return /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
|
|
55388
55756
|
className: "flex gap-3 flex-row animate-in",
|
|
55389
55757
|
children: [/*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
55390
55758
|
className: "flex-shrink-0 mt-1",
|
|
55391
55759
|
children: /*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
55392
|
-
className: "w-8 h-8 rounded-full flex items-center justify-center ".concat(isDark ? "bg-gray-700" : "bg-gray-200"),
|
|
55393
|
-
children: /*#__PURE__*/jsxRuntimeExports.jsx(
|
|
55394
|
-
className: "w-
|
|
55760
|
+
className: "w-8 h-8 rounded-full flex items-center justify-center overflow-hidden ".concat(isDark ? "bg-gray-700" : "bg-gray-200"),
|
|
55761
|
+
children: companyLogo ? /*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
55762
|
+
className: "w-full h-full flex items-center justify-center",
|
|
55763
|
+
children: /*#__PURE__*/jsxRuntimeExports.jsx("img", {
|
|
55764
|
+
src: companyLogo,
|
|
55765
|
+
alt: "Company logo",
|
|
55766
|
+
className: "w-full h-full object-cover rounded-full",
|
|
55767
|
+
style: {
|
|
55768
|
+
maxWidth: "100%",
|
|
55769
|
+
maxHeight: "100%"
|
|
55770
|
+
}
|
|
55771
|
+
})
|
|
55772
|
+
}) : /*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
55773
|
+
className: "w-full h-full flex items-center justify-center text-white font-semibold",
|
|
55395
55774
|
style: {
|
|
55396
|
-
|
|
55397
|
-
|
|
55775
|
+
backgroundColor: primaryColor,
|
|
55776
|
+
fontSize: "14px",
|
|
55777
|
+
fontFamily: fontFamily || "Inter"
|
|
55778
|
+
},
|
|
55779
|
+
children: (conciergeName || companyName || "A").charAt(0).toUpperCase()
|
|
55398
55780
|
})
|
|
55399
55781
|
})
|
|
55400
55782
|
}), /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
|
|
@@ -55411,35 +55793,64 @@
|
|
|
55411
55793
|
},
|
|
55412
55794
|
children: isTypingMessage ? /*#__PURE__*/jsxRuntimeExports.jsx(TypingIndicator, {
|
|
55413
55795
|
isDark: isDark
|
|
55414
|
-
}) :
|
|
55415
|
-
|
|
55416
|
-
|
|
55417
|
-
|
|
55418
|
-
|
|
55419
|
-
|
|
55796
|
+
}) : /*#__PURE__*/jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, {
|
|
55797
|
+
children: message.requiresDecision && message.decisionData && onDecision ? /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
|
|
55798
|
+
children: [displayContent && /*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
55799
|
+
className: "mb-3",
|
|
55800
|
+
children: /*#__PURE__*/jsxRuntimeExports.jsx(StreamingMarkdown, {
|
|
55801
|
+
content: displayContent,
|
|
55802
|
+
isStreaming: message.isProcessing,
|
|
55803
|
+
isDark: isDark,
|
|
55804
|
+
isRtl: isRtl,
|
|
55805
|
+
textColor: messageTextColor,
|
|
55806
|
+
fontFamily: messageFontFamily,
|
|
55807
|
+
fontSize: messageFontSize
|
|
55808
|
+
})
|
|
55809
|
+
}), /*#__PURE__*/jsxRuntimeExports.jsx(DecisionWidget, {
|
|
55810
|
+
question: message.decisionData.question,
|
|
55811
|
+
options: message.decisionData.options,
|
|
55812
|
+
onDecision: (optionId, optionValue) => onDecision(message.decisionData.decisionId, optionId, optionValue),
|
|
55813
|
+
disabled: !!message.decisionResponse,
|
|
55814
|
+
isDark: isDark
|
|
55815
|
+
}), message.decisionResponse && /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
|
|
55816
|
+
className: "mt-2 text-xs ".concat(isDark ? "text-gray-400" : "text-gray-500"),
|
|
55817
|
+
children: ["Selected: ", message.decisionResponse.selectedOption]
|
|
55818
|
+
})]
|
|
55819
|
+
}) : displayContent ? /*#__PURE__*/jsxRuntimeExports.jsx(StreamingMarkdown, {
|
|
55820
|
+
content: displayContent,
|
|
55821
|
+
isStreaming: message.isProcessing,
|
|
55822
|
+
isDark: isDark,
|
|
55823
|
+
isRtl: isRtl,
|
|
55824
|
+
textColor: messageTextColor,
|
|
55825
|
+
fontFamily: messageFontFamily,
|
|
55826
|
+
fontSize: messageFontSize
|
|
55827
|
+
}) : null
|
|
55828
|
+
})
|
|
55420
55829
|
}), /*#__PURE__*/jsxRuntimeExports.jsx("p", {
|
|
55421
55830
|
className: "text-[11px] mt-1.5 px-1 ".concat(isDark ? "text-gray-500" : "text-gray-400"),
|
|
55831
|
+
dir: "ltr",
|
|
55422
55832
|
children: formatTime(message.timestamp)
|
|
55423
55833
|
})]
|
|
55424
55834
|
})]
|
|
55425
55835
|
});
|
|
55426
55836
|
};
|
|
55427
|
-
const UserMessage =
|
|
55837
|
+
const UserMessage = _ref16 => {
|
|
55428
55838
|
let {
|
|
55429
55839
|
message,
|
|
55430
55840
|
formatTime,
|
|
55431
55841
|
userMessageBoxColor,
|
|
55432
55842
|
primaryColor,
|
|
55433
55843
|
textColor,
|
|
55844
|
+
userTextColor,
|
|
55434
55845
|
fontFamily,
|
|
55435
55846
|
fontSize,
|
|
55436
55847
|
isDark,
|
|
55437
55848
|
isRtl
|
|
55438
|
-
} =
|
|
55439
|
-
const primary = userMessageBoxColor
|
|
55440
|
-
const messageTextColor = textColor
|
|
55441
|
-
const messageFontFamily = fontFamily
|
|
55442
|
-
const messageFontSize = fontSize
|
|
55849
|
+
} = _ref16;
|
|
55850
|
+
const primary = userMessageBoxColor !== undefined && userMessageBoxColor !== null ? userMessageBoxColor : primaryColor !== undefined && primaryColor !== null ? primaryColor : "#2563eb";
|
|
55851
|
+
const messageTextColor = userTextColor !== undefined && userTextColor !== null ? userTextColor : textColor !== undefined && textColor !== null ? textColor : "#FFFFFF";
|
|
55852
|
+
const messageFontFamily = fontFamily !== undefined && fontFamily !== null ? fontFamily : "Inter";
|
|
55853
|
+
const messageFontSize = fontSize !== undefined && fontSize !== null ? fontSize : "14px";
|
|
55443
55854
|
useGoogleFont(messageFontFamily);
|
|
55444
55855
|
return /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
|
|
55445
55856
|
className: "flex gap-3 flex-row-reverse animate-in",
|
|
@@ -55458,26 +55869,31 @@
|
|
|
55458
55869
|
style: {
|
|
55459
55870
|
background: "linear-gradient(135deg, ".concat(primary, " 0%, ").concat(primary, "dd 100%)"),
|
|
55460
55871
|
fontFamily: messageFontFamily,
|
|
55461
|
-
fontSize: messageFontSize,
|
|
55462
55872
|
textAlign: isRtl ? "right" : "left",
|
|
55463
55873
|
direction: isRtl ? "rtl" : "ltr"
|
|
55464
55874
|
},
|
|
55465
55875
|
children: /*#__PURE__*/jsxRuntimeExports.jsx("p", {
|
|
55466
|
-
className: "
|
|
55876
|
+
className: "whitespace-pre-wrap break-words",
|
|
55467
55877
|
style: {
|
|
55468
55878
|
color: messageTextColor,
|
|
55469
|
-
|
|
55879
|
+
fontFamily: messageFontFamily,
|
|
55880
|
+
fontSize: messageFontSize,
|
|
55881
|
+
lineHeight: "1.5",
|
|
55882
|
+
textAlign: isRtl ? "right" : "left",
|
|
55883
|
+
margin: 0,
|
|
55884
|
+
padding: 0
|
|
55470
55885
|
},
|
|
55471
55886
|
children: message.content
|
|
55472
55887
|
})
|
|
55473
55888
|
}), /*#__PURE__*/jsxRuntimeExports.jsx("p", {
|
|
55474
55889
|
className: "text-[11px] mt-1.5 px-1 ".concat(isDark ? "text-gray-500" : "text-gray-400"),
|
|
55890
|
+
dir: "ltr",
|
|
55475
55891
|
children: formatTime(message.timestamp)
|
|
55476
55892
|
})]
|
|
55477
55893
|
})]
|
|
55478
55894
|
});
|
|
55479
55895
|
};
|
|
55480
|
-
const MessageBubble =
|
|
55896
|
+
const MessageBubble = _ref17 => {
|
|
55481
55897
|
let {
|
|
55482
55898
|
message,
|
|
55483
55899
|
isDark,
|
|
@@ -55485,11 +55901,17 @@
|
|
|
55485
55901
|
agentMessageBubbleColor,
|
|
55486
55902
|
userMessageBoxColor,
|
|
55487
55903
|
textColor,
|
|
55904
|
+
assistantTextColor,
|
|
55905
|
+
userTextColor,
|
|
55488
55906
|
fontFamily,
|
|
55489
55907
|
fontSize,
|
|
55490
55908
|
formatTime,
|
|
55491
|
-
isRtl
|
|
55492
|
-
|
|
55909
|
+
isRtl,
|
|
55910
|
+
onDecision,
|
|
55911
|
+
companyLogo,
|
|
55912
|
+
conciergeName,
|
|
55913
|
+
companyName
|
|
55914
|
+
} = _ref17;
|
|
55493
55915
|
if (!message) {
|
|
55494
55916
|
return null;
|
|
55495
55917
|
}
|
|
@@ -55500,6 +55922,7 @@
|
|
|
55500
55922
|
userMessageBoxColor: userMessageBoxColor,
|
|
55501
55923
|
primaryColor: primaryColor,
|
|
55502
55924
|
textColor: textColor,
|
|
55925
|
+
userTextColor: userTextColor,
|
|
55503
55926
|
fontFamily: fontFamily,
|
|
55504
55927
|
fontSize: fontSize,
|
|
55505
55928
|
isDark: isDark,
|
|
@@ -55513,9 +55936,14 @@
|
|
|
55513
55936
|
primaryColor: primaryColor,
|
|
55514
55937
|
agentMessageBubbleColor: agentMessageBubbleColor,
|
|
55515
55938
|
textColor: textColor,
|
|
55939
|
+
assistantTextColor: assistantTextColor,
|
|
55516
55940
|
fontFamily: fontFamily,
|
|
55517
55941
|
fontSize: fontSize,
|
|
55518
|
-
isRtl: isRtl
|
|
55942
|
+
isRtl: isRtl,
|
|
55943
|
+
onDecision: onDecision,
|
|
55944
|
+
companyLogo: companyLogo,
|
|
55945
|
+
conciergeName: conciergeName,
|
|
55946
|
+
companyName: companyName
|
|
55519
55947
|
});
|
|
55520
55948
|
};
|
|
55521
55949
|
|
|
@@ -55696,6 +56124,7 @@
|
|
|
55696
56124
|
};
|
|
55697
56125
|
};
|
|
55698
56126
|
const QuickQuestions = _ref3 => {
|
|
56127
|
+
var _ref4;
|
|
55699
56128
|
let {
|
|
55700
56129
|
questions = [],
|
|
55701
56130
|
isDark = false,
|
|
@@ -55706,12 +56135,15 @@
|
|
|
55706
56135
|
fontFamily = "Inter",
|
|
55707
56136
|
fontSize = "14px",
|
|
55708
56137
|
textColor,
|
|
55709
|
-
isRtl = false
|
|
56138
|
+
isRtl = false,
|
|
56139
|
+
questionTextColor,
|
|
56140
|
+
questionBoxColor
|
|
55710
56141
|
} = _ref3;
|
|
55711
56142
|
if (!questions.length || isTyping) {
|
|
55712
56143
|
return null;
|
|
55713
56144
|
}
|
|
55714
|
-
const resolvedTextColor =
|
|
56145
|
+
const resolvedTextColor = (_ref4 = questionTextColor !== null && questionTextColor !== void 0 ? questionTextColor : textColor) !== null && _ref4 !== void 0 ? _ref4 : isDark ? "#f3f4f6" : "#111827";
|
|
56146
|
+
const resolvedQuestionBoxColor = questionBoxColor !== null && questionBoxColor !== void 0 ? questionBoxColor : isDark ? "#374151" : "#e5e7eb";
|
|
55715
56147
|
const palette = reactExports.useMemo(() => getQuickQuestionPalette(resolvedTextColor, isDark), [resolvedTextColor, isDark]);
|
|
55716
56148
|
const applyHoverState = (element, isHover) => {
|
|
55717
56149
|
element.style.backgroundColor = isHover ? palette.hoverBackground : palette.background;
|
|
@@ -55760,11 +56192,19 @@
|
|
|
55760
56192
|
})]
|
|
55761
56193
|
});
|
|
55762
56194
|
}
|
|
55763
|
-
|
|
55764
|
-
|
|
56195
|
+
|
|
56196
|
+
// Vertical layout (default)
|
|
56197
|
+
return /*#__PURE__*/jsxRuntimeExports.jsx("div", _objectSpread2(_objectSpread2({
|
|
56198
|
+
className: "space-y-3 flex flex-col items-start pl-[50px]"
|
|
56199
|
+
}, isRtl && {
|
|
56200
|
+
style: {
|
|
56201
|
+
paddingLeft: "0",
|
|
56202
|
+
paddingRight: "50px"
|
|
56203
|
+
}
|
|
56204
|
+
}), {}, {
|
|
55765
56205
|
children: questions.map((question, index) => /*#__PURE__*/jsxRuntimeExports.jsxs("button", {
|
|
55766
56206
|
onClick: () => onQuestionClick === null || onQuestionClick === void 0 ? void 0 : onQuestionClick(question),
|
|
55767
|
-
className: "group relative text-sm px-
|
|
56207
|
+
className: "group relative text-sm px-3 py-3 rounded-2xl font-medium transition-all duration-300 hover:scale-[1.02] active:scale-[0.98] whitespace-normal max-w-[85%] overflow-hidden backdrop-blur-sm ".concat(isRtl ? "text-right" : "text-left"),
|
|
55768
56208
|
style: {
|
|
55769
56209
|
direction: isRtl ? "rtl" : "ltr",
|
|
55770
56210
|
backgroundColor: palette.background,
|
|
@@ -55778,26 +56218,61 @@
|
|
|
55778
56218
|
applyHoverState(e.currentTarget, false);
|
|
55779
56219
|
},
|
|
55780
56220
|
children: [/*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
55781
|
-
|
|
55782
|
-
|
|
56221
|
+
style: {
|
|
56222
|
+
backgroundColor: "#F5F5F5",
|
|
56223
|
+
border: "1px solid ".concat(resolvedQuestionBoxColor)
|
|
56224
|
+
},
|
|
56225
|
+
className: "absolute inset-0 transition-opacity duration-300 rounded-2xl"
|
|
56226
|
+
}), /*#__PURE__*/jsxRuntimeExports.jsx("span", {
|
|
55783
56227
|
className: "relative z-10 flex items-center gap-2.5 text-left",
|
|
55784
|
-
children:
|
|
55785
|
-
className: "h-4 w-4 opacity-60 group-hover:opacity-100 transition-opacity duration-300 flex-shrink-0",
|
|
55786
|
-
style: {
|
|
55787
|
-
color: primaryColor
|
|
55788
|
-
}
|
|
55789
|
-
}), /*#__PURE__*/jsxRuntimeExports.jsx("span", {
|
|
56228
|
+
children: /*#__PURE__*/jsxRuntimeExports.jsx("span", {
|
|
55790
56229
|
className: "flex-1 leading-snug ".concat(isRtl ? "text-right" : "text-left"),
|
|
55791
56230
|
style: {
|
|
55792
56231
|
direction: isRtl ? "rtl" : "ltr",
|
|
55793
|
-
color:
|
|
56232
|
+
color: "#1A1A1A",
|
|
55794
56233
|
fontFamily,
|
|
55795
56234
|
fontSize
|
|
55796
56235
|
},
|
|
55797
56236
|
children: question
|
|
55798
|
-
})
|
|
56237
|
+
})
|
|
55799
56238
|
})]
|
|
55800
56239
|
}, index))
|
|
56240
|
+
}));
|
|
56241
|
+
};
|
|
56242
|
+
|
|
56243
|
+
const LoadingState = _ref => {
|
|
56244
|
+
let {
|
|
56245
|
+
title,
|
|
56246
|
+
description,
|
|
56247
|
+
isAnimated = false
|
|
56248
|
+
} = _ref;
|
|
56249
|
+
return /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
|
|
56250
|
+
className: "flex flex-col items-center justify-center py-12 px-4",
|
|
56251
|
+
children: [isAnimated && /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
|
|
56252
|
+
className: "flex gap-1.5 mb-4",
|
|
56253
|
+
children: [/*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
56254
|
+
className: "w-2 h-2 rounded-full bg-gray-400 animate-bounce",
|
|
56255
|
+
style: {
|
|
56256
|
+
animationDelay: "0ms"
|
|
56257
|
+
}
|
|
56258
|
+
}), /*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
56259
|
+
className: "w-2 h-2 rounded-full bg-gray-400 animate-bounce",
|
|
56260
|
+
style: {
|
|
56261
|
+
animationDelay: "150ms"
|
|
56262
|
+
}
|
|
56263
|
+
}), /*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
56264
|
+
className: "w-2 h-2 rounded-full bg-gray-400 animate-bounce",
|
|
56265
|
+
style: {
|
|
56266
|
+
animationDelay: "300ms"
|
|
56267
|
+
}
|
|
56268
|
+
})]
|
|
56269
|
+
}), title && /*#__PURE__*/jsxRuntimeExports.jsx("h3", {
|
|
56270
|
+
className: "text-sm font-medium text-gray-700 dark:text-gray-300 mb-1",
|
|
56271
|
+
children: title
|
|
56272
|
+
}), description && /*#__PURE__*/jsxRuntimeExports.jsx("p", {
|
|
56273
|
+
className: "text-xs text-gray-500 dark:text-gray-400 text-center max-w-xs",
|
|
56274
|
+
children: description
|
|
56275
|
+
})]
|
|
55801
56276
|
});
|
|
55802
56277
|
};
|
|
55803
56278
|
|
|
@@ -55810,6 +56285,8 @@
|
|
|
55810
56285
|
agentMessageBubbleColor,
|
|
55811
56286
|
userMessageBoxColor,
|
|
55812
56287
|
textColor,
|
|
56288
|
+
assistantTextColor,
|
|
56289
|
+
userTextColor,
|
|
55813
56290
|
fontFamily,
|
|
55814
56291
|
fontSize,
|
|
55815
56292
|
formatTime,
|
|
@@ -55817,9 +56294,20 @@
|
|
|
55817
56294
|
quickQuestions = [],
|
|
55818
56295
|
shouldShowQuickQuestions = false,
|
|
55819
56296
|
onQuickQuestion,
|
|
55820
|
-
quickQuestionsLayout = "vertical"
|
|
56297
|
+
quickQuestionsLayout = "vertical",
|
|
56298
|
+
onDecision,
|
|
56299
|
+
disclaimerText,
|
|
56300
|
+
disclaimerPosition = "top",
|
|
56301
|
+
resolvedAgentBubbleColor,
|
|
56302
|
+
resolvedUserMessageColor,
|
|
56303
|
+
resolvedTextColor,
|
|
56304
|
+
isVoiceSessionActive = false,
|
|
56305
|
+
voiceStatus = "idle",
|
|
56306
|
+
messagesContainerRef,
|
|
56307
|
+
companyLogo,
|
|
56308
|
+
conciergeName,
|
|
56309
|
+
companyName
|
|
55821
56310
|
} = _ref;
|
|
55822
|
-
const containerRef = reactExports.useRef(null);
|
|
55823
56311
|
const messagesEndRef = reactExports.useRef(null);
|
|
55824
56312
|
const shouldAutoScrollRef = reactExports.useRef(true);
|
|
55825
56313
|
const autoScrollKey = reactExports.useMemo(() => messages.map(message => {
|
|
@@ -55827,15 +56315,15 @@
|
|
|
55827
56315
|
return "".concat(message.id, ":").concat((_message$content$leng = (_message$content = message.content) === null || _message$content === void 0 ? void 0 : _message$content.length) !== null && _message$content$leng !== void 0 ? _message$content$leng : 0, ":").concat(message.isProcessing ? 1 : 0);
|
|
55828
56316
|
}).join("|"), [messages]);
|
|
55829
56317
|
const updateAutoScrollIntent = reactExports.useCallback(() => {
|
|
55830
|
-
const container =
|
|
56318
|
+
const container = messagesContainerRef === null || messagesContainerRef === void 0 ? void 0 : messagesContainerRef.current;
|
|
55831
56319
|
if (!container) {
|
|
55832
56320
|
return;
|
|
55833
56321
|
}
|
|
55834
56322
|
const distanceFromBottom = container.scrollHeight - container.scrollTop - container.clientHeight;
|
|
55835
56323
|
shouldAutoScrollRef.current = distanceFromBottom < 160;
|
|
55836
|
-
}, []);
|
|
56324
|
+
}, [messagesContainerRef]);
|
|
55837
56325
|
reactExports.useEffect(() => {
|
|
55838
|
-
const container =
|
|
56326
|
+
const container = messagesContainerRef === null || messagesContainerRef === void 0 ? void 0 : messagesContainerRef.current;
|
|
55839
56327
|
if (!container) {
|
|
55840
56328
|
return undefined;
|
|
55841
56329
|
}
|
|
@@ -55846,7 +56334,7 @@
|
|
|
55846
56334
|
return () => {
|
|
55847
56335
|
container.removeEventListener("scroll", updateAutoScrollIntent);
|
|
55848
56336
|
};
|
|
55849
|
-
}, [updateAutoScrollIntent]);
|
|
56337
|
+
}, [updateAutoScrollIntent, messagesContainerRef]);
|
|
55850
56338
|
reactExports.useEffect(() => {
|
|
55851
56339
|
if (!shouldAutoScrollRef.current) {
|
|
55852
56340
|
return undefined;
|
|
@@ -55865,20 +56353,55 @@
|
|
|
55865
56353
|
window.cancelAnimationFrame(frame);
|
|
55866
56354
|
};
|
|
55867
56355
|
}, [autoScrollKey, isLoading]);
|
|
55868
|
-
return /*#__PURE__*/jsxRuntimeExports.jsxs(
|
|
55869
|
-
|
|
55870
|
-
|
|
55871
|
-
|
|
56356
|
+
return /*#__PURE__*/jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, {
|
|
56357
|
+
children: [isVoiceSessionActive && messages.length === 0 && /*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
56358
|
+
className: "flex flex-col items-center justify-center h-full",
|
|
56359
|
+
children: /*#__PURE__*/jsxRuntimeExports.jsx(LoadingState, {
|
|
56360
|
+
title: "Starting voice session...",
|
|
56361
|
+
description: "Allow microphone access or begin speaking to continue.",
|
|
56362
|
+
isAnimated: true
|
|
56363
|
+
})
|
|
56364
|
+
}), disclaimerText && disclaimerPosition === "top" && /*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
56365
|
+
className: "flex justify-center",
|
|
56366
|
+
children: /*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
56367
|
+
className: "rounded-lg px-2 py-1 max-w-[85%] border",
|
|
56368
|
+
style: {
|
|
56369
|
+
backgroundColor: agentMessageBubbleColor !== undefined && agentMessageBubbleColor !== null ? agentMessageBubbleColor : resolvedAgentBubbleColor || "#F5F5F5",
|
|
56370
|
+
color: assistantTextColor !== undefined && assistantTextColor !== null ? assistantTextColor : "#1A1A1A",
|
|
56371
|
+
fontFamily: fontFamily !== undefined && fontFamily !== null ? fontFamily : "Inter",
|
|
56372
|
+
fontSize: fontSize !== undefined && fontSize !== null ? "calc(".concat(fontSize, " - 2px)") : "12px",
|
|
56373
|
+
direction: isRtl ? "rtl" : "ltr",
|
|
56374
|
+
textAlign: "center",
|
|
56375
|
+
borderColor: isDark ? "#374151" : "#e5e7eb"
|
|
56376
|
+
},
|
|
56377
|
+
children: /*#__PURE__*/jsxRuntimeExports.jsx("p", {
|
|
56378
|
+
className: "leading-relaxed whitespace-pre-wrap break-words",
|
|
56379
|
+
dir: isRtl ? "rtl" : "ltr",
|
|
56380
|
+
style: {
|
|
56381
|
+
color: assistantTextColor !== undefined && assistantTextColor !== null ? assistantTextColor : "#1A1A1A",
|
|
56382
|
+
fontFamily: fontFamily !== undefined && fontFamily !== null ? fontFamily : "Inter",
|
|
56383
|
+
fontSize: fontSize !== undefined && fontSize !== null ? "calc(".concat(fontSize, " - 2px)") : "12px"
|
|
56384
|
+
},
|
|
56385
|
+
children: disclaimerText
|
|
56386
|
+
})
|
|
56387
|
+
})
|
|
56388
|
+
}), messages.map(message => /*#__PURE__*/jsxRuntimeExports.jsx(MessageBubble, {
|
|
55872
56389
|
message: message,
|
|
55873
56390
|
isDark: isDark,
|
|
55874
56391
|
primaryColor: primaryColor,
|
|
55875
56392
|
agentMessageBubbleColor: agentMessageBubbleColor,
|
|
55876
56393
|
userMessageBoxColor: userMessageBoxColor,
|
|
55877
56394
|
textColor: textColor,
|
|
56395
|
+
assistantTextColor: assistantTextColor,
|
|
56396
|
+
userTextColor: userTextColor,
|
|
55878
56397
|
fontFamily: fontFamily,
|
|
55879
56398
|
fontSize: fontSize,
|
|
55880
56399
|
formatTime: formatTime,
|
|
55881
|
-
isRtl: isRtl
|
|
56400
|
+
isRtl: isRtl,
|
|
56401
|
+
onDecision: onDecision,
|
|
56402
|
+
companyLogo: companyLogo,
|
|
56403
|
+
conciergeName: conciergeName,
|
|
56404
|
+
companyName: companyName
|
|
55882
56405
|
}, message.id)), shouldShowQuickQuestions && quickQuestions.length > 0 && /*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
55883
56406
|
className: "pt-1",
|
|
55884
56407
|
children: /*#__PURE__*/jsxRuntimeExports.jsx(QuickQuestions, {
|
|
@@ -55891,7 +56414,9 @@
|
|
|
55891
56414
|
fontFamily: fontFamily,
|
|
55892
56415
|
fontSize: fontSize,
|
|
55893
56416
|
textColor: textColor,
|
|
55894
|
-
isRtl: isRtl
|
|
56417
|
+
isRtl: isRtl,
|
|
56418
|
+
questionTextColor: assistantTextColor,
|
|
56419
|
+
questionBoxColor: agentMessageBubbleColor
|
|
55895
56420
|
})
|
|
55896
56421
|
}), /*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
55897
56422
|
ref: messagesEndRef,
|
|
@@ -55914,7 +56439,15 @@
|
|
|
55914
56439
|
textColor,
|
|
55915
56440
|
fontFamily,
|
|
55916
56441
|
fontSize,
|
|
55917
|
-
isRtl = false
|
|
56442
|
+
isRtl = false,
|
|
56443
|
+
enableVoiceInteraction = false,
|
|
56444
|
+
isVoiceSessionActive = false,
|
|
56445
|
+
voiceStatus = "idle",
|
|
56446
|
+
voiceError = null,
|
|
56447
|
+
onVoiceToggle,
|
|
56448
|
+
onBidiSubmit,
|
|
56449
|
+
disclaimerText,
|
|
56450
|
+
disclaimerPosition = "top"
|
|
55918
56451
|
} = _ref;
|
|
55919
56452
|
const textareaRef = reactExports.useRef(null);
|
|
55920
56453
|
useGoogleFont(fontFamily);
|
|
@@ -55924,17 +56457,29 @@
|
|
|
55924
56457
|
(_textareaRef$current = textareaRef.current) === null || _textareaRef$current === void 0 || _textareaRef$current.focus();
|
|
55925
56458
|
}
|
|
55926
56459
|
}, [isOpen, isMinimized]);
|
|
56460
|
+
|
|
56461
|
+
// Auto-resize textarea
|
|
55927
56462
|
reactExports.useEffect(() => {
|
|
55928
56463
|
const textarea = textareaRef.current;
|
|
55929
56464
|
if (textarea) {
|
|
56465
|
+
// Reset height to auto to get accurate scrollHeight
|
|
55930
56466
|
textarea.style.height = "auto";
|
|
55931
|
-
|
|
56467
|
+
// Calculate new height based on scrollHeight
|
|
56468
|
+
const scrollHeight = textarea.scrollHeight;
|
|
56469
|
+
// Ensure minimum height when there's text (lineHeight 1.4 means we need at least ~20px per line)
|
|
56470
|
+
const minHeightWithText = inputValue.trim().length > 0 ? 20 : 48;
|
|
56471
|
+
const newHeight = Math.max(minHeightWithText, Math.min(scrollHeight, 120));
|
|
56472
|
+
textarea.style.height = "".concat(newHeight, "px");
|
|
55932
56473
|
}
|
|
55933
56474
|
}, [inputValue]);
|
|
55934
56475
|
const handleKeyPress = event => {
|
|
55935
56476
|
if (event.key === "Enter" && !event.shiftKey) {
|
|
55936
56477
|
event.preventDefault();
|
|
55937
|
-
|
|
56478
|
+
if (isVoiceSessionActive && onBidiSubmit) {
|
|
56479
|
+
onBidiSubmit();
|
|
56480
|
+
} else {
|
|
56481
|
+
onSend();
|
|
56482
|
+
}
|
|
55938
56483
|
}
|
|
55939
56484
|
};
|
|
55940
56485
|
const handleChange = event => {
|
|
@@ -55942,15 +56487,15 @@
|
|
|
55942
56487
|
};
|
|
55943
56488
|
const isDisabled = !inputValue.trim() || isLoading;
|
|
55944
56489
|
const separatorColor = isDark ? "#374151" : "#e5e7eb";
|
|
55945
|
-
return /*#__PURE__*/jsxRuntimeExports.
|
|
56490
|
+
return /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
|
|
55946
56491
|
className: "px-5 py-4 border-t flex-shrink-0 ".concat(isDark ? "border-gray-700 bg-gray-900" : "border-gray-200 bg-white"),
|
|
55947
56492
|
style: {
|
|
55948
56493
|
borderTopColor: separatorColor,
|
|
55949
56494
|
borderTopWidth: "1px",
|
|
55950
56495
|
borderTopStyle: "solid"
|
|
55951
56496
|
},
|
|
55952
|
-
children: /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
|
|
55953
|
-
className: "flex gap-
|
|
56497
|
+
children: [/*#__PURE__*/jsxRuntimeExports.jsxs("div", {
|
|
56498
|
+
className: "flex items-center gap-1.5",
|
|
55954
56499
|
children: [/*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
55955
56500
|
className: "flex-1 flex items-center min-h-[48px] ".concat(isDark ? "bg-gray-800" : "bg-gray-50", " rounded-2xl border transition-all duration-200"),
|
|
55956
56501
|
style: {
|
|
@@ -55965,35 +56510,316 @@
|
|
|
55965
56510
|
onKeyDown: handleKeyPress,
|
|
55966
56511
|
placeholder: placeholder || "Type your message...",
|
|
55967
56512
|
rows: 1,
|
|
55968
|
-
disabled: isLoading,
|
|
56513
|
+
disabled: isLoading || isVoiceSessionActive && voiceStatus !== "connected",
|
|
55969
56514
|
dir: isRtl ? "rtl" : "ltr",
|
|
55970
|
-
className: "w-full px-4
|
|
56515
|
+
className: "w-full px-4 bg-transparent rounded-xl leading-normal ".concat(isDark ? "text-gray-100" : "text-gray-900", " placeholder-gray-400 resize-none outline-none scrollbar-hide"),
|
|
55971
56516
|
style: {
|
|
56517
|
+
height: "auto",
|
|
55972
56518
|
maxHeight: "120px",
|
|
55973
|
-
|
|
56519
|
+
minHeight: "48px",
|
|
56520
|
+
paddingTop: inputValue.trim().length > 0 ? "12px" : "0px",
|
|
56521
|
+
paddingBottom: inputValue.trim().length > 0 ? "12px" : "0px",
|
|
56522
|
+
lineHeight: inputValue.trim().length > 0 ? "1.4" : "48px",
|
|
55974
56523
|
fontFamily: fontFamily || "Inter",
|
|
55975
56524
|
fontSize: fontSize || "14px",
|
|
55976
|
-
color: textColor || (isDark ? "#
|
|
55977
|
-
textAlign: isRtl ? "right" : "left"
|
|
56525
|
+
color: textColor || (isDark ? "#F5F5F5" : "#1A1A1A"),
|
|
56526
|
+
textAlign: isRtl ? "right" : "left",
|
|
56527
|
+
direction: isRtl ? "rtl" : "ltr",
|
|
56528
|
+
wordSpacing: "0",
|
|
56529
|
+
letterSpacing: "0"
|
|
55978
56530
|
}
|
|
55979
56531
|
})
|
|
56532
|
+
}), enableVoiceInteraction && /*#__PURE__*/jsxRuntimeExports.jsx("button", {
|
|
56533
|
+
type: "button",
|
|
56534
|
+
onClick: onVoiceToggle,
|
|
56535
|
+
className: "h-10 w-10 rounded-xl flex items-center justify-center transition-all duration-200 shadow-md ".concat(isVoiceSessionActive ? "bg-red-500 text-white hover:bg-red-600" : isDark ? "bg-gray-800 text-gray-200 hover:bg-gray-700" : "bg-white text-gray-600 hover:bg-gray-100", " ").concat(voiceStatus === "connecting" ? "opacity-60 cursor-not-allowed shadow-none" : ""),
|
|
56536
|
+
disabled: voiceStatus === "connecting",
|
|
56537
|
+
children: voiceStatus === "connecting" ? /*#__PURE__*/jsxRuntimeExports.jsx(Loader2, {
|
|
56538
|
+
className: "w-4 h-4 animate-spin"
|
|
56539
|
+
}) : /*#__PURE__*/jsxRuntimeExports.jsx(AudioLines, {
|
|
56540
|
+
className: "w-4 h-4"
|
|
56541
|
+
})
|
|
55980
56542
|
}), /*#__PURE__*/jsxRuntimeExports.jsx("button", {
|
|
55981
|
-
onClick: onSend,
|
|
55982
|
-
disabled: isDisabled,
|
|
55983
|
-
className: "h-
|
|
56543
|
+
onClick: isVoiceSessionActive && onBidiSubmit ? onBidiSubmit : onSend,
|
|
56544
|
+
disabled: isDisabled || isVoiceSessionActive && voiceStatus !== "connected",
|
|
56545
|
+
className: "h-10 w-10 rounded-xl transition-all duration-200 flex items-center justify-center shadow-md disabled:opacity-40 disabled:cursor-not-allowed disabled:shadow-none ".concat(inputValue.trim() ? "scale-100" : "scale-95"),
|
|
55984
56546
|
style: {
|
|
55985
|
-
backgroundColor:
|
|
55986
|
-
color:
|
|
56547
|
+
backgroundColor: inputValue.trim() ? primaryColor : isDark ? "#374151" : "#e5e7eb",
|
|
56548
|
+
color: inputValue.trim() ? "white" : "#9ca3af"
|
|
55987
56549
|
},
|
|
55988
56550
|
"aria-label": "Send message",
|
|
55989
56551
|
children: /*#__PURE__*/jsxRuntimeExports.jsx(Send, {
|
|
55990
|
-
className: "w-
|
|
56552
|
+
className: "w-4 h-4 transition-transform",
|
|
56553
|
+
style: isRtl ? {
|
|
56554
|
+
transform: "rotate(-90deg)"
|
|
56555
|
+
} : undefined
|
|
55991
56556
|
})
|
|
55992
56557
|
})]
|
|
55993
|
-
})
|
|
56558
|
+
}), isVoiceSessionActive && /*#__PURE__*/jsxRuntimeExports.jsxs("p", {
|
|
56559
|
+
className: "text-[11px] mt-2 px-1 ".concat(voiceStatus === "connected" ? "text-green-500" : "text-gray-500", " flex items-center gap-1"),
|
|
56560
|
+
children: [/*#__PURE__*/jsxRuntimeExports.jsx("span", {
|
|
56561
|
+
className: "w-1.5 h-1.5 rounded-full bg-current inline-flex"
|
|
56562
|
+
}), voiceStatus === "connected" ? "Voice session live — speak or type to converse." : "Connecting to voice session..."]
|
|
56563
|
+
}), voiceError && /*#__PURE__*/jsxRuntimeExports.jsx("p", {
|
|
56564
|
+
className: "text-[11px] mt-1 px-1 text-red-500",
|
|
56565
|
+
children: voiceError
|
|
56566
|
+
}), disclaimerText && disclaimerPosition === "footer" && /*#__PURE__*/jsxRuntimeExports.jsx("p", {
|
|
56567
|
+
className: "text-xs mt-2 text-center",
|
|
56568
|
+
style: {
|
|
56569
|
+
color: isDark ? "#FFFFFF" : "#000000",
|
|
56570
|
+
fontFamily: fontFamily || "Inter",
|
|
56571
|
+
fontSize: fontSize ? "calc(".concat(fontSize, " - 2px)") : "12px",
|
|
56572
|
+
direction: isRtl ? "rtl" : "ltr"
|
|
56573
|
+
},
|
|
56574
|
+
dir: isRtl ? "rtl" : "ltr",
|
|
56575
|
+
children: disclaimerText
|
|
56576
|
+
})]
|
|
55994
56577
|
});
|
|
55995
56578
|
};
|
|
55996
56579
|
|
|
56580
|
+
const LOGO_MAX_HEIGHT = "3.5rem";
|
|
56581
|
+
const LOGO_MAX_HEIGHT_COMPACT = "2.5rem";
|
|
56582
|
+
const LOGO_MAX_WIDTH_DEFAULT = "4.5rem";
|
|
56583
|
+
const LOGO_MAX_WIDTH_DEFAULT_COMPACT = "3rem";
|
|
56584
|
+
const LOGO_MAX_WIDTH_WIDE = "9rem";
|
|
56585
|
+
const LOGO_MAX_WIDTH_WIDE_COMPACT = "5.5rem";
|
|
56586
|
+
const STATUS_DOT_SIZE = "0.8rem";
|
|
56587
|
+
const STATUS_DOT_SIZE_COMPACT = "0.65rem";
|
|
56588
|
+
const STATUS_DOT_BORDER_WIDTH = "2px";
|
|
56589
|
+
const STATUS_DOT_BORDER_WIDTH_COMPACT = "1.5px";
|
|
56590
|
+
const STATUS_DOT_DEFAULT_COLOR = "#34d399";
|
|
56591
|
+
const STATUS_DOT_OFFSET = "38%";
|
|
56592
|
+
const STATUS_DOT_OFFSET_COMPACT = "22%";
|
|
56593
|
+
const LogoImage = _ref => {
|
|
56594
|
+
let {
|
|
56595
|
+
src,
|
|
56596
|
+
showStatusDot = false,
|
|
56597
|
+
statusColor = STATUS_DOT_DEFAULT_COLOR,
|
|
56598
|
+
size = "default"
|
|
56599
|
+
} = _ref;
|
|
56600
|
+
const [aspect, setAspect] = reactExports.useState("square");
|
|
56601
|
+
const isCompact = size === "compact";
|
|
56602
|
+
reactExports.useEffect(() => {
|
|
56603
|
+
if (typeof window === "undefined" || !src) {
|
|
56604
|
+
return;
|
|
56605
|
+
}
|
|
56606
|
+
const img = new Image();
|
|
56607
|
+
img.src = src;
|
|
56608
|
+
img.onload = () => {
|
|
56609
|
+
if (img.width > img.height) {
|
|
56610
|
+
setAspect("wide");
|
|
56611
|
+
} else if (img.height > img.width) {
|
|
56612
|
+
setAspect("tall");
|
|
56613
|
+
} else {
|
|
56614
|
+
setAspect("square");
|
|
56615
|
+
}
|
|
56616
|
+
};
|
|
56617
|
+
}, [src]);
|
|
56618
|
+
const containerStyle = {
|
|
56619
|
+
position: "relative",
|
|
56620
|
+
display: "inline-flex"
|
|
56621
|
+
};
|
|
56622
|
+
const imageStyle = {
|
|
56623
|
+
display: "block",
|
|
56624
|
+
objectFit: "cover",
|
|
56625
|
+
height: "100%",
|
|
56626
|
+
width: "100%",
|
|
56627
|
+
// borderRadius:'50%',
|
|
56628
|
+
maxHeight: isCompact ? LOGO_MAX_HEIGHT_COMPACT : LOGO_MAX_HEIGHT,
|
|
56629
|
+
maxWidth: isCompact ? LOGO_MAX_WIDTH_DEFAULT_COMPACT : LOGO_MAX_WIDTH_DEFAULT
|
|
56630
|
+
};
|
|
56631
|
+
if (aspect === "wide") {
|
|
56632
|
+
imageStyle.maxWidth = isCompact ? LOGO_MAX_WIDTH_WIDE_COMPACT : LOGO_MAX_WIDTH_WIDE;
|
|
56633
|
+
}
|
|
56634
|
+
if (aspect === "tall") {
|
|
56635
|
+
imageStyle.maxHeight = isCompact ? "3rem" : "4rem";
|
|
56636
|
+
imageStyle.maxWidth = isCompact ? "3rem" : "4rem";
|
|
56637
|
+
}
|
|
56638
|
+
return /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
|
|
56639
|
+
style: containerStyle,
|
|
56640
|
+
children: [/*#__PURE__*/jsxRuntimeExports.jsx("img", {
|
|
56641
|
+
src: src,
|
|
56642
|
+
alt: "Logo",
|
|
56643
|
+
style: imageStyle,
|
|
56644
|
+
loading: "lazy"
|
|
56645
|
+
}), showStatusDot && /*#__PURE__*/jsxRuntimeExports.jsx("span", {
|
|
56646
|
+
style: {
|
|
56647
|
+
position: "absolute",
|
|
56648
|
+
bottom: 0,
|
|
56649
|
+
right: 0,
|
|
56650
|
+
width: isCompact ? STATUS_DOT_SIZE_COMPACT : STATUS_DOT_SIZE,
|
|
56651
|
+
height: isCompact ? STATUS_DOT_SIZE_COMPACT : STATUS_DOT_SIZE,
|
|
56652
|
+
borderRadius: "9999px",
|
|
56653
|
+
backgroundColor: statusColor,
|
|
56654
|
+
border: "".concat(isCompact ? STATUS_DOT_BORDER_WIDTH_COMPACT : STATUS_DOT_BORDER_WIDTH, " solid #ffffff"),
|
|
56655
|
+
transform: "translate(".concat(isCompact ? STATUS_DOT_OFFSET_COMPACT : STATUS_DOT_OFFSET, ", ").concat(isCompact ? STATUS_DOT_OFFSET_COMPACT : STATUS_DOT_OFFSET, ")"),
|
|
56656
|
+
pointerEvents: "none"
|
|
56657
|
+
}
|
|
56658
|
+
})]
|
|
56659
|
+
});
|
|
56660
|
+
};
|
|
56661
|
+
|
|
56662
|
+
const ChatHeader = _ref => {
|
|
56663
|
+
let {
|
|
56664
|
+
conciergeName,
|
|
56665
|
+
companyName,
|
|
56666
|
+
companyLogo,
|
|
56667
|
+
primaryColor,
|
|
56668
|
+
isDark,
|
|
56669
|
+
isMinimized = false,
|
|
56670
|
+
textColor,
|
|
56671
|
+
fontFamily,
|
|
56672
|
+
fontSize,
|
|
56673
|
+
onToggleTheme,
|
|
56674
|
+
onMinimize,
|
|
56675
|
+
onClose,
|
|
56676
|
+
headerTextBold = false,
|
|
56677
|
+
headerTextItalic = false
|
|
56678
|
+
} = _ref;
|
|
56679
|
+
useGoogleFont(fontFamily);
|
|
56680
|
+
const agentData = {
|
|
56681
|
+
fontFamily,
|
|
56682
|
+
fontSize,
|
|
56683
|
+
headerTextBold,
|
|
56684
|
+
headerTextItalic,
|
|
56685
|
+
textColor
|
|
56686
|
+
};
|
|
56687
|
+
return /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
|
|
56688
|
+
className: "text-white ".concat(isMinimized ? "px-4 py-2.5" : "px-5 py-4", " flex items-center justify-between relative overflow-hidden rounded-t-2xl"),
|
|
56689
|
+
style: {
|
|
56690
|
+
background: "linear-gradient(135deg, ".concat(primaryColor, " 0%, ").concat(primaryColor, "dd 100%)"),
|
|
56691
|
+
fontFamily
|
|
56692
|
+
},
|
|
56693
|
+
children: [/*#__PURE__*/jsxRuntimeExports.jsxs("div", {
|
|
56694
|
+
className: "flex gap-2 w-96",
|
|
56695
|
+
children: [/*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
56696
|
+
className: "absolute inset-0 bg-gradient-to-br from-white/10 to-transparent pointer-events-none"
|
|
56697
|
+
}), companyLogo && /*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
56698
|
+
className: "w-[48px] h-[48px] rounded-full overflow-hidden flex items-center justify-center bg-white/10",
|
|
56699
|
+
children: /*#__PURE__*/jsxRuntimeExports.jsx(LogoImage, {
|
|
56700
|
+
src: companyLogo
|
|
56701
|
+
})
|
|
56702
|
+
}), /*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
56703
|
+
className: "flex items-center gap-2 ".concat(!companyLogo ? "px-3" : ""),
|
|
56704
|
+
style: {
|
|
56705
|
+
fontFamily: (agentData === null || agentData === void 0 ? void 0 : agentData.fontFamily) || "Inter"
|
|
56706
|
+
},
|
|
56707
|
+
children: /*#__PURE__*/jsxRuntimeExports.jsx("h3", {
|
|
56708
|
+
className: cn("font-semibold leading-tight", (agentData === null || agentData === void 0 ? void 0 : agentData.headerTextBold) && "font-bold", (agentData === null || agentData === void 0 ? void 0 : agentData.headerTextItalic) && "italic"),
|
|
56709
|
+
style: {
|
|
56710
|
+
fontSize: agentData !== null && agentData !== void 0 && agentData.fontSize ? "calc(".concat(agentData.fontSize, " + 2px)") : "15px",
|
|
56711
|
+
color: (agentData === null || agentData === void 0 ? void 0 : agentData.textColor) || "#FFFFFF"
|
|
56712
|
+
},
|
|
56713
|
+
children: companyName
|
|
56714
|
+
})
|
|
56715
|
+
})]
|
|
56716
|
+
}), /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
|
|
56717
|
+
className: "flex items-center gap-0 relative z-10 text-white flex-shrink-0 ml-1",
|
|
56718
|
+
children: [/*#__PURE__*/jsxRuntimeExports.jsx("span", {
|
|
56719
|
+
role: "button",
|
|
56720
|
+
tabIndex: 0,
|
|
56721
|
+
"aria-label": "Toggle theme",
|
|
56722
|
+
onClick: onToggleTheme,
|
|
56723
|
+
onKeyDown: event => {
|
|
56724
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
56725
|
+
event.preventDefault();
|
|
56726
|
+
onToggleTheme === null || onToggleTheme === void 0 || onToggleTheme(event);
|
|
56727
|
+
}
|
|
56728
|
+
},
|
|
56729
|
+
className: "inline-flex h-7 w-7 items-center justify-center cursor-pointer transition-opacity duration-200 hover:opacity-80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/40 rounded-full",
|
|
56730
|
+
children: isDark ? /*#__PURE__*/jsxRuntimeExports.jsx(Sun, {
|
|
56731
|
+
className: "w-3.5 h-3.5",
|
|
56732
|
+
strokeWidth: 1.6
|
|
56733
|
+
}) : /*#__PURE__*/jsxRuntimeExports.jsx(Moon, {
|
|
56734
|
+
className: "w-3.5 h-3.5",
|
|
56735
|
+
strokeWidth: 1.6
|
|
56736
|
+
})
|
|
56737
|
+
}), onMinimize && /*#__PURE__*/jsxRuntimeExports.jsx("span", {
|
|
56738
|
+
role: "button",
|
|
56739
|
+
tabIndex: 0,
|
|
56740
|
+
"aria-label": isMinimized ? "Expand" : "Minimize",
|
|
56741
|
+
onClick: onMinimize,
|
|
56742
|
+
onKeyDown: event => {
|
|
56743
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
56744
|
+
event.preventDefault();
|
|
56745
|
+
onMinimize === null || onMinimize === void 0 || onMinimize(event);
|
|
56746
|
+
}
|
|
56747
|
+
},
|
|
56748
|
+
className: "inline-flex h-7 w-7 items-center justify-center cursor-pointer transition-opacity duration-200 hover:opacity-80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/40 rounded-full",
|
|
56749
|
+
children: isMinimized ? /*#__PURE__*/jsxRuntimeExports.jsx(Maximize2, {
|
|
56750
|
+
className: "w-3.5 h-3.5",
|
|
56751
|
+
strokeWidth: 1.6
|
|
56752
|
+
}) : /*#__PURE__*/jsxRuntimeExports.jsx(Minimize2, {
|
|
56753
|
+
className: "w-3.5 h-3.5",
|
|
56754
|
+
strokeWidth: 1.6
|
|
56755
|
+
})
|
|
56756
|
+
}), /*#__PURE__*/jsxRuntimeExports.jsx("span", {
|
|
56757
|
+
role: "button",
|
|
56758
|
+
tabIndex: 0,
|
|
56759
|
+
"aria-label": "Close",
|
|
56760
|
+
onClick: onClose,
|
|
56761
|
+
onKeyDown: event => {
|
|
56762
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
56763
|
+
event.preventDefault();
|
|
56764
|
+
onClose === null || onClose === void 0 || onClose(event);
|
|
56765
|
+
}
|
|
56766
|
+
},
|
|
56767
|
+
className: "inline-flex h-7 w-7 items-center justify-center cursor-pointer transition-opacity duration-200 hover:opacity-80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/40 rounded-full",
|
|
56768
|
+
children: /*#__PURE__*/jsxRuntimeExports.jsx(X, {
|
|
56769
|
+
className: "w-3.5 h-3.5",
|
|
56770
|
+
strokeWidth: 1.6
|
|
56771
|
+
})
|
|
56772
|
+
})]
|
|
56773
|
+
})]
|
|
56774
|
+
});
|
|
56775
|
+
};
|
|
56776
|
+
|
|
56777
|
+
/**
|
|
56778
|
+
* Auto-scroll hook that scrolls to bottom when dependencies change
|
|
56779
|
+
*/
|
|
56780
|
+
function useAutoScroll(containerRef) {
|
|
56781
|
+
let dependencies = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
56782
|
+
let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
56783
|
+
const {
|
|
56784
|
+
enabled = true,
|
|
56785
|
+
threshold = 30,
|
|
56786
|
+
behavior = "smooth",
|
|
56787
|
+
delay = 0
|
|
56788
|
+
} = options;
|
|
56789
|
+
const shouldScrollRef = reactExports.useRef(true);
|
|
56790
|
+
reactExports.useRef(0);
|
|
56791
|
+
reactExports.useEffect(() => {
|
|
56792
|
+
if (!enabled || !containerRef.current) {
|
|
56793
|
+
return;
|
|
56794
|
+
}
|
|
56795
|
+
const container = containerRef.current;
|
|
56796
|
+
const checkScrollPosition = () => {
|
|
56797
|
+
const distanceFromBottom = container.scrollHeight - container.scrollTop - container.clientHeight;
|
|
56798
|
+
shouldScrollRef.current = distanceFromBottom < threshold;
|
|
56799
|
+
};
|
|
56800
|
+
const handleScroll = () => {
|
|
56801
|
+
checkScrollPosition();
|
|
56802
|
+
};
|
|
56803
|
+
container.addEventListener("scroll", handleScroll, {
|
|
56804
|
+
passive: true
|
|
56805
|
+
});
|
|
56806
|
+
checkScrollPosition();
|
|
56807
|
+
const scrollToBottom = () => {
|
|
56808
|
+
if (shouldScrollRef.current && container) {
|
|
56809
|
+
container.scrollTo({
|
|
56810
|
+
top: container.scrollHeight,
|
|
56811
|
+
behavior
|
|
56812
|
+
});
|
|
56813
|
+
}
|
|
56814
|
+
};
|
|
56815
|
+
const timeoutId = setTimeout(scrollToBottom, delay);
|
|
56816
|
+
return () => {
|
|
56817
|
+
container.removeEventListener("scroll", handleScroll);
|
|
56818
|
+
clearTimeout(timeoutId);
|
|
56819
|
+
};
|
|
56820
|
+
}, [containerRef, enabled, threshold, behavior, delay, ...dependencies]);
|
|
56821
|
+
}
|
|
56822
|
+
|
|
55997
56823
|
const DEFAULT_AGENT_BUBBLE_COLOR = "#ffffff";
|
|
55998
56824
|
const DEFAULT_USER_MESSAGE_COLOR = "#f5f5f5";
|
|
55999
56825
|
const DEFAULT_TEXT_COLOR = "#000000";
|
|
@@ -56039,23 +56865,38 @@
|
|
|
56039
56865
|
quickQuestionsLayout = "vertical",
|
|
56040
56866
|
agentMessageBubbleColor,
|
|
56041
56867
|
userMessageBoxColor,
|
|
56868
|
+
assistantTextColor,
|
|
56869
|
+
userTextColor,
|
|
56042
56870
|
fontFamily = "Inter",
|
|
56043
56871
|
fontSize = "14px",
|
|
56044
|
-
defaultLanguage = "en"
|
|
56872
|
+
defaultLanguage = "en",
|
|
56873
|
+
onDecision,
|
|
56874
|
+
headerTextBold = false,
|
|
56875
|
+
headerTextItalic = false,
|
|
56876
|
+
enableVoiceInteraction = false,
|
|
56877
|
+
isVoiceSessionActive = false,
|
|
56878
|
+
voiceStatus = "idle",
|
|
56879
|
+
voiceError = null,
|
|
56880
|
+
onVoiceToggle,
|
|
56881
|
+
onBidiSubmit,
|
|
56882
|
+
disclaimerText,
|
|
56883
|
+
disclaimerPosition = "top",
|
|
56884
|
+
apiBaseUrl,
|
|
56885
|
+
apiKey,
|
|
56886
|
+
organizationId
|
|
56045
56887
|
} = _ref;
|
|
56046
56888
|
useGoogleFont(fontFamily);
|
|
56889
|
+
const messagesContainerRef = reactExports.useRef(null);
|
|
56890
|
+
|
|
56891
|
+
// Auto-scroll hook
|
|
56892
|
+
useAutoScroll(messagesContainerRef, [messages, isLoading], {
|
|
56893
|
+
enabled: true,
|
|
56894
|
+
threshold: 30,
|
|
56895
|
+
behavior: "smooth",
|
|
56896
|
+
delay: 0
|
|
56897
|
+
});
|
|
56047
56898
|
const defaultLanguageCode = defaultLanguage === null || defaultLanguage === void 0 || (_defaultLanguage$toLo = defaultLanguage.toLowerCase) === null || _defaultLanguage$toLo === void 0 ? void 0 : _defaultLanguage$toLo.call(defaultLanguage);
|
|
56048
56899
|
const isRtlLanguage = Boolean(defaultLanguageCode && defaultLanguageCode.startsWith("ar"));
|
|
56049
|
-
const basePrimaryColor = primaryColor || "#2563eb";
|
|
56050
|
-
const containerStyle = reactExports.useMemo(() => {
|
|
56051
|
-
if (isDark) {
|
|
56052
|
-
return undefined;
|
|
56053
|
-
}
|
|
56054
|
-
return {
|
|
56055
|
-
backgroundColor: basePrimaryColor
|
|
56056
|
-
// borderColor: basePrimaryColor,
|
|
56057
|
-
};
|
|
56058
|
-
}, [basePrimaryColor, isDark]);
|
|
56059
56900
|
const resolvedAgentBubbleColor = reactExports.useMemo(() => {
|
|
56060
56901
|
if (isDark) {
|
|
56061
56902
|
if (isDefaultColor(agentMessageBubbleColor, DEFAULT_AGENT_BUBBLE_COLOR)) {
|
|
@@ -56090,42 +56931,57 @@
|
|
|
56090
56931
|
return null;
|
|
56091
56932
|
}
|
|
56092
56933
|
return /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
|
|
56093
|
-
className: "
|
|
56094
|
-
|
|
56095
|
-
|
|
56096
|
-
|
|
56097
|
-
|
|
56098
|
-
|
|
56099
|
-
|
|
56100
|
-
|
|
56101
|
-
|
|
56102
|
-
|
|
56103
|
-
|
|
56104
|
-
|
|
56105
|
-
|
|
56106
|
-
|
|
56107
|
-
|
|
56108
|
-
|
|
56109
|
-
|
|
56110
|
-
|
|
56111
|
-
|
|
56112
|
-
|
|
56113
|
-
|
|
56114
|
-
|
|
56115
|
-
|
|
56116
|
-
|
|
56117
|
-
|
|
56118
|
-
|
|
56119
|
-
|
|
56120
|
-
|
|
56121
|
-
|
|
56122
|
-
|
|
56123
|
-
|
|
56124
|
-
|
|
56125
|
-
|
|
56126
|
-
|
|
56127
|
-
|
|
56128
|
-
|
|
56934
|
+
className: "".concat(isMinimized ? "w-80" : "w-[380px]", " max-w-[92vw] flex-shrink-0 border rounded-2xl shadow-2xl bg-white border-gray-200 flex flex-col ").concat(isMinimized ? "h-auto" : "h-[650px] max-h-[85vh]", " overflow-hidden z-50 ").concat(isDark ? "bg-gray-900 border-gray-700" : ""),
|
|
56935
|
+
children: [/*#__PURE__*/jsxRuntimeExports.jsx(ChatHeader, {
|
|
56936
|
+
conciergeName: conciergeName,
|
|
56937
|
+
companyName: companyName,
|
|
56938
|
+
companyLogo: companyLogo,
|
|
56939
|
+
primaryColor: primaryColor,
|
|
56940
|
+
isDark: isDark,
|
|
56941
|
+
isMinimized: isMinimized,
|
|
56942
|
+
textColor: resolvedTextColor,
|
|
56943
|
+
fontFamily: fontFamily,
|
|
56944
|
+
fontSize: fontSize,
|
|
56945
|
+
onToggleTheme: onToggleTheme,
|
|
56946
|
+
onMinimize: onMinimize,
|
|
56947
|
+
onClose: onClose,
|
|
56948
|
+
headerTextBold: headerTextBold,
|
|
56949
|
+
headerTextItalic: headerTextItalic
|
|
56950
|
+
}), !isMinimized && /*#__PURE__*/jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, {
|
|
56951
|
+
children: [/*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
56952
|
+
ref: messagesContainerRef,
|
|
56953
|
+
className: "chat-messages flex-1 overflow-y-auto px-5 py-4 space-y-4 ".concat(isDark ? "bg-gray-900" : "bg-gradient-to-b from-gray-50/50 to-white", " break-words"),
|
|
56954
|
+
children: /*#__PURE__*/jsxRuntimeExports.jsx(MessageList, {
|
|
56955
|
+
messages: messages,
|
|
56956
|
+
isDark: isDark,
|
|
56957
|
+
primaryColor: primaryColor,
|
|
56958
|
+
isLoading: isLoading,
|
|
56959
|
+
agentMessageBubbleColor: agentMessageBubbleColor,
|
|
56960
|
+
userMessageBoxColor: userMessageBoxColor,
|
|
56961
|
+
textColor: textColor,
|
|
56962
|
+
assistantTextColor: assistantTextColor,
|
|
56963
|
+
userTextColor: userTextColor,
|
|
56964
|
+
fontFamily: fontFamily,
|
|
56965
|
+
fontSize: fontSize,
|
|
56966
|
+
formatTime: formatTime,
|
|
56967
|
+
isRtl: isRtlLanguage,
|
|
56968
|
+
quickQuestions: quickQuestions,
|
|
56969
|
+
shouldShowQuickQuestions: shouldShowQuickQuestions,
|
|
56970
|
+
onQuickQuestion: onQuickQuestion !== null && onQuickQuestion !== void 0 ? onQuickQuestion : onDirectSend,
|
|
56971
|
+
quickQuestionsLayout: quickQuestionsLayout,
|
|
56972
|
+
onDecision: onDecision,
|
|
56973
|
+
disclaimerText: disclaimerText,
|
|
56974
|
+
disclaimerPosition: disclaimerPosition,
|
|
56975
|
+
resolvedAgentBubbleColor: resolvedAgentBubbleColor,
|
|
56976
|
+
resolvedUserMessageColor: resolvedUserMessageColor,
|
|
56977
|
+
resolvedTextColor: resolvedTextColor,
|
|
56978
|
+
isVoiceSessionActive: isVoiceSessionActive,
|
|
56979
|
+
voiceStatus: voiceStatus,
|
|
56980
|
+
messagesContainerRef: messagesContainerRef,
|
|
56981
|
+
companyLogo: companyLogo,
|
|
56982
|
+
conciergeName: conciergeName,
|
|
56983
|
+
companyName: companyName
|
|
56984
|
+
})
|
|
56129
56985
|
}), /*#__PURE__*/jsxRuntimeExports.jsx(ChatInput, {
|
|
56130
56986
|
inputValue: inputValue,
|
|
56131
56987
|
setInputValue: setInputValue,
|
|
@@ -56139,7 +56995,15 @@
|
|
|
56139
56995
|
textColor: resolvedTextColor,
|
|
56140
56996
|
fontFamily: fontFamily,
|
|
56141
56997
|
fontSize: fontSize,
|
|
56142
|
-
isRtl: isRtlLanguage
|
|
56998
|
+
isRtl: isRtlLanguage,
|
|
56999
|
+
enableVoiceInteraction: enableVoiceInteraction,
|
|
57000
|
+
isVoiceSessionActive: isVoiceSessionActive,
|
|
57001
|
+
voiceStatus: voiceStatus,
|
|
57002
|
+
voiceError: voiceError,
|
|
57003
|
+
onVoiceToggle: onVoiceToggle,
|
|
57004
|
+
onBidiSubmit: onBidiSubmit,
|
|
57005
|
+
disclaimerText: disclaimerText,
|
|
57006
|
+
disclaimerPosition: disclaimerPosition
|
|
56143
57007
|
})]
|
|
56144
57008
|
})]
|
|
56145
57009
|
});
|
|
@@ -56150,7 +57014,8 @@
|
|
|
56150
57014
|
isOpen,
|
|
56151
57015
|
isDark,
|
|
56152
57016
|
primaryColor,
|
|
56153
|
-
onToggle
|
|
57017
|
+
onToggle,
|
|
57018
|
+
textColor
|
|
56154
57019
|
} = _ref;
|
|
56155
57020
|
return /*#__PURE__*/jsxRuntimeExports.jsxs("button", {
|
|
56156
57021
|
onClick: onToggle,
|
|
@@ -56168,7 +57033,10 @@
|
|
|
56168
57033
|
className: "w-7 h-7"
|
|
56169
57034
|
}) : /*#__PURE__*/jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, {
|
|
56170
57035
|
children: [/*#__PURE__*/jsxRuntimeExports.jsx(MessageCircle, {
|
|
56171
|
-
className: "w-7 h-7"
|
|
57036
|
+
className: "w-7 h-7",
|
|
57037
|
+
style: {
|
|
57038
|
+
color: textColor
|
|
57039
|
+
}
|
|
56172
57040
|
}), /*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
56173
57041
|
className: "absolute -top-1 -right-1 w-5 h-5 bg-red-500 rounded-full flex items-center justify-center text-[10px] font-bold border-2 border-white animate-pulse",
|
|
56174
57042
|
children: "1"
|
|
@@ -56192,6 +57060,8 @@
|
|
|
56192
57060
|
textColor = "#000000",
|
|
56193
57061
|
agentMessageBubbleColor,
|
|
56194
57062
|
userMessageBoxColor,
|
|
57063
|
+
assistantTextColor,
|
|
57064
|
+
userTextColor,
|
|
56195
57065
|
fontFamily = "Inter",
|
|
56196
57066
|
fontSize = "14px",
|
|
56197
57067
|
defaultLanguage = "en",
|
|
@@ -56201,7 +57071,12 @@
|
|
|
56201
57071
|
autoOpen = false,
|
|
56202
57072
|
openDelay = 0,
|
|
56203
57073
|
locale = "en",
|
|
56204
|
-
className = ""
|
|
57074
|
+
className = "",
|
|
57075
|
+
headerTextBold = false,
|
|
57076
|
+
headerTextItalic = false,
|
|
57077
|
+
enableVoiceInteraction = false,
|
|
57078
|
+
disclaimerText,
|
|
57079
|
+
disclaimerPosition = "top"
|
|
56205
57080
|
} = _ref;
|
|
56206
57081
|
const {
|
|
56207
57082
|
isOpen,
|
|
@@ -56218,7 +57093,13 @@
|
|
|
56218
57093
|
toggleChat,
|
|
56219
57094
|
toggleTheme,
|
|
56220
57095
|
toggleMinimize,
|
|
56221
|
-
closeChat
|
|
57096
|
+
closeChat,
|
|
57097
|
+
handleDecision,
|
|
57098
|
+
isVoiceSessionActive,
|
|
57099
|
+
voiceStatus,
|
|
57100
|
+
voiceError,
|
|
57101
|
+
handleVoiceToggle,
|
|
57102
|
+
sendBidiTextMessage
|
|
56222
57103
|
} = useChatState({
|
|
56223
57104
|
welcomeMessage,
|
|
56224
57105
|
quickQuestions,
|
|
@@ -56227,7 +57108,8 @@
|
|
|
56227
57108
|
organizationId,
|
|
56228
57109
|
autoOpen,
|
|
56229
57110
|
openDelay,
|
|
56230
|
-
darkMode
|
|
57111
|
+
darkMode,
|
|
57112
|
+
enableVoiceInteraction
|
|
56231
57113
|
});
|
|
56232
57114
|
|
|
56233
57115
|
// Set CSS variables for theming
|
|
@@ -56274,14 +57156,31 @@
|
|
|
56274
57156
|
quickQuestionsLayout: quickQuestionsLayout,
|
|
56275
57157
|
agentMessageBubbleColor: agentMessageBubbleColor,
|
|
56276
57158
|
userMessageBoxColor: userMessageBoxColor,
|
|
57159
|
+
assistantTextColor: assistantTextColor,
|
|
57160
|
+
userTextColor: userTextColor,
|
|
56277
57161
|
fontFamily: fontFamily,
|
|
56278
57162
|
fontSize: fontSize,
|
|
56279
|
-
defaultLanguage: defaultLanguage || locale
|
|
56280
|
-
|
|
57163
|
+
defaultLanguage: defaultLanguage || locale,
|
|
57164
|
+
onDecision: handleDecision,
|
|
57165
|
+
headerTextBold: headerTextBold,
|
|
57166
|
+
headerTextItalic: headerTextItalic,
|
|
57167
|
+
enableVoiceInteraction: enableVoiceInteraction,
|
|
57168
|
+
isVoiceSessionActive: isVoiceSessionActive,
|
|
57169
|
+
voiceStatus: voiceStatus,
|
|
57170
|
+
voiceError: voiceError,
|
|
57171
|
+
onVoiceToggle: handleVoiceToggle,
|
|
57172
|
+
onBidiSubmit: () => sendBidiTextMessage(inputValue),
|
|
57173
|
+
disclaimerText: disclaimerText,
|
|
57174
|
+
disclaimerPosition: disclaimerPosition,
|
|
57175
|
+
apiBaseUrl: apiBaseUrl,
|
|
57176
|
+
apiKey: apiKey,
|
|
57177
|
+
organizationId: organizationId
|
|
57178
|
+
}), !isOpen && /*#__PURE__*/jsxRuntimeExports.jsx(ToggleButton, {
|
|
56281
57179
|
isOpen: isOpen,
|
|
56282
57180
|
isDark: isDark,
|
|
56283
57181
|
primaryColor: primaryColor,
|
|
56284
|
-
onToggle: toggleChat
|
|
57182
|
+
onToggle: toggleChat,
|
|
57183
|
+
textColor: textColor
|
|
56285
57184
|
})]
|
|
56286
57185
|
});
|
|
56287
57186
|
};
|
|
@@ -56301,9 +57200,11 @@
|
|
|
56301
57200
|
welcomeMessage: 'Hi! How can we help?',
|
|
56302
57201
|
quickQuestions: [],
|
|
56303
57202
|
quickQuestionsLayout: 'vertical',
|
|
56304
|
-
textColor: '#
|
|
57203
|
+
textColor: '#fcfcfc',
|
|
56305
57204
|
agentMessageBubbleColor: undefined,
|
|
56306
57205
|
userMessageBoxColor: undefined,
|
|
57206
|
+
assistantTextColor: undefined,
|
|
57207
|
+
userTextColor: undefined,
|
|
56307
57208
|
fontFamily: 'Inter',
|
|
56308
57209
|
fontSize: '14px',
|
|
56309
57210
|
defaultLanguage: 'en',
|
|
@@ -56311,18 +57212,24 @@
|
|
|
56311
57212
|
openDelay: 0,
|
|
56312
57213
|
apiBaseUrl: null,
|
|
56313
57214
|
apiKey: null,
|
|
57215
|
+
organizationId: null,
|
|
56314
57216
|
sessionUrl: null,
|
|
56315
57217
|
userId: null,
|
|
56316
57218
|
userName: null,
|
|
56317
57219
|
userEmail: null,
|
|
56318
57220
|
locale: 'en',
|
|
57221
|
+
headerTextBold: false,
|
|
57222
|
+
headerTextItalic: false,
|
|
57223
|
+
enableVoiceInteraction: false,
|
|
57224
|
+
disclaimerText: undefined,
|
|
57225
|
+
disclaimerPosition: 'top',
|
|
56319
57226
|
onOpen: null,
|
|
56320
57227
|
onClose: null
|
|
56321
57228
|
};
|
|
56322
57229
|
const API = {
|
|
56323
|
-
/**
|
|
56324
|
-
* Initialize the chat widget
|
|
56325
|
-
* @param {Object} options - Configuration options
|
|
57230
|
+
/**
|
|
57231
|
+
* Initialize the chat widget
|
|
57232
|
+
* @param {Object} options - Configuration options
|
|
56326
57233
|
*/
|
|
56327
57234
|
init: async function () {
|
|
56328
57235
|
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
@@ -56362,17 +57269,17 @@
|
|
|
56362
57269
|
}
|
|
56363
57270
|
return API;
|
|
56364
57271
|
},
|
|
56365
|
-
/**
|
|
56366
|
-
* Update configuration
|
|
56367
|
-
* @param {Object} newConfig - New configuration options
|
|
57272
|
+
/**
|
|
57273
|
+
* Update configuration
|
|
57274
|
+
* @param {Object} newConfig - New configuration options
|
|
56368
57275
|
*/
|
|
56369
57276
|
updateConfig: function (newConfig) {
|
|
56370
57277
|
config = _objectSpread2(_objectSpread2({}, config), newConfig);
|
|
56371
57278
|
this.init(config);
|
|
56372
57279
|
return API;
|
|
56373
57280
|
},
|
|
56374
|
-
/**
|
|
56375
|
-
* Open the chat widget
|
|
57281
|
+
/**
|
|
57282
|
+
* Open the chat widget
|
|
56376
57283
|
*/
|
|
56377
57284
|
open: function () {
|
|
56378
57285
|
// Trigger open by updating config
|
|
@@ -56383,8 +57290,8 @@
|
|
|
56383
57290
|
if (config.onOpen) config.onOpen();
|
|
56384
57291
|
return API;
|
|
56385
57292
|
},
|
|
56386
|
-
/**
|
|
56387
|
-
* Close the chat widget
|
|
57293
|
+
/**
|
|
57294
|
+
* Close the chat widget
|
|
56388
57295
|
*/
|
|
56389
57296
|
close: function () {
|
|
56390
57297
|
this.updateConfig({
|
|
@@ -56393,8 +57300,8 @@
|
|
|
56393
57300
|
if (config.onClose) config.onClose();
|
|
56394
57301
|
return API;
|
|
56395
57302
|
},
|
|
56396
|
-
/**
|
|
56397
|
-
* Toggle dark mode
|
|
57303
|
+
/**
|
|
57304
|
+
* Toggle dark mode
|
|
56398
57305
|
*/
|
|
56399
57306
|
toggleTheme: function () {
|
|
56400
57307
|
config.darkMode = !config.darkMode;
|
|
@@ -56403,8 +57310,8 @@
|
|
|
56403
57310
|
});
|
|
56404
57311
|
return API;
|
|
56405
57312
|
},
|
|
56406
|
-
/**
|
|
56407
|
-
* Destroy the widget
|
|
57313
|
+
/**
|
|
57314
|
+
* Destroy the widget
|
|
56408
57315
|
*/
|
|
56409
57316
|
destroy: function () {
|
|
56410
57317
|
if (root) {
|
|
@@ -56419,8 +57326,8 @@
|
|
|
56419
57326
|
config = {};
|
|
56420
57327
|
return API;
|
|
56421
57328
|
},
|
|
56422
|
-
/**
|
|
56423
|
-
* Get current configuration
|
|
57329
|
+
/**
|
|
57330
|
+
* Get current configuration
|
|
56424
57331
|
*/
|
|
56425
57332
|
getConfig: function () {
|
|
56426
57333
|
return _objectSpread2({}, config);
|