|
|
|
|
@ -1,5 +1,6 @@
|
|
|
|
|
import type { FC } from 'react'
|
|
|
|
|
import {
|
|
|
|
|
memo,
|
|
|
|
|
useRef,
|
|
|
|
|
useState,
|
|
|
|
|
} from 'react'
|
|
|
|
|
@ -126,100 +127,102 @@ const ChatInput: FC<ChatInputProps> = ({
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
className={`
|
|
|
|
|
relative p-[5.5px] max-h-[150px] bg-white border-[1.5px] border-gray-200 rounded-xl overflow-y-auto
|
|
|
|
|
${isDragActive && 'border-primary-600'}
|
|
|
|
|
`}
|
|
|
|
|
>
|
|
|
|
|
{
|
|
|
|
|
visionConfig?.enabled && (
|
|
|
|
|
<>
|
|
|
|
|
<div className='absolute bottom-2 left-2 flex items-center'>
|
|
|
|
|
<ChatImageUploader
|
|
|
|
|
settings={visionConfig}
|
|
|
|
|
onUpload={onUpload}
|
|
|
|
|
disabled={files.length >= visionConfig.number_limits}
|
|
|
|
|
/>
|
|
|
|
|
<div className='mx-1 w-[1px] h-4 bg-black/5' />
|
|
|
|
|
</div>
|
|
|
|
|
<div className='pl-[52px]'>
|
|
|
|
|
<ImageList
|
|
|
|
|
list={files}
|
|
|
|
|
onRemove={onRemove}
|
|
|
|
|
onReUpload={onReUpload}
|
|
|
|
|
onImageLinkLoadSuccess={onImageLinkLoadSuccess}
|
|
|
|
|
onImageLinkLoadError={onImageLinkLoadError}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
<Textarea
|
|
|
|
|
<div className='relative'>
|
|
|
|
|
<div
|
|
|
|
|
className={`
|
|
|
|
|
block w-full px-2 pr-[118px] py-[7px] leading-5 max-h-none text-sm text-gray-700 outline-none appearance-none resize-none
|
|
|
|
|
${visionConfig?.enabled && 'pl-12'}
|
|
|
|
|
p-[5.5px] max-h-[150px] bg-white border-[1.5px] border-gray-200 rounded-xl overflow-y-auto
|
|
|
|
|
${isDragActive && 'border-primary-600'}
|
|
|
|
|
`}
|
|
|
|
|
value={query}
|
|
|
|
|
onChange={handleContentChange}
|
|
|
|
|
onKeyUp={handleKeyUp}
|
|
|
|
|
onKeyDown={handleKeyDown}
|
|
|
|
|
onPaste={onPaste}
|
|
|
|
|
onDragEnter={onDragEnter}
|
|
|
|
|
onDragLeave={onDragLeave}
|
|
|
|
|
onDragOver={onDragOver}
|
|
|
|
|
onDrop={onDrop}
|
|
|
|
|
autoSize
|
|
|
|
|
/>
|
|
|
|
|
<div className='absolute bottom-[7px] right-2 flex items-center h-8'>
|
|
|
|
|
<div className='flex items-center px-1 h-5 rounded-md bg-gray-100 text-xs font-medium text-gray-500'>
|
|
|
|
|
{query.trim().length}
|
|
|
|
|
</div>
|
|
|
|
|
>
|
|
|
|
|
{
|
|
|
|
|
query
|
|
|
|
|
? (
|
|
|
|
|
<div className='flex justify-center items-center ml-2 w-8 h-8 cursor-pointer hover:bg-gray-100 rounded-lg' onClick={() => setQuery('')}>
|
|
|
|
|
<XCircle className='w-4 h-4 text-[#98A2B3]' />
|
|
|
|
|
visionConfig?.enabled && (
|
|
|
|
|
<>
|
|
|
|
|
<div className='absolute bottom-2 left-2 flex items-center'>
|
|
|
|
|
<ChatImageUploader
|
|
|
|
|
settings={visionConfig}
|
|
|
|
|
onUpload={onUpload}
|
|
|
|
|
disabled={files.length >= visionConfig.number_limits}
|
|
|
|
|
/>
|
|
|
|
|
<div className='mx-1 w-[1px] h-4 bg-black/5' />
|
|
|
|
|
</div>
|
|
|
|
|
<div className='pl-[52px]'>
|
|
|
|
|
<ImageList
|
|
|
|
|
list={files}
|
|
|
|
|
onRemove={onRemove}
|
|
|
|
|
onReUpload={onReUpload}
|
|
|
|
|
onImageLinkLoadSuccess={onImageLinkLoadSuccess}
|
|
|
|
|
onImageLinkLoadError={onImageLinkLoadError}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
: speechToTextConfig?.enabled
|
|
|
|
|
</>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
<Textarea
|
|
|
|
|
className={`
|
|
|
|
|
block w-full px-2 pr-[118px] py-[7px] leading-5 max-h-none text-sm text-gray-700 outline-none appearance-none resize-none
|
|
|
|
|
${visionConfig?.enabled && 'pl-12'}
|
|
|
|
|
`}
|
|
|
|
|
value={query}
|
|
|
|
|
onChange={handleContentChange}
|
|
|
|
|
onKeyUp={handleKeyUp}
|
|
|
|
|
onKeyDown={handleKeyDown}
|
|
|
|
|
onPaste={onPaste}
|
|
|
|
|
onDragEnter={onDragEnter}
|
|
|
|
|
onDragLeave={onDragLeave}
|
|
|
|
|
onDragOver={onDragOver}
|
|
|
|
|
onDrop={onDrop}
|
|
|
|
|
autoSize
|
|
|
|
|
/>
|
|
|
|
|
<div className='absolute bottom-[7px] right-2 flex items-center h-8'>
|
|
|
|
|
<div className='flex items-center px-1 h-5 rounded-md bg-gray-100 text-xs font-medium text-gray-500'>
|
|
|
|
|
{query.trim().length}
|
|
|
|
|
</div>
|
|
|
|
|
{
|
|
|
|
|
query
|
|
|
|
|
? (
|
|
|
|
|
<div
|
|
|
|
|
className='group flex justify-center items-center ml-2 w-8 h-8 hover:bg-primary-50 rounded-lg cursor-pointer'
|
|
|
|
|
onClick={handleVoiceInputShow}
|
|
|
|
|
>
|
|
|
|
|
<Microphone01 className='block w-4 h-4 text-gray-500 group-hover:hidden' />
|
|
|
|
|
<Microphone01Solid className='hidden w-4 h-4 text-primary-600 group-hover:block' />
|
|
|
|
|
<div className='flex justify-center items-center ml-2 w-8 h-8 cursor-pointer hover:bg-gray-100 rounded-lg' onClick={() => setQuery('')}>
|
|
|
|
|
<XCircle className='w-4 h-4 text-[#98A2B3]' />
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
: null
|
|
|
|
|
: speechToTextConfig?.enabled
|
|
|
|
|
? (
|
|
|
|
|
<div
|
|
|
|
|
className='group flex justify-center items-center ml-2 w-8 h-8 hover:bg-primary-50 rounded-lg cursor-pointer'
|
|
|
|
|
onClick={handleVoiceInputShow}
|
|
|
|
|
>
|
|
|
|
|
<Microphone01 className='block w-4 h-4 text-gray-500 group-hover:hidden' />
|
|
|
|
|
<Microphone01Solid className='hidden w-4 h-4 text-primary-600 group-hover:block' />
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
: null
|
|
|
|
|
}
|
|
|
|
|
<div className='mx-2 w-[1px] h-4 bg-black opacity-5' />
|
|
|
|
|
{isMobile
|
|
|
|
|
? sendBtn
|
|
|
|
|
: (
|
|
|
|
|
<TooltipPlus
|
|
|
|
|
popupContent={
|
|
|
|
|
<div>
|
|
|
|
|
<div>{t('common.operation.send')} Enter</div>
|
|
|
|
|
<div>{t('common.operation.lineBreak')} Shift Enter</div>
|
|
|
|
|
</div>
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
{sendBtn}
|
|
|
|
|
</TooltipPlus>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
{
|
|
|
|
|
voiceInputShow && (
|
|
|
|
|
<VoiceInput
|
|
|
|
|
onCancel={() => setVoiceInputShow(false)}
|
|
|
|
|
onConverted={text => setQuery(text)}
|
|
|
|
|
/>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
<div className='mx-2 w-[1px] h-4 bg-black opacity-5' />
|
|
|
|
|
{isMobile
|
|
|
|
|
? sendBtn
|
|
|
|
|
: (
|
|
|
|
|
<TooltipPlus
|
|
|
|
|
popupContent={
|
|
|
|
|
<div>
|
|
|
|
|
<div>{t('common.operation.send')} Enter</div>
|
|
|
|
|
<div>{t('common.operation.lineBreak')} Shift Enter</div>
|
|
|
|
|
</div>
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
{sendBtn}
|
|
|
|
|
</TooltipPlus>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
{
|
|
|
|
|
voiceInputShow && (
|
|
|
|
|
<VoiceInput
|
|
|
|
|
onCancel={() => setVoiceInputShow(false)}
|
|
|
|
|
onConverted={text => setQuery(text)}
|
|
|
|
|
/>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default ChatInput
|
|
|
|
|
export default memo(ChatInput)
|
|
|
|
|
|