Pārlūkot izejas kodu

feat: Delete the files uploaded in the external dialog box #1880 (#1967)

### What problem does this PR solve?

feat: Delete the files uploaded in the external dialog box #1880

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
tags/v0.10.0
balibabu pirms 1 gada
vecāks
revīzija
7bdd5a48c0
Revīzijas autora e-pasta adrese nav piesaistīta nevienam kontam

+ 2
- 0
web/src/components/message-input/index.less Parādīt failu

} }
.listWrapper { .listWrapper {
padding: 0 10px; padding: 0 10px;
overflow: auto;
max-height: 170px;
} }
.inputWrapper { .inputWrapper {
border-radius: 8px; border-radius: 8px;

+ 59
- 19
web/src/components/message-input/index.tsx Parādīt failu

import { Authorization } from '@/constants/authorization'; import { Authorization } from '@/constants/authorization';
import { useTranslate } from '@/hooks/common-hooks'; import { useTranslate } from '@/hooks/common-hooks';
import { import {
useDeleteDocument,
useFetchDocumentInfosByIds, useFetchDocumentInfosByIds,
useRemoveNextDocument, useRemoveNextDocument,
} from '@/hooks/document-hooks'; } from '@/hooks/document-hooks';
import { getAuthorization } from '@/utils/authorization-util'; import { getAuthorization } from '@/utils/authorization-util';
import { getExtension } from '@/utils/document-util'; import { getExtension } from '@/utils/document-util';
import { formatBytes } from '@/utils/file-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 type { GetProp, UploadFile } from 'antd';
import { import {
Button, Button,
return ids; 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 { interface IProps {
disabled: boolean; disabled: boolean;
value: string; value: string;
onInputChange: ChangeEventHandler<HTMLInputElement>; onInputChange: ChangeEventHandler<HTMLInputElement>;
conversationId: string; conversationId: string;
uploadUrl?: string; uploadUrl?: string;
isShared?: boolean;
} }


const getBase64 = (file: FileType): Promise<string> => const getBase64 = (file: FileType): Promise<string> =>
}); });


const MessageInput = ({ const MessageInput = ({
isShared = false,
disabled, disabled,
value, value,
onPressEnter, onPressEnter,
}: IProps) => { }: IProps) => {
const { t } = useTranslate('chat'); const { t } = useTranslate('chat');
const { removeDocument } = useRemoveNextDocument(); const { removeDocument } = useRemoveNextDocument();
const { deleteDocument } = useDeleteDocument();
const { data: documentInfos, setDocumentIds } = useFetchDocumentInfosByIds(); const { data: documentInfos, setDocumentIds } = useFetchDocumentInfosByIds();


const [fileList, setFileList] = useState<UploadFile[]>([]); const [fileList, setFileList] = useState<UploadFile[]>([]);


const handlePressEnter = useCallback(async () => { const handlePressEnter = useCallback(async () => {
if (isUploadingFile) return; if (isUploadingFile) return;
const ids = getFileIds(fileList);
const ids = getFileIds(fileList.filter((x) => isUploadSuccess(x)));


onPressEnter(ids); onPressEnter(ids);
setFileList([]); setFileList([]);
const handleRemove = useCallback( const handleRemove = useCallback(
async (file: UploadFile) => { async (file: UploadFile) => {
const ids = get(file, 'response.data', []); 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) => { setFileList((preList) => {
return preList.filter((x) => getFileId(x) !== ids[0]); 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( const getDocumentInfoById = useCallback(
<LoadingOutlined style={{ fontSize: 24 }} spin /> <LoadingOutlined style={{ fontSize: 24 }} spin />
} }
/> />
) : !getFileId(item) ? (
<InfoCircleOutlined
size={30}
// width={30}
></InfoCircleOutlined>
) : ( ) : (
<FileIcon id={id} name={item.name}></FileIcon> <FileIcon id={id} name={item.name}></FileIcon>
)} )}
> >
<b> {item.name}</b> <b> {item.name}</b>
</Text> </Text>
{item.percent !== 100 ? (
t('uploading')
) : !item.response ? (
t('parsing')
{isUploadError(item) ? (
t('uploadFailed')
) : ( ) : (
<Space>
<span>{fileExtension?.toUpperCase()},</span>
<span>
{formatBytes(getDocumentInfoById(id)?.size ?? 0)}
</span>
</Space>
<>
{item.percent !== 100 ? (
t('uploading')
) : !item.response ? (
t('parsing')
) : (
<Space>
<span>{fileExtension?.toUpperCase()},</span>
<span>
{formatBytes(
getDocumentInfoById(id)?.size ?? 0,
)}
</span>
</Space>
)}
</>
)} )}
</Flex> </Flex>
</Flex> </Flex>


{item.status !== 'uploading' && ( {item.status !== 'uploading' && (
<CloseCircleOutlined
className={styles.deleteIcon}
onClick={() => handleRemove(item)}
/>
<span className={styles.deleteIcon}>
<CloseCircleOutlined onClick={() => handleRemove(item)} />
</span>
)} )}
</Card> </Card>
</List.Item> </List.Item>

+ 20
- 0
web/src/hooks/document-hooks.ts Parādīt failu



return { data, loading, removeDocument: mutateAsync }; 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 };
};

+ 1
- 0
web/src/locales/en.ts Parādīt failu

searching: 'searching...', searching: 'searching...',
parsing: 'Parsing', parsing: 'Parsing',
uploading: 'Uploading', uploading: 'Uploading',
uploadFailed: 'Upload failed',
}, },
setting: { setting: {
profile: 'Profile', profile: 'Profile',

+ 1
- 0
web/src/locales/zh-traditional.ts Parādīt failu

searching: '搜索中', searching: '搜索中',
parsing: '解析中', parsing: '解析中',
uploading: '上傳中', uploading: '上傳中',
uploadFailed: '上傳失敗',
}, },
setting: { setting: {
profile: '概述', profile: '概述',

+ 1
- 0
web/src/locales/zh.ts Parādīt failu

searching: '搜索中', searching: '搜索中',
parsing: '解析中', parsing: '解析中',
uploading: '上传中', uploading: '上传中',
uploadFailed: '上传失败',
}, },
setting: { setting: {
profile: '概要', profile: '概要',

+ 1
- 0
web/src/pages/chat/share/large.tsx Parādīt failu

</Flex> </Flex>


<MessageInput <MessageInput
isShared
value={value} value={value}
disabled={false} disabled={false}
sendDisabled={sendDisabled} sendDisabled={sendDisabled}

+ 17
- 13
web/src/pages/chat/shared-hooks.ts Parādīt failu

} from '@/hooks/chat-hooks'; } from '@/hooks/chat-hooks';
import { useSendMessageWithSse } from '@/hooks/logic-hooks'; import { useSendMessageWithSse } from '@/hooks/logic-hooks';
import { useOneNamespaceEffectsLoading } from '@/hooks/store-hooks'; import { useOneNamespaceEffectsLoading } from '@/hooks/store-hooks';
import { IAnswer } from '@/interfaces/database/chat';
import { IAnswer, Message } from '@/interfaces/database/chat';
import api from '@/utils/api'; import api from '@/utils/api';
import omit from 'lodash/omit'; import omit from 'lodash/omit';
import trim from 'lodash/trim'; import trim from 'lodash/trim';


const ref = useScrollToBottom(currentConversation); const ref = useScrollToBottom(currentConversation);


const addNewestConversation = useCallback((message: string) => {
const addNewestConversation = useCallback((message: Partial<Message>) => {
setCurrentConversation((pre) => { setCurrentConversation((pre) => {
return { return {
...pre, ...pre,
...(pre.message ?? []), ...(pre.message ?? []),
{ {
role: MessageType.User, role: MessageType.User,
content: message,
content: message.content,
doc_ids: message.doc_ids,
id: uuid(), id: uuid(),
} as IMessage, } as IMessage,
{ {
role: MessageType.Assistant, role: MessageType.Assistant,
content: '', content: '',
id: uuid(), id: uuid(),
reference: [],
reference: {},
} as IMessage, } as IMessage,
], ],
}; };


export const useSendSharedMessage = ( export const useSendSharedMessage = (
conversation: IClientConversation, conversation: IClientConversation,
addNewestConversation: (message: string) => void,
addNewestConversation: (message: Partial<Message>, answer?: string) => void,
removeLatestMessage: () => void, removeLatestMessage: () => void,
setCurrentConversation: Dispatch<SetStateAction<IClientConversation>>, setCurrentConversation: Dispatch<SetStateAction<IClientConversation>>,
addNewestAnswer: (answer: IAnswer) => void, addNewestAnswer: (answer: IAnswer) => void,
} }
}, [answer, addNewestAnswer]); }, [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 { return {
handlePressEnter, handlePressEnter,

+ 5
- 0
web/src/services/knowledge-service.ts Parādīt failu

get_document_list, get_document_list,
document_change_status, document_change_status,
document_rm, document_rm,
document_delete,
document_create, document_create,
document_change_parser, document_change_parser,
document_thumbnails, document_thumbnails,
url: knowledge_graph, url: knowledge_graph,
method: 'get', method: 'get',
}, },
document_delete: {
url: document_delete,
method: 'delete',
},
}; };


const kbService = registerServer<keyof typeof methods>(methods, request); const kbService = registerServer<keyof typeof methods>(methods, request);

+ 1
- 0
web/src/utils/api.ts Parādīt failu

get_document_list: `${api_host}/document/list`, get_document_list: `${api_host}/document/list`,
document_change_status: `${api_host}/document/change_status`, document_change_status: `${api_host}/document/change_status`,
document_rm: `${api_host}/document/rm`, document_rm: `${api_host}/document/rm`,
document_delete: `${api_host}/api/document`,
document_rename: `${api_host}/document/rename`, document_rename: `${api_host}/document/rename`,
document_create: `${api_host}/document/create`, document_create: `${api_host}/document/create`,
document_run: `${api_host}/document/run`, document_run: `${api_host}/document/run`,

+ 3
- 1
web/src/utils/register-server.ts Parādīt failu

(params?: any, urlAppendix?: string) => any (params?: any, urlAppendix?: string) => any
>; >;


const Methods = ['post', 'delete', 'put'];

const registerServer = <T extends string>( const registerServer = <T extends string>(
opt: Record<T, { url: string; method: string }>, opt: Record<T, { url: string; method: string }>,
request: RequestMethod, request: RequestMethod,
if (urlAppendix) { if (urlAppendix) {
url = url + '/' + 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, { return request(url, {
method: opt[key].method, method: opt[key].method,
data: params, data: params,

Notiek ielāde…
Atcelt
Saglabāt