123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112 |
- import { ChatContext } from '@/app/chat-context';
- import { apiInterceptors, getDocumentList } from '@/client/api';
- import { IDocument } from '@/types/knowledge';
- import { SendOutlined } from '@ant-design/icons';
- import { Button, Input } from 'antd';
- import { PropsWithChildren, useContext, useEffect, useMemo, useRef, useState } from 'react';
- import DocList from '../chat/doc-list';
- import DocUpload from '../chat/doc-upload';
- import PromptBot from './prompt-bot';
- type TextAreaProps = Omit<Parameters<typeof Input.TextArea>[0], 'value' | 'onPressEnter' | 'onChange' | 'onSubmit'>;
- interface Props {
- onSubmit: (val: string) => void;
- handleFinish?: (val: boolean) => void;
- loading?: boolean;
- placeholder?: string;
- }
- function CompletionInput({
- children,
- loading,
- onSubmit,
- handleFinish,
- placeholder,
- ...props
- }: PropsWithChildren<Props & TextAreaProps>) {
- const { dbParam, scene } = useContext(ChatContext);
- const [userInput, setUserInput] = useState('');
- const showUpload = useMemo(() => scene === 'chat_knowledge', [scene]);
- const [documents, setDocuments] = useState<IDocument[]>([]);
- const uploadCountRef = useRef(0);
- useEffect(() => {
- showUpload && fetchDocuments();
- }, [dbParam]);
- async function fetchDocuments() {
- if (!dbParam) {
- return null;
- }
- const [_, data] = await apiInterceptors(
- getDocumentList(dbParam, {
- page: 1,
- page_size: uploadCountRef.current,
- }),
- );
- setDocuments(data?.data || []);
- }
- const onUploadFinish = async () => {
- uploadCountRef.current += 1;
- await fetchDocuments();
- };
- return (
- <div className='flex-1 relative'>
- <DocList documents={documents} dbParam={dbParam} />
- {showUpload && (
- <DocUpload handleFinish={handleFinish} onUploadFinish={onUploadFinish} className='absolute z-10 top-2 left-2' />
- )}
- <Input.TextArea
- className={`flex-1 ${showUpload ? 'pl-10' : ''} pr-10`}
- size='large'
- value={userInput}
- autoSize={{ minRows: 1, maxRows: 4 }}
- {...props}
- onPressEnter={e => {
- if (!userInput.trim()) return;
- if (e.keyCode === 13) {
- if (e.shiftKey) {
- e.preventDefault();
- setUserInput(state => state + '\n');
- return;
- }
- onSubmit(userInput);
- setTimeout(() => {
- setUserInput('');
- }, 0);
- }
- }}
- onChange={e => {
- if (typeof props.maxLength === 'number') {
- setUserInput(e.target.value.substring(0, props.maxLength));
- return;
- }
- setUserInput(e.target.value);
- }}
- placeholder={placeholder}
- />
- <Button
- className='ml-2 flex items-center justify-center absolute right-0 bottom-0'
- size='large'
- type='text'
- loading={loading}
- icon={<SendOutlined />}
- onClick={() => {
- onSubmit(userInput);
- }}
- />
- <PromptBot
- submit={prompt => {
- setUserInput(userInput + prompt);
- }}
- />
- {children}
- </div>
- );
- }
- export default CompletionInput;
|