diff --git a/web/app/components/base/chat/chat/chat-input-area/index.tsx b/web/app/components/base/chat/chat/chat-input-area/index.tsx index c79df7d7bb..c4a7b7306c 100644 --- a/web/app/components/base/chat/chat/chat-input-area/index.tsx +++ b/web/app/components/base/chat/chat/chat-input-area/index.tsx @@ -1,14 +1,38 @@ import { memo, + useCallback, useState, } from 'react' import Textarea from 'rc-textarea' +import { useTranslation } from 'react-i18next' +import Recorder from 'js-audio-recorder' +import type { + EnableType, + OnSend, + VisionConfig, +} from '../../types' +import type { Theme } from '../../embedded-chatbot/theme/theme-context' import { useTextAreaHeight } from './hooks' import Operation from './operation' import cn from '@/utils/classnames' import { FileListFlexOperation } from '@/app/components/base/file-uploader' +import VoiceInput from '@/app/components/base/voice-input' +import { useToastContext } from '@/app/components/base/toast' -const ChatInputArea = () => { +type ChatInputAreaProps = { + visionConfig?: VisionConfig + speechToTextConfig?: EnableType + onSend?: OnSend + theme?: Theme | null +} +const ChatInputArea = ({ + visionConfig, + speechToTextConfig = { enabled: true }, + onSend, + theme, +}: ChatInputAreaProps) => { + const { t } = useTranslation() + const { notify } = useToastContext() const { wrapperRef, textareaRef, @@ -18,16 +42,31 @@ const ChatInputArea = () => { isMultipleLine, } = useTextAreaHeight() const [value, setValue] = useState('') + const [showVoiceInput, setShowVoiceInput] = useState(false) - const operation = + const handleShowVoiceInput = useCallback(() => { + (Recorder as any).getPermission().then(() => { + setShowVoiceInput(true) + }, () => { + notify({ type: 'error', message: t('common.voiceInput.notAllow') }) + }) + }, [t, notify]) + + const operation = ( + + ) return (
-
+
{ !isMultipleLine && operation }
+ { + showVoiceInput && ( + setShowVoiceInput(false)} + onConverted={text => setValue(text)} + /> + ) + }
{ - isMultipleLine && operation + isMultipleLine && ( +
{operation}
+ ) }
) diff --git a/web/app/components/base/chat/chat/chat-input-area/operation.tsx b/web/app/components/base/chat/chat/chat-input-area/operation.tsx index db8ae62636..f33f79739e 100644 --- a/web/app/components/base/chat/chat/chat-input-area/operation.tsx +++ b/web/app/components/base/chat/chat/chat-input-area/operation.tsx @@ -1,10 +1,27 @@ -import { forwardRef } from 'react' -import { RiSendPlane2Fill } from '@remixicon/react' +import { + forwardRef, + memo, +} from 'react' +import { + RiMicLine, + RiSendPlane2Fill, +} from '@remixicon/react' +import type { + EnableType, +} from '../../types' import Button from '@/app/components/base/button' +import ActionButton from '@/app/components/base/action-button' import { FileUploaderInChatInput } from '@/app/components/base/file-uploader' import cn from '@/utils/classnames' -const Operation = forwardRef((_, ref) => { +type OperationProps = { + speechToTextConfig?: EnableType + onShowVoiceInput?: () => void +} +const Operation = forwardRef(({ + speechToTextConfig, + onShowVoiceInput, +}, ref) => { return (
((_, ref) => { className='flex items-center pl-1' ref={ref} > -
+
+ { + speechToTextConfig?.enabled && ( + + + + ) + }
) }) diff --git a/web/app/components/base/file-uploader/file-uploader-in-attachment/index.tsx b/web/app/components/base/file-uploader/file-uploader-in-attachment/index.tsx index 87841b3a18..5715231fc1 100644 --- a/web/app/components/base/file-uploader/file-uploader-in-attachment/index.tsx +++ b/web/app/components/base/file-uploader/file-uploader-in-attachment/index.tsx @@ -31,7 +31,7 @@ const FileUploaderInAttachment = () => { className='grow' > {option.icon} - {option.label} + {option.label} )) }