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}
))
}