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