diff --git a/web/src/components/message-input/index.less b/web/src/components/message-input/index.less index c4648dfca..daf074799 100644 --- a/web/src/components/message-input/index.less +++ b/web/src/components/message-input/index.less @@ -14,6 +14,8 @@ } .listWrapper { padding: 0 10px; + overflow: auto; + max-height: 170px; } .inputWrapper { border-radius: 8px; diff --git a/web/src/components/message-input/index.tsx b/web/src/components/message-input/index.tsx index 61a762c47..65b23a51b 100644 --- a/web/src/components/message-input/index.tsx +++ b/web/src/components/message-input/index.tsx @@ -1,13 +1,18 @@ import { Authorization } from '@/constants/authorization'; import { useTranslate } from '@/hooks/common-hooks'; import { + useDeleteDocument, useFetchDocumentInfosByIds, useRemoveNextDocument, } from '@/hooks/document-hooks'; import { getAuthorization } from '@/utils/authorization-util'; import { getExtension } from '@/utils/document-util'; import { formatBytes } from '@/utils/file-util'; -import { CloseCircleOutlined, LoadingOutlined } from '@ant-design/icons'; +import { + CloseCircleOutlined, + InfoCircleOutlined, + LoadingOutlined, +} from '@ant-design/icons'; import type { GetProp, UploadFile } from 'antd'; import { Button, @@ -41,6 +46,16 @@ const getFileIds = (fileList: UploadFile[]) => { return ids; }; +const isUploadError = (file: UploadFile) => { + const retcode = get(file, 'response.retcode'); + return typeof retcode === 'number' && retcode !== 0; +}; + +const isUploadSuccess = (file: UploadFile) => { + const retcode = get(file, 'response.retcode'); + return typeof retcode === 'number' && retcode === 0; +}; + interface IProps { disabled: boolean; value: string; @@ -50,6 +65,7 @@ interface IProps { onInputChange: ChangeEventHandler; conversationId: string; uploadUrl?: string; + isShared?: boolean; } const getBase64 = (file: FileType): Promise => @@ -61,6 +77,7 @@ const getBase64 = (file: FileType): Promise => }); const MessageInput = ({ + isShared = false, disabled, value, onPressEnter, @@ -72,6 +89,7 @@ const MessageInput = ({ }: IProps) => { const { t } = useTranslate('chat'); const { removeDocument } = useRemoveNextDocument(); + const { deleteDocument } = useDeleteDocument(); const { data: documentInfos, setDocumentIds } = useFetchDocumentInfosByIds(); const [fileList, setFileList] = useState([]); @@ -89,7 +107,7 @@ const MessageInput = ({ const handlePressEnter = useCallback(async () => { if (isUploadingFile) return; - const ids = getFileIds(fileList); + const ids = getFileIds(fileList.filter((x) => isUploadSuccess(x))); onPressEnter(ids); setFileList([]); @@ -98,14 +116,24 @@ const MessageInput = ({ const handleRemove = useCallback( async (file: UploadFile) => { const ids = get(file, 'response.data', []); - if (ids.length) { - await removeDocument(ids[0]); + // Upload Successfully + if (Array.isArray(ids) && ids.length) { + if (isShared) { + await deleteDocument(ids); + } else { + await removeDocument(ids[0]); + } setFileList((preList) => { return preList.filter((x) => getFileId(x) !== ids[0]); }); + } else { + // Upload failed + setFileList((preList) => { + return preList.filter((x) => x.uid !== file.uid); + }); } }, - [removeDocument], + [removeDocument, deleteDocument, isShared], ); const getDocumentInfoById = useCallback( @@ -192,6 +220,11 @@ const MessageInput = ({ } /> + ) : !getFileId(item) ? ( + ) : ( )} @@ -202,26 +235,33 @@ const MessageInput = ({ > {item.name} - {item.percent !== 100 ? ( - t('uploading') - ) : !item.response ? ( - t('parsing') + {isUploadError(item) ? ( + t('uploadFailed') ) : ( - - {fileExtension?.toUpperCase()}, - - {formatBytes(getDocumentInfoById(id)?.size ?? 0)} - - + <> + {item.percent !== 100 ? ( + t('uploading') + ) : !item.response ? ( + t('parsing') + ) : ( + + {fileExtension?.toUpperCase()}, + + {formatBytes( + getDocumentInfoById(id)?.size ?? 0, + )} + + + )} + )} {item.status !== 'uploading' && ( - handleRemove(item)} - /> + + handleRemove(item)} /> + )} diff --git a/web/src/hooks/document-hooks.ts b/web/src/hooks/document-hooks.ts index 58c32050f..5ff178d48 100644 --- a/web/src/hooks/document-hooks.ts +++ b/web/src/hooks/document-hooks.ts @@ -313,3 +313,23 @@ export const useRemoveNextDocument = () => { return { data, loading, removeDocument: mutateAsync }; }; + +export const useDeleteDocument = () => { + // const queryClient = useQueryClient(); + const { + data, + isPending: loading, + mutateAsync, + } = useMutation({ + mutationKey: ['deleteDocument'], + mutationFn: async (documentIds: string[]) => { + const data = await kbService.document_delete({ doc_ids: documentIds }); + // if (data.retcode === 0) { + // queryClient.invalidateQueries({ queryKey: ['fetchFlowList'] }); + // } + return data; + }, + }); + + return { data, loading, deleteDocument: mutateAsync }; +}; diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index 2a5686461..8fa8dd143 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -424,6 +424,7 @@ The above is the content you need to summarize.`, searching: 'searching...', parsing: 'Parsing', uploading: 'Uploading', + uploadFailed: 'Upload failed', }, setting: { profile: 'Profile', diff --git a/web/src/locales/zh-traditional.ts b/web/src/locales/zh-traditional.ts index cdc3cdb6f..b8b982ea9 100644 --- a/web/src/locales/zh-traditional.ts +++ b/web/src/locales/zh-traditional.ts @@ -394,6 +394,7 @@ export default { searching: '搜索中', parsing: '解析中', uploading: '上傳中', + uploadFailed: '上傳失敗', }, setting: { profile: '概述', diff --git a/web/src/locales/zh.ts b/web/src/locales/zh.ts index 9a8763ef3..9c0bafeee 100644 --- a/web/src/locales/zh.ts +++ b/web/src/locales/zh.ts @@ -411,6 +411,7 @@ export default { searching: '搜索中', parsing: '解析中', uploading: '上传中', + uploadFailed: '上传失败', }, setting: { profile: '概要', diff --git a/web/src/pages/chat/share/large.tsx b/web/src/pages/chat/share/large.tsx index 20b2bf2b0..d65cda6a6 100644 --- a/web/src/pages/chat/share/large.tsx +++ b/web/src/pages/chat/share/large.tsx @@ -65,6 +65,7 @@ const ChatContainer = () => { { const ref = useScrollToBottom(currentConversation); - const addNewestConversation = useCallback((message: string) => { + const addNewestConversation = useCallback((message: Partial) => { setCurrentConversation((pre) => { return { ...pre, @@ -65,14 +65,15 @@ export const useSelectCurrentSharedConversation = (conversationId: string) => { ...(pre.message ?? []), { role: MessageType.User, - content: message, + content: message.content, + doc_ids: message.doc_ids, id: uuid(), } as IMessage, { role: MessageType.Assistant, content: '', id: uuid(), - reference: [], + reference: {}, } as IMessage, ], }; @@ -140,7 +141,7 @@ export const useSendButtonDisabled = (value: string) => { export const useSendSharedMessage = ( conversation: IClientConversation, - addNewestConversation: (message: string) => void, + addNewestConversation: (message: Partial, answer?: string) => void, removeLatestMessage: () => void, setCurrentConversation: Dispatch>, addNewestAnswer: (answer: IAnswer) => void, @@ -205,14 +206,17 @@ export const useSendSharedMessage = ( } }, [answer, addNewestAnswer]); - const handlePressEnter = useCallback(() => { - if (trim(value) === '') return; - if (done) { - setValue(''); - addNewestConversation(value); - handleSendMessage(value.trim()); - } - }, [addNewestConversation, done, handleSendMessage, setValue, value]); + const handlePressEnter = useCallback( + (documentIds: string[]) => { + if (trim(value) === '') return; + if (done) { + setValue(''); + addNewestConversation({ content: value, doc_ids: documentIds }); + handleSendMessage(value.trim()); + } + }, + [addNewestConversation, done, handleSendMessage, setValue, value], + ); return { handlePressEnter, diff --git a/web/src/services/knowledge-service.ts b/web/src/services/knowledge-service.ts index 6463a344f..a9162101d 100644 --- a/web/src/services/knowledge-service.ts +++ b/web/src/services/knowledge-service.ts @@ -12,6 +12,7 @@ const { get_document_list, document_change_status, document_rm, + document_delete, document_create, document_change_parser, document_thumbnails, @@ -131,6 +132,10 @@ const methods = { url: knowledge_graph, method: 'get', }, + document_delete: { + url: document_delete, + method: 'delete', + }, }; const kbService = registerServer(methods, request); diff --git a/web/src/utils/api.ts b/web/src/utils/api.ts index f8fd59e8a..ab73ccb79 100644 --- a/web/src/utils/api.ts +++ b/web/src/utils/api.ts @@ -41,6 +41,7 @@ export default { get_document_list: `${api_host}/document/list`, document_change_status: `${api_host}/document/change_status`, document_rm: `${api_host}/document/rm`, + document_delete: `${api_host}/api/document`, document_rename: `${api_host}/document/rename`, document_create: `${api_host}/document/create`, document_run: `${api_host}/document/run`, diff --git a/web/src/utils/register-server.ts b/web/src/utils/register-server.ts index c2161411a..3aa987538 100644 --- a/web/src/utils/register-server.ts +++ b/web/src/utils/register-server.ts @@ -6,6 +6,8 @@ type Service = Record< (params?: any, urlAppendix?: string) => any >; +const Methods = ['post', 'delete', 'put']; + const registerServer = ( opt: Record, request: RequestMethod, @@ -18,7 +20,7 @@ const registerServer = ( if (urlAppendix) { url = url + '/' + urlAppendix; } - if (opt[key].method === 'post' || opt[key].method === 'POST') { + if (Methods.some((x) => x === opt[key].method.toLowerCase())) { return request(url, { method: opt[key].method, data: params,