@clikvn/agent-widget-embedded 1.1.5-dev-08 → 1.1.5-dev-10
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/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/components/Chat/MultimodalInput.d.ts.map +1 -1
- package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/components/Chat/MultimodalInput.js +43 -42
- package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/components/Chat/MultimodalInput.js.map +1 -1
- package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/components/Chat/PreviewFileAttachment.d.ts.map +1 -1
- package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/components/Chat/PreviewFileAttachment.js +0 -1
- package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/components/Chat/PreviewFileAttachment.js.map +1 -1
- package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/components/Chat/VoiceRecordingUI.d.ts +1 -0
- package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/components/Chat/VoiceRecordingUI.d.ts.map +1 -1
- package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/components/Chat/VoiceRecordingUI.js +51 -17
- package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/components/Chat/VoiceRecordingUI.js.map +1 -1
- package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/hooks/useAudioAnalyzer.d.ts +1 -1
- package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/hooks/useAudioAnalyzer.d.ts.map +1 -1
- package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/hooks/useAudioAnalyzer.js +29 -7
- package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/hooks/useAudioAnalyzer.js.map +1 -1
- package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/hooks/useAudioRecording.d.ts +2 -1
- package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/hooks/useAudioRecording.d.ts.map +1 -1
- package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/hooks/useAudioRecording.js +9 -3
- package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/hooks/useAudioRecording.js.map +1 -1
- package/dist/commons/constants/bookMeeting.d.ts +14 -0
- package/dist/commons/constants/bookMeeting.d.ts.map +1 -0
- package/dist/commons/constants/index.d.ts +1 -0
- package/dist/commons/constants/index.d.ts.map +1 -1
- package/dist/components/Chat/BookMeetingForm.d.ts +4 -0
- package/dist/components/Chat/BookMeetingForm.d.ts.map +1 -0
- package/dist/components/Chat/Chat.d.ts.map +1 -1
- package/dist/components/Chat/Icons.d.ts +82 -76
- package/dist/components/Chat/Icons.d.ts.map +1 -1
- package/dist/components/Chat/Message.d.ts.map +1 -1
- package/dist/components/Chat/MultimodalInput.d.ts.map +1 -1
- package/dist/components/Chat/PreviewFileAttachment.d.ts.map +1 -1
- package/dist/components/Chat/UserContactForm.d.ts.map +1 -1
- package/dist/components/Chat/VoiceRecordingUI.d.ts +1 -0
- package/dist/components/Chat/VoiceRecordingUI.d.ts.map +1 -1
- package/dist/components/Chat/ui/Button.d.ts +1 -1
- package/dist/components/Chat/ui/DataPickerCustom.d.ts +9 -0
- package/dist/components/Chat/ui/DataPickerCustom.d.ts.map +1 -0
- package/dist/components/Chat/ui/PhoneNumberInput.d.ts +11 -0
- package/dist/components/Chat/ui/PhoneNumberInput.d.ts.map +1 -0
- package/dist/components/Chat/ui/SelectBox.d.ts +19 -0
- package/dist/components/Chat/ui/SelectBox.d.ts.map +1 -0
- package/dist/components/Chat/ui/SelectBoxWithIcon.d.ts +19 -0
- package/dist/components/Chat/ui/SelectBoxWithIcon.d.ts.map +1 -0
- package/dist/constants/form.d.ts +13 -0
- package/dist/constants/form.d.ts.map +1 -0
- package/dist/features/AgentWidget/index.d.ts.map +1 -1
- package/dist/hooks/useAudioAnalyzer.d.ts +1 -1
- package/dist/hooks/useAudioAnalyzer.d.ts.map +1 -1
- package/dist/hooks/useAudioRecording.d.ts +2 -1
- package/dist/hooks/useAudioRecording.d.ts.map +1 -1
- package/dist/hooks/useConfiguration.d.ts +15 -0
- package/dist/hooks/useConfiguration.d.ts.map +1 -1
- package/dist/services/apis.d.ts +2 -0
- package/dist/services/apis.d.ts.map +1 -1
- package/dist/services/bookMeeting.service.d.ts +3 -0
- package/dist/services/bookMeeting.service.d.ts.map +1 -0
- package/dist/services/userContact.service.d.ts +7 -0
- package/dist/services/userContact.service.d.ts.map +1 -0
- package/dist/types/bookMeeting.type.d.ts +9 -0
- package/dist/types/bookMeeting.type.d.ts.map +1 -0
- package/dist/types/userContact.type.d.ts +16 -0
- package/dist/types/userContact.type.d.ts.map +1 -0
- package/dist/utils/functionUtils.d.ts +1 -0
- package/dist/utils/functionUtils.d.ts.map +1 -1
- package/dist/utils/toolUtils.d.ts.map +1 -1
- package/dist/web.js +1 -1
- package/dist/web.js.map +1 -1
- package/package.json +3 -1
- package/tailwind.config.cjs +12 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultimodalInput.d.ts","sourceRoot":"","sources":["../../../src/components/Chat/MultimodalInput.tsx"],"names":[],"mappings":"AACA,OAAO,EAEL,EAAE,EAKH,MAAM,OAAO,CAAC;AAIf,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AASnD,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"MultimodalInput.d.ts","sourceRoot":"","sources":["../../../src/components/Chat/MultimodalInput.tsx"],"names":[],"mappings":"AACA,OAAO,EAEL,EAAE,EAKH,MAAM,OAAO,CAAC;AAIf,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AASnD,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAqBxE,KAAK,SAAS,GAAG;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,WAAW,EAAE,CAAC,QAAQ,EAAE,eAAe,EAAE,KAAK,IAAI,CAAC;IACnD,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,CACZ,KAAK,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,IAAI,CAAA;KAAE,EACvC,KAAK,CAAC,EAAE,WAAW,EAAE,KAClB,IAAI,CAAC;IACV,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,WAAW,CAAC,EAAE,WAAW,EAAE,CAAC;IAC5B,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,KAAK,IAAI,CAAC;IACzE,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,SAAS,EAAE,OAAO,CAAC;IACnB,gBAAgB,CAAC,EAAE,cAAc,EAAE,CAAC;CACrC,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,EAAE,CAAC,SAAS,CAwoBzC,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { LAYOUT_MODE } from 'commons/constants';
|
|
3
3
|
import { useCallback, useEffect, useRef, useState, } from 'react';
|
|
4
4
|
import { motion, AnimatePresence } from 'framer-motion';
|
|
@@ -10,18 +10,16 @@ import { useConfiguration } from '../../hooks/useConfiguration';
|
|
|
10
10
|
import { createAttachments, getAudioTranscript, } from '../../services/chat.service';
|
|
11
11
|
import { cn, generateExtendedFileName, generateUUID, } from '../../utils/commonUtils';
|
|
12
12
|
import { getBestMimeType, getFileExtension } from '../../utils/fileUtils';
|
|
13
|
-
import { ArrowUpIcon, ClikMicrophoneIcon, PlusIcon } from './Icons';
|
|
13
|
+
import { ArrowUpIcon, ClikMicrophoneIcon, PlusIcon, StopIcon } from './Icons';
|
|
14
14
|
import SuggestedActions from './SuggestedActions';
|
|
15
15
|
import { Button } from './ui/Button';
|
|
16
16
|
import { Textarea } from './ui/Textarea';
|
|
17
17
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from './ui/DropdownMenu';
|
|
18
18
|
import { VoiceRecordingUI } from './VoiceRecordingUI';
|
|
19
19
|
import { PreviewFileAttachment } from './PreviewFileAttachment';
|
|
20
|
-
const DEFAULT_COLOR_ICON = '#595959';
|
|
21
|
-
const ACTIVE_COLOR_ICON = '#0A82F7';
|
|
22
20
|
export const MultimodalInput = ({ input, setInput, isLoading, stop, messages, setMessages, chatId, handleSubmit, className, append, attachments, setAttachments, bot, apiHost, setEnableTTS, enableTTS, suggestedActions, }) => {
|
|
23
|
-
const { theme,
|
|
24
|
-
const { isRecording,
|
|
21
|
+
const { theme, onLoaded } = useConfiguration();
|
|
22
|
+
const { isRecording, onRecordingCancelled, onRecordingStopped, onRecordingStarted, elapsedTime, audioData, updateMaxHistoryLength, } = useAudioRecording();
|
|
25
23
|
const { listeners } = useChatData();
|
|
26
24
|
const textareaRef = useRef(null);
|
|
27
25
|
const inputRef = useRef(null);
|
|
@@ -34,7 +32,6 @@ export const MultimodalInput = ({ input, setInput, isLoading, stop, messages, se
|
|
|
34
32
|
?.find((option) => option.code === theme?.language?.code)
|
|
35
33
|
?.name?.toLowerCase() || 'en';
|
|
36
34
|
const [suggestedActionRows, setSuggestedActionRows] = useState(defaultRows); // only use for scroll mode SuggestedActions
|
|
37
|
-
const [openVoice, setOpenVoice] = useState(false);
|
|
38
35
|
const [transcribing, setTranscribing] = useState(false);
|
|
39
36
|
const [isMultiline, setIsMultiline] = useState(false);
|
|
40
37
|
const [dropdownOpen, setDropdownOpen] = useState(false);
|
|
@@ -240,9 +237,6 @@ export const MultimodalInput = ({ input, setInput, isLoading, stop, messages, se
|
|
|
240
237
|
}
|
|
241
238
|
}
|
|
242
239
|
}, [setUploadQueue, uploadFile]);
|
|
243
|
-
const handleLogicShowFAQ = () => {
|
|
244
|
-
setSuggestedActionRows(suggestedActionRows === defaultRows ? expandedRows : defaultRows);
|
|
245
|
-
};
|
|
246
240
|
const handleFileChange = useCallback(async (event) => {
|
|
247
241
|
const files = Array.from(event.target.files || []);
|
|
248
242
|
try {
|
|
@@ -319,6 +313,9 @@ export const MultimodalInput = ({ input, setInput, isLoading, stop, messages, se
|
|
|
319
313
|
submitForm();
|
|
320
314
|
}
|
|
321
315
|
}, [submitForm, isRecording]);
|
|
316
|
+
const handleWidthChange = useCallback((maxBars) => {
|
|
317
|
+
updateMaxHistoryLength(maxBars);
|
|
318
|
+
}, [updateMaxHistoryLength]);
|
|
322
319
|
const placeholder = !isRecording && !transcribing
|
|
323
320
|
? theme?.input?.placeholder || 'Send a message...'
|
|
324
321
|
: theme?.input?.transcribingPlaceholder || 'Transcribing...';
|
|
@@ -345,35 +342,12 @@ export const MultimodalInput = ({ input, setInput, isLoading, stop, messages, se
|
|
|
345
342
|
setDropdownOpen(false);
|
|
346
343
|
}, className: "flex items-center gap-2 px-4", children: [_jsx(Paperclip, { size: 16 }), _jsx("span", { className: "text-[14px]", children: "Upload File" })] }), _jsxs(DropdownMenuItem, { onClick: () => {
|
|
347
344
|
setEnableTTS(!enableTTS);
|
|
348
|
-
}, className: `flex items-center gap-2 px-4 ${enableTTS ? 'bg-[#CBE1F3] text-[#0A82F7]' : ''}`, children: [_jsx(Volume2, {}), _jsx("span", { className: "text-[14px]", children: theme?.buttons?.textBtnSpeak || 'Speak' })] })] })] })), _jsxs("div", { className: "block flex-1 min-w-0 relative", children: [
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
if (isRecording) {
|
|
355
|
-
return;
|
|
356
|
-
}
|
|
357
|
-
if (event.key === 'Enter' && !event.shiftKey) {
|
|
358
|
-
event.preventDefault();
|
|
359
|
-
if (isLoading) {
|
|
360
|
-
console.error('Please wait for the model to finish its response!');
|
|
361
|
-
}
|
|
362
|
-
else if (uploadQueue.length) {
|
|
363
|
-
console.error('Please wait for file is uploading!');
|
|
364
|
-
}
|
|
365
|
-
else if (input.length > 0) {
|
|
366
|
-
handleSend();
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
} }, "input"), _jsx(motion.div, { initial: { opacity: 0, height: 40 }, animate: { opacity: 1, height: 'auto' }, exit: { opacity: 0, height: 40 }, transition: {
|
|
370
|
-
duration: 0.2,
|
|
371
|
-
ease: 'easeInOut',
|
|
372
|
-
}, style: {
|
|
373
|
-
display: isMultiline ? 'block' : 'none',
|
|
374
|
-
}, children: _jsx(Textarea, { readOnly: readonly, ref: textareaRef, placeholder: placeholder, value: input, onChange: handleInput, className: cn(`min-h-[24px] max-h-[160px] resize-none text-base bg-muted bg-[#ffffff] scrollbar-hidden p-[12px] pb-[32px] rounded-[24px] border border-[#E5E5E5] shadow-[0px_2px_6px_0px_rgba(0,0,0,0.08)] backdrop-blur-[50px] ${suggestedActionRows === expandedRows && 'p-[12px]'} `, className), style: {
|
|
375
|
-
height: suggestedActionRows === expandedRows ? 60 : undefined,
|
|
376
|
-
}, autoFocus: true, onKeyDown: (event) => {
|
|
345
|
+
}, className: `flex items-center gap-2 px-4 ${enableTTS ? 'bg-[#CBE1F3] text-[#0A82F7]' : ''}`, children: [_jsx(Volume2, {}), _jsx("span", { className: "text-[14px]", children: theme?.buttons?.textBtnSpeak || 'Speak' })] })] })] })), _jsxs("div", { className: "block flex-1 min-w-0 relative", children: [_jsx(AnimatePresence, { mode: "wait", children: !isRecording && (_jsxs(_Fragment, { children: [_jsx(motion.input, { type: "text", readOnly: readonly, ref: inputRef, placeholder: placeholder, value: input, onChange: handleInput, className: cn(`h-[40px] outline-none text-base bg-muted bg-[#ffffff] scrollbar-hidden p-[12px] pr-[68px] rounded-[24px] backdrop-blur-[50px] w-full ${readonly ? 'hidden' : ''}`, className), autoFocus: true, initial: { opacity: 0, height: 0 }, animate: { opacity: 1, height: 40 }, exit: { opacity: 0, height: 0 }, transition: {
|
|
346
|
+
duration: 0.2,
|
|
347
|
+
ease: 'easeInOut',
|
|
348
|
+
}, style: {
|
|
349
|
+
display: isMultiline || transcribing ? 'none' : 'block',
|
|
350
|
+
}, onKeyDown: (event) => {
|
|
377
351
|
if (isRecording) {
|
|
378
352
|
return;
|
|
379
353
|
}
|
|
@@ -389,12 +363,39 @@ export const MultimodalInput = ({ input, setInput, isLoading, stop, messages, se
|
|
|
389
363
|
handleSend();
|
|
390
364
|
}
|
|
391
365
|
}
|
|
392
|
-
} }
|
|
366
|
+
} }, "input"), _jsx(motion.div, { initial: { opacity: 0, height: 40 }, animate: { opacity: 1, height: 'auto' }, exit: { opacity: 0, height: 40 }, transition: {
|
|
367
|
+
duration: 0.2,
|
|
368
|
+
ease: 'easeInOut',
|
|
369
|
+
}, style: {
|
|
370
|
+
display: isMultiline || transcribing ? 'block' : 'none',
|
|
371
|
+
}, children: _jsx(Textarea, { readOnly: readonly, ref: textareaRef, placeholder: placeholder, value: input, onChange: handleInput, className: cn(`min-h-[24px] max-h-[160px] resize-none text-base bg-muted bg-[#ffffff] scrollbar-hidden p-[12px] pb-[32px] rounded-[24px] border border-[#E5E5E5] shadow-[0px_2px_6px_0px_rgba(0,0,0,0.08)] backdrop-blur-[50px] ${suggestedActionRows === expandedRows && 'p-[12px]'} `, className), style: {
|
|
372
|
+
height: suggestedActionRows === expandedRows ? 60 : undefined,
|
|
373
|
+
}, autoFocus: true, onKeyDown: (event) => {
|
|
374
|
+
if (isRecording) {
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
if (event.key === 'Enter' && !event.shiftKey) {
|
|
378
|
+
event.preventDefault();
|
|
379
|
+
if (isLoading) {
|
|
380
|
+
console.error('Please wait for the model to finish its response!');
|
|
381
|
+
}
|
|
382
|
+
else if (uploadQueue.length) {
|
|
383
|
+
console.error('Please wait for file is uploading!');
|
|
384
|
+
}
|
|
385
|
+
else if (input.length > 0) {
|
|
386
|
+
handleSend();
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
} }) }, "textarea")] })) }), _jsx("div", { className: "w-full ", children: _jsx(VoiceRecordingUI, { isRecording: isRecording, elapsedTime: elapsedTime, onCancel: handleCancelRecording, transcribing: transcribing, audioData: audioData, label: recordingPlaceholder, onWidthChange: handleWidthChange }) }), _jsxs("div", { className: "button-voice right-[4px] absolute bottom-[4px] flex gap-[12px]", children: [!isRecording && (_jsx(Button, { className: "rounded-full z-[2] p-1.5 h-[32px] w-[32px] m-0 bg-transparent", onClick: (event) => {
|
|
393
390
|
event.preventDefault();
|
|
394
391
|
handleStartRecording();
|
|
395
|
-
}, disabled: isLoading, children: _jsx(ClikMicrophoneIcon, { size: 20 }) })), _jsx(Button, { className: "rounded-full z-[2] p-1.5 h-[32px] w-[32px] m-0 border bg-[#71717A]", onClick: (event) => {
|
|
392
|
+
}, disabled: isLoading, children: _jsx(ClikMicrophoneIcon, { size: 20 }) })), isLoading ? (_jsx(Button, { className: "rounded-full z-[2] p-1.5 h-[32px] w-[32px] m-0 border bg-[#71717A]", onClick: (event) => {
|
|
393
|
+
event.preventDefault();
|
|
394
|
+
stop();
|
|
395
|
+
setMessages(messages);
|
|
396
|
+
}, children: _jsx(StopIcon, { size: 20 }) })) : (_jsx(Button, { className: "rounded-full z-[2] p-1.5 h-[32px] w-[32px] m-0 border bg-[#71717A]", onClick: (event) => {
|
|
396
397
|
event.preventDefault();
|
|
397
398
|
handleSend();
|
|
398
|
-
}, disabled: isRecording || input.length === 0 || !!uploadQueue.length, children: _jsx(ArrowUpIcon, { size: 20 }) })] })] }), _jsx("input", { type: "file", ref: fileInputRef, onChange: handleFileChange, multiple: true, accept: "image/*,video/*,audio/*,.pdf,.doc,.docx,.txt", style: { display: 'none' } })] })] }));
|
|
399
|
+
}, disabled: isRecording || input.length === 0 || !!uploadQueue.length, children: _jsx(ArrowUpIcon, { size: 20 }) }))] })] }), _jsx("input", { type: "file", ref: fileInputRef, onChange: handleFileChange, multiple: true, accept: "image/*,video/*,audio/*,.pdf,.doc,.docx,.txt", style: { display: 'none' } })] })] }));
|
|
399
400
|
};
|
|
400
401
|
//# sourceMappingURL=MultimodalInput.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultimodalInput.js","sourceRoot":"","sources":["../../../src/components/Chat/MultimodalInput.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAGL,WAAW,EACX,SAAS,EACT,MAAM,EACN,QAAQ,GACT,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGlD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EACL,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,6BAA6B,CAAC;AAGrC,OAAO,EACL,EAAE,EACF,wBAAwB,EACxB,YAAY,GACb,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACpE,OAAO,gBAAgB,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,MAAM,kBAAkB,GAAG,SAAS,CAAC;AACrC,MAAM,iBAAiB,GAAG,SAAS,CAAC;AAyBpC,MAAM,CAAC,MAAM,eAAe,GAAkB,CAAC,EAC7C,KAAK,EACL,QAAQ,EACR,SAAS,EACT,IAAI,EACJ,QAAQ,EACR,WAAW,EACX,MAAM,EACN,YAAY,EACZ,SAAS,EACT,MAAM,EACN,WAAW,EACX,cAAc,EACd,GAAG,EACH,OAAO,EACP,YAAY,EACZ,SAAS,EACT,gBAAgB,GACjB,EAAE,EAAE;IACH,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,QAAQ,EAAE,GAC9D,gBAAgB,EAAE,CAAC;IACrB,MAAM,EACJ,WAAW,EACX,cAAc,EACd,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,EAClB,WAAW,EACX,kBAAkB,EAClB,SAAS,GACV,GAAG,iBAAiB,EAAE,CAAC;IACxB,MAAM,EAAE,SAAS,EAAE,GAAG,WAAW,EAAE,CAAC;IACpC,MAAM,WAAW,GAAG,MAAM,CAA6B,IAAI,CAAC,CAAC;IAC7D,MAAM,QAAQ,GAAG,MAAM,CAA0B,IAAI,CAAC,CAAC;IACvD,MAAM,WAAW,GAAG,MAAM,CAAmC,IAAI,CAAC,CAAC;IAEnE,MAAM,EAAE,KAAK,EAAE,GAAG,aAAa,EAAE,CAAC;IAElC,MAAM,WAAW,GAAG,KAAK,EAAE,UAAU,EAAE,WAAW,IAAI,CAAC,CAAC;IACxD,MAAM,YAAY,GAAG,KAAK,EAAE,UAAU,EAAE,YAAY,IAAI,CAAC,CAAC;IAC1D,MAAM,yBAAyB,GAC7B,KAAK,EAAE,UAAU,EAAE,UAAU,IAAI,WAAW,CAAC,MAAM,CAAC;IAEtD,MAAM,QAAQ,GACZ,KAAK,EAAE,QAAQ,EAAE,OAAO;QACtB,EAAE,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC;QACzD,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,IAAI,CAAC;IAElC,MAAM,CAAC,mBAAmB,EAAE,sBAAsB,CAAC,GACjD,QAAQ,CAAS,WAAW,CAAC,CAAC,CAAC,4CAA4C;IAE7E,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAU,KAAK,CAAC,CAAC;IAC3D,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAU,KAAK,CAAC,CAAC;IACjE,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAU,KAAK,CAAC,CAAC;IAC/D,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAU,KAAK,CAAC,CAAC;IAEjE,MAAM,YAAY,GAAG,GAAG,EAAE;QACxB,IAAI,WAAW,CAAC,OAAO,EAAE,CAAC;YACvB,WAAW,CAAC,OAA+B,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;YAClE,WAAW,CAAC,OAA+B,CAAC,KAAK,CAAC,MAAM;gBACvD,GAAG,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,CAAC,IAAI,CAAC;QACjD,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,CAAC,iBAAiB,EAAE,oBAAoB,CAAC,GAAG,eAAe,CAC/D,OAAO,EACP,EAAE,CACH,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,WAAW,CAAC,OAAO,EAAE,CAAC;YACxB,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC;YAC5C,yDAAyD;YACzD,MAAM,UAAU,GAAG,QAAQ,IAAI,iBAAiB,IAAI,EAAE,CAAC;YACvD,QAAQ,CAAC,UAAU,CAAC,CAAC;YACrB,YAAY,EAAE,CAAC;YAEf,UAAU,CAAC,GAAG,EAAE;gBACd,IAAI,WAAW,CAAC,OAAO,EAAE,CAAC;oBACxB,WAAW,CAAC,OAAO,CAAC,SAAS,GAAG,WAAW,CAAC,OAAO,CAAC,YAAY,CAAC;gBACnE,CAAC;YACH,CAAC,EAAE,GAAG,CAAC,CAAC;QACV,CAAC;QACD,gCAAgC;QAChC,uDAAuD;IACzD,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,SAAS,CAAC,GAAG,EAAE;QACb,oBAAoB,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,CAAC,CAAC,CAAC;IAElC,MAAM,QAAQ,GAAG,WAAW,IAAI,YAAY,CAAC;IAC7C,MAAM,cAAc,GAAG,CAAC,KAAa,EAAE,EAAE;QACvC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClB,CAAC,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,YAAY,EAAE,CAAC;QACf,IAAI,mBAAmB,KAAK,WAAW,EAAE,CAAC;YACxC,sBAAsB,CAAC,WAAW,CAAC,CAAC;QACtC,CAAC;IACH,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC;IAEtB,+DAA+D;IAC/D,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,WAAW,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;YACrC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACzB,sBAAsB;YACtB,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC;YAC7C,QAAQ,CAAC,OAAO,CAAC,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACrD,CAAC;aAAM,IAAI,WAAW,IAAI,WAAW,CAAC,OAAO,EAAE,CAAC;YAC9C,WAAW,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YAC5B,sBAAsB;YACtB,MAAM,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC;YAChD,WAAW,CAAC,OAAO,CAAC,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACtD,kBAAkB;YAClB,WAAW,CAAC,OAAO,CAAC,SAAS,GAAG,WAAW,CAAC,OAAO,CAAC,YAAY,CAAC;QACnE,CAAC;IACH,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;IAElB,SAAS,CAAC,GAAG,EAAE;QACb,WAAW,CAAC,OAAO,GAAG,QAAQ,CAAC;IACjC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEf,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,QAAQ,EAAE,CAAC;YACb,QAAQ,CAAC;gBACP,QAAQ,EAAE,CAAC,GAAG,EAAQ,EAAE;oBACtB,IAAI,WAAW,CAAC,OAAO,EAAE,CAAC;wBACxB,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC;oBACjC,CAAC;gBACH,CAAC;gBACD,cAAc,EAAE,KAAK,IAAI,EAAE;oBACzB,oBAAoB,EAAE,CAAC;gBACzB,CAAC;aACF,CAAC,CAAC;QACL,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,WAAW,GAAG,CAClB,KAA0D,EAC1D,EAAE;QACF,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;QACpC,cAAc,CAAC,QAAQ,CAAC,CAAC;QAEzB,uDAAuD;QACvD,IAAI,CAAC,WAAW,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5C,cAAc,CAAC,IAAI,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QAED,0CAA0C;QAC1C,IAAI,CAAC,WAAW,IAAI,QAAQ,CAAC,OAAO,IAAI,QAAQ,EAAE,CAAC;YACjD,qCAAqC;YACrC,UAAU,CAAC,GAAG,EAAE;gBACd,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC;gBACtC,IAAI,YAAY,EAAE,CAAC;oBACjB,MAAM,SAAS,GAAG,YAAY,CAAC,WAAW,GAAG,YAAY,CAAC,WAAW,CAAC;oBACtE,IAAI,SAAS,EAAE,CAAC;wBACd,cAAc,CAAC,IAAI,CAAC,CAAC;oBACvB,CAAC;gBACH,CAAC;YACH,CAAC,EAAE,CAAC,CAAC,CAAC;QACR,CAAC;QAED,uCAAuC;QACvC,IAAI,CAAC,QAAQ,IAAI,WAAW,EAAE,CAAC;YAC7B,cAAc,CAAC,KAAK,CAAC,CAAC;QACxB,CAAC;QAED,IAAI,WAAW,CAAC,OAAO,EAAE,CAAC;YACxB,WAAW,CAAC,OAAO,CAAC,SAAS,GAAG,WAAW,CAAC,OAAO,CAAC,YAAY,CAAC;QACnE,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,YAAY,GAAG,MAAM,CAA0B,IAAI,CAAC,CAAC;IAC3D,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAgB,EAAE,CAAC,CAAC;IAElE,MAAM,UAAU,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QACxC,YAAY,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QACrC,oBAAoB,CAAC,EAAE,CAAC,CAAC;QACzB,IAAI,cAAc,EAAE,CAAC;YACnB,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;YAC1B,IAAI,YAAY,CAAC,OAAO,EAAE,CAAC;gBACxB,YAAY,CAAC,OAA4B,CAAC,KAAK,GAAG,EAAE,CAAC;YACxD,CAAC;QACH,CAAC;QACD,IAAI,KAAK,IAAI,KAAK,GAAG,GAAG,EAAE,CAAC;YACzB,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;QAC/B,CAAC;IACH,CAAC,EAAE,CAAC,YAAY,EAAE,oBAAoB,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IAE1E,MAAM,UAAU,GAAG,WAAW,CAC5B,KAAK,EAAE,IAAU,EAAE,EAAE;QACnB,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC;QAChC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,wBAAwB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACnE,IAAI,CAAC;YACH,OAAO,MAAM,iBAAiB,CAAC;gBAC7B,MAAM;gBACN,OAAO;gBACP,IAAI,EAAE,QAAQ;aACf,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC,EACD,CAAC,MAAM,CAAC,CACT,CAAC;IAEF,MAAM,aAAa,GAAG,CAAC,IAAU,EAAE,EAAE;QACnC,OAAO,IAAI,OAAO,CAAc,CAAC,OAAO,EAAE,EAAE;YAC1C,IAAI,QAAQ,GAAG,eAAe,EAAE,CAAC;YACjC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACnC,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;gBACf,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC;YACvB,CAAC;iBAAM,CAAC;gBACN,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YACzC,CAAC;YAED,gCAAgC;YAChC,MAAM,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;YAChC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;YAC3B,MAAM,CAAC,SAAS,GAAG,GAAG,EAAE;gBACtB,MAAM,UAAU,GAAG,MAAM,CAAC,MAAgB,CAAC;gBAC3C,MAAM,MAAM,GAAgB;oBAC1B,MAAM,EAAE,YAAY,EAAE;oBACtB,IAAI,EAAE,UAAU;oBAChB,IAAI,EAAE,OAAO;oBACb,IAAI,EAAE,SAAS,IAAI,CAAC,GAAG,EAAE,IAAI,gBAAgB,CAAC,QAAQ,CAAC,EAAE;oBACzD,IAAI,EAAE,QAAQ;iBACf,CAAC;gBACF,OAAO,CAAC,MAAM,CAAC,CAAC;YAClB,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAG,KAAK,EACpB,IAAU,EACV,IAAI,GAAG,MAAM,EACqB,EAAE;QACpC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;YAChC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;YAC3B,MAAM,CAAC,MAAM,GAAG,GAAG,EAAE;gBACnB,OAAO,CAAC;oBACN,MAAM,EAAE,YAAY,EAAE;oBACtB,IAAI,EAAE,MAAM,CAAC,MAAgB;oBAC7B,IAAI;oBACJ,IAAI,EAAE,wBAAwB,CAAC,IAAI,CAAC,IAAI,CAAC;oBACzC,IAAI,EAAE,IAAI,CAAC,IAAI;iBAChB,CAAC,CAAC;YACL,CAAC,CAAC;YACF,MAAM,CAAC,OAAO,GAAG,GAAG,EAAE;gBACpB,MAAM,EAAE,CAAC;YACX,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,eAAe,GAAG,WAAW,CACjC,KAAK,EAAE,IAAU,EAAoC,EAAE;QACrD,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAClC,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;aAAM,CAAC;YACN,cAAc,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YAC5B,MAAM,QAAQ,GAAQ,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;YAC7C,IAAI,QAAQ,EAAE,IAAI,IAAI,WAAW,EAAE,CAAC;gBAClC,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;gBAC7B,IAAI,CAAC,CAAC,EAAE,CAAC;oBACP,OAAO;gBACT,CAAC;gBACD,OAAO;oBACL,MAAM,EAAE,YAAY,EAAE;oBACtB,IAAI,EAAE,CAAC,CAAC,OAAO;oBACf,IAAI,EAAE,CAAC,CAAC,IAAI;oBACZ,IAAI,EAAE,CAAC,CAAC,QAAQ;oBAChB,IAAI,EAAE,QAAQ,EAAE,IAAI;iBACrB,CAAC;YACJ,CAAC;iBAAM,IAAI,QAAQ,EAAE,IAAI,IAAI,UAAU,EAAE,CAAC;gBACxC,MAAM,EAAE,SAAS,EAAE,GAAG,QAAQ,CAAC,MAAM,CAAC;gBACtC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;oBACtB,OAAO;gBACT,CAAC;gBACD,OAAO,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;IACH,CAAC,EACD,CAAC,cAAc,EAAE,UAAU,CAAC,CAC7B,CAAC;IAEF,MAAM,kBAAkB,GAAG,GAAG,EAAE;QAC9B,sBAAsB,CACpB,mBAAmB,KAAK,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,WAAW,CACjE,CAAC;IACJ,CAAC,CAAC;IAEF,MAAM,gBAAgB,GAAG,WAAW,CAClC,KAAK,EAAE,KAAoC,EAAE,EAAE;QAC7C,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;QACnD,IAAI,CAAC;YACH,MAAM,cAAc,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;YAClE,MAAM,mBAAmB,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;YAC9D,MAAM,+BAA+B,GAAG,mBAAmB,CAAC,MAAM,CAChE,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,KAAK,SAAS,CACxB,CAAC;YACnB,IAAI,cAAc,EAAE,CAAC;gBACnB,cAAc,CAAC,CAAC,kBAAiC,EAAE,EAAE,CAAC;oBACpD,GAAG,kBAAkB;oBACrB,GAAG,+BAA+B;iBACnC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,KAAK,CAAC,CAAC;QACjD,CAAC;gBAAS,CAAC;YACT,cAAc,CAAC,EAAE,CAAC,CAAC;QACrB,CAAC;IACH,CAAC,EACD,CAAC,cAAc,EAAE,eAAe,CAAC,CAClC,CAAC;IAEF,MAAM,YAAY,GAAG,KAAK,EAAE,IAAU,EAAE,EAAE;QACxC,IAAI,CAAC;YACH,eAAe,CAAC,IAAI,CAAC,CAAC;YACtB,cAAc,CAAC,IAAI,CAAC,CAAC;YACrB,MAAM,UAAU,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAC;YAC7C,MAAM,UAAU,GAAG,UAAU,CAAC,IAAK,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC;YACpE,MAAM,cAAc,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,uBAAuB;YAChE,MAAM,WAAW,GAAG,IAAI,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;YAErD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,cAAc,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC/C,WAAW,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAChD,CAAC;YAED,MAAM,SAAS,GAAG,IAAI,UAAU,CAAC,WAAW,CAAC,CAAC;YAC9C,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,SAAS,CAAC,EAAE,UAAU,CAAC,IAAI,EAAE;gBAClD,YAAY,EAAE,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE;gBAClC,IAAI,EAAE,UAAU,CAAC,IAAI;aACtB,CAAC,CAAC;YAEH,MAAM,IAAI,GAAG,MAAM,kBAAkB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;YACnE,IAAI,IAAI,EAAE,CAAC;gBACT,cAAc,CAAC,IAAI,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,iCAAiC,EAAE,KAAK,CAAC,CAAC;QAC1D,CAAC;gBAAS,CAAC;YACT,eAAe,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,qBAAqB,GAAG,GAAG,EAAE;QACjC,IAAI,WAAW,EAAE,CAAC;YAChB,kBAAkB,CAAC,YAAY,CAAC,CAAC;QACnC,CAAC;QACD,IAAI,SAAS,EAAE,CAAC,uBAAuB,CAAC,EAAE,CAAC;YACzC,SAAS,CAAC,uBAAuB,CAAC,EAAE,CAAC;QACvC,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,oBAAoB,GAAG,GAAG,EAAE;QAChC,cAAc,CAAC,KAAK,CAAC,CAAC;QACtB,kBAAkB,EAAE,CAAC;QACrB,cAAc,CAAC,EAAE,CAAC,CAAC;QACnB,IAAI,SAAS,EAAE,CAAC,oBAAoB,CAAC,EAAE,CAAC;YACtC,SAAS,CAAC,oBAAoB,CAAC,EAAE,CAAC;QACpC,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,qBAAqB,GAAG,GAAG,EAAE;QACjC,oBAAoB,EAAE,CAAC;QACvB,cAAc,CAAC,EAAE,CAAC,CAAC;QACnB,IAAI,SAAS,EAAE,CAAC,qBAAqB,CAAC,EAAE,CAAC;YACvC,SAAS,CAAC,qBAAqB,CAAC,EAAE,CAAC;QACrC,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,UAAU,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QACxC,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,UAAU,EAAE,CAAC;QACf,CAAC;IACH,CAAC,EAAE,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC;IAE9B,MAAM,WAAW,GACf,CAAC,WAAW,IAAI,CAAC,YAAY;QAC3B,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,WAAW,IAAI,mBAAmB;QAClD,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,uBAAuB,IAAI,iBAAiB,CAAC;IAEjE,MAAM,oBAAoB,GACxB,WAAW,IAAI,CAAC,YAAY;QAC1B,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,oBAAoB,IAAI,cAAc;QACtD,CAAC,CAAC,EAAE,CAAC;IAET,OAAO,CACL,eAAK,SAAS,EAAC,qCAAqC,aACjD,CAAC,CAAC,gBAAgB,EAAE,MAAM,IAAI,CAC7B,KAAC,gBAAgB,IACf,gBAAgB,EAAE,gBAAgB,EAClC,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,yBAAyB,EACrC,mBAAmB,EAAE,mBAAmB,GACxC,CACH,EACA,CAAC,CAAC,WAAW,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CACtE,eAAK,SAAS,EAAC,kEAAkE,aAC9E,WAAW,EAAE,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAChC,KAAC,qBAAqB,IAEpB,UAAU,EAAE,UAAU,EACtB,kBAAkB,EAAE,GAAG,EAAE;4BACvB,cAAc,EAAE,CAAC,CAAC,kBAAiC,EAAE,EAAE,CACrD,kBAAkB,CAAC,MAAM,CACvB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,MAAM,CACtC,CACF,CAAC;wBACJ,CAAC,IARI,UAAU,CAAC,MAAM,CAStB,CACH,CAAC,EACD,WAAW,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAC7B,KAAC,qBAAqB,IAEpB,kBAAkB,EAAE,GAAG,EAAE;4BACvB,cAAc,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC;wBAC5D,CAAC,EACD,UAAU,EAAE;4BACV,IAAI,EAAE,EAAE;4BACR,IAAI,EAAE,QAAQ;4BACd,IAAI,EAAE,EAAE;4BACR,IAAI,EAAE,EAAE;yBACT,EACD,WAAW,UAVN,QAAQ,CAWb,CACH,CAAC,IACE,CACP,EACD,eAAK,SAAS,EAAC,0CAA0C,aACtD,WAAW,CAAC,CAAC,CAAC,CACb,KAAC,MAAM,IACL,SAAS,EAAE,6EAA6E,EACxF,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;4BACjB,KAAK,CAAC,cAAc,EAAE,CAAC;4BACvB,qBAAqB,EAAE,CAAC;wBAC1B,CAAC,YAED,cAAK,SAAS,EAAC,oDAAoD,GAAO,GACnE,CACV,CAAC,CAAC,CAAC,CACF,MAAC,YAAY,IAAC,IAAI,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,aAC7D,KAAC,mBAAmB,IAAC,OAAO,kBAC1B,KAAC,MAAM,IACL,SAAS,EAAE,2EAA2E,EACtF,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;wCACjB,KAAK,CAAC,cAAc,EAAE,CAAC;oCACzB,CAAC,YAED,KAAC,QAAQ,IAAC,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,GAAI,GACjC,GACW,EACtB,MAAC,mBAAmB,IAClB,IAAI,EAAC,KAAK,EACV,KAAK,EAAC,OAAO,EACb,SAAS,EAAC,+DAA+D,aAEzE,MAAC,gBAAgB,IACf,OAAO,EAAE,GAAG,EAAE;4CACZ,qBAAqB;4CACrB,YAAY,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;4CAC9B,eAAe,CAAC,KAAK,CAAC,CAAC;wCACzB,CAAC,EACD,SAAS,EAAC,8BAA8B,aAExC,KAAC,SAAS,IAAC,IAAI,EAAE,EAAE,GAAI,EACvB,eAAM,SAAS,EAAC,aAAa,4BAAmB,IAC/B,EACnB,MAAC,gBAAgB,IACf,OAAO,EAAE,GAAG,EAAE;4CACZ,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC;wCAC3B,CAAC,EACD,SAAS,EAAE,gCAAgC,SAAS,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAC,CAAC,EAAE,EAAE,aAE3F,KAAC,OAAO,KAAG,EACX,eAAM,SAAS,EAAC,aAAa,YAC1B,KAAK,EAAE,OAAO,EAAE,YAAY,IAAI,OAAO,GACnC,IACU,IACC,IACT,CAChB,EACD,eAAK,SAAS,EAAC,+BAA+B,aAE5C,MAAC,eAAe,IAAC,IAAI,EAAC,MAAM,aAC1B,KAAC,MAAM,CAAC,KAAK,IAEX,IAAI,EAAC,MAAM,EACX,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,QAAQ,EACb,WAAW,EAAE,WAAW,EACxB,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,WAAW,EACrB,SAAS,EAAE,EAAE,CACX,yIAAyI,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,EACnK,SAAS,CACV,EACD,SAAS,QACT,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAClC,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EACnC,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAC/B,UAAU,EAAE;4CACV,QAAQ,EAAE,GAAG;4CACb,IAAI,EAAE,WAAW;yCAClB,EACD,KAAK,EAAE;4CACL,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO;yCACxC,EACD,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;4CACnB,IAAI,WAAW,EAAE,CAAC;gDAChB,OAAO;4CACT,CAAC;4CAED,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;gDAC7C,KAAK,CAAC,cAAc,EAAE,CAAC;gDACvB,IAAI,SAAS,EAAE,CAAC;oDACd,OAAO,CAAC,KAAK,CACX,mDAAmD,CACpD,CAAC;gDACJ,CAAC;qDAAM,IAAI,WAAW,CAAC,MAAM,EAAE,CAAC;oDAC9B,OAAO,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;gDACtD,CAAC;qDAAM,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oDAC5B,UAAU,EAAE,CAAC;gDACf,CAAC;4CACH,CAAC;wCACH,CAAC,IAvCG,OAAO,CAwCX,EACF,KAAC,MAAM,CAAC,GAAG,IAET,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EACnC,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EACvC,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAChC,UAAU,EAAE;4CACV,QAAQ,EAAE,GAAG;4CACb,IAAI,EAAE,WAAW;yCAClB,EACD,KAAK,EAAE;4CACL,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM;yCACxC,YAED,KAAC,QAAQ,IACP,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,WAAW,EAChB,WAAW,EAAE,WAAW,EACxB,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,WAAW,EACrB,SAAS,EAAE,EAAE,CACX,oNAAoN,mBAAmB,KAAK,YAAY,IAAI,UAAU,GAAG,EACzQ,SAAS,CACV,EACD,KAAK,EAAE;gDACL,MAAM,EAAE,mBAAmB,KAAK,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;6CAC9D,EACD,SAAS,QACT,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;gDACnB,IAAI,WAAW,EAAE,CAAC;oDAChB,OAAO;gDACT,CAAC;gDAED,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;oDAC7C,KAAK,CAAC,cAAc,EAAE,CAAC;oDACvB,IAAI,SAAS,EAAE,CAAC;wDACd,OAAO,CAAC,KAAK,CACX,mDAAmD,CACpD,CAAC;oDACJ,CAAC;yDAAM,IAAI,WAAW,CAAC,MAAM,EAAE,CAAC;wDAC9B,OAAO,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;oDACtD,CAAC;yDAAM,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wDAC5B,UAAU,EAAE,CAAC;oDACf,CAAC;gDACH,CAAC;4CACH,CAAC,GACD,IA5CE,UAAU,CA6CH,IACG,EAElB,KAAC,gBAAgB,IACf,WAAW,EAAE,WAAW,EACxB,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,qBAAqB,EAC/B,YAAY,EAAE,YAAY,EAC1B,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,oBAAoB,GAC3B,EACF,eAAK,SAAS,EAAC,gEAAgE,aAC5E,CAAC,WAAW,IAAI,CACf,KAAC,MAAM,IACL,SAAS,EAAC,+DAA+D,EACzE,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;4CACjB,KAAK,CAAC,cAAc,EAAE,CAAC;4CACvB,oBAAoB,EAAE,CAAC;wCACzB,CAAC,EACD,QAAQ,EAAE,SAAS,YAEnB,KAAC,kBAAkB,IAAC,IAAI,EAAE,EAAE,GAAI,GACzB,CACV,EACD,KAAC,MAAM,IACL,SAAS,EAAC,oEAAoE,EAC9E,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;4CACjB,KAAK,CAAC,cAAc,EAAE,CAAC;4CACvB,UAAU,EAAE,CAAC;wCACf,CAAC,EACD,QAAQ,EACN,WAAW,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,MAAM,YAG3D,KAAC,WAAW,IAAC,IAAI,EAAE,EAAE,GAAI,GAClB,IACL,IACF,EAEN,gBACE,IAAI,EAAC,MAAM,EACX,GAAG,EAAE,YAAY,EACjB,QAAQ,EAAE,gBAAgB,EAC1B,QAAQ,QACR,MAAM,EAAC,8CAA8C,EACrD,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,GAC1B,IACE,IACF,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { LAYOUT_MODE } from 'commons/constants';\nimport {\n type ChangeEvent,\n FC,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport { Volume2, Paperclip } from 'lucide-react';\n\nimport { SuggestionType } from 'types/common.type';\nimport { useLocalStorage, useWindowSize } from 'usehooks-ts';\nimport { useAudioRecording } from '../../hooks/useAudioRecording';\nimport { useChatData } from '../../hooks/useChatData';\nimport { useConfiguration } from '../../hooks/useConfiguration';\nimport {\n createAttachments,\n getAudioTranscript,\n} from '../../services/chat.service';\nimport { BotType } from '../../types/bot.type';\nimport { ChatMessageType, IFileUpload } from '../../types/flowise.type';\nimport {\n cn,\n generateExtendedFileName,\n generateUUID,\n} from '../../utils/commonUtils';\nimport { getBestMimeType, getFileExtension } from '../../utils/fileUtils';\nimport { ArrowUpIcon, ClikMicrophoneIcon, PlusIcon } from './Icons';\nimport SuggestedActions from './SuggestedActions';\nimport { Button } from './ui/Button';\nimport { Textarea } from './ui/Textarea';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from './ui/DropdownMenu';\nimport VoiceWidget from './voice/VoiceWidget';\nimport { VoiceRecordingUI } from './VoiceRecordingUI';\nimport { PreviewFileAttachment } from './PreviewFileAttachment';\n\nconst DEFAULT_COLOR_ICON = '#595959';\nconst ACTIVE_COLOR_ICON = '#0A82F7';\n\ntype PropsType = {\n input: string;\n setInput: (value: string) => void;\n isLoading: boolean;\n stop: () => void;\n messages: ChatMessageType[];\n setMessages: (messages: ChatMessageType[]) => void;\n chatId: string;\n handleSubmit: (\n event?: { preventDefault?: () => void },\n files?: IFileUpload[]\n ) => void;\n className?: string;\n append?: (message: ChatMessageType) => Promise<void>;\n attachments?: IFileUpload[];\n setAttachments?: (func: (files: IFileUpload[]) => IFileUpload[]) => void;\n bot: BotType | null;\n apiHost: string;\n setEnableTTS: (value: boolean) => void;\n enableTTS: boolean;\n suggestedActions?: SuggestionType[];\n};\n\nexport const MultimodalInput: FC<PropsType> = ({\n input,\n setInput,\n isLoading,\n stop,\n messages,\n setMessages,\n chatId,\n handleSubmit,\n className,\n append,\n attachments,\n setAttachments,\n bot,\n apiHost,\n setEnableTTS,\n enableTTS,\n suggestedActions,\n}) => {\n const { theme, voice, overrideConfig, skipSuggestion, onLoaded } =\n useConfiguration();\n const {\n isRecording,\n setIsRecording,\n onRecordingCancelled,\n onRecordingStopped,\n onRecordingStarted,\n elapsedTime,\n isLoadingRecording,\n audioData,\n } = useAudioRecording();\n const { listeners } = useChatData();\n const textareaRef = useRef<HTMLTextAreaElement | null>(null);\n const inputRef = useRef<HTMLInputElement | null>(null);\n const setInputRef = useRef<((input: string) => void) | null>(null);\n\n const { width } = useWindowSize();\n\n const defaultRows = theme?.suggestion?.defaultRows || 1;\n const expandedRows = theme?.suggestion?.expandedRows || 2;\n const suggestedActionLayoutMode =\n theme?.suggestion?.layoutMode || LAYOUT_MODE.SCROLL;\n\n const language =\n theme?.language?.options\n ?.find((option) => option.code === theme?.language?.code)\n ?.name?.toLowerCase() || 'en';\n\n const [suggestedActionRows, setSuggestedActionRows] =\n useState<number>(defaultRows); // only use for scroll mode SuggestedActions\n\n const [openVoice, setOpenVoice] = useState<boolean>(false);\n const [transcribing, setTranscribing] = useState<boolean>(false);\n const [isMultiline, setIsMultiline] = useState<boolean>(false);\n const [dropdownOpen, setDropdownOpen] = useState<boolean>(false);\n\n const adjustHeight = () => {\n if (textareaRef.current) {\n (textareaRef.current as HTMLTextAreaElement).style.height = 'auto';\n (textareaRef.current as HTMLTextAreaElement).style.height =\n `${textareaRef.current?.scrollHeight + 2}px`;\n }\n };\n\n const [localStorageInput, setLocalStorageInput] = useLocalStorage(\n 'input',\n ''\n );\n\n useEffect(() => {\n if (textareaRef.current) {\n const domValue = textareaRef.current?.value;\n // Prefer DOM value over localStorage to handle hydration\n const finalValue = domValue || localStorageInput || '';\n setInput(finalValue);\n adjustHeight();\n\n setTimeout(() => {\n if (textareaRef.current) {\n textareaRef.current.scrollTop = textareaRef.current.scrollHeight;\n }\n }, 500);\n }\n // Only run once after hydration\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n setLocalStorageInput(input);\n }, [input, setLocalStorageInput]);\n\n const readonly = isRecording || transcribing;\n const handleSetInput = (value: string) => {\n setInput(value);\n };\n\n useEffect(() => {\n adjustHeight();\n if (suggestedActionRows !== defaultRows) {\n setSuggestedActionRows(defaultRows);\n }\n }, [input, readonly]);\n\n // Focus vào element đúng khi chuyển đổi giữa input và textarea\n useEffect(() => {\n if (!isMultiline && inputRef.current) {\n inputRef.current.focus();\n // Set cursor tới cuối\n const length = inputRef.current.value.length;\n inputRef.current.setSelectionRange(length, length);\n } else if (isMultiline && textareaRef.current) {\n textareaRef.current.focus();\n // Set cursor tới cuối\n const length = textareaRef.current.value.length;\n textareaRef.current.setSelectionRange(length, length);\n // Scroll tới cuối\n textareaRef.current.scrollTop = textareaRef.current.scrollHeight;\n }\n }, [isMultiline]);\n\n useEffect(() => {\n setInputRef.current = setInput;\n }, [setInput]);\n\n useEffect(() => {\n if (onLoaded) {\n onLoaded({\n setInput: (txt): void => {\n if (setInputRef.current) {\n setInputRef.current(txt || '');\n }\n },\n startRecording: async () => {\n handleStartRecording();\n },\n });\n }\n }, []);\n\n const handleInput = (\n event: ChangeEvent<HTMLTextAreaElement | HTMLInputElement>\n ) => {\n const newValue = event.target.value;\n handleSetInput(newValue);\n\n // Nếu có newline (Enter) thì chuyển sang textarea ngay\n if (!isMultiline && newValue.includes('\\n')) {\n setIsMultiline(true);\n return;\n }\n\n // Kiểm tra scroll ngay khi input thay đổi\n if (!isMultiline && inputRef.current && newValue) {\n // Đợi DOM update rồi kiểm tra scroll\n setTimeout(() => {\n const currentInput = inputRef.current;\n if (currentInput) {\n const hasScroll = currentInput.scrollWidth > currentInput.clientWidth;\n if (hasScroll) {\n setIsMultiline(true);\n }\n }\n }, 0);\n }\n\n // Nếu xóa hết text thì chuyển về input\n if (!newValue && isMultiline) {\n setIsMultiline(false);\n }\n\n if (textareaRef.current) {\n textareaRef.current.scrollTop = textareaRef.current.scrollHeight;\n }\n };\n\n const fileInputRef = useRef<HTMLInputElement | null>(null);\n const [uploadQueue, setUploadQueue] = useState<Array<string>>([]);\n\n const submitForm = useCallback(async () => {\n handleSubmit(undefined, attachments);\n setLocalStorageInput('');\n if (setAttachments) {\n setAttachments((_) => []);\n if (fileInputRef.current) {\n (fileInputRef.current as HTMLInputElement).value = '';\n }\n }\n if (width && width > 768) {\n textareaRef.current?.focus();\n }\n }, [handleSubmit, setLocalStorageInput, width, attachments, chatId, bot]);\n\n const uploadFile = useCallback(\n async (file: File) => {\n const formData = new FormData();\n formData.append('file', file, generateExtendedFileName(file.name));\n try {\n return await createAttachments({\n chatId,\n apiHost,\n body: formData,\n });\n } catch (error) {\n console.error('Failed to upload file, please try again!');\n }\n },\n [chatId]\n );\n\n const toAudioBase64 = (blob: Blob) => {\n return new Promise<IFileUpload>((resolve) => {\n let mimeType = getBestMimeType();\n const pos = blob.type.indexOf(';');\n if (pos === -1) {\n mimeType = blob.type;\n } else {\n mimeType = blob.type.substring(0, pos);\n }\n\n // read blob and add to previews\n const reader = new FileReader();\n reader.readAsDataURL(blob);\n reader.onloadend = () => {\n const base64data = reader.result as string;\n const upload: IFileUpload = {\n tempId: generateUUID(),\n data: base64data,\n type: 'audio',\n name: `audio_${Date.now()}.${getFileExtension(mimeType)}`,\n mime: mimeType,\n };\n resolve(upload);\n };\n });\n };\n\n const toBase64 = async (\n file: File,\n type = 'file'\n ): Promise<IFileUpload | undefined> => {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.readAsDataURL(file);\n reader.onload = () => {\n resolve({\n tempId: generateUUID(),\n data: reader.result as string,\n type,\n name: generateExtendedFileName(file.name),\n mime: file.type,\n });\n };\n reader.onerror = () => {\n reject();\n };\n });\n };\n\n const checkUploadFile = useCallback(\n async (file: File): Promise<IFileUpload | undefined> => {\n if (file.type.startsWith('image')) {\n return toBase64(file);\n } else {\n setUploadQueue([file.name]);\n const response: any = await uploadFile(file);\n if (response?.type == 'file:full') {\n const f = response.result[0];\n if (!f) {\n return;\n }\n return {\n tempId: generateUUID(),\n data: f.content,\n name: f.name,\n mime: f.mimeType,\n type: response?.type,\n };\n } else if (response?.type == 'file:rag') {\n const { addedDocs } = response.result;\n if (!addedDocs.length) {\n return;\n }\n return toBase64(file, response?.type);\n }\n }\n },\n [setUploadQueue, uploadFile]\n );\n\n const handleLogicShowFAQ = () => {\n setSuggestedActionRows(\n suggestedActionRows === defaultRows ? expandedRows : defaultRows\n );\n };\n\n const handleFileChange = useCallback(\n async (event: ChangeEvent<HTMLInputElement>) => {\n const files = Array.from(event.target.files || []);\n try {\n const uploadPromises = files.map((file) => checkUploadFile(file));\n const uploadedAttachments = await Promise.all(uploadPromises);\n const successfullyUploadedAttachments = uploadedAttachments.filter(\n (attachment) => attachment !== undefined\n ) as IFileUpload[];\n if (setAttachments) {\n setAttachments((currentAttachments: IFileUpload[]) => [\n ...currentAttachments,\n ...successfullyUploadedAttachments,\n ]);\n }\n } catch (error) {\n console.error('Error uploading files!', error);\n } finally {\n setUploadQueue([]);\n }\n },\n [setAttachments, checkUploadFile]\n );\n\n const speechToText = async (blob: Blob) => {\n try {\n setTranscribing(true);\n setIsMultiline(true);\n const fileUpload = await toAudioBase64(blob);\n const base64Data = fileUpload.data!.replace(/^data:.+;base64,/, '');\n const byteCharacters = atob(base64Data); // Decode Base64 string\n const byteNumbers = new Array(byteCharacters.length);\n\n for (let i = 0; i < byteCharacters.length; i++) {\n byteNumbers[i] = byteCharacters.charCodeAt(i);\n }\n\n const byteArray = new Uint8Array(byteNumbers);\n const file = new File([byteArray], fileUpload.name, {\n lastModified: new Date().getTime(),\n type: fileUpload.type,\n });\n\n const text = await getAudioTranscript({ file, apiHost, language });\n if (text) {\n handleSetInput(text);\n }\n } catch (error) {\n console.error('Error getting audio transcript!', error);\n } finally {\n setTranscribing(false);\n }\n };\n\n const handleFinishRecording = () => {\n if (isRecording) {\n onRecordingStopped(speechToText);\n }\n if (listeners?.['ON_FINISHED_RECORDING']) {\n listeners['ON_FINISHED_RECORDING']();\n }\n };\n\n const handleStartRecording = () => {\n setIsMultiline(false);\n onRecordingStarted();\n handleSetInput('');\n if (listeners?.['ON_START_RECORDING']) {\n listeners['ON_START_RECORDING']();\n }\n };\n\n const handleCancelRecording = () => {\n onRecordingCancelled();\n handleSetInput('');\n if (listeners?.['ON_CANCEL_RECORDING']) {\n listeners['ON_CANCEL_RECORDING']();\n }\n };\n\n const handleSend = useCallback(async () => {\n if (!isRecording) {\n submitForm();\n }\n }, [submitForm, isRecording]);\n\n const placeholder =\n !isRecording && !transcribing\n ? theme?.input?.placeholder || 'Send a message...'\n : theme?.input?.transcribingPlaceholder || 'Transcribing...';\n\n const recordingPlaceholder =\n isRecording && !transcribing\n ? theme?.input?.recordingPlaceholder || 'Recording...'\n : '';\n\n return (\n <div className=\"relative w-full flex gap-4 flex-col\">\n {!!suggestedActions?.length && (\n <SuggestedActions\n suggestedActions={suggestedActions}\n append={append}\n layoutMode={suggestedActionLayoutMode}\n suggestedActionRows={suggestedActionRows}\n />\n )}\n {((attachments && attachments.length > 0) || uploadQueue.length > 0) && (\n <div className=\"list-attachments flex flex-row gap-2 overflow-x-scroll items-end\">\n {attachments?.map((attachment) => (\n <PreviewFileAttachment\n key={attachment.tempId}\n attachment={attachment}\n onRemoveAttachment={() => {\n setAttachments?.((currentAttachments: IFileUpload[]) =>\n currentAttachments.filter(\n (f) => f.tempId !== attachment.tempId\n )\n );\n }}\n />\n ))}\n {uploadQueue.map((filename) => (\n <PreviewFileAttachment\n key={filename}\n onRemoveAttachment={() => {\n setUploadQueue(uploadQueue.filter((f) => f !== filename));\n }}\n attachment={{\n data: '',\n name: filename,\n mime: '',\n type: '',\n }}\n isUploading\n />\n ))}\n </div>\n )}\n <div className=\" w-full flex gap-4 justify-end items-end\">\n {isRecording ? (\n <Button\n className={` rounded-full w-[40px] h-[40px] flex items-center justify-center bg-white `}\n onClick={(event) => {\n event.preventDefault();\n handleFinishRecording();\n }}\n >\n <div className=\"w-[12px] h-[12px] bg-muted-foreground rounded-full\"></div>\n </Button>\n ) : (\n <DropdownMenu open={dropdownOpen} onOpenChange={setDropdownOpen}>\n <DropdownMenuTrigger asChild>\n <Button\n className={` rounded-full w-[40px] h-[40px] flex items-center justify-center bg-white`}\n onClick={(event) => {\n event.preventDefault();\n }}\n >\n <PlusIcon size={20} color={'#71717A'} />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent\n side=\"top\"\n align=\"start\"\n className=\"w-48 rounded-2xl border py-[6px] border-[#0d0d0d0d] shadow-sm\"\n >\n <DropdownMenuItem\n onClick={() => {\n // Trigger file input\n fileInputRef.current?.click();\n setDropdownOpen(false);\n }}\n className=\"flex items-center gap-2 px-4\"\n >\n <Paperclip size={16} />\n <span className=\"text-[14px]\">Upload File</span>\n </DropdownMenuItem>\n <DropdownMenuItem\n onClick={() => {\n setEnableTTS(!enableTTS);\n }}\n className={`flex items-center gap-2 px-4 ${enableTTS ? 'bg-[#CBE1F3] text-[#0A82F7]' : ''}`}\n >\n <Volume2 />\n <span className=\"text-[14px]\">\n {theme?.buttons?.textBtnSpeak || 'Speak'}\n </span>\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n <div className=\"block flex-1 min-w-0 relative\">\n {/* Animated Input/Textarea Container */}\n <AnimatePresence mode=\"wait\">\n <motion.input\n key=\"input\"\n type=\"text\"\n readOnly={readonly}\n ref={inputRef}\n placeholder={placeholder}\n value={input}\n onChange={handleInput}\n className={cn(\n `h-[40px] outline-none text-base bg-muted bg-[#ffffff] scrollbar-hidden p-[12px] pr-[68px] rounded-[24px] backdrop-blur-[50px] w-full ${readonly ? 'hidden' : ''}`,\n className\n )}\n autoFocus\n initial={{ opacity: 0, height: 0 }}\n animate={{ opacity: 1, height: 40 }}\n exit={{ opacity: 0, height: 0 }}\n transition={{\n duration: 0.2,\n ease: 'easeInOut',\n }}\n style={{\n display: isMultiline ? 'none' : 'block',\n }}\n onKeyDown={(event) => {\n if (isRecording) {\n return;\n }\n\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n if (isLoading) {\n console.error(\n 'Please wait for the model to finish its response!'\n );\n } else if (uploadQueue.length) {\n console.error('Please wait for file is uploading!');\n } else if (input.length > 0) {\n handleSend();\n }\n }\n }}\n />\n <motion.div\n key=\"textarea\"\n initial={{ opacity: 0, height: 40 }}\n animate={{ opacity: 1, height: 'auto' }}\n exit={{ opacity: 0, height: 40 }}\n transition={{\n duration: 0.2,\n ease: 'easeInOut',\n }}\n style={{\n display: isMultiline ? 'block' : 'none',\n }}\n >\n <Textarea\n readOnly={readonly}\n ref={textareaRef}\n placeholder={placeholder}\n value={input}\n onChange={handleInput}\n className={cn(\n `min-h-[24px] max-h-[160px] resize-none text-base bg-muted bg-[#ffffff] scrollbar-hidden p-[12px] pb-[32px] rounded-[24px] border border-[#E5E5E5] shadow-[0px_2px_6px_0px_rgba(0,0,0,0.08)] backdrop-blur-[50px] ${suggestedActionRows === expandedRows && 'p-[12px]'} `,\n className\n )}\n style={{\n height: suggestedActionRows === expandedRows ? 60 : undefined,\n }}\n autoFocus\n onKeyDown={(event) => {\n if (isRecording) {\n return;\n }\n\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n if (isLoading) {\n console.error(\n 'Please wait for the model to finish its response!'\n );\n } else if (uploadQueue.length) {\n console.error('Please wait for file is uploading!');\n } else if (input.length > 0) {\n handleSend();\n }\n }\n }}\n />\n </motion.div>\n </AnimatePresence>\n {/* Voice Recording UI Overlay */}\n <VoiceRecordingUI\n isRecording={isRecording}\n elapsedTime={elapsedTime}\n onCancel={handleCancelRecording}\n transcribing={transcribing}\n audioData={audioData}\n label={recordingPlaceholder}\n />\n <div className=\"button-voice right-[4px] absolute bottom-[4px] flex gap-[12px]\">\n {!isRecording && (\n <Button\n className=\"rounded-full z-[2] p-1.5 h-[32px] w-[32px] m-0 bg-transparent\"\n onClick={(event) => {\n event.preventDefault();\n handleStartRecording();\n }}\n disabled={isLoading}\n >\n <ClikMicrophoneIcon size={20} />\n </Button>\n )}\n <Button\n className=\"rounded-full z-[2] p-1.5 h-[32px] w-[32px] m-0 border bg-[#71717A]\"\n onClick={(event) => {\n event.preventDefault();\n handleSend();\n }}\n disabled={\n isRecording || input.length === 0 || !!uploadQueue.length\n }\n >\n <ArrowUpIcon size={20} />\n </Button>\n </div>\n </div>\n {/* Hidden file input */}\n <input\n type=\"file\"\n ref={fileInputRef}\n onChange={handleFileChange}\n multiple\n accept=\"image/*,video/*,audio/*,.pdf,.doc,.docx,.txt\"\n style={{ display: 'none' }}\n />\n </div>\n </div>\n );\n};\n"]}
|
|
1
|
+
{"version":3,"file":"MultimodalInput.js","sourceRoot":"","sources":["../../../src/components/Chat/MultimodalInput.tsx"],"names":[],"mappings":"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","sourcesContent":["import { LAYOUT_MODE } from 'commons/constants';\nimport {\n type ChangeEvent,\n FC,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport { Volume2, Paperclip } from 'lucide-react';\n\nimport { SuggestionType } from 'types/common.type';\nimport { useLocalStorage, useWindowSize } from 'usehooks-ts';\nimport { useAudioRecording } from '../../hooks/useAudioRecording';\nimport { useChatData } from '../../hooks/useChatData';\nimport { useConfiguration } from '../../hooks/useConfiguration';\nimport {\n createAttachments,\n getAudioTranscript,\n} from '../../services/chat.service';\nimport { BotType } from '../../types/bot.type';\nimport { ChatMessageType, IFileUpload } from '../../types/flowise.type';\nimport {\n cn,\n generateExtendedFileName,\n generateUUID,\n} from '../../utils/commonUtils';\nimport { getBestMimeType, getFileExtension } from '../../utils/fileUtils';\nimport { ArrowUpIcon, ClikMicrophoneIcon, PlusIcon, StopIcon } from './Icons';\nimport SuggestedActions from './SuggestedActions';\nimport { Button } from './ui/Button';\nimport { Textarea } from './ui/Textarea';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from './ui/DropdownMenu';\n\nimport { VoiceRecordingUI } from './VoiceRecordingUI';\nimport { PreviewFileAttachment } from './PreviewFileAttachment';\n\ntype PropsType = {\n input: string;\n setInput: (value: string) => void;\n isLoading: boolean;\n stop: () => void;\n messages: ChatMessageType[];\n setMessages: (messages: ChatMessageType[]) => void;\n chatId: string;\n handleSubmit: (\n event?: { preventDefault?: () => void },\n files?: IFileUpload[]\n ) => void;\n className?: string;\n append?: (message: ChatMessageType) => Promise<void>;\n attachments?: IFileUpload[];\n setAttachments?: (func: (files: IFileUpload[]) => IFileUpload[]) => void;\n bot: BotType | null;\n apiHost: string;\n setEnableTTS: (value: boolean) => void;\n enableTTS: boolean;\n suggestedActions?: SuggestionType[];\n};\n\nexport const MultimodalInput: FC<PropsType> = ({\n input,\n setInput,\n isLoading,\n stop,\n messages,\n setMessages,\n chatId,\n handleSubmit,\n className,\n append,\n attachments,\n setAttachments,\n bot,\n apiHost,\n setEnableTTS,\n enableTTS,\n suggestedActions,\n}) => {\n const { theme, onLoaded } = useConfiguration();\n const {\n isRecording,\n onRecordingCancelled,\n onRecordingStopped,\n onRecordingStarted,\n elapsedTime,\n audioData,\n updateMaxHistoryLength,\n } = useAudioRecording();\n const { listeners } = useChatData();\n const textareaRef = useRef<HTMLTextAreaElement | null>(null);\n const inputRef = useRef<HTMLInputElement | null>(null);\n const setInputRef = useRef<((input: string) => void) | null>(null);\n\n const { width } = useWindowSize();\n\n const defaultRows = theme?.suggestion?.defaultRows || 1;\n const expandedRows = theme?.suggestion?.expandedRows || 2;\n const suggestedActionLayoutMode =\n theme?.suggestion?.layoutMode || LAYOUT_MODE.SCROLL;\n\n const language =\n theme?.language?.options\n ?.find((option) => option.code === theme?.language?.code)\n ?.name?.toLowerCase() || 'en';\n\n const [suggestedActionRows, setSuggestedActionRows] =\n useState<number>(defaultRows); // only use for scroll mode SuggestedActions\n\n const [transcribing, setTranscribing] = useState<boolean>(false);\n const [isMultiline, setIsMultiline] = useState<boolean>(false);\n const [dropdownOpen, setDropdownOpen] = useState<boolean>(false);\n\n const adjustHeight = () => {\n if (textareaRef.current) {\n (textareaRef.current as HTMLTextAreaElement).style.height = 'auto';\n (textareaRef.current as HTMLTextAreaElement).style.height =\n `${textareaRef.current?.scrollHeight + 2}px`;\n }\n };\n\n const [localStorageInput, setLocalStorageInput] = useLocalStorage(\n 'input',\n ''\n );\n\n useEffect(() => {\n if (textareaRef.current) {\n const domValue = textareaRef.current?.value;\n // Prefer DOM value over localStorage to handle hydration\n const finalValue = domValue || localStorageInput || '';\n setInput(finalValue);\n adjustHeight();\n\n setTimeout(() => {\n if (textareaRef.current) {\n textareaRef.current.scrollTop = textareaRef.current.scrollHeight;\n }\n }, 500);\n }\n // Only run once after hydration\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n setLocalStorageInput(input);\n }, [input, setLocalStorageInput]);\n\n const readonly = isRecording || transcribing;\n const handleSetInput = (value: string) => {\n setInput(value);\n };\n\n useEffect(() => {\n adjustHeight();\n if (suggestedActionRows !== defaultRows) {\n setSuggestedActionRows(defaultRows);\n }\n }, [input, readonly]);\n\n // Focus vào element đúng khi chuyển đổi giữa input và textarea\n useEffect(() => {\n if (!isMultiline && inputRef.current) {\n inputRef.current.focus();\n // Set cursor tới cuối\n const length = inputRef.current.value.length;\n inputRef.current.setSelectionRange(length, length);\n } else if (isMultiline && textareaRef.current) {\n textareaRef.current.focus();\n // Set cursor tới cuối\n const length = textareaRef.current.value.length;\n textareaRef.current.setSelectionRange(length, length);\n // Scroll tới cuối\n textareaRef.current.scrollTop = textareaRef.current.scrollHeight;\n }\n }, [isMultiline]);\n\n useEffect(() => {\n setInputRef.current = setInput;\n }, [setInput]);\n\n useEffect(() => {\n if (onLoaded) {\n onLoaded({\n setInput: (txt): void => {\n if (setInputRef.current) {\n setInputRef.current(txt || '');\n }\n },\n startRecording: async () => {\n handleStartRecording();\n },\n });\n }\n }, []);\n\n const handleInput = (\n event: ChangeEvent<HTMLTextAreaElement | HTMLInputElement>\n ) => {\n const newValue = event.target.value;\n handleSetInput(newValue);\n\n // Nếu có newline (Enter) thì chuyển sang textarea ngay\n if (!isMultiline && newValue.includes('\\n')) {\n setIsMultiline(true);\n return;\n }\n\n // Kiểm tra scroll ngay khi input thay đổi\n if (!isMultiline && inputRef.current && newValue) {\n // Đợi DOM update rồi kiểm tra scroll\n setTimeout(() => {\n const currentInput = inputRef.current;\n if (currentInput) {\n const hasScroll = currentInput.scrollWidth > currentInput.clientWidth;\n if (hasScroll) {\n setIsMultiline(true);\n }\n }\n }, 0);\n }\n\n // Nếu xóa hết text thì chuyển về input\n if (!newValue && isMultiline) {\n setIsMultiline(false);\n }\n\n if (textareaRef.current) {\n textareaRef.current.scrollTop = textareaRef.current.scrollHeight;\n }\n };\n\n const fileInputRef = useRef<HTMLInputElement | null>(null);\n const [uploadQueue, setUploadQueue] = useState<Array<string>>([]);\n\n const submitForm = useCallback(async () => {\n handleSubmit(undefined, attachments);\n setLocalStorageInput('');\n if (setAttachments) {\n setAttachments((_) => []);\n if (fileInputRef.current) {\n (fileInputRef.current as HTMLInputElement).value = '';\n }\n }\n if (width && width > 768) {\n textareaRef.current?.focus();\n }\n }, [handleSubmit, setLocalStorageInput, width, attachments, chatId, bot]);\n\n const uploadFile = useCallback(\n async (file: File) => {\n const formData = new FormData();\n formData.append('file', file, generateExtendedFileName(file.name));\n try {\n return await createAttachments({\n chatId,\n apiHost,\n body: formData,\n });\n } catch (error) {\n console.error('Failed to upload file, please try again!');\n }\n },\n [chatId]\n );\n\n const toAudioBase64 = (blob: Blob) => {\n return new Promise<IFileUpload>((resolve) => {\n let mimeType = getBestMimeType();\n const pos = blob.type.indexOf(';');\n if (pos === -1) {\n mimeType = blob.type;\n } else {\n mimeType = blob.type.substring(0, pos);\n }\n\n // read blob and add to previews\n const reader = new FileReader();\n reader.readAsDataURL(blob);\n reader.onloadend = () => {\n const base64data = reader.result as string;\n const upload: IFileUpload = {\n tempId: generateUUID(),\n data: base64data,\n type: 'audio',\n name: `audio_${Date.now()}.${getFileExtension(mimeType)}`,\n mime: mimeType,\n };\n resolve(upload);\n };\n });\n };\n\n const toBase64 = async (\n file: File,\n type = 'file'\n ): Promise<IFileUpload | undefined> => {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.readAsDataURL(file);\n reader.onload = () => {\n resolve({\n tempId: generateUUID(),\n data: reader.result as string,\n type,\n name: generateExtendedFileName(file.name),\n mime: file.type,\n });\n };\n reader.onerror = () => {\n reject();\n };\n });\n };\n\n const checkUploadFile = useCallback(\n async (file: File): Promise<IFileUpload | undefined> => {\n if (file.type.startsWith('image')) {\n return toBase64(file);\n } else {\n setUploadQueue([file.name]);\n const response: any = await uploadFile(file);\n if (response?.type == 'file:full') {\n const f = response.result[0];\n if (!f) {\n return;\n }\n return {\n tempId: generateUUID(),\n data: f.content,\n name: f.name,\n mime: f.mimeType,\n type: response?.type,\n };\n } else if (response?.type == 'file:rag') {\n const { addedDocs } = response.result;\n if (!addedDocs.length) {\n return;\n }\n return toBase64(file, response?.type);\n }\n }\n },\n [setUploadQueue, uploadFile]\n );\n\n const handleFileChange = useCallback(\n async (event: ChangeEvent<HTMLInputElement>) => {\n const files = Array.from(event.target.files || []);\n try {\n const uploadPromises = files.map((file) => checkUploadFile(file));\n const uploadedAttachments = await Promise.all(uploadPromises);\n const successfullyUploadedAttachments = uploadedAttachments.filter(\n (attachment) => attachment !== undefined\n ) as IFileUpload[];\n if (setAttachments) {\n setAttachments((currentAttachments: IFileUpload[]) => [\n ...currentAttachments,\n ...successfullyUploadedAttachments,\n ]);\n }\n } catch (error) {\n console.error('Error uploading files!', error);\n } finally {\n setUploadQueue([]);\n }\n },\n [setAttachments, checkUploadFile]\n );\n\n const speechToText = async (blob: Blob) => {\n try {\n setTranscribing(true);\n setIsMultiline(true);\n const fileUpload = await toAudioBase64(blob);\n const base64Data = fileUpload.data!.replace(/^data:.+;base64,/, '');\n const byteCharacters = atob(base64Data); // Decode Base64 string\n const byteNumbers = new Array(byteCharacters.length);\n\n for (let i = 0; i < byteCharacters.length; i++) {\n byteNumbers[i] = byteCharacters.charCodeAt(i);\n }\n\n const byteArray = new Uint8Array(byteNumbers);\n const file = new File([byteArray], fileUpload.name, {\n lastModified: new Date().getTime(),\n type: fileUpload.type,\n });\n\n const text = await getAudioTranscript({ file, apiHost, language });\n if (text) {\n handleSetInput(text);\n }\n } catch (error) {\n console.error('Error getting audio transcript!', error);\n } finally {\n setTranscribing(false);\n }\n };\n\n const handleFinishRecording = () => {\n if (isRecording) {\n onRecordingStopped(speechToText);\n }\n if (listeners?.['ON_FINISHED_RECORDING']) {\n listeners['ON_FINISHED_RECORDING']();\n }\n };\n\n const handleStartRecording = () => {\n setIsMultiline(false);\n onRecordingStarted();\n handleSetInput('');\n if (listeners?.['ON_START_RECORDING']) {\n listeners['ON_START_RECORDING']();\n }\n };\n\n const handleCancelRecording = () => {\n onRecordingCancelled();\n handleSetInput('');\n if (listeners?.['ON_CANCEL_RECORDING']) {\n listeners['ON_CANCEL_RECORDING']();\n }\n };\n\n const handleSend = useCallback(async () => {\n if (!isRecording) {\n submitForm();\n }\n }, [submitForm, isRecording]);\n\n const handleWidthChange = useCallback(\n (maxBars: number) => {\n updateMaxHistoryLength(maxBars);\n },\n [updateMaxHistoryLength]\n );\n\n const placeholder =\n !isRecording && !transcribing\n ? theme?.input?.placeholder || 'Send a message...'\n : theme?.input?.transcribingPlaceholder || 'Transcribing...';\n\n const recordingPlaceholder =\n isRecording && !transcribing\n ? theme?.input?.recordingPlaceholder || 'Recording...'\n : '';\n\n return (\n <div className=\"relative w-full flex gap-4 flex-col\">\n {!!suggestedActions?.length && (\n <SuggestedActions\n suggestedActions={suggestedActions}\n append={append}\n layoutMode={suggestedActionLayoutMode}\n suggestedActionRows={suggestedActionRows}\n />\n )}\n {((attachments && attachments.length > 0) || uploadQueue.length > 0) && (\n <div className=\"list-attachments flex flex-row gap-2 overflow-x-scroll items-end\">\n {attachments?.map((attachment) => (\n <PreviewFileAttachment\n key={attachment.tempId}\n attachment={attachment}\n onRemoveAttachment={() => {\n setAttachments?.((currentAttachments: IFileUpload[]) =>\n currentAttachments.filter(\n (f) => f.tempId !== attachment.tempId\n )\n );\n }}\n />\n ))}\n {uploadQueue.map((filename) => (\n <PreviewFileAttachment\n key={filename}\n onRemoveAttachment={() => {\n setUploadQueue(uploadQueue.filter((f) => f !== filename));\n }}\n attachment={{\n data: '',\n name: filename,\n mime: '',\n type: '',\n }}\n isUploading\n />\n ))}\n </div>\n )}\n <div className=\" w-full flex gap-4 justify-end items-end\">\n {isRecording ? (\n <Button\n className={` rounded-full w-[40px] h-[40px] flex items-center justify-center bg-white `}\n onClick={(event) => {\n event.preventDefault();\n handleFinishRecording();\n }}\n >\n <div className=\"w-[12px] h-[12px] bg-muted-foreground rounded-full\"></div>\n </Button>\n ) : (\n <DropdownMenu open={dropdownOpen} onOpenChange={setDropdownOpen}>\n <DropdownMenuTrigger asChild>\n <Button\n className={` rounded-full w-[40px] h-[40px] flex items-center justify-center bg-white`}\n onClick={(event) => {\n event.preventDefault();\n }}\n >\n <PlusIcon size={20} color={'#71717A'} />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent\n side=\"top\"\n align=\"start\"\n className=\"w-48 rounded-2xl border py-[6px] border-[#0d0d0d0d] shadow-sm\"\n >\n <DropdownMenuItem\n onClick={() => {\n // Trigger file input\n fileInputRef.current?.click();\n setDropdownOpen(false);\n }}\n className=\"flex items-center gap-2 px-4\"\n >\n <Paperclip size={16} />\n <span className=\"text-[14px]\">Upload File</span>\n </DropdownMenuItem>\n <DropdownMenuItem\n onClick={() => {\n setEnableTTS(!enableTTS);\n }}\n className={`flex items-center gap-2 px-4 ${enableTTS ? 'bg-[#CBE1F3] text-[#0A82F7]' : ''}`}\n >\n <Volume2 />\n <span className=\"text-[14px]\">\n {theme?.buttons?.textBtnSpeak || 'Speak'}\n </span>\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n <div className=\"block flex-1 min-w-0 relative\">\n {/* Animated Input/Textarea Container */}\n <AnimatePresence mode=\"wait\">\n {!isRecording && (\n <>\n <motion.input\n key=\"input\"\n type=\"text\"\n readOnly={readonly}\n ref={inputRef}\n placeholder={placeholder}\n value={input}\n onChange={handleInput}\n className={cn(\n `h-[40px] outline-none text-base bg-muted bg-[#ffffff] scrollbar-hidden p-[12px] pr-[68px] rounded-[24px] backdrop-blur-[50px] w-full ${readonly ? 'hidden' : ''}`,\n className\n )}\n autoFocus\n initial={{ opacity: 0, height: 0 }}\n animate={{ opacity: 1, height: 40 }}\n exit={{ opacity: 0, height: 0 }}\n transition={{\n duration: 0.2,\n ease: 'easeInOut',\n }}\n style={{\n display: isMultiline || transcribing ? 'none' : 'block',\n }}\n onKeyDown={(event) => {\n if (isRecording) {\n return;\n }\n\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n if (isLoading) {\n console.error(\n 'Please wait for the model to finish its response!'\n );\n } else if (uploadQueue.length) {\n console.error('Please wait for file is uploading!');\n } else if (input.length > 0) {\n handleSend();\n }\n }\n }}\n />\n <motion.div\n key=\"textarea\"\n initial={{ opacity: 0, height: 40 }}\n animate={{ opacity: 1, height: 'auto' }}\n exit={{ opacity: 0, height: 40 }}\n transition={{\n duration: 0.2,\n ease: 'easeInOut',\n }}\n style={{\n display: isMultiline || transcribing ? 'block' : 'none',\n }}\n >\n <Textarea\n readOnly={readonly}\n ref={textareaRef}\n placeholder={placeholder}\n value={input}\n onChange={handleInput}\n className={cn(\n `min-h-[24px] max-h-[160px] resize-none text-base bg-muted bg-[#ffffff] scrollbar-hidden p-[12px] pb-[32px] rounded-[24px] border border-[#E5E5E5] shadow-[0px_2px_6px_0px_rgba(0,0,0,0.08)] backdrop-blur-[50px] ${suggestedActionRows === expandedRows && 'p-[12px]'} `,\n className\n )}\n style={{\n height:\n suggestedActionRows === expandedRows ? 60 : undefined,\n }}\n autoFocus\n onKeyDown={(event) => {\n if (isRecording) {\n return;\n }\n\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n if (isLoading) {\n console.error(\n 'Please wait for the model to finish its response!'\n );\n } else if (uploadQueue.length) {\n console.error('Please wait for file is uploading!');\n } else if (input.length > 0) {\n handleSend();\n }\n }\n }}\n />\n </motion.div>\n </>\n )}\n </AnimatePresence>\n {/* Voice Recording UI Overlay */}\n <div className=\"w-full \">\n <VoiceRecordingUI\n isRecording={isRecording}\n elapsedTime={elapsedTime}\n onCancel={handleCancelRecording}\n transcribing={transcribing}\n audioData={audioData}\n label={recordingPlaceholder}\n onWidthChange={handleWidthChange}\n />\n </div>\n\n <div className=\"button-voice right-[4px] absolute bottom-[4px] flex gap-[12px]\">\n {!isRecording && (\n <Button\n className=\"rounded-full z-[2] p-1.5 h-[32px] w-[32px] m-0 bg-transparent\"\n onClick={(event) => {\n event.preventDefault();\n handleStartRecording();\n }}\n disabled={isLoading}\n >\n <ClikMicrophoneIcon size={20} />\n </Button>\n )}\n\n {isLoading ? (\n <Button\n className=\"rounded-full z-[2] p-1.5 h-[32px] w-[32px] m-0 border bg-[#71717A]\"\n onClick={(event) => {\n event.preventDefault();\n stop();\n setMessages(messages);\n }}\n >\n <StopIcon size={20} />\n </Button>\n ) : (\n <Button\n className=\"rounded-full z-[2] p-1.5 h-[32px] w-[32px] m-0 border bg-[#71717A]\"\n onClick={(event) => {\n event.preventDefault();\n handleSend();\n }}\n disabled={\n isRecording || input.length === 0 || !!uploadQueue.length\n }\n >\n <ArrowUpIcon size={20} />\n </Button>\n )}\n </div>\n </div>\n {/* Hidden file input */}\n <input\n type=\"file\"\n ref={fileInputRef}\n onChange={handleFileChange}\n multiple\n accept=\"image/*,video/*,audio/*,.pdf,.doc,.docx,.txt\"\n style={{ display: 'none' }}\n />\n </div>\n </div>\n );\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PreviewFileAttachment.d.ts","sourceRoot":"","sources":["../../../src/components/Chat/PreviewFileAttachment.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAKvD,eAAO,MAAM,qBAAqB,qDAI/B;IACD,UAAU,EAAE,WAAW,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;CACjC,
|
|
1
|
+
{"version":3,"file":"PreviewFileAttachment.d.ts","sourceRoot":"","sources":["../../../src/components/Chat/PreviewFileAttachment.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAKvD,eAAO,MAAM,qBAAqB,qDAI/B;IACD,UAAU,EAAE,WAAW,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;CACjC,4CAiDA,CAAC"}
|
|
@@ -12,7 +12,6 @@ export const PreviewFileAttachment = ({ attachment, isUploading = false, onRemov
|
|
|
12
12
|
}
|
|
13
13
|
return (_jsx("div", { className: "w-[40px] h-[40px] flex items-center justify-center bg-blue-600 rounded-md", children: _jsx(File, { size: 20, color: "white" }) }));
|
|
14
14
|
};
|
|
15
|
-
console.log('attachment', attachment);
|
|
16
15
|
return (_jsx("div", { className: "flex flex-col gap-2", children: _jsxs("div", { className: "w-[58px] h-[58px] bg-white rounded-md relative flex flex-col items-center justify-center", children: [_jsx("div", { onClick: (e) => {
|
|
17
16
|
e.preventDefault();
|
|
18
17
|
e.stopPropagation();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PreviewFileAttachment.js","sourceRoot":"","sources":["../../../src/components/Chat/PreviewFileAttachment.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAG7C,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,EACpC,UAAU,EACV,WAAW,GAAG,KAAK,EACnB,kBAAkB,GAAG,GAAG,EAAE,GAAE,CAAC,GAK9B,EAAE,EAAE;IACH,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC;IAEhD,MAAM,gBAAgB,GAAG,GAAG,EAAE;QAC5B,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7B,OAAO,CACL,gBAAO,QAAQ,kBACb,iBAAQ,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,GAAI,GAC3B,CACT,CAAC;QACJ,CAAC;QACD,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7B,OAAO,CACL,cACE,GAAG,EAAE,IAAI,EACT,GAAG,EAAE,IAAI,IAAI,qBAAqB,EAClC,SAAS,EAAC,oCAAoC,GAC9C,CACH,CAAC;QACJ,CAAC;QACD,OAAO,CACL,cAAK,SAAS,EAAC,2EAA2E,YACxF,KAAC,IAAI,IAAC,IAAI,EAAE,EAAE,EAAE,KAAK,EAAC,OAAO,GAAG,GAC5B,CACP,CAAC;IACJ,CAAC,CAAC;IAEF,OAAO,
|
|
1
|
+
{"version":3,"file":"PreviewFileAttachment.js","sourceRoot":"","sources":["../../../src/components/Chat/PreviewFileAttachment.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAG7C,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,EACpC,UAAU,EACV,WAAW,GAAG,KAAK,EACnB,kBAAkB,GAAG,GAAG,EAAE,GAAE,CAAC,GAK9B,EAAE,EAAE;IACH,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC;IAEhD,MAAM,gBAAgB,GAAG,GAAG,EAAE;QAC5B,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7B,OAAO,CACL,gBAAO,QAAQ,kBACb,iBAAQ,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,GAAI,GAC3B,CACT,CAAC;QACJ,CAAC;QACD,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7B,OAAO,CACL,cACE,GAAG,EAAE,IAAI,EACT,GAAG,EAAE,IAAI,IAAI,qBAAqB,EAClC,SAAS,EAAC,oCAAoC,GAC9C,CACH,CAAC;QACJ,CAAC;QACD,OAAO,CACL,cAAK,SAAS,EAAC,2EAA2E,YACxF,KAAC,IAAI,IAAC,IAAI,EAAE,EAAE,EAAE,KAAK,EAAC,OAAO,GAAG,GAC5B,CACP,CAAC;IACJ,CAAC,CAAC;IAEF,OAAO,CACL,cAAK,SAAS,EAAC,qBAAqB,YAClC,eAAK,SAAS,EAAC,2FAA2F,aACxG,cACE,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;wBACb,CAAC,CAAC,cAAc,EAAE,CAAC;wBACnB,CAAC,CAAC,eAAe,EAAE,CAAC;wBACpB,kBAAkB,EAAE,CAAC;oBACvB,CAAC,EACD,SAAS,EAAC,+FAA+F,YAEzG,KAAC,OAAO,IAAC,IAAI,EAAE,EAAE,EAAE,KAAK,EAAC,OAAO,GAAG,GAC/B,EACL,IAAI,IAAI,gBAAgB,EAAE,EAC1B,WAAW,IAAI,CACd,cAAK,SAAS,EAAC,qCAAqC,YAClD,KAAC,UAAU,KAAG,GACV,CACP,IACG,GACF,CACP,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { IFileUpload } from '../../types/flowise.type';\nimport { LoaderIcon } from './Icons';\nimport { CircleX, File } from 'lucide-react';\nimport React from 'react';\n\nexport const PreviewFileAttachment = ({\n attachment,\n isUploading = false,\n onRemoveAttachment = () => {},\n}: {\n attachment: IFileUpload;\n isUploading?: boolean;\n onRemoveAttachment?: () => void;\n}) => {\n const { name, data, mime, tempId } = attachment;\n\n const renderAttachment = () => {\n if (mime.startsWith('audio')) {\n return (\n <audio controls>\n <source src={data} type={mime} />\n </audio>\n );\n }\n if (mime.startsWith('image')) {\n return (\n <img\n src={data}\n alt={name ?? 'An image attachment'}\n className=\"rounded-md size-full object-cover \"\n />\n );\n }\n return (\n <div className=\"w-[40px] h-[40px] flex items-center justify-center bg-blue-600 rounded-md\">\n <File size={20} color=\"white\" />\n </div>\n );\n };\n\n return (\n <div className=\"flex flex-col gap-2\">\n <div className=\"w-[58px] h-[58px] bg-white rounded-md relative flex flex-col items-center justify-center\">\n <div\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n onRemoveAttachment();\n }}\n className=\"w-fit h-fit flex items-center justify-center absolute top-0 right-[4px] bg-black rounded-full\"\n >\n <CircleX size={20} color=\"white\" />\n </div>\n {data && renderAttachment()}\n {isUploading && (\n <div className=\"animate-spin absolute text-zinc-500\">\n <LoaderIcon />\n </div>\n )}\n </div>\n </div>\n );\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VoiceRecordingUI.d.ts","sourceRoot":"","sources":["../../../src/components/Chat/VoiceRecordingUI.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"VoiceRecordingUI.d.ts","sourceRoot":"","sources":["../../../src/components/Chat/VoiceRecordingUI.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkD,MAAM,OAAO,CAAC;AAIvE,UAAU,iBAAiB;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,UAAU,qBAAqB;IAC7B,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3C;AAED,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAmJ5D,CAAC"}
|
|
@@ -1,37 +1,71 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React, { useRef, useEffect, useMemo, useCallback } from 'react';
|
|
2
3
|
import { motion, AnimatePresence } from 'framer-motion';
|
|
3
4
|
import { ClikCloseIcon } from './Icons';
|
|
4
|
-
export const VoiceRecordingUI = ({ isRecording, elapsedTime, onCancel, transcribing = false, audioData, label = 'Transcription', }) => {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
export const VoiceRecordingUI = React.memo(({ isRecording, elapsedTime, onCancel, transcribing = false, audioData, label = 'Transcription', onWidthChange, }) => {
|
|
6
|
+
const waveformContainerRef = useRef(null);
|
|
7
|
+
// Debounced width change callback for better performance
|
|
8
|
+
const timeoutRef = useRef();
|
|
9
|
+
const debouncedWidthChange = useCallback((maxBars) => {
|
|
10
|
+
if (timeoutRef.current) {
|
|
11
|
+
clearTimeout(timeoutRef.current);
|
|
12
|
+
}
|
|
13
|
+
timeoutRef.current = setTimeout(() => {
|
|
14
|
+
onWidthChange?.(maxBars);
|
|
15
|
+
}, 100);
|
|
16
|
+
}, [onWidthChange]);
|
|
17
|
+
// Measure container width and calculate optimal bar count
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (waveformContainerRef.current && isRecording && onWidthChange) {
|
|
20
|
+
const resizeObserver = new ResizeObserver((entries) => {
|
|
21
|
+
const width = entries[0].contentRect.width;
|
|
22
|
+
const rightPadding = 20;
|
|
23
|
+
const minBars = 50;
|
|
24
|
+
const maxBarsDefault = 200;
|
|
25
|
+
// Calculate optimal bar count
|
|
26
|
+
// Each bar: 2px width + 1px margin = 3px total
|
|
27
|
+
const barWidth = 3;
|
|
28
|
+
const optimalBarCount = Math.floor((width - rightPadding) / barWidth);
|
|
29
|
+
// Clamp between reasonable limits: min 50, max 200 (reduced for performance)
|
|
30
|
+
const maxBars = Math.min(Math.max(optimalBarCount, minBars), maxBarsDefault);
|
|
31
|
+
debouncedWidthChange(maxBars);
|
|
32
|
+
});
|
|
33
|
+
resizeObserver.observe(waveformContainerRef.current);
|
|
34
|
+
return () => resizeObserver.disconnect();
|
|
35
|
+
}
|
|
36
|
+
}, [isRecording, onWidthChange, debouncedWidthChange]);
|
|
37
|
+
// Constants for waveform calculation
|
|
7
38
|
const maxHeight = 50;
|
|
8
39
|
const minHeight = 2;
|
|
9
40
|
const amplitude = 0.7;
|
|
10
|
-
//
|
|
11
|
-
const waveformData =
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
41
|
+
// Memoize waveform data calculation for performance
|
|
42
|
+
const waveformData = useMemo(() => {
|
|
43
|
+
const volumeHistory = audioData?.frequencies || [];
|
|
44
|
+
return volumeHistory.map((volume) => {
|
|
45
|
+
// Direct mapping of volume to bar height
|
|
46
|
+
// Volume range: 0-100 -> Bar height: 2-50px
|
|
47
|
+
return Math.max(minHeight, Math.min(maxHeight, minHeight + volume * amplitude));
|
|
48
|
+
});
|
|
49
|
+
}, [audioData?.frequencies, maxHeight, minHeight, amplitude]);
|
|
16
50
|
return (_jsx(AnimatePresence, { children: isRecording && (_jsxs(motion.div, { initial: { opacity: 0, height: 0 }, animate: { opacity: 1, height: 'auto' }, exit: { opacity: 0, height: 0 }, transition: {
|
|
17
51
|
duration: 0.3,
|
|
18
52
|
ease: 'easeInOut',
|
|
19
53
|
height: { duration: 0.2 },
|
|
20
54
|
opacity: { duration: 0.15 },
|
|
21
|
-
}, className: "bg-white w-full rounded-[20px] z-10 flex flex-col pt-[8px] pl-[12px] pr-[4px] pb-[4px] gap-[4px]", children: [_jsx("div", { className: "w-full text-[14px] font-normal text-[#71717A] leading-[20px]", children: label }), _jsxs("div", { className: "flex w-full items-center justify-center pr-[40px] gap-[4px]", children: [_jsx("div", { className: "text-sm font-mono flex-shrink-0 min-w-[45px]", children: elapsedTime }), _jsxs("div", { className: "flex-1 flex items-center justify-center h-8 relative overflow-hidden rounded-lg min-w-0", children: [_jsx("div", { className: "absolute inset-0 flex items-center", children: _jsx("div", { className: "w-full h-px bg-gray-300" }) }), _jsx("div", { className: "flex items-center h-full w-full relative", children: waveformData.map((barHeight, index) => {
|
|
22
|
-
return (_jsx("div", { className:
|
|
23
|
-
|
|
24
|
-
`, style: {
|
|
55
|
+
}, className: "bg-white w-full rounded-[20px] z-10 flex flex-col pt-[8px] pl-[12px] pr-[4px] pb-[4px] gap-[4px]", children: [_jsx("div", { className: "w-full text-[14px] font-normal text-[#71717A] leading-[20px]", children: label }), _jsxs("div", { className: "flex w-full items-center justify-center pr-[40px] gap-[4px]", children: [_jsx("div", { className: "text-sm font-mono flex-shrink-0 min-w-[45px]", children: elapsedTime }), _jsxs("div", { className: "flex-1 flex items-center justify-center h-8 relative overflow-hidden rounded-lg min-w-0", children: [_jsx("div", { className: "absolute inset-0 flex items-center", children: _jsx("div", { className: "w-full h-px bg-gray-300" }) }), _jsx("div", { ref: waveformContainerRef, className: "flex items-center h-full w-full relative", children: waveformData.map((barHeight, index) => {
|
|
56
|
+
return (_jsx("div", { className: "rounded-full flex-shrink-0 bg-[#71717A]", style: {
|
|
25
57
|
width: '2px',
|
|
26
|
-
height: `${barHeight}px`,
|
|
58
|
+
height: `${barHeight}px`, // Fixed height
|
|
27
59
|
marginRight: '1px',
|
|
28
|
-
|
|
29
|
-
|
|
60
|
+
// transform: `scaleY(${scaleY})`, // Use transform for better performance
|
|
61
|
+
// transformOrigin: 'bottom',
|
|
62
|
+
transition: 'transform 0.15s ease-out, opacity 0.3s ease-out',
|
|
63
|
+
opacity: barHeight <= minHeight ? 0.3 : 1, // Fade out bars that are at minimum height
|
|
30
64
|
} }, `volume-bar-${index}`));
|
|
31
65
|
}) })] }), _jsx(motion.button, { onClick: (event) => {
|
|
32
66
|
event.preventDefault();
|
|
33
67
|
event.stopPropagation();
|
|
34
68
|
onCancel();
|
|
35
69
|
}, disabled: transcribing, whileHover: { scale: 1.1 }, whileTap: { scale: 0.9 }, className: "w-8 h-8 rounded-full bg-gray-100 hover:bg-gray-200 flex items-center justify-center disabled:opacity-50 disabled:cursor-not-allowed flex-shrink-0", children: _jsx(ClikCloseIcon, { size: 16 }) })] })] })) }));
|
|
36
|
-
};
|
|
70
|
+
});
|
|
37
71
|
//# sourceMappingURL=VoiceRecordingUI.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VoiceRecordingUI.js","sourceRoot":"","sources":["../../../src/components/Chat/VoiceRecordingUI.tsx"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"VoiceRecordingUI.js","sourceRoot":"","sources":["../../../src/components/Chat/VoiceRecordingUI.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useRef, useEffect, useMemo, useCallback } from 'react';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport { ClikCloseIcon } from './Icons';\n\ninterface AudioAnalyzerData {\n volume: number;\n frequencies: number[];\n}\n\ninterface VoiceRecordingUIProps {\n isRecording: boolean;\n elapsedTime: string;\n onCancel: () => void;\n transcribing?: boolean;\n audioData?: AudioAnalyzerData;\n label?: string;\n onWidthChange?: (maxBars: number) => void;\n}\n\nexport const VoiceRecordingUI: React.FC<VoiceRecordingUIProps> = React.memo(\n ({\n isRecording,\n elapsedTime,\n onCancel,\n transcribing = false,\n audioData,\n label = 'Transcription',\n onWidthChange,\n }) => {\n const waveformContainerRef = useRef<HTMLDivElement>(null);\n\n // Debounced width change callback for better performance\n const timeoutRef = useRef<NodeJS.Timeout>();\n const debouncedWidthChange = useCallback(\n (maxBars: number) => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n timeoutRef.current = setTimeout(() => {\n onWidthChange?.(maxBars);\n }, 100);\n },\n [onWidthChange]\n );\n\n // Measure container width and calculate optimal bar count\n useEffect(() => {\n if (waveformContainerRef.current && isRecording && onWidthChange) {\n const resizeObserver = new ResizeObserver((entries) => {\n const width = entries[0].contentRect.width;\n const rightPadding = 20;\n const minBars = 50;\n const maxBarsDefault = 200;\n\n // Calculate optimal bar count\n // Each bar: 2px width + 1px margin = 3px total\n const barWidth = 3;\n const optimalBarCount = Math.floor((width - rightPadding) / barWidth);\n\n // Clamp between reasonable limits: min 50, max 200 (reduced for performance)\n const maxBars = Math.min(\n Math.max(optimalBarCount, minBars),\n maxBarsDefault\n );\n debouncedWidthChange(maxBars);\n });\n\n resizeObserver.observe(waveformContainerRef.current);\n\n return () => resizeObserver.disconnect();\n }\n }, [isRecording, onWidthChange, debouncedWidthChange]);\n\n // Constants for waveform calculation\n const maxHeight = 50;\n const minHeight = 2;\n const amplitude = 0.7;\n\n // Memoize waveform data calculation for performance\n const waveformData = useMemo(() => {\n const volumeHistory = audioData?.frequencies || [];\n return volumeHistory.map((volume) => {\n // Direct mapping of volume to bar height\n // Volume range: 0-100 -> Bar height: 2-50px\n return Math.max(\n minHeight,\n Math.min(maxHeight, minHeight + volume * amplitude)\n );\n });\n }, [audioData?.frequencies, maxHeight, minHeight, amplitude]);\n\n return (\n <AnimatePresence>\n {isRecording && (\n <motion.div\n initial={{ opacity: 0, height: 0 }}\n animate={{ opacity: 1, height: 'auto' }}\n exit={{ opacity: 0, height: 0 }}\n transition={{\n duration: 0.3,\n ease: 'easeInOut',\n height: { duration: 0.2 },\n opacity: { duration: 0.15 },\n }}\n className=\"bg-white w-full rounded-[20px] z-10 flex flex-col pt-[8px] pl-[12px] pr-[4px] pb-[4px] gap-[4px]\"\n >\n <div className=\"w-full text-[14px] font-normal text-[#71717A] leading-[20px]\">\n {label}\n </div>\n {/* Audio Waveform Visualization */}\n <div className=\"flex w-full items-center justify-center pr-[40px] gap-[4px]\">\n <div className=\"text-sm font-mono flex-shrink-0 min-w-[45px]\">\n {elapsedTime}\n </div>\n <div className=\"flex-1 flex items-center justify-center h-8 relative overflow-hidden rounded-lg min-w-0\">\n {/* Background baseline */}\n <div className=\"absolute inset-0 flex items-center\">\n <div className=\"w-full h-px bg-gray-300\"></div>\n </div>\n\n {/* Waveform container - Volume History Visualization */}\n <div\n ref={waveformContainerRef}\n className=\"flex items-center h-full w-full relative\"\n >\n {/* Display volume history from frequencies array */}\n {waveformData.map((barHeight, index) => {\n return (\n <div\n key={`volume-bar-${index}`}\n className=\"rounded-full flex-shrink-0 bg-[#71717A]\"\n style={{\n width: '2px',\n height: `${barHeight}px`, // Fixed height\n marginRight: '1px',\n // transform: `scaleY(${scaleY})`, // Use transform for better performance\n // transformOrigin: 'bottom',\n transition:\n 'transform 0.15s ease-out, opacity 0.3s ease-out',\n opacity: barHeight <= minHeight ? 0.3 : 1, // Fade out bars that are at minimum height\n }}\n />\n );\n })}\n </div>\n </div>\n {/* Cancel Button */}\n <motion.button\n onClick={(event) => {\n event.preventDefault();\n event.stopPropagation();\n onCancel();\n }}\n disabled={transcribing}\n whileHover={{ scale: 1.1 }}\n whileTap={{ scale: 0.9 }}\n className=\"w-8 h-8 rounded-full bg-gray-100 hover:bg-gray-200 flex items-center justify-center disabled:opacity-50 disabled:cursor-not-allowed flex-shrink-0\"\n >\n <ClikCloseIcon size={16} />\n </motion.button>\n </div>\n </motion.div>\n )}\n </AnimatePresence>\n );\n }\n);\n"]}
|
|
@@ -2,7 +2,7 @@ export interface AudioAnalyzerData {
|
|
|
2
2
|
volume: number;
|
|
3
3
|
frequencies: number[];
|
|
4
4
|
}
|
|
5
|
-
export declare const useAudioAnalyzer: () => {
|
|
5
|
+
export declare const useAudioAnalyzer: (maxHistoryLength?: number) => {
|
|
6
6
|
audioData: AudioAnalyzerData;
|
|
7
7
|
isAnalyzing: boolean;
|
|
8
8
|
startAnalyzing: (stream: MediaStream) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAudioAnalyzer.d.ts","sourceRoot":"","sources":["../../src/hooks/useAudioAnalyzer.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;
|
|
1
|
+
{"version":3,"file":"useAudioAnalyzer.d.ts","sourceRoot":"","sources":["../../src/hooks/useAudioAnalyzer.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAMD,eAAO,MAAM,gBAAgB,sBACT,MAAM;;;6BAsCb,WAAW;;CAuHvB,CAAC"}
|