@clikvn/agent-widget-embedded 1.1.5-dev-08 → 1.1.5-dev-09

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.
Files changed (30) hide show
  1. package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/.tsbuildinfo +1 -0
  2. package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/components/Chat/MultimodalInput.d.ts.map +1 -1
  3. package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/components/Chat/MultimodalInput.js +43 -42
  4. package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/components/Chat/MultimodalInput.js.map +1 -1
  5. package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/components/Chat/PreviewFileAttachment.d.ts.map +1 -1
  6. package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/components/Chat/PreviewFileAttachment.js +0 -1
  7. package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/components/Chat/PreviewFileAttachment.js.map +1 -1
  8. package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/components/Chat/VoiceRecordingUI.d.ts +1 -0
  9. package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/components/Chat/VoiceRecordingUI.d.ts.map +1 -1
  10. package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/components/Chat/VoiceRecordingUI.js +51 -17
  11. package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/components/Chat/VoiceRecordingUI.js.map +1 -1
  12. package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/hooks/useAudioAnalyzer.d.ts +1 -1
  13. package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/hooks/useAudioAnalyzer.d.ts.map +1 -1
  14. package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/hooks/useAudioAnalyzer.js +29 -7
  15. package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/hooks/useAudioAnalyzer.js.map +1 -1
  16. package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/hooks/useAudioRecording.d.ts +2 -1
  17. package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/hooks/useAudioRecording.d.ts.map +1 -1
  18. package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/hooks/useAudioRecording.js +9 -3
  19. package/.rollup.cache/Users/tungthai/Desktop/Develop/clik-ai-chatbot-embedded/dist/hooks/useAudioRecording.js.map +1 -1
  20. package/dist/components/Chat/MultimodalInput.d.ts.map +1 -1
  21. package/dist/components/Chat/PreviewFileAttachment.d.ts.map +1 -1
  22. package/dist/components/Chat/VoiceRecordingUI.d.ts +1 -0
  23. package/dist/components/Chat/VoiceRecordingUI.d.ts.map +1 -1
  24. package/dist/hooks/useAudioAnalyzer.d.ts +1 -1
  25. package/dist/hooks/useAudioAnalyzer.d.ts.map +1 -1
  26. package/dist/hooks/useAudioRecording.d.ts +2 -1
  27. package/dist/hooks/useAudioRecording.d.ts.map +1 -1
  28. package/dist/web.js +1 -1
  29. package/dist/web.js.map +1 -1
  30. package/package.json +1 -1
@@ -1 +1 @@
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 } 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,4CAkDA,CAAC"}
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,CAAC,GAAG,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;IACtC,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 console.log('attachment', attachment);\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
+ {"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"]}
@@ -10,6 +10,7 @@ interface VoiceRecordingUIProps {
10
10
  transcribing?: boolean;
11
11
  audioData?: AudioAnalyzerData;
12
12
  label?: string;
13
+ onWidthChange?: (maxBars: number) => void;
13
14
  }
14
15
  export declare const VoiceRecordingUI: React.FC<VoiceRecordingUIProps>;
15
16
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"VoiceRecordingUI.d.ts","sourceRoot":"","sources":["../../../src/components/Chat/VoiceRecordingUI.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,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;CAChB;AAED,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CA8F5D,CAAC"}
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
- // Use frequencies array from audioData as volume history
6
- const volumeHistory = audioData?.frequencies || [];
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
- // Convert volume values to bar heights
11
- const waveformData = volumeHistory.map((volume) => {
12
- // Direct mapping of volume to bar height
13
- // Volume range
14
- return Math.max(minHeight, Math.min(maxHeight, minHeight + volume * amplitude));
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: `rounded-full flex-shrink-0 bg-[#71717A]
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
- transition: 'height 0.2s ease-out, opacity 0.4s ease-out',
29
- opacity: barHeight <= 2 ? 0.3 : 1, // Fade out bars that are at minimum height
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":"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","sourcesContent":["import React 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}\n\nexport const VoiceRecordingUI: React.FC<VoiceRecordingUIProps> = ({\n isRecording,\n elapsedTime,\n onCancel,\n transcribing = false,\n audioData,\n label = 'Transcription',\n}) => {\n // Use frequencies array from audioData as volume history\n const volumeHistory = audioData?.frequencies || [];\n const maxHeight = 50;\n const minHeight = 2;\n const amplitude = 0.7;\n // Convert volume values to bar heights\n const waveformData = volumeHistory.map((volume) => {\n // Direct mapping of volume to bar height\n // Volume range\n return Math.max(\n minHeight,\n Math.min(maxHeight, minHeight + volume * amplitude)\n );\n });\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 className=\"flex items-center h-full w-full relative\">\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 \n `}\n style={{\n width: '2px',\n height: `${barHeight}px`,\n marginRight: '1px',\n transition:\n 'height 0.2s ease-out, opacity 0.4s ease-out',\n opacity: barHeight <= 2 ? 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"]}
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;AAOD,eAAO,MAAM,gBAAgB;;;6BAYiB,WAAW;;CAoHxD,CAAC"}
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"}
@@ -1,23 +1,45 @@
1
1
  import { useCallback, useEffect, useRef, useState } from 'react';
2
2
  let lastUpdateTime = 0;
3
3
  const updateInterval = 100;
4
- const maxHistoryLength = 65;
5
- const defaultFrequencies = Array(maxHistoryLength).fill(1);
6
- export const useAudioAnalyzer = () => {
4
+ const DEFAULT_MAX_HISTORY_LENGTH = 65;
5
+ export const useAudioAnalyzer = (maxHistoryLength = DEFAULT_MAX_HISTORY_LENGTH) => {
7
6
  const [audioData, setAudioData] = useState({
8
7
  volume: 0,
9
- frequencies: defaultFrequencies, // Start with empty array for volume history
8
+ frequencies: Array(maxHistoryLength).fill(1), // Dynamic array size
10
9
  });
11
10
  const [isAnalyzing, setIsAnalyzing] = useState(false);
12
11
  const audioContextRef = useRef(null);
13
12
  const analyzerRef = useRef(null);
14
13
  const sourceRef = useRef(null);
15
14
  const animationFrameRef = useRef(null);
15
+ // Update frequencies array when maxHistoryLength changes
16
+ useEffect(() => {
17
+ setAudioData((prevData) => {
18
+ const newFrequencies = [...prevData.frequencies];
19
+ if (newFrequencies.length > maxHistoryLength) {
20
+ // Trim from beginning if too long
21
+ return {
22
+ ...prevData,
23
+ frequencies: newFrequencies.slice(-maxHistoryLength),
24
+ };
25
+ }
26
+ else if (newFrequencies.length < maxHistoryLength) {
27
+ // Pad with zeros if too short
28
+ const padding = Array(maxHistoryLength - newFrequencies.length).fill(0);
29
+ return {
30
+ ...prevData,
31
+ frequencies: [...padding, ...newFrequencies],
32
+ };
33
+ }
34
+ return prevData;
35
+ });
36
+ }, [maxHistoryLength]);
16
37
  const startAnalyzing = useCallback((stream) => {
17
38
  try {
18
39
  // Create audio context
19
40
  audioContextRef.current = new (window.AudioContext ||
20
- window.webkitAudioContext)();
41
+ window
42
+ .webkitAudioContext)();
21
43
  // Create analyzer
22
44
  analyzerRef.current = audioContextRef.current.createAnalyser();
23
45
  analyzerRef.current.fftSize = 256;
@@ -48,7 +70,7 @@ export const useAudioAnalyzer = () => {
48
70
  const newFrequencies = [...prevData.frequencies];
49
71
  // Add current volume to the end of the array
50
72
  newFrequencies.push(volume);
51
- // Keep only the last 40 volume values for waveform display
73
+ // Keep only the last DEFAULT_MAX_HISTORY_LENGTH volume values for waveform display
52
74
  if (newFrequencies.length > maxHistoryLength) {
53
75
  newFrequencies.shift(); // Remove oldest value
54
76
  }
@@ -72,7 +94,7 @@ export const useAudioAnalyzer = () => {
72
94
  catch (error) {
73
95
  console.error('Error starting audio analysis:', error);
74
96
  }
75
- }, []);
97
+ }, [maxHistoryLength]);
76
98
  const stopAnalyzing = useCallback(() => {
77
99
  setIsAnalyzing(false);
78
100
  if (animationFrameRef.current) {
@@ -1 +1 @@
1
- {"version":3,"file":"useAudioAnalyzer.js","sourceRoot":"","sources":["../../src/hooks/useAudioAnalyzer.ts"],"names":[],"mappings":"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","sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nexport interface AudioAnalyzerData {\n volume: number; // 0-100\n frequencies: number[]; // Array of frequency data\n}\n\nlet lastUpdateTime = 0;\nconst updateInterval = 100;\nconst maxHistoryLength = 65;\nconst defaultFrequencies = Array(maxHistoryLength).fill(1);\n\nexport const useAudioAnalyzer = () => {\n const [audioData, setAudioData] = useState<AudioAnalyzerData>({\n volume: 0,\n frequencies: defaultFrequencies, // Start with empty array for volume history\n });\n const [isAnalyzing, setIsAnalyzing] = useState(false);\n\n const audioContextRef = useRef<AudioContext | null>(null);\n const analyzerRef = useRef<AnalyserNode | null>(null);\n const sourceRef = useRef<MediaStreamAudioSourceNode | null>(null);\n const animationFrameRef = useRef<number | null>(null);\n\n const startAnalyzing = useCallback((stream: MediaStream) => {\n try {\n // Create audio context\n audioContextRef.current = new (window.AudioContext ||\n (window as any).webkitAudioContext)();\n\n // Create analyzer\n analyzerRef.current = audioContextRef.current.createAnalyser();\n analyzerRef.current.fftSize = 256;\n analyzerRef.current.smoothingTimeConstant = 0.8;\n\n // Create source from stream\n sourceRef.current =\n audioContextRef.current.createMediaStreamSource(stream);\n sourceRef.current.connect(analyzerRef.current);\n\n setIsAnalyzing(true);\n\n // Add throttling variables\n\n // Start analyzing\n const analyze = () => {\n if (!analyzerRef.current) return;\n\n const bufferLength = analyzerRef.current.frequencyBinCount;\n const dataArray = new Uint8Array(bufferLength);\n analyzerRef.current.getByteFrequencyData(dataArray);\n\n // Calculate volume (0-100)\n const sum = dataArray.reduce((acc, value) => acc + value, 0);\n const average = sum / bufferLength;\n const volume = Math.min(100, (average / 255) * 100);\n\n // Throttle updates - only update every 150ms\n const currentTime = Date.now();\n if (currentTime - lastUpdateTime >= updateInterval) {\n lastUpdateTime = currentTime;\n\n // Use frequencies array to store volume history\n setAudioData((prevData) => {\n const newFrequencies = [...prevData.frequencies];\n\n // Add current volume to the end of the array\n newFrequencies.push(volume);\n\n // Keep only the last 40 volume values for waveform display\n\n if (newFrequencies.length > maxHistoryLength) {\n newFrequencies.shift(); // Remove oldest value\n }\n\n return {\n volume, // Always update current volume for real-time display\n frequencies: newFrequencies,\n };\n });\n } else {\n // Still update current volume for real-time feedback\n setAudioData((prevData) => ({\n ...prevData,\n volume, // Update volume but keep same frequencies array\n }));\n }\n\n animationFrameRef.current = requestAnimationFrame(analyze);\n };\n\n analyze();\n } catch (error) {\n console.error('Error starting audio analysis:', error);\n }\n }, []);\n\n const stopAnalyzing = useCallback(() => {\n setIsAnalyzing(false);\n\n if (animationFrameRef.current) {\n cancelAnimationFrame(animationFrameRef.current);\n animationFrameRef.current = null;\n }\n\n if (sourceRef.current) {\n sourceRef.current.disconnect();\n sourceRef.current = null;\n }\n\n if (analyzerRef.current) {\n analyzerRef.current.disconnect();\n analyzerRef.current = null;\n }\n\n if (audioContextRef.current) {\n audioContextRef.current.close();\n audioContextRef.current = null;\n }\n\n // Smooth reset: gradually fade out frequencies instead of instant reset\n setAudioData((prevData) => ({\n volume: 0,\n frequencies: prevData.frequencies.map(() => 0), // Fade to 0 instead of defaultFrequencies\n }));\n }, []);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n stopAnalyzing();\n };\n }, [stopAnalyzing]);\n\n return {\n audioData,\n isAnalyzing,\n startAnalyzing,\n stopAnalyzing,\n };\n};\n"]}
1
+ {"version":3,"file":"useAudioAnalyzer.js","sourceRoot":"","sources":["../../src/hooks/useAudioAnalyzer.ts"],"names":[],"mappings":"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","sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nexport interface AudioAnalyzerData {\n volume: number; // 0-100\n frequencies: number[]; // Array of frequency data\n}\n\nlet lastUpdateTime = 0;\nconst updateInterval = 100;\nconst DEFAULT_MAX_HISTORY_LENGTH = 65;\n\nexport const useAudioAnalyzer = (\n maxHistoryLength: number = DEFAULT_MAX_HISTORY_LENGTH\n) => {\n const [audioData, setAudioData] = useState<AudioAnalyzerData>({\n volume: 0,\n frequencies: Array(maxHistoryLength).fill(1), // Dynamic array size\n });\n const [isAnalyzing, setIsAnalyzing] = useState(false);\n\n const audioContextRef = useRef<AudioContext | null>(null);\n const analyzerRef = useRef<AnalyserNode | null>(null);\n const sourceRef = useRef<MediaStreamAudioSourceNode | null>(null);\n const animationFrameRef = useRef<number | null>(null);\n\n // Update frequencies array when maxHistoryLength changes\n useEffect(() => {\n setAudioData((prevData) => {\n const newFrequencies = [...prevData.frequencies];\n\n if (newFrequencies.length > maxHistoryLength) {\n // Trim from beginning if too long\n return {\n ...prevData,\n frequencies: newFrequencies.slice(-maxHistoryLength),\n };\n } else if (newFrequencies.length < maxHistoryLength) {\n // Pad with zeros if too short\n const padding = Array(maxHistoryLength - newFrequencies.length).fill(0);\n return {\n ...prevData,\n frequencies: [...padding, ...newFrequencies],\n };\n }\n\n return prevData;\n });\n }, [maxHistoryLength]);\n\n const startAnalyzing = useCallback(\n (stream: MediaStream) => {\n try {\n // Create audio context\n audioContextRef.current = new (window.AudioContext ||\n (window as unknown as { webkitAudioContext: typeof AudioContext })\n .webkitAudioContext)();\n\n // Create analyzer\n analyzerRef.current = audioContextRef.current.createAnalyser();\n analyzerRef.current.fftSize = 256;\n analyzerRef.current.smoothingTimeConstant = 0.8;\n\n // Create source from stream\n sourceRef.current =\n audioContextRef.current.createMediaStreamSource(stream);\n sourceRef.current.connect(analyzerRef.current);\n\n setIsAnalyzing(true);\n\n // Add throttling variables\n\n // Start analyzing\n const analyze = () => {\n if (!analyzerRef.current) return;\n\n const bufferLength = analyzerRef.current.frequencyBinCount;\n const dataArray = new Uint8Array(bufferLength);\n analyzerRef.current.getByteFrequencyData(dataArray);\n\n // Calculate volume (0-100)\n const sum = dataArray.reduce((acc, value) => acc + value, 0);\n const average = sum / bufferLength;\n const volume = Math.min(100, (average / 255) * 100);\n\n // Throttle updates - only update every 150ms\n const currentTime = Date.now();\n if (currentTime - lastUpdateTime >= updateInterval) {\n lastUpdateTime = currentTime;\n\n // Use frequencies array to store volume history\n setAudioData((prevData) => {\n const newFrequencies = [...prevData.frequencies];\n\n // Add current volume to the end of the array\n newFrequencies.push(volume);\n\n // Keep only the last DEFAULT_MAX_HISTORY_LENGTH volume values for waveform display\n\n if (newFrequencies.length > maxHistoryLength) {\n newFrequencies.shift(); // Remove oldest value\n }\n\n return {\n volume, // Always update current volume for real-time display\n frequencies: newFrequencies,\n };\n });\n } else {\n // Still update current volume for real-time feedback\n setAudioData((prevData) => ({\n ...prevData,\n volume, // Update volume but keep same frequencies array\n }));\n }\n\n animationFrameRef.current = requestAnimationFrame(analyze);\n };\n\n analyze();\n } catch (error) {\n console.error('Error starting audio analysis:', error);\n }\n },\n [maxHistoryLength]\n );\n\n const stopAnalyzing = useCallback(() => {\n setIsAnalyzing(false);\n\n if (animationFrameRef.current) {\n cancelAnimationFrame(animationFrameRef.current);\n animationFrameRef.current = null;\n }\n\n if (sourceRef.current) {\n sourceRef.current.disconnect();\n sourceRef.current = null;\n }\n\n if (analyzerRef.current) {\n analyzerRef.current.disconnect();\n analyzerRef.current = null;\n }\n\n if (audioContextRef.current) {\n audioContextRef.current.close();\n audioContextRef.current = null;\n }\n\n // Smooth reset: gradually fade out frequencies instead of instant reset\n setAudioData((prevData) => ({\n volume: 0,\n frequencies: prevData.frequencies.map(() => 0), // Fade to 0 instead of defaultFrequencies\n }));\n }, []);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n stopAnalyzing();\n };\n }, [stopAnalyzing]);\n\n return {\n audioData,\n isAnalyzing,\n startAnalyzing,\n stopAnalyzing,\n };\n};\n"]}
@@ -1,4 +1,4 @@
1
- export declare const useAudioRecording: () => {
1
+ export declare const useAudioRecording: (maxHistoryLength?: number) => {
2
2
  elapsedTime: string;
3
3
  recordingNotSupported: boolean;
4
4
  isLoadingRecording: boolean;
@@ -8,5 +8,6 @@ export declare const useAudioRecording: () => {
8
8
  onRecordingStopped: (onStop: null | ((blob: Blob) => void)) => void;
9
9
  onRecordingStarted: () => void;
10
10
  audioData: import("./useAudioAnalyzer").AudioAnalyzerData;
11
+ updateMaxHistoryLength: (newLength: number) => void;
11
12
  };
12
13
  //# sourceMappingURL=useAudioRecording.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useAudioRecording.d.ts","sourceRoot":"","sources":["../../src/hooks/useAudioRecording.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,iBAAiB;;;;;;;iCAgCQ,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;;;CAwBlE,CAAC"}
1
+ {"version":3,"file":"useAudioRecording.d.ts","sourceRoot":"","sources":["../../src/hooks/useAudioRecording.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,iBAAiB,sBAAuB,MAAM;;;;;;;iCAoCrB,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;;;wCAYtB,MAAM;CAkBlD,CAAC"}
@@ -1,13 +1,14 @@
1
1
  import { useState } from 'react';
2
2
  import { cancelAudioRecording, startAudioRecording, stopAudioRecording, audioRecorder, } from '../utils/audioRecording';
3
3
  import { useAudioAnalyzer } from './useAudioAnalyzer';
4
- export const useAudioRecording = () => {
4
+ export const useAudioRecording = (maxHistoryLength) => {
5
5
  const [elapsedTime, setElapsedTime] = useState('00:00');
6
6
  const [recordingNotSupported, setRecordingNotSupported] = useState(false);
7
7
  const [isLoadingRecording, setIsLoadingRecording] = useState(false);
8
8
  const [isRecording, setIsRecording] = useState(false);
9
- // Add audio analyzer
10
- const { audioData, startAnalyzing, stopAnalyzing } = useAudioAnalyzer();
9
+ const [dynamicMaxLength, setDynamicMaxLength] = useState(maxHistoryLength || 65);
10
+ // Add audio analyzer with dynamic maxHistoryLength
11
+ const { audioData, startAnalyzing, stopAnalyzing } = useAudioAnalyzer(dynamicMaxLength);
11
12
  const onRecordingStarted = () => {
12
13
  setIsRecording(true);
13
14
  setIsLoadingRecording(false);
@@ -37,6 +38,9 @@ export const useAudioRecording = () => {
37
38
  }
38
39
  });
39
40
  };
41
+ const updateMaxHistoryLength = (newLength) => {
42
+ setDynamicMaxLength(newLength);
43
+ };
40
44
  return {
41
45
  elapsedTime,
42
46
  recordingNotSupported,
@@ -48,6 +52,8 @@ export const useAudioRecording = () => {
48
52
  onRecordingStarted,
49
53
  // Add audio data for visualization
50
54
  audioData,
55
+ // Add function to update maxHistoryLength
56
+ updateMaxHistoryLength,
51
57
  };
52
58
  };
53
59
  //# sourceMappingURL=useAudioRecording.js.map