### What problem does this PR solve? fix: Change document status with @tanstack/react-query #13306 ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue) - [ ] New Feature (non-breaking change which adds functionality) - [ ] Documentation Update - [ ] Refactoring - [ ] Performance Improvement - [ ] Other (please describe):tags/v0.13.0
| history: { | history: { | ||||
| type: 'browser', | type: 'browser', | ||||
| }, | }, | ||||
| plugins: ['@react-dev-inspector/umi4-plugin', '@umijs/plugins/dist/dva'], | |||||
| dva: {}, | |||||
| plugins: ['@react-dev-inspector/umi4-plugin'], | |||||
| jsMinifier: 'terser', | jsMinifier: 'terser', | ||||
| lessLoader: { | lessLoader: { | ||||
| modifyVars: { | modifyVars: { | 
| import MaxTokenNumber from '@/components/max-token-number'; | import MaxTokenNumber from '@/components/max-token-number'; | ||||
| import { IModalManagerChildrenProps } from '@/components/modal-manager'; | import { IModalManagerChildrenProps } from '@/components/modal-manager'; | ||||
| import { IKnowledgeFileParserConfig } from '@/interfaces/database/knowledge'; | |||||
| import { IChangeParserConfigRequestBody } from '@/interfaces/request/document'; | |||||
| import { | import { | ||||
| MinusCircleOutlined, | MinusCircleOutlined, | ||||
| PlusOutlined, | PlusOutlined, | ||||
| import { useFetchParserListOnMount } from './hooks'; | import { useFetchParserListOnMount } from './hooks'; | ||||
| import { useTranslate } from '@/hooks/common-hooks'; | import { useTranslate } from '@/hooks/common-hooks'; | ||||
| import { IParserConfig } from '@/interfaces/database/document'; | |||||
| import { IChangeParserConfigRequestBody } from '@/interfaces/request/document'; | |||||
| import Delimiter from '../delimiter'; | import Delimiter from '../delimiter'; | ||||
| import EntityTypesItem from '../entity-types-item'; | import EntityTypesItem from '../entity-types-item'; | ||||
| import ExcelToHtml from '../excel-to-html'; | import ExcelToHtml from '../excel-to-html'; | ||||
| ) => void; | ) => void; | ||||
| showModal?(): void; | showModal?(): void; | ||||
| parserId: string; | parserId: string; | ||||
| parserConfig: IKnowledgeFileParserConfig; | |||||
| parserConfig: IParserConfig; | |||||
| documentExtension: string; | documentExtension: string; | ||||
| documentId: string; | documentId: string; | ||||
| } | } | ||||
| useEffect(() => { | useEffect(() => { | ||||
| if (visible) { | if (visible) { | ||||
| const pages = | const pages = | ||||
| parserConfig.pages?.map((x) => ({ from: x[0], to: x[1] })) ?? []; | |||||
| parserConfig?.pages?.map((x) => ({ from: x[0], to: x[1] })) ?? []; | |||||
| form.setFieldsValue({ | form.setFieldsValue({ | ||||
| pages: pages.length > 0 ? pages : [{ from: 1, to: 1024 }], | pages: pages.length > 0 ? pages : [{ from: 1, to: 1024 }], | ||||
| parser_config: omit(parserConfig, 'pages'), | parser_config: omit(parserConfig, 'pages'), | 
| import { getExtension } from '@/utils/document-util'; | import { getExtension } from '@/utils/document-util'; | ||||
| import SvgIcon from '../svg-icon'; | import SvgIcon from '../svg-icon'; | ||||
| import { useSelectFileThumbnails } from '@/hooks/knowledge-hooks'; | |||||
| import { useFetchDocumentThumbnailsByIds } from '@/hooks/document-hooks'; | |||||
| import { useEffect } from 'react'; | |||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| interface IProps { | interface IProps { | ||||
| const FileIcon = ({ name, id }: IProps) => { | const FileIcon = ({ name, id }: IProps) => { | ||||
| const fileExtension = getExtension(name); | const fileExtension = getExtension(name); | ||||
| // TODO: replace this line with react query | |||||
| const fileThumbnails = useSelectFileThumbnails(); | |||||
| const { data: fileThumbnails, setDocumentIds } = | |||||
| useFetchDocumentThumbnailsByIds(); | |||||
| const fileThumbnail = fileThumbnails[id]; | const fileThumbnail = fileThumbnails[id]; | ||||
| useEffect(() => { | |||||
| setDocumentIds([id]); | |||||
| }, [id, setDocumentIds]); | |||||
| return fileThumbnail ? ( | return fileThumbnail ? ( | ||||
| <img src={fileThumbnail} className={styles.thumbnailImg}></img> | <img src={fileThumbnail} className={styles.thumbnailImg}></img> | ||||
| ) : ( | ) : ( | 
| import { ReactComponent as AssistantIcon } from '@/assets/svg/assistant.svg'; | import { ReactComponent as AssistantIcon } from '@/assets/svg/assistant.svg'; | ||||
| import { MessageType } from '@/constants/chat'; | import { MessageType } from '@/constants/chat'; | ||||
| import { useSetModalState } from '@/hooks/common-hooks'; | import { useSetModalState } from '@/hooks/common-hooks'; | ||||
| import { useSelectFileThumbnails } from '@/hooks/knowledge-hooks'; | |||||
| import { IReference } from '@/interfaces/database/chat'; | import { IReference } from '@/interfaces/database/chat'; | ||||
| import { IChunk } from '@/interfaces/database/knowledge'; | import { IChunk } from '@/interfaces/database/knowledge'; | ||||
| import classNames from 'classnames'; | import classNames from 'classnames'; | ||||
| }: IProps) => { | }: IProps) => { | ||||
| const isAssistant = item.role === MessageType.Assistant; | const isAssistant = item.role === MessageType.Assistant; | ||||
| const isUser = item.role === MessageType.User; | const isUser = item.role === MessageType.User; | ||||
| const fileThumbnails = useSelectFileThumbnails(); | |||||
| const { data: documentList, setDocumentIds } = useFetchDocumentInfosByIds(); | const { data: documentList, setDocumentIds } = useFetchDocumentInfosByIds(); | ||||
| const { data: documentThumbnails, setDocumentIds: setIds } = | const { data: documentThumbnails, setDocumentIds: setIds } = | ||||
| useFetchDocumentThumbnailsByIds(); | useFetchDocumentThumbnailsByIds(); | ||||
| const ids = item?.doc_ids ?? []; | const ids = item?.doc_ids ?? []; | ||||
| if (ids.length) { | if (ids.length) { | ||||
| setDocumentIds(ids); | setDocumentIds(ids); | ||||
| const documentIds = ids.filter((x) => !(x in fileThumbnails)); | |||||
| const documentIds = ids.filter((x) => !(x in documentThumbnails)); | |||||
| if (documentIds.length) { | if (documentIds.length) { | ||||
| setIds(documentIds); | setIds(documentIds); | ||||
| } | } | ||||
| } | } | ||||
| }, [item.doc_ids, setDocumentIds, setIds, fileThumbnails]); | |||||
| }, [item.doc_ids, setDocumentIds, setIds, documentThumbnails]); | |||||
| return ( | return ( | ||||
| <div | <div | ||||
| renderItem={(item) => { | renderItem={(item) => { | ||||
| // TODO: | // TODO: | ||||
| const fileThumbnail = | const fileThumbnail = | ||||
| documentThumbnails[item.id] || fileThumbnails[item.id]; | |||||
| documentThumbnails[item.id] || documentThumbnails[item.id]; | |||||
| const fileExtension = getExtension(item.name); | const fileExtension = getExtension(item.name); | ||||
| return ( | return ( | ||||
| <List.Item> | <List.Item> | 
| import { IDocumentInfo } from '@/interfaces/database/document'; | import { IDocumentInfo } from '@/interfaces/database/document'; | ||||
| import { IChunk, IKnowledgeFile } from '@/interfaces/database/knowledge'; | |||||
| import { IChunk } from '@/interfaces/database/knowledge'; | |||||
| import { IChangeParserConfigRequestBody } from '@/interfaces/request/document'; | import { IChangeParserConfigRequestBody } from '@/interfaces/request/document'; | ||||
| import i18n from '@/locales/config'; | |||||
| import chatService from '@/services/chat-service'; | import chatService from '@/services/chat-service'; | ||||
| import kbService from '@/services/knowledge-service'; | import kbService from '@/services/knowledge-service'; | ||||
| import { api_host } from '@/utils/api'; | import { api_host } from '@/utils/api'; | ||||
| import { buildChunkHighlights } from '@/utils/document-util'; | import { buildChunkHighlights } from '@/utils/document-util'; | ||||
| import { useMutation, useQuery } from '@tanstack/react-query'; | |||||
| import { UploadFile } from 'antd'; | |||||
| import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; | |||||
| import { UploadFile, message } from 'antd'; | |||||
| import { get } from 'lodash'; | |||||
| import { useCallback, useMemo, useState } from 'react'; | import { useCallback, useMemo, useState } from 'react'; | ||||
| import { IHighlight } from 'react-pdf-highlighter'; | import { IHighlight } from 'react-pdf-highlighter'; | ||||
| import { useDispatch, useSelector } from 'umi'; | |||||
| import { useGetKnowledgeSearchParams } from './route-hook'; | |||||
| import { useOneNamespaceEffectsLoading } from './store-hooks'; | |||||
| import { | |||||
| useGetPaginationWithRouter, | |||||
| useHandleSearchChange, | |||||
| } from './logic-hooks'; | |||||
| import { | |||||
| useGetKnowledgeSearchParams, | |||||
| useSetPaginationParams, | |||||
| } from './route-hook'; | |||||
| export const useGetDocumentUrl = (documentId?: string) => { | export const useGetDocumentUrl = (documentId?: string) => { | ||||
| const getDocumentUrl = useCallback( | const getDocumentUrl = useCallback( | ||||
| return { highlights, setWidthAndHeight }; | return { highlights, setWidthAndHeight }; | ||||
| }; | }; | ||||
| export const useFetchDocumentList = () => { | |||||
| export const useFetchNextDocumentList = () => { | |||||
| const { knowledgeId } = useGetKnowledgeSearchParams(); | const { knowledgeId } = useGetKnowledgeSearchParams(); | ||||
| const dispatch = useDispatch(); | |||||
| const fetchKfList = useCallback(() => { | |||||
| return dispatch<any>({ | |||||
| type: 'kFModel/getKfList', | |||||
| payload: { | |||||
| const { searchString, handleInputChange } = useHandleSearchChange(); | |||||
| const { pagination, setPagination } = useGetPaginationWithRouter(); | |||||
| const { data, isFetching: loading } = useQuery<{ | |||||
| docs: IDocumentInfo[]; | |||||
| total: number; | |||||
| }>({ | |||||
| queryKey: ['fetchDocumentList', searchString, pagination], | |||||
| initialData: { docs: [], total: 0 }, | |||||
| refetchInterval: 15000, | |||||
| queryFn: async () => { | |||||
| const ret = await kbService.get_document_list({ | |||||
| kb_id: knowledgeId, | kb_id: knowledgeId, | ||||
| }, | |||||
| }); | |||||
| }, [dispatch, knowledgeId]); | |||||
| return fetchKfList; | |||||
| }; | |||||
| keywords: searchString, | |||||
| page_size: pagination.pageSize, | |||||
| page: pagination.current, | |||||
| }); | |||||
| if (ret.data.retcode === 0) { | |||||
| return ret.data.data; | |||||
| } | |||||
| export const useSetDocumentStatus = () => { | |||||
| const dispatch = useDispatch(); | |||||
| const { knowledgeId } = useGetKnowledgeSearchParams(); | |||||
| return { | |||||
| docs: [], | |||||
| total: 0, | |||||
| }; | |||||
| }, | |||||
| }); | |||||
| const setDocumentStatus = useCallback( | |||||
| (status: boolean, documentId: string) => { | |||||
| dispatch({ | |||||
| type: 'kFModel/updateDocumentStatus', | |||||
| payload: { | |||||
| doc_id: documentId, | |||||
| status: Number(status), | |||||
| kb_id: knowledgeId, | |||||
| }, | |||||
| }); | |||||
| const onInputChange: React.ChangeEventHandler<HTMLInputElement> = useCallback( | |||||
| (e) => { | |||||
| setPagination({ page: 1 }); | |||||
| handleInputChange(e); | |||||
| }, | }, | ||||
| [dispatch, knowledgeId], | |||||
| [handleInputChange, setPagination], | |||||
| ); | ); | ||||
| return setDocumentStatus; | |||||
| }; | |||||
| export const useSelectDocumentList = () => { | |||||
| const list: IKnowledgeFile[] = useSelector( | |||||
| (state: any) => state.kFModel.data, | |||||
| ); | |||||
| return list; | |||||
| return { | |||||
| loading, | |||||
| searchString, | |||||
| documents: data.docs, | |||||
| pagination: { ...pagination, total: data?.total }, | |||||
| handleInputChange: onInputChange, | |||||
| setPagination, | |||||
| }; | |||||
| }; | }; | ||||
| export const useSaveDocumentName = () => { | |||||
| const dispatch = useDispatch(); | |||||
| const { knowledgeId } = useGetKnowledgeSearchParams(); | |||||
| export const useSetNextDocumentStatus = () => { | |||||
| const queryClient = useQueryClient(); | |||||
| const saveName = useCallback( | |||||
| (documentId: string, name: string) => { | |||||
| return dispatch<any>({ | |||||
| type: 'kFModel/document_rename', | |||||
| payload: { | |||||
| doc_id: documentId, | |||||
| name: name, | |||||
| kb_id: knowledgeId, | |||||
| }, | |||||
| const { | |||||
| data, | |||||
| isPending: loading, | |||||
| mutateAsync, | |||||
| } = useMutation({ | |||||
| mutationKey: ['updateDocumentStatus'], | |||||
| mutationFn: async ({ | |||||
| status, | |||||
| documentId, | |||||
| }: { | |||||
| status: boolean; | |||||
| documentId: string; | |||||
| }) => { | |||||
| const { data } = await kbService.document_change_status({ | |||||
| doc_id: documentId, | |||||
| status: Number(status), | |||||
| }); | }); | ||||
| if (data.retcode === 0) { | |||||
| message.success(i18n.t('message.modified')); | |||||
| queryClient.invalidateQueries({ queryKey: ['fetchDocumentList'] }); | |||||
| } | |||||
| return data; | |||||
| }, | }, | ||||
| [dispatch, knowledgeId], | |||||
| ); | |||||
| }); | |||||
| return saveName; | |||||
| return { setDocumentStatus: mutateAsync, data, loading }; | |||||
| }; | }; | ||||
| export const useCreateDocument = () => { | |||||
| const dispatch = useDispatch(); | |||||
| const { knowledgeId } = useGetKnowledgeSearchParams(); | |||||
| export const useSaveNextDocumentName = () => { | |||||
| const queryClient = useQueryClient(); | |||||
| const createDocument = useCallback( | |||||
| (name: string) => { | |||||
| try { | |||||
| return dispatch<any>({ | |||||
| type: 'kFModel/document_create', | |||||
| payload: { | |||||
| name, | |||||
| kb_id: knowledgeId, | |||||
| }, | |||||
| }); | |||||
| } catch (errorInfo) { | |||||
| console.log('Failed:', errorInfo); | |||||
| const { | |||||
| data, | |||||
| isPending: loading, | |||||
| mutateAsync, | |||||
| } = useMutation({ | |||||
| mutationKey: ['saveDocumentName'], | |||||
| mutationFn: async ({ | |||||
| name, | |||||
| documentId, | |||||
| }: { | |||||
| name: string; | |||||
| documentId: string; | |||||
| }) => { | |||||
| const { data } = await kbService.document_rename({ | |||||
| doc_id: documentId, | |||||
| name: name, | |||||
| }); | |||||
| if (data.retcode === 0) { | |||||
| message.success(i18n.t('message.renamed')); | |||||
| queryClient.invalidateQueries({ queryKey: ['fetchDocumentList'] }); | |||||
| } | } | ||||
| return data.retcode; | |||||
| }, | }, | ||||
| [dispatch, knowledgeId], | |||||
| ); | |||||
| }); | |||||
| return createDocument; | |||||
| return { loading, saveName: mutateAsync, data }; | |||||
| }; | }; | ||||
| export const useSetDocumentParser = () => { | |||||
| const dispatch = useDispatch(); | |||||
| export const useCreateNextDocument = () => { | |||||
| const { knowledgeId } = useGetKnowledgeSearchParams(); | const { knowledgeId } = useGetKnowledgeSearchParams(); | ||||
| const { setPaginationParams, page } = useSetPaginationParams(); | |||||
| const queryClient = useQueryClient(); | |||||
| const setDocumentParser = useCallback( | |||||
| ( | |||||
| parserId: string, | |||||
| documentId: string, | |||||
| parserConfig: IChangeParserConfigRequestBody, | |||||
| ) => { | |||||
| try { | |||||
| return dispatch<any>({ | |||||
| type: 'kFModel/document_change_parser', | |||||
| payload: { | |||||
| parser_id: parserId, | |||||
| doc_id: documentId, | |||||
| kb_id: knowledgeId, | |||||
| parser_config: parserConfig, | |||||
| }, | |||||
| }); | |||||
| } catch (errorInfo) { | |||||
| console.log('Failed:', errorInfo); | |||||
| const { | |||||
| data, | |||||
| isPending: loading, | |||||
| mutateAsync, | |||||
| } = useMutation({ | |||||
| mutationKey: ['createDocument'], | |||||
| mutationFn: async (name: string) => { | |||||
| const { data } = await kbService.document_create({ | |||||
| name, | |||||
| kb_id: knowledgeId, | |||||
| }); | |||||
| if (data.retcode === 0) { | |||||
| if (page === 1) { | |||||
| queryClient.invalidateQueries({ queryKey: ['fetchDocumentList'] }); | |||||
| } else { | |||||
| setPaginationParams(); // fetch document list | |||||
| } | |||||
| message.success(i18n.t('message.created')); | |||||
| } | } | ||||
| return data.retcode; | |||||
| }, | }, | ||||
| [dispatch, knowledgeId], | |||||
| ); | |||||
| }); | |||||
| return setDocumentParser; | |||||
| return { createDocument: mutateAsync, loading, data }; | |||||
| }; | }; | ||||
| export const useRemoveDocument = () => { | |||||
| const dispatch = useDispatch(); | |||||
| const { knowledgeId } = useGetKnowledgeSearchParams(); | |||||
| export const useSetNextDocumentParser = () => { | |||||
| const queryClient = useQueryClient(); | |||||
| const removeDocument = useCallback( | |||||
| (documentIds: string[]) => { | |||||
| try { | |||||
| return dispatch<any>({ | |||||
| type: 'kFModel/document_rm', | |||||
| payload: { | |||||
| doc_id: documentIds, | |||||
| kb_id: knowledgeId, | |||||
| }, | |||||
| }); | |||||
| } catch (errorInfo) { | |||||
| console.log('Failed:', errorInfo); | |||||
| const { | |||||
| data, | |||||
| isPending: loading, | |||||
| mutateAsync, | |||||
| } = useMutation({ | |||||
| mutationKey: ['setDocumentParser'], | |||||
| mutationFn: async ({ | |||||
| parserId, | |||||
| documentId, | |||||
| parserConfig, | |||||
| }: { | |||||
| parserId: string; | |||||
| documentId: string; | |||||
| parserConfig: IChangeParserConfigRequestBody; | |||||
| }) => { | |||||
| const { data } = await kbService.document_change_parser({ | |||||
| parser_id: parserId, | |||||
| doc_id: documentId, | |||||
| parser_config: parserConfig, | |||||
| }); | |||||
| if (data.retcode === 0) { | |||||
| queryClient.invalidateQueries({ queryKey: ['fetchDocumentList'] }); | |||||
| message.success(i18n.t('message.modified')); | |||||
| } | } | ||||
| return data.retcode; | |||||
| }, | }, | ||||
| [dispatch, knowledgeId], | |||||
| ); | |||||
| }); | |||||
| return removeDocument; | |||||
| return { setDocumentParser: mutateAsync, data, loading }; | |||||
| }; | }; | ||||
| export const useUploadDocument = () => { | |||||
| const dispatch = useDispatch(); | |||||
| export const useUploadNextDocument = () => { | |||||
| const queryClient = useQueryClient(); | |||||
| const { knowledgeId } = useGetKnowledgeSearchParams(); | const { knowledgeId } = useGetKnowledgeSearchParams(); | ||||
| const uploadDocument = useCallback( | |||||
| (fileList: UploadFile[]) => { | |||||
| const { | |||||
| data, | |||||
| isPending: loading, | |||||
| mutateAsync, | |||||
| } = useMutation({ | |||||
| mutationKey: ['uploadDocument'], | |||||
| mutationFn: async (fileList: UploadFile[]) => { | |||||
| const formData = new FormData(); | |||||
| formData.append('kb_id', knowledgeId); | |||||
| fileList.forEach((file: any) => { | |||||
| formData.append('file', file); | |||||
| }); | |||||
| try { | try { | ||||
| return dispatch<any>({ | |||||
| type: 'kFModel/upload_document', | |||||
| payload: { | |||||
| fileList, | |||||
| kb_id: knowledgeId, | |||||
| }, | |||||
| }); | |||||
| } catch (errorInfo) { | |||||
| console.log('Failed:', errorInfo); | |||||
| const ret = await kbService.document_upload(formData); | |||||
| const retcode = get(ret, 'data.retcode'); | |||||
| if (retcode === 0) { | |||||
| message.success(i18n.t('message.uploaded')); | |||||
| } | |||||
| if (retcode === 0 || retcode === 500) { | |||||
| queryClient.invalidateQueries({ queryKey: ['fetchDocumentList'] }); | |||||
| } | |||||
| return ret?.data; | |||||
| } catch (error) { | |||||
| console.warn(error); | |||||
| return {}; | |||||
| } | } | ||||
| }, | }, | ||||
| [dispatch, knowledgeId], | |||||
| ); | |||||
| }); | |||||
| return uploadDocument; | |||||
| return { uploadDocument: mutateAsync, loading, data }; | |||||
| }; | }; | ||||
| export const useWebCrawl = () => { | |||||
| const dispatch = useDispatch(); | |||||
| export const useNextWebCrawl = () => { | |||||
| const { knowledgeId } = useGetKnowledgeSearchParams(); | const { knowledgeId } = useGetKnowledgeSearchParams(); | ||||
| return useCallback( | |||||
| (name: string, url: string) => { | |||||
| try { | |||||
| return dispatch<any>({ | |||||
| type: 'kFModel/web_crawl', | |||||
| payload: { | |||||
| name, | |||||
| url, | |||||
| kb_id: knowledgeId, | |||||
| }, | |||||
| }); | |||||
| } catch (errorInfo) { | |||||
| console.log('Failed:', errorInfo); | |||||
| const { | |||||
| data, | |||||
| isPending: loading, | |||||
| mutateAsync, | |||||
| } = useMutation({ | |||||
| mutationKey: ['webCrawl'], | |||||
| mutationFn: async ({ name, url }: { name: string; url: string }) => { | |||||
| const formData = new FormData(); | |||||
| formData.append('name', name); | |||||
| formData.append('url', url); | |||||
| formData.append('kb_id', knowledgeId); | |||||
| const ret = await kbService.web_crawl(formData); | |||||
| const retcode = get(ret, 'data.retcode'); | |||||
| if (retcode === 0) { | |||||
| message.success(i18n.t('message.uploaded')); | |||||
| } | } | ||||
| return retcode; | |||||
| }, | }, | ||||
| [dispatch], | |||||
| ); | |||||
| }); | |||||
| return { | |||||
| data, | |||||
| loading, | |||||
| webCrawl: mutateAsync, | |||||
| }; | |||||
| }; | }; | ||||
| export const useRunDocument = () => { | |||||
| const dispatch = useDispatch(); | |||||
| export const useRunNextDocument = () => { | |||||
| const queryClient = useQueryClient(); | |||||
| const runDocumentByIds = useCallback( | |||||
| (payload: any) => { | |||||
| try { | |||||
| return dispatch<any>({ | |||||
| type: 'kFModel/document_run', | |||||
| payload, | |||||
| }); | |||||
| } catch (errorInfo) { | |||||
| console.log('Failed:', errorInfo); | |||||
| const { | |||||
| data, | |||||
| isPending: loading, | |||||
| mutateAsync, | |||||
| } = useMutation({ | |||||
| mutationKey: ['runDocumentByIds'], | |||||
| mutationFn: async ({ | |||||
| documentIds, | |||||
| run, | |||||
| }: { | |||||
| documentIds: string[]; | |||||
| run: number; | |||||
| }) => { | |||||
| const ret = await kbService.document_run({ | |||||
| doc_ids: documentIds, | |||||
| run, | |||||
| }); | |||||
| const retcode = get(ret, 'data.retcode'); | |||||
| if (retcode === 0) { | |||||
| queryClient.invalidateQueries({ queryKey: ['fetchDocumentList'] }); | |||||
| message.success(i18n.t('message.operated')); | |||||
| } | } | ||||
| }, | |||||
| [dispatch], | |||||
| ); | |||||
| return runDocumentByIds; | |||||
| }; | |||||
| return retcode; | |||||
| }, | |||||
| }); | |||||
| export const useSelectRunDocumentLoading = () => { | |||||
| const loading = useOneNamespaceEffectsLoading('kFModel', ['document_run']); | |||||
| return loading; | |||||
| return { runDocumentByIds: mutateAsync, loading, data }; | |||||
| }; | }; | ||||
| export const useFetchDocumentInfosByIds = () => { | export const useFetchDocumentInfosByIds = () => { | ||||
| }; | }; | ||||
| export const useRemoveNextDocument = () => { | export const useRemoveNextDocument = () => { | ||||
| // const queryClient = useQueryClient(); | |||||
| const queryClient = useQueryClient(); | |||||
| const { | const { | ||||
| data, | data, | ||||
| isPending: loading, | isPending: loading, | ||||
| mutateAsync, | mutateAsync, | ||||
| } = useMutation({ | } = useMutation({ | ||||
| mutationKey: ['removeDocument'], | 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; | |||||
| mutationFn: async (documentIds: string | string[]) => { | |||||
| const { data } = await kbService.document_rm({ doc_id: documentIds }); | |||||
| if (data.retcode === 0) { | |||||
| message.success(i18n.t('message.deleted')); | |||||
| queryClient.invalidateQueries({ queryKey: ['fetchDocumentList'] }); | |||||
| } | |||||
| return data.retcode; | |||||
| }, | }, | ||||
| }); | }); | ||||
| ], | ], | ||||
| initialData: {}, | initialData: {}, | ||||
| gcTime: 0, | gcTime: 0, | ||||
| queryFn: async (params: any) => { | |||||
| console.info(params); | |||||
| queryFn: async () => { | |||||
| const { data } = await fileManagerService.listFile({ | const { data } = await fileManagerService.listFile({ | ||||
| parent_id: id, | parent_id: id, | ||||
| keywords: searchString, | keywords: searchString, | 
| import { useShowDeleteConfirm } from '@/hooks/common-hooks'; | |||||
| import { ResponsePostType } from '@/interfaces/database/base'; | import { ResponsePostType } from '@/interfaces/database/base'; | ||||
| import { IKnowledge, ITestingResult } from '@/interfaces/database/knowledge'; | import { IKnowledge, ITestingResult } from '@/interfaces/database/knowledge'; | ||||
| import i18n from '@/locales/config'; | import i18n from '@/locales/config'; | ||||
| useQueryClient, | useQueryClient, | ||||
| } from '@tanstack/react-query'; | } from '@tanstack/react-query'; | ||||
| import { message } from 'antd'; | import { message } from 'antd'; | ||||
| import { useCallback, useEffect } from 'react'; | |||||
| import { useDispatch, useSearchParams, useSelector } from 'umi'; | |||||
| import { useSearchParams } from 'umi'; | |||||
| import { useSetPaginationParams } from './route-hook'; | import { useSetPaginationParams } from './route-hook'; | ||||
| export const useKnowledgeBaseId = (): string => { | export const useKnowledgeBaseId = (): string => { | ||||
| return knowledgeBaseId || ''; | return knowledgeBaseId || ''; | ||||
| }; | }; | ||||
| export const useDeleteDocumentById = (): { | |||||
| removeDocument: (documentId: string) => Promise<number>; | |||||
| } => { | |||||
| const dispatch = useDispatch(); | |||||
| const knowledgeBaseId = useKnowledgeBaseId(); | |||||
| const showDeleteConfirm = useShowDeleteConfirm(); | |||||
| const removeDocument = (documentId: string) => () => { | |||||
| return dispatch({ | |||||
| type: 'kFModel/document_rm', | |||||
| payload: { | |||||
| doc_id: documentId, | |||||
| kb_id: knowledgeBaseId, | |||||
| }, | |||||
| }); | |||||
| }; | |||||
| const onRmDocument = (documentId: string): Promise<number> => { | |||||
| return showDeleteConfirm({ onOk: removeDocument(documentId) }); | |||||
| }; | |||||
| return { | |||||
| removeDocument: onRmDocument, | |||||
| }; | |||||
| }; | |||||
| export const useFetchKnowledgeBaseConfiguration = () => { | export const useFetchKnowledgeBaseConfiguration = () => { | ||||
| const knowledgeBaseId = useKnowledgeBaseId(); | const knowledgeBaseId = useKnowledgeBaseId(); | ||||
| return { data, loading, deleteKnowledge: mutateAsync }; | return { data, loading, deleteKnowledge: mutateAsync }; | ||||
| }; | }; | ||||
| export const useSelectFileThumbnails = () => { | |||||
| const fileThumbnails: Record<string, string> = useSelector( | |||||
| (state: any) => state.kFModel.fileThumbnails, | |||||
| ); | |||||
| return fileThumbnails; | |||||
| }; | |||||
| export const useFetchFileThumbnails = (docIds?: Array<string>) => { | |||||
| const dispatch = useDispatch(); | |||||
| const fileThumbnails = useSelectFileThumbnails(); | |||||
| const fetchFileThumbnails = useCallback( | |||||
| (docIds: Array<string>) => { | |||||
| dispatch({ | |||||
| type: 'kFModel/fetch_document_thumbnails', | |||||
| payload: { doc_ids: docIds.join(',') }, | |||||
| }); | |||||
| }, | |||||
| [dispatch], | |||||
| ); | |||||
| useEffect(() => { | |||||
| if (docIds) { | |||||
| fetchFileThumbnails(docIds); | |||||
| } | |||||
| }, [docIds, fetchFileThumbnails]); | |||||
| return { fileThumbnails, fetchFileThumbnails }; | |||||
| }; | |||||
| //#region knowledge configuration | //#region knowledge configuration | ||||
| export const useUpdateKnowledge = () => { | export const useUpdateKnowledge = () => { | 
| import { Authorization } from '@/constants/authorization'; | import { Authorization } from '@/constants/authorization'; | ||||
| import { MessageType } from '@/constants/chat'; | import { MessageType } from '@/constants/chat'; | ||||
| import { LanguageTranslationMap } from '@/constants/common'; | import { LanguageTranslationMap } from '@/constants/common'; | ||||
| import { Pagination } from '@/interfaces/common'; | |||||
| import { ResponseType } from '@/interfaces/database/base'; | import { ResponseType } from '@/interfaces/database/base'; | ||||
| import { IAnswer, Message } from '@/interfaces/database/chat'; | import { IAnswer, Message } from '@/interfaces/database/chat'; | ||||
| import { IKnowledgeFile } from '@/interfaces/database/knowledge'; | import { IKnowledgeFile } from '@/interfaces/database/knowledge'; | ||||
| import { IChangeParserConfigRequestBody } from '@/interfaces/request/document'; | |||||
| import { IClientConversation, IMessage } from '@/pages/chat/interface'; | import { IClientConversation, IMessage } from '@/pages/chat/interface'; | ||||
| import api from '@/utils/api'; | import api from '@/utils/api'; | ||||
| import { getAuthorization } from '@/utils/authorization-util'; | import { getAuthorization } from '@/utils/authorization-util'; | ||||
| useState, | useState, | ||||
| } from 'react'; | } from 'react'; | ||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||
| import { useDispatch } from 'umi'; | |||||
| import { v4 as uuid } from 'uuid'; | import { v4 as uuid } from 'uuid'; | ||||
| import { useSetModalState, useTranslate } from './common-hooks'; | |||||
| import { useSetDocumentParser } from './document-hooks'; | |||||
| import { useTranslate } from './common-hooks'; | |||||
| import { useSetPaginationParams } from './route-hook'; | import { useSetPaginationParams } from './route-hook'; | ||||
| import { useOneNamespaceEffectsLoading } from './store-hooks'; | |||||
| import { useFetchTenantInfo, useSaveSetting } from './user-setting-hooks'; | import { useFetchTenantInfo, useSaveSetting } from './user-setting-hooks'; | ||||
| export const useChangeDocumentParser = (documentId: string) => { | |||||
| const setDocumentParser = useSetDocumentParser(); | |||||
| const { | |||||
| visible: changeParserVisible, | |||||
| hideModal: hideChangeParserModal, | |||||
| showModal: showChangeParserModal, | |||||
| } = useSetModalState(); | |||||
| const loading = useOneNamespaceEffectsLoading('kFModel', [ | |||||
| 'document_change_parser', | |||||
| ]); | |||||
| const onChangeParserOk = useCallback( | |||||
| async (parserId: string, parserConfig: IChangeParserConfigRequestBody) => { | |||||
| const ret = await setDocumentParser(parserId, documentId, parserConfig); | |||||
| if (ret === 0) { | |||||
| hideChangeParserModal(); | |||||
| } | |||||
| }, | |||||
| [hideChangeParserModal, setDocumentParser, documentId], | |||||
| ); | |||||
| return { | |||||
| changeParserLoading: loading, | |||||
| onChangeParserOk, | |||||
| changeParserVisible, | |||||
| hideChangeParserModal, | |||||
| showChangeParserModal, | |||||
| }; | |||||
| }; | |||||
| export const useSetSelectedRecord = <T = IKnowledgeFile>() => { | export const useSetSelectedRecord = <T = IKnowledgeFile>() => { | ||||
| const [currentRecord, setCurrentRecord] = useState<T>({} as T); | const [currentRecord, setCurrentRecord] = useState<T>({} as T); | ||||
| }; | }; | ||||
| }; | }; | ||||
| export const useSetPagination = (namespace: string) => { | |||||
| const dispatch = useDispatch(); | |||||
| const setPagination = useCallback( | |||||
| (pageNumber = 1, pageSize?: number) => { | |||||
| const pagination: Pagination = { | |||||
| current: pageNumber, | |||||
| } as Pagination; | |||||
| if (pageSize) { | |||||
| pagination.pageSize = pageSize; | |||||
| } | |||||
| dispatch({ | |||||
| type: `${namespace}/setPagination`, | |||||
| payload: pagination, | |||||
| }); | |||||
| }, | |||||
| [dispatch, namespace], | |||||
| ); | |||||
| return setPagination; | |||||
| }; | |||||
| export interface AppConf { | export interface AppConf { | ||||
| appName: string; | appName: string; | ||||
| } | } | 
| import { getOneNamespaceEffectsLoading } from '@/utils/store-util'; | |||||
| import { useSelector } from 'umi'; | |||||
| // Get the loading status of given effects under a certain namespace | |||||
| export const useOneNamespaceEffectsLoading = ( | |||||
| namespace: string, | |||||
| effectNames: Array<string>, | |||||
| ) => { | |||||
| const effects = useSelector((state: any) => state.loading.effects); | |||||
| return getOneNamespaceEffectsLoading(namespace, effects, effectNames); | |||||
| }; | 
| import { RunningStatus } from '@/constants/knowledge'; | |||||
| export interface IDocumentInfo { | export interface IDocumentInfo { | ||||
| chunk_num: number; | chunk_num: number; | ||||
| create_date: string; | create_date: string; | ||||
| kb_id: string; | kb_id: string; | ||||
| location: string; | location: string; | ||||
| name: string; | name: string; | ||||
| parser_config: Parserconfig; | |||||
| parser_config: IParserConfig; | |||||
| parser_id: string; | parser_id: string; | ||||
| process_begin_at: null; | process_begin_at: null; | ||||
| process_duation: number; | process_duation: number; | ||||
| progress: number; | progress: number; | ||||
| progress_msg: string; | progress_msg: string; | ||||
| run: string; | |||||
| run: RunningStatus; | |||||
| size: number; | size: number; | ||||
| source_type: string; | source_type: string; | ||||
| status: string; | status: string; | ||||
| update_time: number; | update_time: number; | ||||
| } | } | ||||
| interface Parserconfig { | |||||
| chunk_token_num: number; | |||||
| export interface IParserConfig { | |||||
| delimiter: string; | |||||
| html4excel: boolean; | |||||
| layout_recognize: boolean; | layout_recognize: boolean; | ||||
| pages: any[]; | |||||
| raptor: Raptor; | raptor: Raptor; | ||||
| } | } | ||||
| import { ReactComponent as RunIcon } from '@/assets/svg/run.svg'; | import { ReactComponent as RunIcon } from '@/assets/svg/run.svg'; | ||||
| import { useShowDeleteConfirm, useTranslate } from '@/hooks/common-hooks'; | import { useShowDeleteConfirm, useTranslate } from '@/hooks/common-hooks'; | ||||
| import { | import { | ||||
| useRemoveDocument, | |||||
| useRunDocument, | |||||
| useSetDocumentStatus, | |||||
| useRemoveNextDocument, | |||||
| useRunNextDocument, | |||||
| useSetNextDocumentStatus, | |||||
| } from '@/hooks/document-hooks'; | } from '@/hooks/document-hooks'; | ||||
| import { useGetKnowledgeSearchParams } from '@/hooks/route-hook'; | |||||
| import { | import { | ||||
| DownOutlined, | DownOutlined, | ||||
| FileOutlined, | FileOutlined, | ||||
| } from '@ant-design/icons'; | } from '@ant-design/icons'; | ||||
| import { Button, Dropdown, Flex, Input, MenuProps, Space } from 'antd'; | import { Button, Dropdown, Flex, Input, MenuProps, Space } from 'antd'; | ||||
| import { useCallback, useMemo } from 'react'; | import { useCallback, useMemo } from 'react'; | ||||
| import { | |||||
| useFetchDocumentListOnMount, | |||||
| useGetPagination, | |||||
| useHandleSearchChange, | |||||
| } from './hooks'; | |||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| interface IProps { | interface IProps { | ||||
| showCreateModal(): void; | showCreateModal(): void; | ||||
| showWebCrawlModal(): void; | showWebCrawlModal(): void; | ||||
| showDocumentUploadModal(): void; | showDocumentUploadModal(): void; | ||||
| searchString: string; | |||||
| handleInputChange: React.ChangeEventHandler<HTMLInputElement>; | |||||
| } | } | ||||
| const DocumentToolbar = ({ | const DocumentToolbar = ({ | ||||
| searchString, | |||||
| selectedRowKeys, | selectedRowKeys, | ||||
| showCreateModal, | showCreateModal, | ||||
| showWebCrawlModal, | |||||
| showDocumentUploadModal, | showDocumentUploadModal, | ||||
| handleInputChange, | |||||
| }: IProps) => { | }: IProps) => { | ||||
| const { t } = useTranslate('knowledgeDetails'); | const { t } = useTranslate('knowledgeDetails'); | ||||
| const { fetchDocumentList } = useFetchDocumentListOnMount(); | |||||
| const { setPagination, searchString } = useGetPagination(fetchDocumentList); | |||||
| const { handleInputChange } = useHandleSearchChange(setPagination); | |||||
| const removeDocument = useRemoveDocument(); | |||||
| const { removeDocument } = useRemoveNextDocument(); | |||||
| const showDeleteConfirm = useShowDeleteConfirm(); | const showDeleteConfirm = useShowDeleteConfirm(); | ||||
| const runDocumentByIds = useRunDocument(); | |||||
| const { knowledgeId } = useGetKnowledgeSearchParams(); | |||||
| const changeStatus = useSetDocumentStatus(); | |||||
| const { runDocumentByIds } = useRunNextDocument(); | |||||
| const { setDocumentStatus } = useSetNextDocumentStatus(); | |||||
| const actionItems: MenuProps['items'] = useMemo(() => { | const actionItems: MenuProps['items'] = useMemo(() => { | ||||
| return [ | return [ | ||||
| ), | ), | ||||
| }, | }, | ||||
| { type: 'divider' }, | { type: 'divider' }, | ||||
| // { | |||||
| // key: '2', | |||||
| // onClick: showWebCrawlModal, | |||||
| // label: ( | |||||
| // <div> | |||||
| // <Button type="link"> | |||||
| // <FileTextOutlined /> | |||||
| // {t('webCrawl')} | |||||
| // </Button> | |||||
| // </div> | |||||
| // ), | |||||
| // }, | |||||
| { type: 'divider' }, | |||||
| { | { | ||||
| key: '3', | key: '3', | ||||
| onClick: showCreateModal, | onClick: showCreateModal, | ||||
| const runDocument = useCallback( | const runDocument = useCallback( | ||||
| (run: number) => { | (run: number) => { | ||||
| runDocumentByIds({ | runDocumentByIds({ | ||||
| doc_ids: selectedRowKeys, | |||||
| documentIds: selectedRowKeys, | |||||
| run, | run, | ||||
| knowledgeBaseId: knowledgeId, | |||||
| }); | }); | ||||
| }, | }, | ||||
| [runDocumentByIds, selectedRowKeys, knowledgeId], | |||||
| [runDocumentByIds, selectedRowKeys], | |||||
| ); | ); | ||||
| const handleRunClick = useCallback(() => { | const handleRunClick = useCallback(() => { | ||||
| const onChangeStatus = useCallback( | const onChangeStatus = useCallback( | ||||
| (enabled: boolean) => { | (enabled: boolean) => { | ||||
| selectedRowKeys.forEach((id) => { | selectedRowKeys.forEach((id) => { | ||||
| changeStatus(enabled, id); | |||||
| setDocumentStatus({ status: enabled, documentId: id }); | |||||
| }); | }); | ||||
| }, | }, | ||||
| [selectedRowKeys, changeStatus], | |||||
| [selectedRowKeys, setDocumentStatus], | |||||
| ); | ); | ||||
| const handleEnableClick = useCallback(() => { | const handleEnableClick = useCallback(() => { | 
| import { useSetModalState, useTranslate } from '@/hooks/common-hooks'; | |||||
| import { useSetModalState } from '@/hooks/common-hooks'; | |||||
| import { | import { | ||||
| useCreateDocument, | |||||
| useFetchDocumentList, | |||||
| useRunDocument, | |||||
| useSaveDocumentName, | |||||
| useSelectRunDocumentLoading, | |||||
| useSetDocumentParser, | |||||
| useUploadDocument, | |||||
| useWebCrawl, | |||||
| useCreateNextDocument, | |||||
| useNextWebCrawl, | |||||
| useRunNextDocument, | |||||
| useSaveNextDocumentName, | |||||
| useSetNextDocumentParser, | |||||
| useUploadNextDocument, | |||||
| } from '@/hooks/document-hooks'; | } from '@/hooks/document-hooks'; | ||||
| import { useGetKnowledgeSearchParams } from '@/hooks/route-hook'; | import { useGetKnowledgeSearchParams } from '@/hooks/route-hook'; | ||||
| import { useOneNamespaceEffectsLoading } from '@/hooks/store-hooks'; | |||||
| import { Pagination } from '@/interfaces/common'; | |||||
| import { IChangeParserConfigRequestBody } from '@/interfaces/request/document'; | import { IChangeParserConfigRequestBody } from '@/interfaces/request/document'; | ||||
| import { getUnSupportedFilesCount } from '@/utils/document-util'; | import { getUnSupportedFilesCount } from '@/utils/document-util'; | ||||
| import { PaginationProps, UploadFile } from 'antd'; | |||||
| import { useCallback, useEffect, useMemo, useState } from 'react'; | |||||
| import { useDispatch, useNavigate, useSelector } from 'umi'; | |||||
| import { UploadFile } from 'antd'; | |||||
| import { useCallback, useState } from 'react'; | |||||
| import { useNavigate } from 'umi'; | |||||
| import { KnowledgeRouteKey } from './constant'; | import { KnowledgeRouteKey } from './constant'; | ||||
| export const useFetchDocumentListOnMount = () => { | |||||
| const { knowledgeId } = useGetKnowledgeSearchParams(); | |||||
| const fetchDocumentList = useFetchDocumentList(); | |||||
| const dispatch = useDispatch(); | |||||
| useEffect(() => { | |||||
| if (knowledgeId) { | |||||
| fetchDocumentList(); | |||||
| dispatch({ | |||||
| type: 'kFModel/pollGetDocumentList-start', | |||||
| payload: knowledgeId, | |||||
| }); | |||||
| } | |||||
| return () => { | |||||
| dispatch({ | |||||
| type: 'kFModel/pollGetDocumentList-stop', | |||||
| }); | |||||
| }; | |||||
| }, [knowledgeId, dispatch, fetchDocumentList]); | |||||
| return { fetchDocumentList }; | |||||
| }; | |||||
| export const useGetPagination = (fetchDocumentList: () => void) => { | |||||
| const dispatch = useDispatch(); | |||||
| const kFModel = useSelector((state: any) => state.kFModel); | |||||
| const { t } = useTranslate('common'); | |||||
| const setPagination = useCallback( | |||||
| (pageNumber = 1, pageSize?: number) => { | |||||
| const pagination: Pagination = { | |||||
| current: pageNumber, | |||||
| } as Pagination; | |||||
| if (pageSize) { | |||||
| pagination.pageSize = pageSize; | |||||
| } | |||||
| dispatch({ | |||||
| type: 'kFModel/setPagination', | |||||
| payload: pagination, | |||||
| }); | |||||
| }, | |||||
| [dispatch], | |||||
| ); | |||||
| const onPageChange: PaginationProps['onChange'] = useCallback( | |||||
| (pageNumber: number, pageSize: number) => { | |||||
| setPagination(pageNumber, pageSize); | |||||
| fetchDocumentList(); | |||||
| }, | |||||
| [fetchDocumentList, setPagination], | |||||
| ); | |||||
| const pagination: PaginationProps = useMemo(() => { | |||||
| return { | |||||
| showQuickJumper: true, | |||||
| total: kFModel.total, | |||||
| showSizeChanger: true, | |||||
| current: kFModel.pagination.current, | |||||
| pageSize: kFModel.pagination.pageSize, | |||||
| pageSizeOptions: [1, 2, 10, 20, 50, 100], | |||||
| onChange: onPageChange, | |||||
| showTotal: (total) => `${t('total')} ${total}`, | |||||
| }; | |||||
| }, [kFModel, onPageChange, t]); | |||||
| return { | |||||
| pagination, | |||||
| setPagination, | |||||
| total: kFModel.total, | |||||
| searchString: kFModel.searchString, | |||||
| }; | |||||
| }; | |||||
| export const useSelectDocumentListLoading = () => { | |||||
| return useOneNamespaceEffectsLoading('kFModel', [ | |||||
| 'getKfList', | |||||
| 'updateDocumentStatus', | |||||
| ]); | |||||
| }; | |||||
| export const useNavigateToOtherPage = () => { | export const useNavigateToOtherPage = () => { | ||||
| const navigate = useNavigate(); | const navigate = useNavigate(); | ||||
| const { knowledgeId } = useGetKnowledgeSearchParams(); | const { knowledgeId } = useGetKnowledgeSearchParams(); | ||||
| return { linkToUploadPage, toChunk }; | return { linkToUploadPage, toChunk }; | ||||
| }; | }; | ||||
| export const useHandleSearchChange = (setPagination: () => void) => { | |||||
| const dispatch = useDispatch(); | |||||
| const { knowledgeId } = useGetKnowledgeSearchParams(); | |||||
| const throttledGetDocumentList = useCallback(() => { | |||||
| dispatch({ | |||||
| type: 'kFModel/throttledGetDocumentList', | |||||
| payload: knowledgeId, | |||||
| }); | |||||
| }, [dispatch, knowledgeId]); | |||||
| const handleInputChange = useCallback( | |||||
| (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => { | |||||
| const value = e.target.value; | |||||
| dispatch({ type: 'kFModel/setSearchString', payload: value }); | |||||
| setPagination(); | |||||
| throttledGetDocumentList(); | |||||
| }, | |||||
| [setPagination, throttledGetDocumentList, dispatch], | |||||
| ); | |||||
| return { handleInputChange }; | |||||
| }; | |||||
| export const useRenameDocument = (documentId: string) => { | export const useRenameDocument = (documentId: string) => { | ||||
| const saveName = useSaveDocumentName(); | |||||
| const { saveName, loading } = useSaveNextDocumentName(); | |||||
| const { | const { | ||||
| visible: renameVisible, | visible: renameVisible, | ||||
| hideModal: hideRenameModal, | hideModal: hideRenameModal, | ||||
| showModal: showRenameModal, | showModal: showRenameModal, | ||||
| } = useSetModalState(); | } = useSetModalState(); | ||||
| const loading = useOneNamespaceEffectsLoading('kFModel', ['document_rename']); | |||||
| const onRenameOk = useCallback( | const onRenameOk = useCallback( | ||||
| async (name: string) => { | async (name: string) => { | ||||
| const ret = await saveName(documentId, name); | |||||
| const ret = await saveName({ documentId, name }); | |||||
| if (ret === 0) { | if (ret === 0) { | ||||
| hideRenameModal(); | hideRenameModal(); | ||||
| } | } | ||||
| }; | }; | ||||
| export const useCreateEmptyDocument = () => { | export const useCreateEmptyDocument = () => { | ||||
| const createDocument = useCreateDocument(); | |||||
| const { createDocument, loading } = useCreateNextDocument(); | |||||
| const { | const { | ||||
| visible: createVisible, | visible: createVisible, | ||||
| hideModal: hideCreateModal, | hideModal: hideCreateModal, | ||||
| showModal: showCreateModal, | showModal: showCreateModal, | ||||
| } = useSetModalState(); | } = useSetModalState(); | ||||
| const loading = useOneNamespaceEffectsLoading('kFModel', ['document_create']); | |||||
| const onCreateOk = useCallback( | const onCreateOk = useCallback( | ||||
| async (name: string) => { | async (name: string) => { | ||||
| }; | }; | ||||
| export const useChangeDocumentParser = (documentId: string) => { | export const useChangeDocumentParser = (documentId: string) => { | ||||
| const setDocumentParser = useSetDocumentParser(); | |||||
| const { setDocumentParser, loading } = useSetNextDocumentParser(); | |||||
| const { | const { | ||||
| visible: changeParserVisible, | visible: changeParserVisible, | ||||
| hideModal: hideChangeParserModal, | hideModal: hideChangeParserModal, | ||||
| showModal: showChangeParserModal, | showModal: showChangeParserModal, | ||||
| } = useSetModalState(); | } = useSetModalState(); | ||||
| const loading = useOneNamespaceEffectsLoading('kFModel', [ | |||||
| 'document_change_parser', | |||||
| ]); | |||||
| const onChangeParserOk = useCallback( | const onChangeParserOk = useCallback( | ||||
| async (parserId: string, parserConfig: IChangeParserConfigRequestBody) => { | async (parserId: string, parserConfig: IChangeParserConfigRequestBody) => { | ||||
| const ret = await setDocumentParser(parserId, documentId, parserConfig); | |||||
| const ret = await setDocumentParser({ | |||||
| parserId, | |||||
| documentId, | |||||
| parserConfig, | |||||
| }); | |||||
| if (ret === 0) { | if (ret === 0) { | ||||
| hideChangeParserModal(); | hideChangeParserModal(); | ||||
| } | } | ||||
| hideModal: hideDocumentUploadModal, | hideModal: hideDocumentUploadModal, | ||||
| showModal: showDocumentUploadModal, | showModal: showDocumentUploadModal, | ||||
| } = useSetModalState(); | } = useSetModalState(); | ||||
| const uploadDocument = useUploadDocument(); | |||||
| const { uploadDocument, loading } = useUploadNextDocument(); | |||||
| const onDocumentUploadOk = useCallback( | const onDocumentUploadOk = useCallback( | ||||
| async (fileList: UploadFile[]): Promise<number | undefined> => { | async (fileList: UploadFile[]): Promise<number | undefined> => { | ||||
| if (fileList.length > 0) { | if (fileList.length > 0) { | ||||
| const ret: any = await uploadDocument(fileList); | const ret: any = await uploadDocument(fileList); | ||||
| const count = getUnSupportedFilesCount(ret.retmsg); | |||||
| if (typeof ret?.retmsg !== 'string') { | |||||
| return; | |||||
| } | |||||
| const count = getUnSupportedFilesCount(ret?.retmsg); | |||||
| /// 500 error code indicates that some file types are not supported | /// 500 error code indicates that some file types are not supported | ||||
| let retcode = ret.retcode; | |||||
| let retcode = ret?.retcode; | |||||
| if ( | if ( | ||||
| ret.retcode === 0 || | |||||
| (ret.retcode === 500 && count !== fileList.length) // Some files were not uploaded successfully, but some were uploaded successfully. | |||||
| ret?.retcode === 0 || | |||||
| (ret?.retcode === 500 && count !== fileList.length) // Some files were not uploaded successfully, but some were uploaded successfully. | |||||
| ) { | ) { | ||||
| retcode = 0; | retcode = 0; | ||||
| hideDocumentUploadModal(); | hideDocumentUploadModal(); | ||||
| [uploadDocument, hideDocumentUploadModal], | [uploadDocument, hideDocumentUploadModal], | ||||
| ); | ); | ||||
| const loading = useOneNamespaceEffectsLoading('kFModel', ['upload_document']); | |||||
| return { | return { | ||||
| documentUploadLoading: loading, | documentUploadLoading: loading, | ||||
| onDocumentUploadOk, | onDocumentUploadOk, | ||||
| hideModal: hideWebCrawlUploadModal, | hideModal: hideWebCrawlUploadModal, | ||||
| showModal: showWebCrawlUploadModal, | showModal: showWebCrawlUploadModal, | ||||
| } = useSetModalState(); | } = useSetModalState(); | ||||
| const webCrawl = useWebCrawl(); | |||||
| const { webCrawl, loading } = useNextWebCrawl(); | |||||
| const onWebCrawlUploadOk = useCallback( | const onWebCrawlUploadOk = useCallback( | ||||
| async (name: string, url: string) => { | async (name: string, url: string) => { | ||||
| const ret = await webCrawl(name, url); | |||||
| const ret = await webCrawl({ name, url }); | |||||
| if (ret === 0) { | if (ret === 0) { | ||||
| hideWebCrawlUploadModal(); | hideWebCrawlUploadModal(); | ||||
| return 0; | return 0; | ||||
| [webCrawl, hideWebCrawlUploadModal], | [webCrawl, hideWebCrawlUploadModal], | ||||
| ); | ); | ||||
| const loading = useOneNamespaceEffectsLoading('kFModel', ['web_crawl']); | |||||
| return { | return { | ||||
| webCrawlUploadLoading: loading, | webCrawlUploadLoading: loading, | ||||
| onWebCrawlUploadOk, | onWebCrawlUploadOk, | ||||
| }; | }; | ||||
| export const useHandleRunDocumentByIds = (id: string) => { | export const useHandleRunDocumentByIds = (id: string) => { | ||||
| const loading = useSelectRunDocumentLoading(); | |||||
| const runDocumentByIds = useRunDocument(); | |||||
| const { runDocumentByIds, loading } = useRunNextDocument(); | |||||
| const [currentId, setCurrentId] = useState<string>(''); | const [currentId, setCurrentId] = useState<string>(''); | ||||
| const isLoading = loading && currentId !== '' && currentId === id; | const isLoading = loading && currentId !== '' && currentId === id; | ||||
| const handleRunDocumentByIds = async ( | const handleRunDocumentByIds = async ( | ||||
| documentId: string, | documentId: string, | ||||
| knowledgeBaseId: string, | |||||
| isRunning: boolean, | isRunning: boolean, | ||||
| ) => { | ) => { | ||||
| if (isLoading) { | if (isLoading) { | ||||
| setCurrentId(documentId); | setCurrentId(documentId); | ||||
| try { | try { | ||||
| await runDocumentByIds({ | await runDocumentByIds({ | ||||
| doc_ids: [documentId], | |||||
| documentIds: [documentId], | |||||
| run: isRunning ? 2 : 1, | run: isRunning ? 2 : 1, | ||||
| knowledgeBaseId, | |||||
| }); | }); | ||||
| setCurrentId(''); | setCurrentId(''); | ||||
| } catch (error) { | } catch (error) { | 
| import ChunkMethodModal from '@/components/chunk-method-modal'; | import ChunkMethodModal from '@/components/chunk-method-modal'; | ||||
| import SvgIcon from '@/components/svg-icon'; | import SvgIcon from '@/components/svg-icon'; | ||||
| import { | import { | ||||
| useSelectDocumentList, | |||||
| useSetDocumentStatus, | |||||
| useFetchNextDocumentList, | |||||
| useSetNextDocumentStatus, | |||||
| } from '@/hooks/document-hooks'; | } from '@/hooks/document-hooks'; | ||||
| import { useSetSelectedRecord } from '@/hooks/logic-hooks'; | import { useSetSelectedRecord } from '@/hooks/logic-hooks'; | ||||
| import { useSelectParserList } from '@/hooks/user-setting-hooks'; | import { useSelectParserList } from '@/hooks/user-setting-hooks'; | ||||
| import { IKnowledgeFile } from '@/interfaces/database/knowledge'; | |||||
| import { getExtension } from '@/utils/document-util'; | import { getExtension } from '@/utils/document-util'; | ||||
| import { Divider, Flex, Switch, Table, Typography } from 'antd'; | import { Divider, Flex, Switch, Table, Typography } from 'antd'; | ||||
| import type { ColumnsType } from 'antd/es/table'; | import type { ColumnsType } from 'antd/es/table'; | ||||
| import { | import { | ||||
| useChangeDocumentParser, | useChangeDocumentParser, | ||||
| useCreateEmptyDocument, | useCreateEmptyDocument, | ||||
| useFetchDocumentListOnMount, | |||||
| useGetPagination, | |||||
| useGetRowSelection, | useGetRowSelection, | ||||
| useHandleUploadDocument, | useHandleUploadDocument, | ||||
| useHandleWebCrawl, | useHandleWebCrawl, | ||||
| import WebCrawlModal from './web-crawl-modal'; | import WebCrawlModal from './web-crawl-modal'; | ||||
| import FileUploadModal from '@/components/file-upload-modal'; | import FileUploadModal from '@/components/file-upload-modal'; | ||||
| import { IDocumentInfo } from '@/interfaces/database/document'; | |||||
| import { formatDate } from '@/utils/date'; | import { formatDate } from '@/utils/date'; | ||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| const { Text } = Typography; | const { Text } = Typography; | ||||
| const KnowledgeFile = () => { | const KnowledgeFile = () => { | ||||
| const data = useSelectDocumentList(); | |||||
| const { fetchDocumentList } = useFetchDocumentListOnMount(); | |||||
| const { searchString, documents, pagination, handleInputChange } = | |||||
| useFetchNextDocumentList(); | |||||
| const parserList = useSelectParserList(); | const parserList = useSelectParserList(); | ||||
| const { pagination } = useGetPagination(fetchDocumentList); | |||||
| const onChangeStatus = useSetDocumentStatus(); | |||||
| const { setDocumentStatus } = useSetNextDocumentStatus(); | |||||
| const { toChunk } = useNavigateToOtherPage(); | const { toChunk } = useNavigateToOtherPage(); | ||||
| const { currentRecord, setRecord } = useSetSelectedRecord(); | |||||
| const { currentRecord, setRecord } = useSetSelectedRecord<IDocumentInfo>(); | |||||
| const { | const { | ||||
| renameLoading, | renameLoading, | ||||
| onRenameOk, | onRenameOk, | ||||
| const rowSelection = useGetRowSelection(); | const rowSelection = useGetRowSelection(); | ||||
| const columns: ColumnsType<IKnowledgeFile> = [ | |||||
| const columns: ColumnsType<IDocumentInfo> = [ | |||||
| { | { | ||||
| title: t('name'), | title: t('name'), | ||||
| dataIndex: 'name', | dataIndex: 'name', | ||||
| <Switch | <Switch | ||||
| checked={status === '1'} | checked={status === '1'} | ||||
| onChange={(e) => { | onChange={(e) => { | ||||
| onChangeStatus(e, id); | |||||
| setDocumentStatus({ status: e, documentId: id }); | |||||
| }} | }} | ||||
| /> | /> | ||||
| </> | </> | ||||
| showCreateModal={showCreateModal} | showCreateModal={showCreateModal} | ||||
| showWebCrawlModal={showWebCrawlUploadModal} | showWebCrawlModal={showWebCrawlUploadModal} | ||||
| showDocumentUploadModal={showDocumentUploadModal} | showDocumentUploadModal={showDocumentUploadModal} | ||||
| searchString={searchString} | |||||
| handleInputChange={handleInputChange} | |||||
| ></DocumentToolbar> | ></DocumentToolbar> | ||||
| <Table | <Table | ||||
| rowKey="id" | rowKey="id" | ||||
| columns={finalColumns} | columns={finalColumns} | ||||
| dataSource={data} | |||||
| // loading={loading} | |||||
| dataSource={documents} | |||||
| pagination={pagination} | pagination={pagination} | ||||
| rowSelection={rowSelection} | rowSelection={rowSelection} | ||||
| className={styles.documentTable} | className={styles.documentTable} | 
| import { BaseState } from '@/interfaces/common'; | |||||
| import { IKnowledgeFile } from '@/interfaces/database/knowledge'; | |||||
| import i18n from '@/locales/config'; | |||||
| import kbService, { getDocumentFile } from '@/services/knowledge-service'; | |||||
| import { message } from 'antd'; | |||||
| import omit from 'lodash/omit'; | |||||
| import pick from 'lodash/pick'; | |||||
| import { DvaModel } from 'umi'; | |||||
| export interface KFModelState extends BaseState { | |||||
| tenantIfo: any; | |||||
| data: IKnowledgeFile[]; | |||||
| total: number; | |||||
| currentRecord: Nullable<IKnowledgeFile>; | |||||
| fileThumbnails: Record<string, string>; | |||||
| } | |||||
| const model: DvaModel<KFModelState> = { | |||||
| namespace: 'kFModel', | |||||
| state: { | |||||
| tenantIfo: {}, | |||||
| data: [], | |||||
| total: 0, | |||||
| currentRecord: null, | |||||
| searchString: '', | |||||
| pagination: { | |||||
| current: 1, | |||||
| pageSize: 10, | |||||
| }, | |||||
| fileThumbnails: {} as Record<string, string>, | |||||
| }, | |||||
| reducers: { | |||||
| updateState(state, { payload }) { | |||||
| return { | |||||
| ...state, | |||||
| ...payload, | |||||
| }; | |||||
| }, | |||||
| setCurrentRecord(state, { payload }) { | |||||
| return { ...state, currentRecord: payload }; | |||||
| }, | |||||
| setSearchString(state, { payload }) { | |||||
| return { ...state, searchString: payload }; | |||||
| }, | |||||
| setPagination(state, { payload }) { | |||||
| return { ...state, pagination: { ...state.pagination, ...payload } }; | |||||
| }, | |||||
| setFileThumbnails(state, { payload }) { | |||||
| return { ...state, fileThumbnails: payload }; | |||||
| }, | |||||
| }, | |||||
| effects: { | |||||
| *createKf({ payload = {} }, { call }) { | |||||
| const { data } = yield call(kbService.createKb, payload); | |||||
| const { retcode } = data; | |||||
| if (retcode === 0) { | |||||
| message.success(i18n.t('message.created')); | |||||
| } | |||||
| }, | |||||
| *updateKf({ payload = {} }, { call }) { | |||||
| const { data } = yield call(kbService.updateKb, payload); | |||||
| const { retcode } = data; | |||||
| if (retcode === 0) { | |||||
| message.success(i18n.t('message.modified')); | |||||
| } | |||||
| }, | |||||
| *getKfDetail({ payload = {} }, { call }) { | |||||
| const { data } = yield call(kbService.get_kb_detail, payload); | |||||
| }, | |||||
| *getKfList({ payload = {} }, { call, put, select }) { | |||||
| const state: KFModelState = yield select((state: any) => state.kFModel); | |||||
| const requestBody = { | |||||
| ...payload, | |||||
| page: state.pagination.current, | |||||
| page_size: state.pagination.pageSize, | |||||
| }; | |||||
| if (state.searchString) { | |||||
| requestBody['keywords'] = state.searchString; | |||||
| } | |||||
| const { data } = yield call(kbService.get_document_list, requestBody); | |||||
| const { retcode, data: res } = data; | |||||
| if (retcode === 0) { | |||||
| yield put({ | |||||
| type: 'updateState', | |||||
| payload: { | |||||
| data: res.docs, | |||||
| total: res.total, | |||||
| }, | |||||
| }); | |||||
| } | |||||
| }, | |||||
| throttledGetDocumentList: [ | |||||
| function* ({ payload }, { call, put }) { | |||||
| yield put({ type: 'getKfList', payload: { kb_id: payload } }); | |||||
| }, | |||||
| { type: 'throttle', ms: 1000 }, // TODO: Provide type support for this effect | |||||
| ], | |||||
| pollGetDocumentList: [ | |||||
| function* ({ payload }, { call, put }) { | |||||
| yield put({ type: 'getKfList', payload: { kb_id: payload } }); | |||||
| }, | |||||
| { type: 'poll', delay: 15000 }, // TODO: Provide type support for this effect | |||||
| ], | |||||
| *updateDocumentStatus({ payload = {} }, { call, put }) { | |||||
| const { data } = yield call( | |||||
| kbService.document_change_status, | |||||
| pick(payload, ['doc_id', 'status']), | |||||
| ); | |||||
| const { retcode } = data; | |||||
| if (retcode === 0) { | |||||
| message.success(i18n.t('message.modified')); | |||||
| yield put({ | |||||
| type: 'getKfList', | |||||
| payload: { kb_id: payload.kb_id }, | |||||
| }); | |||||
| } | |||||
| }, | |||||
| *document_rm({ payload = {} }, { call, put }) { | |||||
| const { data } = yield call(kbService.document_rm, { | |||||
| doc_id: payload.doc_id, | |||||
| }); | |||||
| const { retcode } = data; | |||||
| if (retcode === 0) { | |||||
| message.success(i18n.t('message.deleted')); | |||||
| yield put({ | |||||
| type: 'getKfList', | |||||
| payload: { kb_id: payload.kb_id }, | |||||
| }); | |||||
| } | |||||
| return retcode; | |||||
| }, | |||||
| *document_rename({ payload = {} }, { call, put }) { | |||||
| const { data } = yield call( | |||||
| kbService.document_rename, | |||||
| omit(payload, ['kb_id']), | |||||
| ); | |||||
| const { retcode } = data; | |||||
| if (retcode === 0) { | |||||
| message.success(i18n.t('message.renamed')); | |||||
| yield put({ | |||||
| type: 'getKfList', | |||||
| payload: { kb_id: payload.kb_id }, | |||||
| }); | |||||
| } | |||||
| return retcode; | |||||
| }, | |||||
| *document_create({ payload = {} }, { call, put }) { | |||||
| const { data } = yield call(kbService.document_create, payload); | |||||
| const { retcode } = data; | |||||
| if (retcode === 0) { | |||||
| yield put({ | |||||
| type: 'getKfList', | |||||
| payload: { kb_id: payload.kb_id }, | |||||
| }); | |||||
| message.success(i18n.t('message.created')); | |||||
| } | |||||
| return retcode; | |||||
| }, | |||||
| *document_run({ payload = {} }, { call, put }) { | |||||
| const { data } = yield call( | |||||
| kbService.document_run, | |||||
| omit(payload, ['knowledgeBaseId']), | |||||
| ); | |||||
| const { retcode } = data; | |||||
| if (retcode === 0) { | |||||
| if (payload.knowledgeBaseId) { | |||||
| yield put({ | |||||
| type: 'getKfList', | |||||
| payload: { kb_id: payload.knowledgeBaseId }, | |||||
| }); | |||||
| } | |||||
| message.success(i18n.t('message.operated')); | |||||
| } | |||||
| return retcode; | |||||
| }, | |||||
| *document_change_parser({ payload = {} }, { call, put }) { | |||||
| const { data } = yield call( | |||||
| kbService.document_change_parser, | |||||
| omit(payload, ['kb_id']), | |||||
| ); | |||||
| const { retcode } = data; | |||||
| if (retcode === 0) { | |||||
| yield put({ | |||||
| type: 'getKfList', | |||||
| payload: { kb_id: payload.kb_id }, | |||||
| }); | |||||
| message.success(i18n.t('message.modified')); | |||||
| } | |||||
| return retcode; | |||||
| }, | |||||
| *fetch_document_thumbnails({ payload = {} }, { call, put }) { | |||||
| const { data } = yield call(kbService.document_thumbnails, payload); | |||||
| if (data.retcode === 0) { | |||||
| yield put({ type: 'setFileThumbnails', payload: data.data }); | |||||
| } | |||||
| }, | |||||
| *fetch_document_file({ payload = {} }, { call }) { | |||||
| const documentId = payload; | |||||
| try { | |||||
| const ret = yield call(getDocumentFile, documentId); | |||||
| return ret; | |||||
| } catch (error) { | |||||
| console.warn(error); | |||||
| } | |||||
| }, | |||||
| *upload_document({ payload = {} }, { call, put }) { | |||||
| const fileList = payload.fileList; | |||||
| const formData = new FormData(); | |||||
| formData.append('kb_id', payload.kb_id); | |||||
| fileList.forEach((file: any) => { | |||||
| formData.append('file', file); | |||||
| }); | |||||
| const ret = yield call(kbService.document_upload, formData); | |||||
| const succeed = ret?.data?.retcode === 0; | |||||
| if (succeed) { | |||||
| message.success(i18n.t('message.uploaded')); | |||||
| } | |||||
| if (succeed || ret?.data?.retcode === 500) { | |||||
| yield put({ | |||||
| type: 'getKfList', | |||||
| payload: { kb_id: payload.kb_id }, | |||||
| }); | |||||
| } | |||||
| return ret?.data; | |||||
| }, | |||||
| *web_crawl({ payload = {} }, { call, put }) { | |||||
| const formData = new FormData(); | |||||
| formData.append('name', payload.name); | |||||
| formData.append('url', payload.url); | |||||
| formData.append('kb_id', payload.kb_id); | |||||
| const { data } = yield call(kbService.web_crawl, formData); | |||||
| const succeed = data.retcode === 0; | |||||
| if (succeed) { | |||||
| message.success(i18n.t('message.uploaded')); | |||||
| } | |||||
| if (succeed || data.retcode === 500) { | |||||
| yield put({ | |||||
| type: 'getKfList', | |||||
| payload: { kb_id: payload.kb_id }, | |||||
| }); | |||||
| } | |||||
| return data.retcode; | |||||
| }, | |||||
| }, | |||||
| subscriptions: { | |||||
| setup({ dispatch, history }) { | |||||
| history.listen(({ location }) => { | |||||
| const state: { from: string } = (location.state ?? { | |||||
| from: '', | |||||
| }) as { from: string }; | |||||
| if ( | |||||
| state.from === '/knowledge' || // TODO: Just directly determine whether the current page is on the knowledge list page. | |||||
| location.pathname === '/knowledge/dataset/upload' | |||||
| ) { | |||||
| dispatch({ | |||||
| type: 'setPagination', | |||||
| payload: { current: 1, pageSize: 10 }, | |||||
| }); | |||||
| } | |||||
| }); | |||||
| }, | |||||
| }, | |||||
| }; | |||||
| export default model; | 
| import { useShowDeleteConfirm, useTranslate } from '@/hooks/common-hooks'; | import { useShowDeleteConfirm, useTranslate } from '@/hooks/common-hooks'; | ||||
| import { useRemoveDocument } from '@/hooks/document-hooks'; | |||||
| import { IKnowledgeFile } from '@/interfaces/database/knowledge'; | |||||
| import { useRemoveNextDocument } from '@/hooks/document-hooks'; | |||||
| import { IDocumentInfo } from '@/interfaces/database/document'; | |||||
| import { api_host } from '@/utils/api'; | import { api_host } from '@/utils/api'; | ||||
| import { downloadFile } from '@/utils/file-util'; | import { downloadFile } from '@/utils/file-util'; | ||||
| import { | import { | ||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| interface IProps { | interface IProps { | ||||
| record: IKnowledgeFile; | |||||
| setCurrentRecord: (record: IKnowledgeFile) => void; | |||||
| record: IDocumentInfo; | |||||
| setCurrentRecord: (record: IDocumentInfo) => void; | |||||
| showRenameModal: () => void; | showRenameModal: () => void; | ||||
| showChangeParserModal: () => void; | showChangeParserModal: () => void; | ||||
| } | } | ||||
| const documentId = record.id; | const documentId = record.id; | ||||
| const isRunning = isParserRunning(record.run); | const isRunning = isParserRunning(record.run); | ||||
| const { t } = useTranslate('knowledgeDetails'); | const { t } = useTranslate('knowledgeDetails'); | ||||
| const removeDocument = useRemoveDocument(); | |||||
| const { removeDocument } = useRemoveNextDocument(); | |||||
| const showDeleteConfirm = useShowDeleteConfirm(); | const showDeleteConfirm = useShowDeleteConfirm(); | ||||
| const onRmDocument = () => { | const onRmDocument = () => { | 
| import { ReactComponent as RefreshIcon } from '@/assets/svg/refresh.svg'; | import { ReactComponent as RefreshIcon } from '@/assets/svg/refresh.svg'; | ||||
| import { ReactComponent as RunIcon } from '@/assets/svg/run.svg'; | import { ReactComponent as RunIcon } from '@/assets/svg/run.svg'; | ||||
| import { useTranslate } from '@/hooks/common-hooks'; | import { useTranslate } from '@/hooks/common-hooks'; | ||||
| import { IKnowledgeFile } from '@/interfaces/database/knowledge'; | |||||
| import { IDocumentInfo } from '@/interfaces/database/document'; | |||||
| import { Badge, DescriptionsProps, Flex, Popover, Space, Tag } from 'antd'; | import { Badge, DescriptionsProps, Flex, Popover, Space, Tag } from 'antd'; | ||||
| import classNames from 'classnames'; | import classNames from 'classnames'; | ||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||
| }; | }; | ||||
| interface IProps { | interface IProps { | ||||
| record: IKnowledgeFile; | |||||
| record: IDocumentInfo; | |||||
| } | } | ||||
| const PopoverContent = ({ record }: IProps) => { | const PopoverContent = ({ record }: IProps) => { | ||||
| const label = t(`knowledgeDetails.runningStatus${text}`); | const label = t(`knowledgeDetails.runningStatus${text}`); | ||||
| const handleOperationIconClick = () => { | const handleOperationIconClick = () => { | ||||
| handleRunDocumentByIds(record.id, record.kb_id, isRunning); | |||||
| handleRunDocumentByIds(record.id, isRunning); | |||||
| }; | }; | ||||
| return ( | return ( | 
| } from '@/hooks/route-hook'; | } from '@/hooks/route-hook'; | ||||
| import { Breadcrumb } from 'antd'; | import { Breadcrumb } from 'antd'; | ||||
| import { ItemType } from 'antd/es/breadcrumb/Breadcrumb'; | import { ItemType } from 'antd/es/breadcrumb/Breadcrumb'; | ||||
| import { useEffect, useMemo } from 'react'; | |||||
| import { useMemo } from 'react'; | |||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||
| import { Link, Outlet, useDispatch, useLocation } from 'umi'; | |||||
| import { Link, Outlet } from 'umi'; | |||||
| import Siderbar from './components/knowledge-sidebar'; | import Siderbar from './components/knowledge-sidebar'; | ||||
| import { KnowledgeDatasetRouteKey, KnowledgeRouteKey } from './constant'; | import { KnowledgeDatasetRouteKey, KnowledgeRouteKey } from './constant'; | ||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| const KnowledgeAdding = () => { | const KnowledgeAdding = () => { | ||||
| const dispatch = useDispatch(); | |||||
| const knowledgeBaseId = useKnowledgeBaseId(); | const knowledgeBaseId = useKnowledgeBaseId(); | ||||
| const { t } = useTranslation(); | const { t } = useTranslation(); | ||||
| const location = useLocation(); | |||||
| const activeKey: KnowledgeRouteKey = | const activeKey: KnowledgeRouteKey = | ||||
| (useSecondPathName() as KnowledgeRouteKey) || KnowledgeRouteKey.Dataset; | (useSecondPathName() as KnowledgeRouteKey) || KnowledgeRouteKey.Dataset; | ||||
| return items; | return items; | ||||
| }, [activeKey, datasetActiveKey, gotoList, knowledgeBaseId, t]); | }, [activeKey, datasetActiveKey, gotoList, knowledgeBaseId, t]); | ||||
| useEffect(() => { | |||||
| const search: string = location.search.slice(1); | |||||
| const map = search.split('&').reduce<Record<string, string>>((obj, cur) => { | |||||
| const [key, value] = cur.split('='); | |||||
| obj[key] = value; | |||||
| return obj; | |||||
| }, {}); | |||||
| dispatch({ | |||||
| type: 'kAModel/updateState', | |||||
| payload: { | |||||
| doc_id: undefined, | |||||
| ...map, | |||||
| }, | |||||
| }); | |||||
| }, [location, dispatch]); | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <div className={styles.container}> | <div className={styles.container}> | 
| import Image from '@/components/image'; | import Image from '@/components/image'; | ||||
| import SvgIcon from '@/components/svg-icon'; | import SvgIcon from '@/components/svg-icon'; | ||||
| import { useSelectFileThumbnails } from '@/hooks/knowledge-hooks'; | |||||
| import { IReference } from '@/interfaces/database/chat'; | import { IReference } from '@/interfaces/database/chat'; | ||||
| import { IChunk } from '@/interfaces/database/knowledge'; | import { IChunk } from '@/interfaces/database/knowledge'; | ||||
| import { getExtension } from '@/utils/document-util'; | import { getExtension } from '@/utils/document-util'; | ||||
| import { InfoCircleOutlined } from '@ant-design/icons'; | import { InfoCircleOutlined } from '@ant-design/icons'; | ||||
| import { Button, Flex, Popover, Space } from 'antd'; | import { Button, Flex, Popover, Space } from 'antd'; | ||||
| import DOMPurify from 'dompurify'; | import DOMPurify from 'dompurify'; | ||||
| import { useCallback, useMemo } from 'react'; | |||||
| import { useCallback, useEffect, useMemo } from 'react'; | |||||
| import Markdown from 'react-markdown'; | import Markdown from 'react-markdown'; | ||||
| import reactStringReplace from 'react-string-replace'; | import reactStringReplace from 'react-string-replace'; | ||||
| import SyntaxHighlighter from 'react-syntax-highlighter'; | import SyntaxHighlighter from 'react-syntax-highlighter'; | ||||
| import remarkGfm from 'remark-gfm'; | import remarkGfm from 'remark-gfm'; | ||||
| import { visitParents } from 'unist-util-visit-parents'; | import { visitParents } from 'unist-util-visit-parents'; | ||||
| import { useFetchDocumentThumbnailsByIds } from '@/hooks/document-hooks'; | |||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| clickDocumentButton?: (documentId: string, chunk: IChunk) => void; | clickDocumentButton?: (documentId: string, chunk: IChunk) => void; | ||||
| }) => { | }) => { | ||||
| const { t } = useTranslation(); | const { t } = useTranslation(); | ||||
| const { setDocumentIds, data: fileThumbnails } = | |||||
| useFetchDocumentThumbnailsByIds(); | |||||
| const contentWithCursor = useMemo(() => { | const contentWithCursor = useMemo(() => { | ||||
| let text = content; | let text = content; | ||||
| if (text === '') { | if (text === '') { | ||||
| return loading ? text?.concat('~~2$$') : text; | return loading ? text?.concat('~~2$$') : text; | ||||
| }, [content, loading, t]); | }, [content, loading, t]); | ||||
| const fileThumbnails = useSelectFileThumbnails(); | |||||
| useEffect(() => { | |||||
| setDocumentIds(reference?.doc_aggs.map((x) => x.doc_id) ?? []); | |||||
| }, [reference, setDocumentIds]); | |||||
| const handleDocumentButtonClick = useCallback( | const handleDocumentButtonClick = useCallback( | ||||
| (documentId: string, chunk: IChunk, isPdf: boolean) => () => { | (documentId: string, chunk: IChunk, isPdf: boolean) => () => { | 
| import { ReactComponent as DeleteIcon } from '@/assets/svg/delete.svg'; | import { ReactComponent as DeleteIcon } from '@/assets/svg/delete.svg'; | ||||
| import SvgIcon from '@/components/svg-icon'; | |||||
| import { useTranslate } from '@/hooks/common-hooks'; | import { useTranslate } from '@/hooks/common-hooks'; | ||||
| import { | |||||
| IListResult, | |||||
| useFetchParentFolderList, | |||||
| } from '@/hooks/file-manager-hooks'; | |||||
| import { | import { | ||||
| DownOutlined, | DownOutlined, | ||||
| FileTextOutlined, | FileTextOutlined, | ||||
| useSelectBreadcrumbItems, | useSelectBreadcrumbItems, | ||||
| } from './hooks'; | } from './hooks'; | ||||
| import SvgIcon from '@/components/svg-icon'; | |||||
| import { | |||||
| IListResult, | |||||
| useFetchParentFolderList, | |||||
| } from '@/hooks/file-manager-hooks'; | |||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| interface IProps | interface IProps | 
| import { KFModelState } from '@/pages/add-knowledge/components/knowledge-file/model'; | |||||
| declare module 'lodash'; | declare module 'lodash'; | ||||
| function useSelector<TState = RootState, TSelected = unknown>( | |||||
| selector: (state: TState) => TSelected, | |||||
| equalityFn?: (left: TSelected, right: TSelected) => boolean, | |||||
| ): TSelected; | |||||
| export interface RootState { | |||||
| kFModel: KFModelState; | |||||
| } | |||||
| declare global { | declare global { | ||||
| type Nullable<T> = T | null; | type Nullable<T> = T | null; | ||||
| } | } | ||||
| declare module 'umi' { | |||||
| export { useSelector }; | |||||
| } |