Feat: Add a data compilation layer. (#16777)

### Summary

Feat: Add a data compilation layer.
This commit is contained in:
balibabu
2026-07-09 17:49:16 +08:00
committed by GitHub
parent 5de823eab9
commit 0083ad0deb
171 changed files with 14477 additions and 791 deletions

View File

@@ -126,8 +126,11 @@ export const useHandleSearchChange = () => {
return { handleInputChange, searchString, pagination, setPagination };
};
export const useGetPagination = () => {
const [pagination, setPagination] = useState({ page: 1, pageSize: 10 });
export const useGetPagination = (options?: { pageSize?: number }) => {
const [pagination, setPagination] = useState({
page: 1,
pageSize: options?.pageSize ?? 10,
});
const { t } = useTranslate('common');
const onPageChange: Pagination['onChange'] = useCallback(
@@ -152,6 +155,7 @@ export const useGetPagination = () => {
return {
pagination: currentPagination,
setPagination,
};
};

View File

@@ -57,6 +57,13 @@ export const useNavigatePage = () => {
[navigate],
);
const navigateToCompilation = useCallback(
(id: string) => () => {
navigate(`${Routes.DatasetBase}${Routes.Compilation}/${id}`);
},
[navigate],
);
const navigateToHome = useCallback(() => {
navigate(Routes.Root);
}, [navigate]);
@@ -201,6 +208,21 @@ export const useNavigatePage = () => {
navigate(`${Routes.UserSetting}${Routes.Model}`);
}, [navigate]);
const navigateToCompilationTemplates = useCallback(() => {
navigate(`${Routes.UserSetting}${Routes.CompilationTemplates}`);
}, [navigate]);
const navigateToCompilationTemplate = useCallback(
(id?: string) => () => {
if (id && id !== 'create') {
navigate(`${Routes.CompilationTemplatesCreateNext}/${id}`);
} else {
navigate(Routes.CompilationTemplatesCreateNext);
}
},
[navigate],
);
return {
navigateToDatasetList,
navigateToDataset,
@@ -224,9 +246,12 @@ export const useNavigatePage = () => {
navigateToOldProfile,
navigateToDataflowResult,
navigateToDataFile,
navigateToCompilation,
navigateToDataSourceDetail,
navigateToMemory,
navigateToMemoryList,
navigateToModelSetting,
navigateToCompilationTemplates,
navigateToCompilationTemplate,
};
};

View File

@@ -122,12 +122,14 @@ export const useFetchChunk = (
export const useFetchNextChunkList = (
enabled = true,
options?: { chunkIds?: string[] },
): ResponseGetType<{
data: IChunk[];
total: number;
documentInfo: IKnowledgeFile;
}> &
IChunkListResult => {
const chunkIds = options?.chunkIds;
const { pagination, setPagination } = useGetPaginationWithRouter();
const { documentId, knowledgeId } = useGetKnowledgeSearchParams();
const { searchString, handleInputChange } = useHandleSearchChange();
@@ -147,6 +149,7 @@ export const useFetchNextChunkList = (
pagination.pageSize,
debouncedSearchString,
available,
chunkIds,
],
placeholderData: (previousData: any) =>
previousData ?? { data: [], total: 0, documentInfo: {} }, // https://github.com/TanStack/query/issues/8183
@@ -156,10 +159,13 @@ export const useFetchNextChunkList = (
const { data } = await kbService.chunkList({
kb_id: knowledgeId,
doc_id: documentId,
page: pagination.current,
size: pagination.pageSize,
page: chunkIds?.length ? 1 : pagination.current,
size: chunkIds?.length
? Math.max(chunkIds.length, 100)
: pagination.pageSize,
available_int: available,
keywords: searchString,
chunk_ids: chunkIds,
});
if (data.code === 0) {
const res = data.data;

View File

@@ -0,0 +1,255 @@
import message from '@/components/ui/message';
import { ICompilationTemplateGroup } from '@/interfaces/database/compilation-template';
import {
ICreateCompilationTemplateGroupRequestBody,
IUpdateCompilationTemplateGroupRequestBody,
} from '@/interfaces/request/compilation-template';
import i18n from '@/locales/config';
import {
compilationTemplateGroupService,
createCompilationTemplateGroup,
deleteCompilationTemplateGroup,
getCompilationTemplateGroup,
updateCompilationTemplateGroup,
} from '@/services/compilation-template-group-service';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useDebounce } from 'ahooks';
import { useCallback, useMemo } from 'react';
import {
useGetPaginationWithRouter,
useHandleSearchChange,
} from './logic-hooks';
export const enum CompilationTemplateGroupApiAction {
FetchCompilationTemplateGroups = 'fetchCompilationTemplateGroups',
FetchCompilationTemplateGroup = 'fetchCompilationTemplateGroup',
CreateCompilationTemplateGroup = 'createCompilationTemplateGroup',
UpdateCompilationTemplateGroup = 'updateCompilationTemplateGroup',
DeleteCompilationTemplateGroup = 'deleteCompilationTemplateGroup',
}
export const CompilationTemplateGroupKeys = {
list: (keywords?: string, page?: number, pageSize?: number) =>
[
CompilationTemplateGroupApiAction.FetchCompilationTemplateGroups,
{ keywords, page, pageSize },
] as const,
detail: (id?: string) =>
[
CompilationTemplateGroupApiAction.FetchCompilationTemplateGroup,
id,
] as const,
all: () =>
[CompilationTemplateGroupApiAction.FetchCompilationTemplateGroups] as const,
};
export const useFetchCompilationTemplateGroupsByPage = () => {
const { searchString, handleInputChange } = useHandleSearchChange();
const { pagination, setPagination } = useGetPaginationWithRouter();
const debouncedSearchString = useDebounce(searchString, { wait: 500 });
const { data, isFetching: loading } = useQuery<{
groups: ICompilationTemplateGroup[];
total: number;
}>({
queryKey: CompilationTemplateGroupKeys.list(
debouncedSearchString,
pagination.current,
pagination.pageSize,
),
initialData: {
groups: [],
total: 0,
},
gcTime: 0,
queryFn: async () => {
const { data } = await compilationTemplateGroupService.listGroups(
{
params: {
keywords: debouncedSearchString,
page: pagination.current,
page_size: pagination.pageSize,
},
},
true,
);
return {
groups: (data?.data?.groups ?? []) as ICompilationTemplateGroup[],
total: data?.data?.total ?? 0,
};
},
});
const currentPagination = useMemo(
() => ({ ...pagination, total: data?.total ?? 0 }),
[pagination, data?.total],
);
return {
groups: data?.groups ?? [],
total: data?.total ?? 0,
searchString,
handleInputChange,
pagination: currentPagination,
setPagination,
loading,
};
};
export const useFetchCompilationTemplateGroup = (id?: string) => {
const { data, isFetching: loading } = useQuery<
ICompilationTemplateGroup | undefined
>({
queryKey: CompilationTemplateGroupKeys.detail(id),
enabled: !!id && id !== 'create',
gcTime: 0,
queryFn: async () => {
if (!id || id === 'create') return undefined;
const { data } = await getCompilationTemplateGroup(id);
return data?.data as ICompilationTemplateGroup | undefined;
},
});
return { data, loading };
};
export const useCreateCompilationTemplateGroup = () => {
const queryClient = useQueryClient();
const {
data,
isPending: loading,
mutateAsync,
} = useMutation({
mutationKey: [
CompilationTemplateGroupApiAction.CreateCompilationTemplateGroup,
],
mutationFn: async (params: ICreateCompilationTemplateGroupRequestBody) => {
const { data } = await createCompilationTemplateGroup(params);
return data;
},
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: [
CompilationTemplateGroupApiAction.FetchCompilationTemplateGroups,
],
});
},
});
const createGroup = useCallback(
async (params: ICreateCompilationTemplateGroupRequestBody) => {
const result = await mutateAsync(params);
if (result.code === 0) {
message.success(i18n.t('message.created'));
}
return result;
},
[mutateAsync],
);
return { data, loading, createGroup };
};
export const useUpdateCompilationTemplateGroup = () => {
const queryClient = useQueryClient();
const {
data,
isPending: loading,
mutateAsync,
} = useMutation({
mutationKey: [
CompilationTemplateGroupApiAction.UpdateCompilationTemplateGroup,
],
mutationFn: async ({
id,
params,
}: {
id: string;
params: IUpdateCompilationTemplateGroupRequestBody;
}) => {
const { data } = await updateCompilationTemplateGroup(id, params);
return data;
},
onSuccess: (_, variables) => {
queryClient.invalidateQueries({
queryKey: [
CompilationTemplateGroupApiAction.FetchCompilationTemplateGroups,
],
});
queryClient.invalidateQueries({
queryKey: CompilationTemplateGroupKeys.detail(variables.id),
});
},
});
const updateGroup = useCallback(
async (id: string, params: IUpdateCompilationTemplateGroupRequestBody) => {
const result = await mutateAsync({ id, params });
if (result.code === 0) {
message.success(i18n.t('message.modified'));
}
return result;
},
[mutateAsync],
);
return { data, loading, updateGroup };
};
export const useDeleteCompilationTemplateGroup = () => {
const queryClient = useQueryClient();
const {
data,
isPending: loading,
mutateAsync,
} = useMutation({
mutationKey: [
CompilationTemplateGroupApiAction.DeleteCompilationTemplateGroup,
],
mutationFn: async (id: string) => {
const { data } = await deleteCompilationTemplateGroup(id);
if (data.code === 0) {
message.success(i18n.t('message.deleted'));
queryClient.invalidateQueries({
queryKey: [
CompilationTemplateGroupApiAction.FetchCompilationTemplateGroups,
],
});
}
return data?.data ?? true;
},
});
const deleteGroup = useCallback(
async (id: string) => {
await mutateAsync(id);
},
[mutateAsync],
);
return { data, loading, deleteGroup };
};
export const useFetchAllCompilationTemplateGroups = () => {
const { data, isFetching: loading } = useQuery<ICompilationTemplateGroup[]>({
queryKey: CompilationTemplateGroupKeys.all(),
initialData: [],
gcTime: 0,
queryFn: async () => {
const { data } = await compilationTemplateGroupService.listGroups(
{
params: { keywords: '', page: 1, page_size: 100 },
},
true,
);
return (data?.data?.groups ?? []) as ICompilationTemplateGroup[];
},
});
return { groups: data ?? [], loading };
};

View File

@@ -0,0 +1,304 @@
import message from '@/components/ui/message';
import {
ICompilationTemplate,
ICompilationTemplateBuiltin,
ICompilationTemplateListResult,
ICompilationTemplateSection,
IWikiPreset,
} from '@/interfaces/database/compilation-template';
import {
ICreateCompilationTemplateRequestBody,
IUpdateCompilationTemplateRequestBody,
} from '@/interfaces/request/compilation-template';
import i18n from '@/locales/config';
import compilationTemplateService, {
createCompilationTemplate,
deleteCompilationTemplate,
getCompilationTemplate,
listBuiltinCompilationTemplates,
listWikiPresets,
updateCompilationTemplate,
} from '@/services/compilation-template-service';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useDebounce } from 'ahooks';
import { useCallback, useMemo } from 'react';
import {
useGetPaginationWithRouter,
useHandleSearchChange,
} from './logic-hooks';
export const enum CompilationTemplateApiAction {
FetchCompilationTemplates = 'fetchCompilationTemplates',
FetchCompilationTemplate = 'fetchCompilationTemplate',
FetchBuiltinCompilationTemplates = 'fetchBuiltinCompilationTemplates',
CreateCompilationTemplate = 'createCompilationTemplate',
UpdateCompilationTemplate = 'updateCompilationTemplate',
DeleteCompilationTemplate = 'deleteCompilationTemplate',
FetchWikiPresets = 'fetchWikiPresets',
}
export const CompilationTemplateKeys = {
list: (keywords?: string, page?: number, pageSize?: number) =>
[
CompilationTemplateApiAction.FetchCompilationTemplates,
{ keywords, page, pageSize },
] as const,
detail: (id?: string) =>
[CompilationTemplateApiAction.FetchCompilationTemplate, id] as const,
builtins: () =>
[CompilationTemplateApiAction.FetchBuiltinCompilationTemplates] as const,
all: () => [CompilationTemplateApiAction.FetchCompilationTemplates] as const,
wikiPresets: () => [CompilationTemplateApiAction.FetchWikiPresets] as const,
};
export const useFetchCompilationTemplatesByPage = () => {
const { searchString, handleInputChange } = useHandleSearchChange();
const { pagination, setPagination } = useGetPaginationWithRouter();
const debouncedSearchString = useDebounce(searchString, { wait: 500 });
const { data, isFetching: loading } =
useQuery<ICompilationTemplateListResult>({
queryKey: CompilationTemplateKeys.list(
debouncedSearchString,
pagination.current,
pagination.pageSize,
),
initialData: {
templates: [],
total: 0,
},
gcTime: 0,
queryFn: async () => {
const { data } = await compilationTemplateService.listTemplates(
{
params: {
keywords: debouncedSearchString,
page: pagination.current,
page_size: pagination.pageSize,
},
},
true,
);
return {
templates: (data?.data?.templates ?? []) as ICompilationTemplate[],
total: data?.data?.total ?? 0,
};
},
});
const currentPagination = useMemo(
() => ({ ...pagination, total: data?.total ?? 0 }),
[pagination, data?.total],
);
return {
templates: data?.templates ?? [],
total: data?.total ?? 0,
searchString,
handleInputChange,
pagination: currentPagination,
setPagination,
loading,
};
};
export const useFetchCompilationTemplate = (id?: string) => {
const { data, isFetching: loading } = useQuery<
ICompilationTemplate | undefined
>({
queryKey: CompilationTemplateKeys.detail(id),
enabled: !!id && id !== 'create',
gcTime: 0,
queryFn: async () => {
if (!id || id === 'create') return undefined;
const { data } = await getCompilationTemplate(id);
return data?.data as ICompilationTemplate | undefined;
},
});
return { data, loading };
};
export const useFetchBuiltinCompilationTemplates = () => {
const { data, isFetching: loading } = useQuery<ICompilationTemplateBuiltin[]>(
{
queryKey: CompilationTemplateKeys.builtins(),
initialData: [],
gcTime: 0,
queryFn: async () => {
const { data } = await listBuiltinCompilationTemplates();
return (data?.data ?? []) as ICompilationTemplateBuiltin[];
},
},
);
const kindOptions = useMemo(() => {
const kindSet = new Set<string>();
(data ?? []).forEach((template) => {
if (template?.kind) kindSet.add(template.kind);
});
return Array.from(kindSet)
.sort()
.map((value) => ({ label: value, value }));
}, [data]);
const typeOptions = useMemo(() => {
const typeSet = new Set<string>();
(data ?? []).forEach((template) => {
Object.entries(template?.config ?? {}).forEach(([key, section]) => {
if (['kind', 'llm_id', 'global_rules'].includes(key)) return;
(section as ICompilationTemplateSection)?.fields?.forEach((field) => {
if (field?.type) typeSet.add(field.type);
});
});
});
return Array.from(typeSet)
.sort()
.map((value) => ({ label: value, value }));
}, [data]);
return { data, typeOptions, kindOptions, loading };
};
export const useCreateCompilationTemplate = () => {
const queryClient = useQueryClient();
const {
data,
isPending: loading,
mutateAsync,
} = useMutation({
mutationKey: [CompilationTemplateApiAction.CreateCompilationTemplate],
mutationFn: async (params: ICreateCompilationTemplateRequestBody) => {
const { data } = await createCompilationTemplate(params);
return data;
},
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: [CompilationTemplateApiAction.FetchCompilationTemplates],
});
},
});
const createTemplate = useCallback(
async (params: ICreateCompilationTemplateRequestBody) => {
const result = await mutateAsync(params);
if (result.code === 0) {
message.success(i18n.t('message.created'));
}
return result;
},
[mutateAsync],
);
return { data, loading, createTemplate };
};
export const useUpdateCompilationTemplate = () => {
const queryClient = useQueryClient();
const {
data,
isPending: loading,
mutateAsync,
} = useMutation({
mutationKey: [CompilationTemplateApiAction.UpdateCompilationTemplate],
mutationFn: async ({
id,
params,
}: {
id: string;
params: IUpdateCompilationTemplateRequestBody;
}) => {
const { data } = await updateCompilationTemplate(id, params);
return data;
},
onSuccess: (_, variables) => {
queryClient.invalidateQueries({
queryKey: [CompilationTemplateApiAction.FetchCompilationTemplates],
});
queryClient.invalidateQueries({
queryKey: CompilationTemplateKeys.detail(variables.id),
});
},
});
const updateTemplate = useCallback(
async (id: string, params: IUpdateCompilationTemplateRequestBody) => {
const result = await mutateAsync({ id, params });
if (result.code === 0) {
message.success(i18n.t('message.modified'));
}
return result;
},
[mutateAsync],
);
return { data, loading, updateTemplate };
};
export const useDeleteCompilationTemplate = () => {
const queryClient = useQueryClient();
const {
data,
isPending: loading,
mutateAsync,
} = useMutation({
mutationKey: [CompilationTemplateApiAction.DeleteCompilationTemplate],
mutationFn: async (id: string) => {
const { data } = await deleteCompilationTemplate(id);
if (data.code === 0) {
message.success(i18n.t('message.deleted'));
queryClient.invalidateQueries({
queryKey: [CompilationTemplateApiAction.FetchCompilationTemplates],
});
}
return data?.data ?? true;
},
});
const deleteTemplate = useCallback(
async (id: string) => {
await mutateAsync(id);
},
[mutateAsync],
);
return { data, loading, deleteTemplate };
};
export const useFetchAllCompilationTemplates = () => {
const { data, isFetching: loading } = useQuery<ICompilationTemplate[]>({
queryKey: CompilationTemplateKeys.all(),
initialData: [],
gcTime: 0,
queryFn: async () => {
const { data } = await compilationTemplateService.listTemplates(
{
params: { keywords: '', page: 1, page_size: 100 },
},
true,
);
return (data?.data?.templates ?? []) as ICompilationTemplate[];
},
});
return { templates: data ?? [], loading };
};
export const useFetchWikiPresets = () => {
const { data, isFetching: loading } = useQuery<IWikiPreset[]>({
queryKey: CompilationTemplateKeys.wikiPresets(),
initialData: [],
gcTime: 0,
queryFn: async () => {
const { data } = await listWikiPresets();
return (data?.data ?? []) as IWikiPreset[];
},
});
return { data: data ?? [], loading };
};

View File

@@ -0,0 +1,53 @@
import {
DatasetSkillPage,
DatasetSkillTree,
} from '@/interfaces/database/dataset-skill';
import datasetSkillService from '@/services/dataset-skill-service';
import { useQuery } from '@tanstack/react-query';
import { useKnowledgeBaseId } from './use-knowledge-request';
export const DatasetSkillKeys = {
all: (kbId: string) => ['dataset_skill', kbId] as const,
tree: (kbId: string) => ['dataset_skill', kbId, 'tree'] as const,
page: (kbId: string, skillKwd: string) =>
['dataset_skill', kbId, 'page', skillKwd] as const,
};
export function useFetchDatasetSkillTree() {
const kbId = useKnowledgeBaseId();
const { data, isFetching: loading } = useQuery<DatasetSkillTree | null>({
queryKey: DatasetSkillKeys.tree(kbId),
initialData: null,
enabled: !!kbId,
gcTime: 0,
queryFn: async () => {
const { data } = await datasetSkillService.getTree({ datasetId: kbId });
return data?.data ?? null;
},
});
return { data, loading };
}
export function useFetchDatasetSkillPage(skillKwd: string | null | undefined) {
const kbId = useKnowledgeBaseId();
const enabled = !!kbId && !!skillKwd;
const { data, isFetching: loading } = useQuery<DatasetSkillPage | null>({
queryKey: DatasetSkillKeys.page(kbId, skillKwd ?? ''),
initialData: null,
enabled,
gcTime: 0,
queryFn: async () => {
const { data } = await datasetSkillService.getPage({
datasetId: kbId,
skillKwd: skillKwd!,
});
return data?.data ?? null;
},
});
return { data, loading };
}

View File

@@ -9,12 +9,14 @@ import {
IDocumentInfo,
IDocumentInfoFilter,
} from '@/interfaces/database/document';
import { IStructureGraphResponse } from '@/interfaces/database/document-structure';
import {
IChangeParserConfigRequestBody,
IDocumentMetaRequestBody,
} from '@/interfaces/request/document';
import i18n from '@/locales/config';
import { EMPTY_METADATA_FIELD } from '@/pages/dataset/dataset/use-select-filters';
import documentStructureService from '@/services/document-structure-service';
import kbService, {
changeDocumentParser,
changeDocumentsStatus,
@@ -59,6 +61,25 @@ export const enum DocumentApiAction {
ParseDocument = 'parseDocument',
}
export const enum DocumentStructureApiAction {
FetchDocumentStructureGraph = 'fetchDocumentStructureGraph',
DeleteDocumentStructureGraph = 'deleteDocumentStructureGraph',
}
const DocumentKeys = {
byIds: (ids: string[]) =>
[DocumentApiAction.FetchDocumentList, 'byIds', ids] as const,
};
export const DocumentStructureKeys = {
graph: (datasetId: string, documentId: string) =>
[
DocumentStructureApiAction.FetchDocumentStructureGraph,
datasetId,
documentId,
] as const,
};
export const useUploadDocument = () => {
const queryClient = useQueryClient();
const { id } = useParams();
@@ -214,6 +235,37 @@ export const useFetchDocumentList = (loop = true) => {
};
};
export const useFetchDocumentsByIds = (ids: string[]) => {
const { id: datasetId } = useParams();
const { data, isFetching: loading } = useQuery<{
docs: IDocumentInfo[];
total: number;
}>({
queryKey: DocumentKeys.byIds(ids),
enabled: ids.length > 0 && !!datasetId,
initialData: { docs: [], total: 0 },
queryFn: async () => {
const ret = await listDocument(
{
id: datasetId,
page: 1,
page_size: ids.length,
},
{
ids,
},
);
if (ret.data.code === 0) {
return ret.data.data;
}
return { docs: [], total: 0 };
},
});
return { documents: data.docs, loading };
};
// get document filter
export const useGetDocumentFilter = (): {
filter: IDocumentInfoFilter;
@@ -566,3 +618,56 @@ export const useFetchDocumentThumbnailsByIds = () => {
return { data, setDocumentIds };
};
export function useFetchDocumentStructureGraph() {
const { knowledgeId: datasetId, documentId } = useGetKnowledgeSearchParams();
const enabled = !!datasetId && !!documentId;
const { data, isFetching: loading } =
useQuery<IStructureGraphResponse | null>({
queryKey: DocumentStructureKeys.graph(datasetId, documentId),
enabled,
initialData: null,
gcTime: 0,
queryFn: async () => {
const { data } =
await documentStructureService.getDocumentStructureGraph(
datasetId,
documentId,
);
return data?.data ?? null;
},
});
return { data, loading };
}
export function useDeleteDocumentStructureGraph() {
const { knowledgeId: datasetId, documentId } = useGetKnowledgeSearchParams();
const queryClient = useQueryClient();
const {
data,
isPending: loading,
mutateAsync,
} = useMutation({
mutationKey: [DocumentStructureApiAction.DeleteDocumentStructureGraph],
mutationFn: async (templateId: string) => {
const { data } =
await documentStructureService.deleteDocumentStructureGraph(
datasetId,
documentId,
templateId,
);
if (data.code === 0) {
message.success(i18n.t('message.deleted'));
queryClient.invalidateQueries({
queryKey: DocumentStructureKeys.graph(datasetId, documentId),
});
}
return data;
},
});
return { deleteDocumentStructureGraph: mutateAsync, loading, data };
}

View File

@@ -1,28 +1,48 @@
import { useHandleFilterSubmit } from '@/components/list-filter-bar/use-handle-filter-submit';
import message from '@/components/ui/message';
import { ParseType } from '@/constants/knowledge';
import { ResponsePostType } from '@/interfaces/database/base';
import { ResponsePostType, ResponseType } from '@/interfaces/database/base';
import {
IArtifact,
IArtifactGraph,
IArtifactPage,
IArtifactTopic,
IDataset,
IDatasetListResult,
IKnowledgeGraph,
INextTestingResult,
IRenameTag,
ITestingResult,
IWikiCommit,
IWikiCommitDetail,
IWikiCommitListResponse,
} from '@/interfaces/database/dataset';
import { ITestRetrievalRequestBody } from '@/interfaces/request/knowledge';
import {
IFetchArtifactGraphRequestParams,
ITestRetrievalRequestBody,
IUpdateArtifactPageRequestParams,
} from '@/interfaces/request/knowledge';
import i18n from '@/locales/config';
import kbService, {
clearWiki,
deleteKnowledgeGraph,
getArtifactGraph,
getArtifactPage,
getKbDetail,
getKnowledgeGraph,
getWikiCommit,
listArtifactTopics,
listArtifacts,
listDataset,
listTag,
listWikiCommits,
removeTag,
renameTag,
updateArtifactPage,
updateKb,
} from '@/services/knowledge-service';
import {
useInfiniteQuery,
useIsMutating,
useMutation,
useMutationState,
@@ -47,10 +67,18 @@ export const enum KnowledgeApiAction {
SaveKnowledge = 'saveKnowledge',
FetchKnowledgeDetail = 'fetchKnowledgeDetail',
FetchKnowledgeGraph = 'fetchKnowledgeGraph',
FetchArtifactList = 'fetchArtifactList',
FetchArtifactTopicList = 'fetchArtifactTopicList',
FetchArtifactPage = 'fetchArtifactPage',
FetchArtifactGraph = 'fetchArtifactGraph',
UpdateArtifactPage = 'updateArtifactPage',
FetchWikiCommits = 'fetchWikiCommits',
FetchWikiCommit = 'fetchWikiCommit',
FetchMetadata = 'fetchMetadata',
FetchMetadataKeys = 'fetchMetadataKeys',
FetchKnowledgeList = 'fetchKnowledgeList',
RemoveKnowledgeGraph = 'removeKnowledgeGraph',
ClearWiki = 'clearWiki',
}
export const useKnowledgeBaseId = (): string => {
@@ -324,6 +352,301 @@ export const useFetchKnowledgeBaseConfiguration = (props?: {
return { data, loading };
};
export const ArtifactKeys = {
list: (
datasetId: string,
keywords: string,
topic?: string,
pageType?: string,
) =>
[
KnowledgeApiAction.FetchArtifactList,
datasetId,
keywords,
topic,
pageType,
] as const,
listByDataset: (datasetId: string) =>
[KnowledgeApiAction.FetchArtifactList, datasetId] as const,
detail: (datasetId: string, pageType: string, slug: string) =>
[KnowledgeApiAction.FetchArtifactPage, datasetId, pageType, slug] as const,
};
export const ArtifactTopicKeys = {
list: (datasetId: string, keywords: string) =>
[KnowledgeApiAction.FetchArtifactTopicList, datasetId, keywords] as const,
listByDataset: (datasetId: string) =>
[KnowledgeApiAction.FetchArtifactTopicList, datasetId] as const,
};
const wikiCommitKeys = {
list: (datasetId: string, pageType: string, slug: string) =>
[KnowledgeApiAction.FetchWikiCommits, datasetId, pageType, slug] as const,
detail: (datasetId: string, commitId: string) =>
[KnowledgeApiAction.FetchWikiCommit, datasetId, commitId] as const,
};
export const useFetchWikiCommits = (
artifact: IArtifact | null,
enabled = true,
) => {
const knowledgeBaseId = useKnowledgeBaseId();
const pageType = artifact?.page_type ?? '';
const slug = artifact?.slug ?? '';
const { data, isFetching: loading } =
useQuery<IWikiCommitListResponse | null>({
queryKey: wikiCommitKeys.list(knowledgeBaseId, pageType, slug),
enabled:
!!knowledgeBaseId && !!artifact && !!pageType && !!slug && enabled,
gcTime: 0,
queryFn: async () => {
const { data } = await listWikiCommits(knowledgeBaseId, pageType, slug);
// The merged file-commit endpoint returns {total, page, page_size, commits},
// while the existing components expect {total, items}. Normalize here.
const raw = (data?.data ?? {}) as {
total?: number;
items?: IWikiCommit[];
commits?: IWikiCommit[];
};
return {
total: raw.total ?? 0,
items: raw.items ?? raw.commits ?? [],
};
},
});
return {
commits: data?.items ?? [],
total: data?.total ?? 0,
loading,
};
};
export function useFetchWikiCommit(commitId: string | null) {
const knowledgeBaseId = useKnowledgeBaseId();
const { data, isFetching: loading } = useQuery<IWikiCommitDetail | null>({
queryKey: wikiCommitKeys.detail(knowledgeBaseId, commitId ?? ''),
enabled: !!knowledgeBaseId && !!commitId,
gcTime: 0,
queryFn: async () => {
const { data } = await getWikiCommit(knowledgeBaseId, commitId!);
return data?.data ?? null;
},
});
return { data, loading };
}
type UseFetchArtifactListOptions = {
keywords?: string;
topic?: string;
pageType?: string;
enabled?: boolean;
};
export const useFetchArtifactList = (
options: UseFetchArtifactListOptions = {},
) => {
const { keywords = '', topic, pageType, enabled = true } = options;
const knowledgeBaseId = useKnowledgeBaseId();
const { data, fetchNextPage, hasNextPage, isFetching, isFetchingNextPage } =
useInfiniteQuery<{
artifacts: IArtifact[];
total: number;
}>({
queryKey: ArtifactKeys.list(knowledgeBaseId, keywords, topic, pageType),
enabled: !!knowledgeBaseId && enabled && !!topic,
gcTime: 0,
initialPageParam: 1,
queryFn: async ({ pageParam }) => {
const page = pageParam as number;
const { data } = await listArtifacts(knowledgeBaseId, {
page,
page_size: 30,
keywords,
topic,
page_type: pageType,
});
const responseData = data?.data;
return {
artifacts: responseData?.items ?? [],
total: responseData?.total ?? 0,
};
},
getNextPageParam: (lastPage, allPages) => {
const loadedCount = allPages.reduce(
(sum, page) => sum + page.artifacts.length,
0,
);
return loadedCount < lastPage.total ? allPages.length + 1 : undefined;
},
});
const artifacts = useMemo(
() => data?.pages.flatMap((page) => page.artifacts) ?? [],
[data],
);
const loading = isFetching || isFetchingNextPage;
const handleScroll = useCallback(
(e: React.UIEvent<HTMLDivElement>) => {
const { scrollTop, scrollHeight, clientHeight } = e.currentTarget;
const threshold = 50;
if (
scrollHeight - scrollTop - clientHeight <= threshold &&
hasNextPage &&
!isFetchingNextPage
) {
fetchNextPage();
}
},
[fetchNextPage, hasNextPage, isFetchingNextPage],
);
return {
artifacts,
loading,
handleScroll,
hasMore: !!hasNextPage,
};
};
type UseFetchArtifactTopicListOptions = {
keywords?: string;
enabled?: boolean;
};
export const useFetchArtifactTopicList = (
options: UseFetchArtifactTopicListOptions = {},
) => {
const { keywords = '', enabled = true } = options;
const knowledgeBaseId = useKnowledgeBaseId();
const { data, fetchNextPage, hasNextPage, isFetching, isFetchingNextPage } =
useInfiniteQuery<{
topics: IArtifactTopic[];
total: number;
}>({
queryKey: ArtifactTopicKeys.list(knowledgeBaseId, keywords),
enabled: !!knowledgeBaseId && enabled,
gcTime: 0,
initialPageParam: 1,
queryFn: async ({ pageParam }) => {
const page = pageParam as number;
const { data } = await listArtifactTopics(knowledgeBaseId, {
page,
page_size: 30,
keywords,
});
const responseData = data?.data;
return {
topics: responseData?.items ?? [],
total: responseData?.total ?? 0,
};
},
getNextPageParam: (lastPage, allPages) => {
const loadedCount = allPages.reduce(
(sum, page) => sum + page.topics.length,
0,
);
return loadedCount < lastPage.total ? allPages.length + 1 : undefined;
},
});
const topics = useMemo(
() => data?.pages.flatMap((page) => page.topics) ?? [],
[data],
);
const loading = isFetching || isFetchingNextPage;
const handleScroll = useCallback(
(e: React.UIEvent<HTMLDivElement>) => {
const { scrollTop, scrollHeight, clientHeight } = e.currentTarget;
const threshold = 50;
if (
scrollHeight - scrollTop - clientHeight <= threshold &&
hasNextPage &&
!isFetchingNextPage
) {
fetchNextPage();
}
},
[fetchNextPage, hasNextPage, isFetchingNextPage],
);
return {
topics,
loading,
handleScroll,
hasMore: !!hasNextPage,
};
};
export function useFetchArtifactPage(artifact: IArtifact | null) {
const knowledgeBaseId = useKnowledgeBaseId();
const pageType = artifact?.page_type ?? '';
const slug = artifact?.slug ?? '';
const { data, isFetching: loading } = useQuery<IArtifactPage | null>({
queryKey: ArtifactKeys.detail(knowledgeBaseId, pageType, slug),
enabled: !!knowledgeBaseId && !!artifact && !!pageType && !!slug,
gcTime: 0,
queryFn: async () => {
const { data } = await getArtifactPage(knowledgeBaseId, pageType, slug);
return data?.data ?? null;
},
});
return { data, loading };
}
export const useUpdateArtifactPage = () => {
const knowledgeBaseId = useKnowledgeBaseId();
const queryClient = useQueryClient();
const {
data,
isPending: loading,
mutateAsync,
} = useMutation<
ResponseType<IArtifactPage>,
Error,
IUpdateArtifactPageRequestParams
>({
mutationKey: [KnowledgeApiAction.UpdateArtifactPage],
mutationFn: async (params) => {
const { data = {} } = await updateArtifactPage(
knowledgeBaseId,
params.pageType,
params.slug,
params.body,
);
if (data.code === 0) {
message.success(i18n.t(`message.updated`));
queryClient.invalidateQueries({
queryKey: ArtifactKeys.detail(
knowledgeBaseId,
params.pageType,
params.slug,
),
});
}
return data;
},
});
return { data, loading, updateArtifactPage: mutateAsync };
};
export function useFetchKnowledgeGraph() {
const knowledgeBaseId = useKnowledgeBaseId();
@@ -341,6 +664,31 @@ export function useFetchKnowledgeGraph() {
return { data, loading };
}
export const artifactGraphKeys = {
graph: (datasetId: string, params?: IFetchArtifactGraphRequestParams) =>
[KnowledgeApiAction.FetchArtifactGraph, datasetId, params?.node] as const,
};
export function useFetchArtifactGraph(
params?: IFetchArtifactGraphRequestParams,
options?: { enabled?: boolean },
) {
const knowledgeBaseId = useKnowledgeBaseId();
const { data, isFetching: loading } = useQuery<IArtifactGraph>({
queryKey: artifactGraphKeys.graph(knowledgeBaseId, params),
initialData: { entities: [], relations: [] } as IArtifactGraph,
enabled: !!knowledgeBaseId && (options?.enabled ?? true),
gcTime: 0,
queryFn: async () => {
const { data } = await getArtifactGraph(knowledgeBaseId, params);
return data?.data ?? { entities: [], relations: [] };
},
});
return { data, loading };
}
export function useFetchKnowledgeMetadata(kbIds: string[] = []) {
const { data, isFetching: loading } = useQuery<
Record<string, Record<string, string[]>>
@@ -403,6 +751,37 @@ export const useRemoveKnowledgeGraph = () => {
return { data, loading, removeKnowledgeGraph: mutateAsync };
};
export const useClearWiki = () => {
const knowledgeBaseId = useKnowledgeBaseId();
const queryClient = useQueryClient();
const {
data,
isPending: loading,
mutateAsync,
} = useMutation({
mutationKey: [KnowledgeApiAction.ClearWiki],
mutationFn: async () => {
const { data } = await clearWiki(knowledgeBaseId);
if (data?.code === 0) {
message.success(i18n.t('message.deleted'));
queryClient.invalidateQueries({
queryKey: ArtifactKeys.listByDataset(knowledgeBaseId),
});
queryClient.invalidateQueries({
queryKey: ArtifactTopicKeys.listByDataset(knowledgeBaseId),
});
queryClient.invalidateQueries({
queryKey: artifactGraphKeys.graph(knowledgeBaseId),
});
}
return data;
},
});
return { data, loading, clearWiki: mutateAsync };
};
export const useFetchKnowledgeList = (
shouldFilterListWithoutDocument: boolean = false,
keywords = '',