From c6c39612508987d8a0c97f59c547e8ca76e0a078 Mon Sep 17 00:00:00 2001 From: balibabu Date: Thu, 15 Aug 2024 09:19:17 +0800 Subject: [PATCH] feat: Delete the file from the upload control of the message input box #1880 (#1946) ### What problem does this PR solve? feat: Delete the file from the upload control of the message input box #1880 ### Type of change - [x] New Feature (non-breaking change which adds functionality) --- web/src/assets/svg/llm/perfx-cloud.svg | 21 +++++---- web/src/components/indented-tree/modal.tsx | 2 +- web/src/components/message-input/index.tsx | 47 +++++++++------------ web/src/components/message-item/index.less | 3 +- web/src/components/message-item/index.tsx | 29 ++++++++++--- web/src/hooks/document-hooks.ts | 33 ++++++++++++--- web/src/pages/chat/chat-container/index.tsx | 18 -------- web/src/pages/chat/hooks.ts | 27 +++++++----- 8 files changed, 100 insertions(+), 80 deletions(-) diff --git a/web/src/assets/svg/llm/perfx-cloud.svg b/web/src/assets/svg/llm/perfx-cloud.svg index edb014702..3767a1e86 100644 --- a/web/src/assets/svg/llm/perfx-cloud.svg +++ b/web/src/assets/svg/llm/perfx-cloud.svg @@ -1,11 +1,10 @@ - - - - - - - - - - - + + logo + + + + + + \ No newline at end of file diff --git a/web/src/components/indented-tree/modal.tsx b/web/src/components/indented-tree/modal.tsx index a54b6c70b..60b4d25dc 100644 --- a/web/src/components/indented-tree/modal.tsx +++ b/web/src/components/indented-tree/modal.tsx @@ -15,7 +15,7 @@ const IndentedTreeModal = ({ return ( ; + onPressEnter(documentIds: string[]): void; onInputChange: ChangeEventHandler; conversationId: string; } @@ -37,50 +38,41 @@ const MessageInput = ({ conversationId, }: IProps) => { const { t } = useTranslate('chat'); + const { removeDocument } = useRemoveNextDocument(); - const [fileList, setFileList] = useState([ - // { - // uid: '-1', - // name: 'image.png', - // status: 'done', - // url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', - // }, - // { - // uid: '-xxx', - // percent: 50, - // name: 'image.png', - // status: 'uploading', - // url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', - // }, - // { - // uid: '-5', - // name: 'image.png', - // status: 'error', - // }, - ]); + const [fileList, setFileList] = useState([]); const handlePreview = async (file: UploadFile) => { if (!file.url && !file.preview) { file.preview = await getBase64(file.originFileObj as FileType); } - - // setPreviewImage(file.url || (file.preview as string)); - // setPreviewOpen(true); }; const handleChange: UploadProps['onChange'] = ({ fileList: newFileList }) => { console.log('🚀 ~ newFileList:', newFileList); setFileList(newFileList); }; + const isUploadingFile = fileList.some((x) => x.status === 'uploading'); const handlePressEnter = useCallback(async () => { + if (isUploadingFile) return; const ids = fileList.reduce((pre, cur) => { return pre.concat(get(cur, 'response.data', [])); }, []); - await onPressEnter(ids); + onPressEnter(ids); setFileList([]); - }, [fileList, onPressEnter]); + }, [fileList, onPressEnter, isUploadingFile]); + + const handleRemove = useCallback( + (file: UploadFile) => { + const ids = get(file, 'response.data', []); + if (ids.length) { + removeDocument(ids[0]); + } + }, + [removeDocument], + ); const uploadButton = ( @@ -119,6 +111,7 @@ const MessageInput = ({ headers={{ [Authorization]: getAuthorization() }} data={{ conversation_id: conversationId }} method="post" + onRemove={handleRemove} > {fileList.length >= 8 ? null : uploadButton} diff --git a/web/src/components/message-item/index.less b/web/src/components/message-item/index.less index fd7b8ca55..a4fe17c8d 100644 --- a/web/src/components/message-item/index.less +++ b/web/src/components/message-item/index.less @@ -7,7 +7,8 @@ width: 80%; } .messageItemSectionRight { - width: 80%; + // width: 80%; + // max-width: 50vw; } .messageItemContent { display: inline-flex; diff --git a/web/src/components/message-item/index.tsx b/web/src/components/message-item/index.tsx index c5a5af958..c0bc4a9b1 100644 --- a/web/src/components/message-item/index.tsx +++ b/web/src/components/message-item/index.tsx @@ -7,15 +7,20 @@ import { IChunk } from '@/interfaces/database/knowledge'; import classNames from 'classnames'; import { memo, useCallback, useEffect, useMemo, useState } from 'react'; -import { useFetchDocumentInfosByIds } from '@/hooks/document-hooks'; +import { + useFetchDocumentInfosByIds, + useFetchDocumentThumbnailsByIds, +} from '@/hooks/document-hooks'; import MarkdownContent from '@/pages/chat/markdown-content'; import { getExtension, isImage } from '@/utils/document-util'; -import { Avatar, Button, Flex, List } from 'antd'; +import { Avatar, Button, Flex, List, Typography } from 'antd'; import IndentedTreeModal from '../indented-tree/modal'; import NewDocumentLink from '../new-document-link'; import SvgIcon from '../svg-icon'; import styles from './index.less'; +const { Text } = Typography; + interface IProps { item: Message; reference: IReference; @@ -38,7 +43,8 @@ const MessageItem = ({ const { t } = useTranslate('chat'); const fileThumbnails = useSelectFileThumbnails(); const { data: documentList, setDocumentIds } = useFetchDocumentInfosByIds(); - console.log('🚀 ~ documentList:', documentList); + const { data: documentThumbnails, setDocumentIds: setIds } = + useFetchDocumentThumbnailsByIds(); const { visible, hideModal, showModal } = useSetModalState(); const [clickedDocumentId, setClickedDocumentId] = useState(''); @@ -66,8 +72,12 @@ const MessageItem = ({ const ids = item?.doc_ids ?? []; if (ids.length) { setDocumentIds(ids); + const documentIds = ids.filter((x) => !(x in fileThumbnails)); + if (documentIds.length) { + setIds(documentIds); + } } - }, [item.doc_ids, setDocumentIds]); + }, [item.doc_ids, setDocumentIds, setIds, fileThumbnails]); return (
{ const fileThumbnail = fileThumbnails[item.doc_id]; + const fileExtension = getExtension(item.doc_name); return ( @@ -151,7 +162,8 @@ const MessageItem = ({ bordered dataSource={documentList} renderItem={(item) => { - const fileThumbnail = fileThumbnails[item.id]; + const fileThumbnail = + documentThumbnails[item.id] || fileThumbnails[item.id]; const fileExtension = getExtension(item.name); return ( @@ -181,7 +193,12 @@ const MessageItem = ({ type={'text'} onClick={handleUserDocumentClick(item.id)} > - {item.name} + + {item.name} + )} diff --git a/web/src/hooks/document-hooks.ts b/web/src/hooks/document-hooks.ts index 65b1bb9d2..58c32050f 100644 --- a/web/src/hooks/document-hooks.ts +++ b/web/src/hooks/document-hooks.ts @@ -4,7 +4,7 @@ import { IChangeParserConfigRequestBody } from '@/interfaces/request/document'; import kbService from '@/services/knowledge-service'; import { api_host } from '@/utils/api'; import { buildChunkHighlights } from '@/utils/document-util'; -import { useQuery } from '@tanstack/react-query'; +import { useMutation, useQuery } from '@tanstack/react-query'; import { UploadFile } from 'antd'; import { useCallback, useMemo, useState } from 'react'; import { IHighlight } from 'react-pdf-highlighter'; @@ -278,15 +278,38 @@ export const useFetchDocumentInfosByIds = () => { export const useFetchDocumentThumbnailsByIds = () => { const [ids, setDocumentIds] = useState([]); - const { data } = useQuery({ + const { data } = useQuery>({ queryKey: ['fetchDocumentThumbnails', ids], - initialData: [], + enabled: ids.length > 0, + initialData: {}, queryFn: async () => { const { data } = await kbService.document_thumbnails({ doc_ids: ids }); - - return data; + if (data.retcode === 0) { + return data.data; + } + return {}; }, }); return { data, setDocumentIds }; }; + +export const useRemoveNextDocument = () => { + // const queryClient = useQueryClient(); + const { + data, + isPending: loading, + mutateAsync, + } = useMutation({ + mutationKey: ['removeDocument'], + mutationFn: async (documentId: string) => { + const data = await kbService.document_rm({ doc_id: documentId }); + // if (data.retcode === 0) { + // queryClient.invalidateQueries({ queryKey: ['fetchFlowList'] }); + // } + return data; + }, + }); + + return { data, loading, removeDocument: mutateAsync }; +}; diff --git a/web/src/pages/chat/chat-container/index.tsx b/web/src/pages/chat/chat-container/index.tsx index 7c26954f2..234fc3f9e 100644 --- a/web/src/pages/chat/chat-container/index.tsx +++ b/web/src/pages/chat/chat-container/index.tsx @@ -80,24 +80,6 @@ const ChatContainer = () => { onPressEnter={handlePressEnter} conversationId={conversation.id} > - {/* - {t('send')} - - } - onPressEnter={handlePressEnter} - onChange={handleInputChange} - /> */} { const { conversationId, dialogId } = useGetChatSearchParams(); const addNewestConversation = useCallback( - (message: string, answer: string = '') => { + (message: Partial, answer: string = '') => { setCurrentConversation((pre) => { return { ...pre, @@ -387,7 +392,8 @@ export const useSelectCurrentConversation = () => { ...pre.message, { role: MessageType.User, - content: message, + content: message.content, + doc_ids: message.doc_ids, id: uuid(), } as IMessage, { @@ -535,7 +541,7 @@ export const useHandleMessageInputChange = () => { export const useSendMessage = ( conversation: IClientConversation, - addNewestConversation: (message: string, answer?: string) => void, + addNewestConversation: (message: Partial, answer?: string) => void, removeLatestMessage: () => void, addNewestAnswer: (answer: IAnswer) => void, ) => { @@ -589,12 +595,12 @@ export const useSendMessage = ( const handleSendMessage = useCallback( async (message: string, documentIds: string[]) => { if (conversationId !== '') { - return sendMessage(message, documentIds); + sendMessage(message, documentIds); } else { const data = await setConversation(message); if (data.retcode === 0) { const id = data.data.id; - return sendMessage(message, documentIds, id); + sendMessage(message, documentIds, id); } } }, @@ -616,15 +622,14 @@ export const useSendMessage = ( }, [setDone, conversationId]); const handlePressEnter = useCallback( - async (documentIds: string[]) => { + (documentIds: string[]) => { if (trim(value) === '') return; - let ret; + + addNewestConversation({ content: value, doc_ids: documentIds }); if (done) { setValue(''); - ret = await handleSendMessage(value.trim(), documentIds); + handleSendMessage(value.trim(), documentIds); } - addNewestConversation(value); - return ret; }, [addNewestConversation, handleSendMessage, done, setValue, value], );