mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
### What problem does this PR solve? Feat: Reparse a file shall reuse existing chunks if possible #3793 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
476 lines
12 KiB
TypeScript
476 lines
12 KiB
TypeScript
import { IReferenceChunk } from '@/interfaces/database/chat';
|
|
import { IDocumentInfo } from '@/interfaces/database/document';
|
|
import { IChunk } from '@/interfaces/database/knowledge';
|
|
import { IChangeParserConfigRequestBody } from '@/interfaces/request/document';
|
|
import i18n from '@/locales/config';
|
|
import chatService from '@/services/chat-service';
|
|
import kbService from '@/services/knowledge-service';
|
|
import api, { api_host } from '@/utils/api';
|
|
import { buildChunkHighlights } from '@/utils/document-util';
|
|
import { post } from '@/utils/request';
|
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
import { UploadFile, message } from 'antd';
|
|
import { get } from 'lodash';
|
|
import { useCallback, useMemo, useState } from 'react';
|
|
import { IHighlight } from 'react-pdf-highlighter';
|
|
import {
|
|
useGetPaginationWithRouter,
|
|
useHandleSearchChange,
|
|
} from './logic-hooks';
|
|
import {
|
|
useGetKnowledgeSearchParams,
|
|
useSetPaginationParams,
|
|
} from './route-hook';
|
|
|
|
export const useGetDocumentUrl = (documentId?: string) => {
|
|
const getDocumentUrl = useCallback(
|
|
(id?: string) => {
|
|
return `${api_host}/document/get/${documentId || id}`;
|
|
},
|
|
[documentId],
|
|
);
|
|
|
|
return getDocumentUrl;
|
|
};
|
|
|
|
export const useGetChunkHighlights = (
|
|
selectedChunk: IChunk | IReferenceChunk,
|
|
) => {
|
|
const [size, setSize] = useState({ width: 849, height: 1200 });
|
|
|
|
const highlights: IHighlight[] = useMemo(() => {
|
|
return buildChunkHighlights(selectedChunk, size);
|
|
}, [selectedChunk, size]);
|
|
|
|
const setWidthAndHeight = (width: number, height: number) => {
|
|
setSize((pre) => {
|
|
if (pre.height !== height || pre.width !== width) {
|
|
return { height, width };
|
|
}
|
|
return pre;
|
|
});
|
|
};
|
|
|
|
return { highlights, setWidthAndHeight };
|
|
};
|
|
|
|
export const useFetchNextDocumentList = () => {
|
|
const { knowledgeId } = useGetKnowledgeSearchParams();
|
|
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,
|
|
keywords: searchString,
|
|
page_size: pagination.pageSize,
|
|
page: pagination.current,
|
|
});
|
|
if (ret.data.code === 0) {
|
|
return ret.data.data;
|
|
}
|
|
|
|
return {
|
|
docs: [],
|
|
total: 0,
|
|
};
|
|
},
|
|
});
|
|
|
|
const onInputChange: React.ChangeEventHandler<HTMLInputElement> = useCallback(
|
|
(e) => {
|
|
setPagination({ page: 1 });
|
|
handleInputChange(e);
|
|
},
|
|
[handleInputChange, setPagination],
|
|
);
|
|
|
|
return {
|
|
loading,
|
|
searchString,
|
|
documents: data.docs,
|
|
pagination: { ...pagination, total: data?.total },
|
|
handleInputChange: onInputChange,
|
|
setPagination,
|
|
};
|
|
};
|
|
|
|
export const useSetNextDocumentStatus = () => {
|
|
const queryClient = useQueryClient();
|
|
|
|
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.code === 0) {
|
|
message.success(i18n.t('message.modified'));
|
|
queryClient.invalidateQueries({ queryKey: ['fetchDocumentList'] });
|
|
}
|
|
return data;
|
|
},
|
|
});
|
|
|
|
return { setDocumentStatus: mutateAsync, data, loading };
|
|
};
|
|
|
|
export const useSaveNextDocumentName = () => {
|
|
const queryClient = useQueryClient();
|
|
|
|
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.code === 0) {
|
|
message.success(i18n.t('message.renamed'));
|
|
queryClient.invalidateQueries({ queryKey: ['fetchDocumentList'] });
|
|
}
|
|
return data.code;
|
|
},
|
|
});
|
|
|
|
return { loading, saveName: mutateAsync, data };
|
|
};
|
|
|
|
export const useCreateNextDocument = () => {
|
|
const { knowledgeId } = useGetKnowledgeSearchParams();
|
|
const { setPaginationParams, page } = useSetPaginationParams();
|
|
const queryClient = useQueryClient();
|
|
|
|
const {
|
|
data,
|
|
isPending: loading,
|
|
mutateAsync,
|
|
} = useMutation({
|
|
mutationKey: ['createDocument'],
|
|
mutationFn: async (name: string) => {
|
|
const { data } = await kbService.document_create({
|
|
name,
|
|
kb_id: knowledgeId,
|
|
});
|
|
if (data.code === 0) {
|
|
if (page === 1) {
|
|
queryClient.invalidateQueries({ queryKey: ['fetchDocumentList'] });
|
|
} else {
|
|
setPaginationParams(); // fetch document list
|
|
}
|
|
|
|
message.success(i18n.t('message.created'));
|
|
}
|
|
return data.code;
|
|
},
|
|
});
|
|
|
|
return { createDocument: mutateAsync, loading, data };
|
|
};
|
|
|
|
export const useSetNextDocumentParser = () => {
|
|
const queryClient = useQueryClient();
|
|
|
|
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.code === 0) {
|
|
queryClient.invalidateQueries({ queryKey: ['fetchDocumentList'] });
|
|
|
|
message.success(i18n.t('message.modified'));
|
|
}
|
|
return data.code;
|
|
},
|
|
});
|
|
|
|
return { setDocumentParser: mutateAsync, data, loading };
|
|
};
|
|
|
|
export const useUploadNextDocument = () => {
|
|
const queryClient = useQueryClient();
|
|
const { knowledgeId } = useGetKnowledgeSearchParams();
|
|
|
|
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 {
|
|
const ret = await kbService.document_upload(formData);
|
|
const code = get(ret, 'data.code');
|
|
if (code === 0) {
|
|
message.success(i18n.t('message.uploaded'));
|
|
}
|
|
|
|
if (code === 0 || code === 500) {
|
|
queryClient.invalidateQueries({ queryKey: ['fetchDocumentList'] });
|
|
}
|
|
return ret?.data;
|
|
} catch (error) {
|
|
console.warn(error);
|
|
return {};
|
|
}
|
|
},
|
|
});
|
|
|
|
return { uploadDocument: mutateAsync, loading, data };
|
|
};
|
|
|
|
export const useNextWebCrawl = () => {
|
|
const { knowledgeId } = useGetKnowledgeSearchParams();
|
|
|
|
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 code = get(ret, 'data.code');
|
|
if (code === 0) {
|
|
message.success(i18n.t('message.uploaded'));
|
|
}
|
|
|
|
return code;
|
|
},
|
|
});
|
|
|
|
return {
|
|
data,
|
|
loading,
|
|
webCrawl: mutateAsync,
|
|
};
|
|
};
|
|
|
|
export const useRunNextDocument = () => {
|
|
const queryClient = useQueryClient();
|
|
|
|
const {
|
|
data,
|
|
isPending: loading,
|
|
mutateAsync,
|
|
} = useMutation({
|
|
mutationKey: ['runDocumentByIds'],
|
|
mutationFn: async ({
|
|
documentIds,
|
|
run,
|
|
shouldDelete,
|
|
}: {
|
|
documentIds: string[];
|
|
run: number;
|
|
shouldDelete: boolean;
|
|
}) => {
|
|
const ret = await kbService.document_run({
|
|
doc_ids: documentIds,
|
|
run,
|
|
delete: shouldDelete,
|
|
});
|
|
const code = get(ret, 'data.code');
|
|
if (code === 0) {
|
|
queryClient.invalidateQueries({ queryKey: ['fetchDocumentList'] });
|
|
message.success(i18n.t('message.operated'));
|
|
}
|
|
|
|
return code;
|
|
},
|
|
});
|
|
|
|
return { runDocumentByIds: mutateAsync, loading, data };
|
|
};
|
|
|
|
export const useFetchDocumentInfosByIds = () => {
|
|
const [ids, setDocumentIds] = useState<string[]>([]);
|
|
const { data } = useQuery<IDocumentInfo[]>({
|
|
queryKey: ['fetchDocumentInfos', ids],
|
|
enabled: ids.length > 0,
|
|
initialData: [],
|
|
queryFn: async () => {
|
|
const { data } = await kbService.document_infos({ doc_ids: ids });
|
|
if (data.code === 0) {
|
|
return data.data;
|
|
}
|
|
|
|
return [];
|
|
},
|
|
});
|
|
|
|
return { data, setDocumentIds };
|
|
};
|
|
|
|
export const useFetchDocumentThumbnailsByIds = () => {
|
|
const [ids, setDocumentIds] = useState<string[]>([]);
|
|
const { data } = useQuery<Record<string, string>>({
|
|
queryKey: ['fetchDocumentThumbnails', ids],
|
|
enabled: ids.length > 0,
|
|
initialData: {},
|
|
queryFn: async () => {
|
|
const { data } = await kbService.document_thumbnails({ doc_ids: ids });
|
|
if (data.code === 0) {
|
|
return data.data;
|
|
}
|
|
return {};
|
|
},
|
|
});
|
|
|
|
return { data, setDocumentIds };
|
|
};
|
|
|
|
export const useRemoveNextDocument = () => {
|
|
const queryClient = useQueryClient();
|
|
const {
|
|
data,
|
|
isPending: loading,
|
|
mutateAsync,
|
|
} = useMutation({
|
|
mutationKey: ['removeDocument'],
|
|
mutationFn: async (documentIds: string | string[]) => {
|
|
const { data } = await kbService.document_rm({ doc_id: documentIds });
|
|
if (data.code === 0) {
|
|
message.success(i18n.t('message.deleted'));
|
|
queryClient.invalidateQueries({ queryKey: ['fetchDocumentList'] });
|
|
}
|
|
return data.code;
|
|
},
|
|
});
|
|
|
|
return { data, loading, removeDocument: mutateAsync };
|
|
};
|
|
|
|
export const useDeleteDocument = () => {
|
|
// const queryClient = useQueryClient();
|
|
const {
|
|
data,
|
|
isPending: loading,
|
|
mutateAsync,
|
|
} = useMutation({
|
|
mutationKey: ['deleteDocument'],
|
|
mutationFn: async (documentIds: string[]) => {
|
|
const data = await kbService.document_delete({ doc_ids: documentIds });
|
|
// if (data.code === 0) {
|
|
// queryClient.invalidateQueries({ queryKey: ['fetchFlowList'] });
|
|
// }
|
|
return data;
|
|
},
|
|
});
|
|
|
|
return { data, loading, deleteDocument: mutateAsync };
|
|
};
|
|
|
|
export const useUploadAndParseDocument = (uploadMethod: string) => {
|
|
const {
|
|
data,
|
|
isPending: loading,
|
|
mutateAsync,
|
|
} = useMutation({
|
|
mutationKey: ['uploadAndParseDocument'],
|
|
mutationFn: async ({
|
|
conversationId,
|
|
fileList,
|
|
}: {
|
|
conversationId: string;
|
|
fileList: UploadFile[];
|
|
}) => {
|
|
try {
|
|
const formData = new FormData();
|
|
formData.append('conversation_id', conversationId);
|
|
fileList.forEach((file: UploadFile) => {
|
|
formData.append('file', file as any);
|
|
});
|
|
if (uploadMethod === 'upload_and_parse') {
|
|
const data = await kbService.upload_and_parse(formData);
|
|
return data?.data;
|
|
}
|
|
const data = await chatService.uploadAndParseExternal(formData);
|
|
return data?.data;
|
|
} catch (error) {
|
|
console.log('🚀 ~ useUploadAndParseDocument ~ error:', error);
|
|
}
|
|
},
|
|
});
|
|
|
|
return { data, loading, uploadAndParseDocument: mutateAsync };
|
|
};
|
|
|
|
export const useParseDocument = () => {
|
|
const {
|
|
data,
|
|
isPending: loading,
|
|
mutateAsync,
|
|
} = useMutation({
|
|
mutationKey: ['parseDocument'],
|
|
mutationFn: async (url: string) => {
|
|
try {
|
|
const data = await post(api.parse, { url });
|
|
if (data?.code === 0) {
|
|
message.success(i18n.t('message.uploaded'));
|
|
}
|
|
return data;
|
|
} catch (error) {
|
|
console.log('🚀 ~ mutationFn: ~ error:', error);
|
|
message.error('error');
|
|
}
|
|
},
|
|
});
|
|
|
|
return { parseDocument: mutateAsync, data, loading };
|
|
};
|