diff --git a/web/src/hooks/knowledge-hooks.ts b/web/src/hooks/knowledge-hooks.ts index ed311a08d..b3ba12c46 100644 --- a/web/src/hooks/knowledge-hooks.ts +++ b/web/src/hooks/knowledge-hooks.ts @@ -6,7 +6,6 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { message } from 'antd'; import { useCallback, useEffect } from 'react'; import { useDispatch, useSearchParams, useSelector } from 'umi'; -import { useGetKnowledgeSearchParams } from './route-hook'; export const useKnowledgeBaseId = (): string => { const [searchParams] = useSearchParams(); @@ -41,44 +40,6 @@ export const useDeleteDocumentById = (): { }; }; -export const useFetchKnowledgeDetail = () => { - const dispatch = useDispatch(); - const { knowledgeId } = useGetKnowledgeSearchParams(); - - const fetchKnowledgeDetail = useCallback( - (knowledgeId: string) => { - dispatch({ - type: 'knowledgeModel/getKnowledgeDetail', - payload: { kb_id: knowledgeId }, - }); - }, - [dispatch], - ); - - useEffect(() => { - fetchKnowledgeDetail(knowledgeId); - }, [fetchKnowledgeDetail, knowledgeId]); - - return fetchKnowledgeDetail; -}; - -export const useSelectKnowledgeDetail = () => { - const knowledge: IKnowledge = useSelector( - (state: any) => state.knowledgeModel.knowledge, - ); - - return knowledge; -}; - -export const useGetDocumentDefaultParser = () => { - const item = useSelectKnowledgeDetail(); - - return { - defaultParserId: item?.parser_id ?? '', - parserConfig: item?.parser_config ?? '', - }; -}; - export const useDeleteChunkByIds = (): { removeChunk: (chunkIds: string[], documentId: string) => Promise; } => { @@ -111,21 +72,21 @@ export const useDeleteChunkByIds = (): { }; export const useFetchKnowledgeBaseConfiguration = () => { - const dispatch = useDispatch(); const knowledgeBaseId = useKnowledgeBaseId(); - const fetchKnowledgeBaseConfiguration = useCallback(() => { - dispatch({ - type: 'kSModel/getKbDetail', - payload: { + const { data, isFetching: loading } = useQuery({ + queryKey: ['fetchKnowledgeDetail'], + initialData: {}, + gcTime: 0, + queryFn: async () => { + const { data } = await kbService.get_kb_detail({ kb_id: knowledgeBaseId, - }, - }); - }, [dispatch, knowledgeBaseId]); + }); + return data?.data ?? {}; + }, + }); - useEffect(() => { - fetchKnowledgeBaseConfiguration(); - }, [fetchKnowledgeBaseConfiguration]); + return { data, loading }; }; export const useNextFetchKnowledgeList = ( @@ -228,27 +189,30 @@ export const useFetchFileThumbnails = (docIds?: Array) => { //#region knowledge configuration export const useUpdateKnowledge = () => { - const dispatch = useDispatch(); - - const saveKnowledgeConfiguration = useCallback( - (payload: any) => { - dispatch({ - type: 'kSModel/updateKb', - payload, + const knowledgeBaseId = useKnowledgeBaseId(); + const queryClient = useQueryClient(); + const { + data, + isPending: loading, + mutateAsync, + } = useMutation({ + mutationKey: ['saveKnowledge'], + mutationFn: async (params: Record) => { + const { data = {} } = await kbService.updateKb({ + kb_id: knowledgeBaseId, + ...params, }); + if (data.retcode === 0) { + message.success(i18n.t(`message.updated`)); + queryClient.invalidateQueries({ queryKey: ['fetchKnowledgeDetail'] }); + } + return data; }, - [dispatch], - ); + }); - return saveKnowledgeConfiguration; + return { data, loading, saveKnowledgeConfiguration: mutateAsync }; }; -export const useSelectKnowledgeDetails = () => { - const knowledgeDetails: IKnowledge = useSelector( - (state: any) => state.kSModel.knowledgeDetails, - ); - return knowledgeDetails; -}; //#endregion //#region Retrieval testing diff --git a/web/src/pages/add-knowledge/components/knowledge-dataset/knowledge-upload-file/index.less b/web/src/pages/add-knowledge/components/knowledge-dataset/knowledge-upload-file/index.less deleted file mode 100644 index e11dd150e..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-dataset/knowledge-upload-file/index.less +++ /dev/null @@ -1,86 +0,0 @@ -.uploadWrapper { - display: flex; - flex-direction: column; - padding: 64px 32px 32px; - height: 100%; - .backToList { - display: none; - padding-bottom: 60px; - } - .footer { - text-align: center; - padding-top: 16px; - .nextButton { - // background-color: @purple; - font-weight: 700; - font-size: 24px; - display: inline-flex; - align-items: center; - padding: 26px 40px; - justify-content: center; - width: 10%; - } - } - .uploadContent { - flex: 1; - padding-top: 60px; - } - .uploader { - :global(.ant-upload) { - height: 126px; - } - } - .hiddenUploader { - :global(.ant-upload-drag) { - display: none; - } - } - .fileIcon { - font-size: 40px; - align-items: end; - } - .uploaderButton { - padding: 10px; - vertical-align: middle; - height: 40px; - } - .uploaderIcon { - svg { - width: 20px; - height: 20px; - } - } - .deleteIcon { - font-size: 20px; - } - .uploaderItem { - margin-top: 16px; - :global(.ant-card-body) { - padding: 16px; - } - } - .uploaderItemProgress { - padding-left: 50px; - } - .uploaderItemTextWrapper { - flex: 1; - text-align: left; - padding-left: 10px; - } -} - -.progressWrapper { - text-align: center; -} - -.progress { - width: 50%; - margin: 0; -} - -.selectFilesText { - transform: translateX(10%); -} -.changeSpecificCategoryText { - transform: translateX(30%); -} diff --git a/web/src/pages/add-knowledge/components/knowledge-dataset/knowledge-upload-file/index.tsx b/web/src/pages/add-knowledge/components/knowledge-dataset/knowledge-upload-file/index.tsx deleted file mode 100644 index db19d1d36..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-dataset/knowledge-upload-file/index.tsx +++ /dev/null @@ -1,310 +0,0 @@ -import { ReactComponent as SelectFilesEndIcon } from '@/assets/svg/select-files-end.svg'; -import { ReactComponent as SelectFilesStartIcon } from '@/assets/svg/select-files-start.svg'; -import ChunkMethodModal from '@/components/chunk-method-modal'; -import { KnowledgeRouteKey } from '@/constants/knowledge'; -import { - useRunDocument, - useSelectDocumentList, - useUploadDocument, -} from '@/hooks/document-hooks'; -import { - useDeleteDocumentById, - useFetchKnowledgeDetail, - useKnowledgeBaseId, -} from '@/hooks/knowledge-hooks'; -import { - useChangeDocumentParser, - useSetSelectedRecord, -} from '@/hooks/logic-hooks'; -import { useFetchTenantInfo } from '@/hooks/user-setting-hooks'; -import { IKnowledgeFile } from '@/interfaces/database/knowledge'; -import { getExtension, isFileUploadDone } from '@/utils/documentUtils'; -import { - ArrowLeftOutlined, - CloudUploadOutlined, - DeleteOutlined, - EditOutlined, - FileDoneOutlined, -} from '@ant-design/icons'; -import { - Button, - Card, - Flex, - Progress, - Space, - Upload, - UploadFile, - UploadProps, -} from 'antd'; -import classNames from 'classnames'; -import { ReactElement, useCallback, useMemo, useRef, useState } from 'react'; -import { Link, useNavigate } from 'umi'; - -import { useTranslate } from '@/hooks/common-hooks'; -import styles from './index.less'; - -const { Dragger } = Upload; - -type UploadRequestOption = Parameters< - NonNullable ->[0]; - -const UploaderItem = ({ - file, - isUpload, - remove, - handleEdit, -}: { - isUpload: boolean; - originNode: ReactElement; - file: UploadFile; - fileList: object[]; - showModal: () => void; - remove: (id: string) => void; - setRecord: (record: IKnowledgeFile) => void; - handleEdit: (id: string) => void; -}) => { - const { removeDocument } = useDeleteDocumentById(); - - const documentId = file?.response?.id; - - const handleRemove = async () => { - if (file.status === 'error') { - remove(documentId); - } else { - const ret: any = await removeDocument(documentId); - if (ret === 0) { - remove(documentId); - } - } - }; - - const handleEditClick = () => { - if (file.status === 'done') { - handleEdit(documentId); - } - }; - - return ( - - - -
-
- {file.name} -
- {file.size} -
- {isUpload ? ( - - ) : ( - - )} -
- - - 100% - -
- ); -}; - -const KnowledgeUploadFile = () => { - const knowledgeBaseId = useKnowledgeBaseId(); - const [isUpload, setIsUpload] = useState(true); - const [uploadedFileIds, setUploadedFileIds] = useState([]); - const fileListRef = useRef([]); - const navigate = useNavigate(); - const { currentRecord, setRecord } = useSetSelectedRecord(); - const { - changeParserLoading, - onChangeParserOk, - changeParserVisible, - hideChangeParserModal, - showChangeParserModal, - } = useChangeDocumentParser(currentRecord.id); - const documentList = useSelectDocumentList(); - const runDocumentByIds = useRunDocument(); - const uploadDocument = useUploadDocument(); - const { t } = useTranslate('knowledgeDetails'); - - const enabled = useMemo(() => { - if (isUpload) { - return ( - uploadedFileIds.length > 0 && - fileListRef.current.filter((x) => isFileUploadDone(x)).length === - uploadedFileIds.length - ); - } - return true; - }, [uploadedFileIds, isUpload]); - - const createRequest: (props: UploadRequestOption) => void = async function ({ - file, - onSuccess, - onError, - // onProgress, - }) { - const data = await uploadDocument(file as UploadFile); - if (data?.retcode === 0) { - setUploadedFileIds((pre) => { - return pre.concat(data.data.id); - }); - if (onSuccess) { - onSuccess(data.data); - } - } else { - if (onError) { - onError(data?.data); - } - } - }; - - const removeIdFromUploadedIds = useCallback((id: string) => { - setUploadedFileIds((pre) => { - return pre.filter((x) => x !== id); - }); - }, []); - - const handleItemEdit = useCallback( - (id: string) => { - const document = documentList.find((x) => x.id === id); - if (document) { - setRecord(document); - } - showChangeParserModal(); - }, - [documentList, showChangeParserModal, setRecord], - ); - - const props: UploadProps = { - name: 'file', - multiple: true, - itemRender(originNode, file, fileList, actions) { - fileListRef.current = fileList; - const remove = (id: string) => { - if (isFileUploadDone(file)) { - removeIdFromUploadedIds(id); - } - actions.remove(); - }; - return ( - - ); - }, - customRequest: createRequest, - onDrop(e) { - console.log('Dropped files', e.dataTransfer.files); - }, - }; - - const runSelectedDocument = () => { - const ids = fileListRef.current.map((x) => x.response.id); - runDocumentByIds({ doc_ids: ids, run: 1 }); - }; - - const handleNextClick = () => { - if (!isUpload) { - runSelectedDocument(); - navigate(`/knowledge/${KnowledgeRouteKey.Dataset}?id=${knowledgeBaseId}`); - } else { - setIsUpload(false); - } - }; - - useFetchTenantInfo(); - useFetchKnowledgeDetail(); - - return ( - <> -
-
- - - - Back to select files - - -
- - - - - - -

- {t('selectFiles')} -

-

- {t('changeSpecificCategory')} -

-
-
-
-
- - -

{t('uploadTitle')}

-

{t('uploadDescription')}

-
-
-
- -
-
- - - ); -}; - -export default KnowledgeUploadFile; diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/hooks.ts b/web/src/pages/add-knowledge/components/knowledge-setting/hooks.ts index 79299b513..7a0fc3937 100644 --- a/web/src/pages/add-knowledge/components/knowledge-setting/hooks.ts +++ b/web/src/pages/add-knowledge/components/knowledge-setting/hooks.ts @@ -1,12 +1,9 @@ import { useFetchKnowledgeBaseConfiguration, - useKnowledgeBaseId, - useSelectKnowledgeDetails, useUpdateKnowledge, } from '@/hooks/knowledge-hooks'; import { useFetchLlmList, useSelectLlmOptions } from '@/hooks/llm-hooks'; import { useNavigateToDataset } from '@/hooks/route-hook'; -import { useOneNamespaceEffectsLoading } from '@/hooks/store-hooks'; import { useFetchTenantInfo, useSelectParserList, @@ -15,6 +12,7 @@ import { getBase64FromUploadFileList, getUploadFileListFromBase64, } from '@/utils/fileUtil'; +import { useIsFetching } from '@tanstack/react-query'; import { Form, UploadFile } from 'antd'; import { FormInstance } from 'antd/lib'; import pick from 'lodash/pick'; @@ -22,32 +20,32 @@ import { useCallback, useEffect } from 'react'; import { LlmModelType } from '../../constant'; export const useSubmitKnowledgeConfiguration = (form: FormInstance) => { - const save = useUpdateKnowledge(); - const knowledgeBaseId = useKnowledgeBaseId(); - const submitLoading = useOneNamespaceEffectsLoading('kSModel', ['updateKb']); + const { saveKnowledgeConfiguration, loading } = useUpdateKnowledge(); const navigateToDataset = useNavigateToDataset(); const submitKnowledgeConfiguration = useCallback(async () => { const values = await form.validateFields(); const avatar = await getBase64FromUploadFileList(values.avatar); - save({ + saveKnowledgeConfiguration({ ...values, avatar, - kb_id: knowledgeBaseId, }); navigateToDataset(); - }, [save, knowledgeBaseId, form, navigateToDataset]); + }, [saveKnowledgeConfiguration, form, navigateToDataset]); - return { submitKnowledgeConfiguration, submitLoading, navigateToDataset }; + return { + submitKnowledgeConfiguration, + submitLoading: loading, + navigateToDataset, + }; }; export const useFetchKnowledgeConfigurationOnMount = (form: FormInstance) => { - const knowledgeDetails = useSelectKnowledgeDetails(); const parserList = useSelectParserList(); const embeddingModelOptions = useSelectLlmOptions(); useFetchTenantInfo(); - useFetchKnowledgeBaseConfiguration(); + const { data: knowledgeDetails } = useFetchKnowledgeBaseConfiguration(); useFetchLlmList(LlmModelType.Embedding); useEffect(() => { @@ -76,7 +74,7 @@ export const useFetchKnowledgeConfigurationOnMount = (form: FormInstance) => { }; export const useSelectKnowledgeDetailsLoading = () => - useOneNamespaceEffectsLoading('kSModel', ['getKbDetail']); + useIsFetching({ queryKey: ['fetchKnowledgeDetail'] }) > 0; export const useHandleChunkMethodChange = () => { const [form] = Form.useForm(); diff --git a/web/src/pages/add-knowledge/components/knowledge-setting/model.ts b/web/src/pages/add-knowledge/components/knowledge-setting/model.ts deleted file mode 100644 index d8706eaf6..000000000 --- a/web/src/pages/add-knowledge/components/knowledge-setting/model.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { IKnowledge } from '@/interfaces/database/knowledge'; -import i18n from '@/locales/config'; -import kbService from '@/services/knowledge-service'; -import { message } from 'antd'; -import { DvaModel } from 'umi'; - -export interface KSModelState { - isShowPSwModal: boolean; - tenantIfo: any; - knowledgeDetails: IKnowledge; -} - -const model: DvaModel = { - namespace: 'kSModel', - state: { - isShowPSwModal: false, - tenantIfo: {}, - knowledgeDetails: {} as any, - }, - reducers: { - updateState(state, { payload }) { - return { - ...state, - ...payload, - }; - }, - setKnowledgeDetails(state, { payload }) { - return { ...state, knowledgeDetails: payload }; - }, - }, - effects: { - *updateKb({ payload = {} }, { call, put }) { - const { data } = yield call(kbService.updateKb, payload); - const { retcode } = data; - if (retcode === 0) { - yield put({ type: 'getKbDetail', payload: { kb_id: payload.kb_id } }); - message.success(i18n.t('message.updated')); - } - }, - *getKbDetail({ payload = {} }, { call, put }) { - const { data } = yield call(kbService.get_kb_detail, payload); - if (data.retcode === 0) { - yield put({ type: 'setKnowledgeDetails', payload: data.data }); - } - return data; - }, - }, -}; -export default model; diff --git a/web/src/pages/add-knowledge/components/knowledge-sidebar/index.tsx b/web/src/pages/add-knowledge/components/knowledge-sidebar/index.tsx index aaf0e088e..07cf18452 100644 --- a/web/src/pages/add-knowledge/components/knowledge-sidebar/index.tsx +++ b/web/src/pages/add-knowledge/components/knowledge-sidebar/index.tsx @@ -3,7 +3,6 @@ import { ReactComponent as DatasetIcon } from '@/assets/svg/knowledge-dataset.sv import { ReactComponent as TestingIcon } from '@/assets/svg/knowledge-testing.svg'; import { useFetchKnowledgeBaseConfiguration } from '@/hooks/knowledge-hooks'; import { useSecondPathName } from '@/hooks/route-hook'; -import { IKnowledge } from '@/interfaces/database/knowledge'; import { getWidth } from '@/utils'; import { Avatar, Menu, MenuProps, Space } from 'antd'; import classNames from 'classnames'; @@ -11,6 +10,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useNavigate, useSelector } from 'umi'; import { KnowledgeRouteKey } from '../../constant'; + import styles from './index.less'; const KnowledgeSidebar = () => { @@ -18,13 +18,11 @@ const KnowledgeSidebar = () => { const { id } = kAModel; let navigate = useNavigate(); const activeKey = useSecondPathName(); - const knowledgeDetails: IKnowledge = useSelector( - (state: any) => state.kSModel.knowledgeDetails, - ); const [windowWidth, setWindowWidth] = useState(getWidth()); const [collapsed, setCollapsed] = useState(false); const { t } = useTranslation(); + const { data: knowledgeDetails } = useFetchKnowledgeBaseConfiguration(); const handleSelect: MenuProps['onSelect'] = (e) => { navigate(`/knowledge/${e.key}?id=${id}`); @@ -94,8 +92,6 @@ const KnowledgeSidebar = () => { }; }, []); - useFetchKnowledgeBaseConfiguration(); - return (
diff --git a/web/src/pages/knowledge/model.ts b/web/src/pages/knowledge/model.ts deleted file mode 100644 index 822edcde3..000000000 --- a/web/src/pages/knowledge/model.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { IKnowledge } from '@/interfaces/database/knowledge'; -import kbService from '@/services/knowledge-service'; -import { DvaModel } from 'umi'; - -export interface KnowledgeModelState { - data: IKnowledge[]; - knowledge: IKnowledge; -} - -const model: DvaModel = { - namespace: 'knowledgeModel', - state: { - data: [], - knowledge: {} as IKnowledge, - }, - reducers: { - updateState(state, { payload }) { - return { - ...state, - ...payload, - }; - }, - setKnowledge(state, { payload }) { - return { - ...state, - knowledge: payload, - }; - }, - }, - effects: { - *rmKb({ payload = {} }, { call, put }) { - const { data } = yield call(kbService.rmKb, payload); - const { retcode } = data; - if (retcode === 0) { - yield put({ - type: 'getList', - payload: {}, - }); - } - }, - *getList({ payload = {} }, { call, put }) { - const { data } = yield call(kbService.getList, payload); - const { retcode, data: res } = data; - - if (retcode === 0) { - yield put({ - type: 'updateState', - payload: { - data: res, - }, - }); - } - }, - *getKnowledgeDetail({ payload = {} }, { call, put }) { - const { data } = yield call(kbService.get_kb_detail, payload); - if (data.retcode === 0) { - yield put({ type: 'setKnowledge', payload: data.data }); - } - return data.retcode; - }, - }, -}; -export default model; diff --git a/web/src/routes.ts b/web/src/routes.ts index 551fcb8ba..879b6716d 100644 --- a/web/src/routes.ts +++ b/web/src/routes.ts @@ -32,11 +32,6 @@ const routes = [ path: '/knowledge/dataset', component: '@/pages/add-knowledge/components/knowledge-file', }, - { - path: '/knowledge/dataset/upload', - component: - '@/pages/add-knowledge/components/knowledge-dataset/knowledge-upload-file', - }, { path: '/knowledge/dataset/chunk', component: '@/pages/add-knowledge/components/knowledge-chunk', diff --git a/web/typings.d.ts b/web/typings.d.ts index 682c112a3..4b9d7f5a4 100644 --- a/web/typings.d.ts +++ b/web/typings.d.ts @@ -1,39 +1,35 @@ -import { ChunkModelState } from '@/pages/add-knowledge/components/knowledge-chunk/model'; -import { KFModelState } from '@/pages/add-knowledge/components/knowledge-file/model'; -import { KSModelState } from '@/pages/add-knowledge/components/knowledge-setting/model'; -import { TestingModelState } from '@/pages/add-knowledge/components/knowledge-testing/model'; -import { kAModelState } from '@/pages/add-knowledge/model'; -import { ChatModelState } from '@/pages/chat/model'; -import { FileManagerModelState } from '@/pages/file-manager/model'; -import { KnowledgeModelState } from '@/pages/knowledge/model'; -import { LoginModelState } from '@/pages/login/model'; -import { SettingModelState } from '@/pages/user-setting/model'; - -declare module 'lodash'; - -function useSelector( - selector: (state: TState) => TSelected, - equalityFn?: (left: TSelected, right: TSelected) => boolean, -): TSelected; - -export interface RootState { - // loading: Loading; - fileManager: FileManagerModelState; - chatModel: ChatModelState; - loginModel: LoginModelState; - knowledgeModel: KnowledgeModelState; - settingModel: SettingModelState; - kFModel: KFModelState; - kAModel: kAModelState; - chunkModel: ChunkModelState; - kSModel: KSModelState; - testingModel: TestingModelState; -} - -declare global { - type Nullable = T | null; -} - -declare module 'umi' { - export { useSelector }; -} +import { ChunkModelState } from '@/pages/add-knowledge/components/knowledge-chunk/model'; +import { KFModelState } from '@/pages/add-knowledge/components/knowledge-file/model'; +import { TestingModelState } from '@/pages/add-knowledge/components/knowledge-testing/model'; +import { kAModelState } from '@/pages/add-knowledge/model'; +import { ChatModelState } from '@/pages/chat/model'; +import { FileManagerModelState } from '@/pages/file-manager/model'; +import { LoginModelState } from '@/pages/login/model'; +import { SettingModelState } from '@/pages/user-setting/model'; + +declare module 'lodash'; + +function useSelector( + selector: (state: TState) => TSelected, + equalityFn?: (left: TSelected, right: TSelected) => boolean, +): TSelected; + +export interface RootState { + // loading: Loading; + fileManager: FileManagerModelState; + chatModel: ChatModelState; + loginModel: LoginModelState; + settingModel: SettingModelState; + kFModel: KFModelState; + kAModel: kAModelState; + chunkModel: ChunkModelState; + testingModel: TestingModelState; +} + +declare global { + type Nullable = T | null; +} + +declare module 'umi' { + export { useSelector }; +}