mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-30 12:39:27 +08:00
Feat: Support pipeline-related configuration at the document level. (#17212)
### Summary Feat: Support pipeline-related configuration at the document level.
This commit is contained in:
@@ -4,6 +4,20 @@
|
||||
* and merge unknown fields into the `ext` field for flexible configuration.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Pipeline parser configs are keyed by operator id (e.g. "Parser:xxx"), so a
|
||||
* top-level key containing ":" marks the pipeline structure, which must be
|
||||
* sent as-is instead of being reshaped by extractParserConfigExt.
|
||||
*/
|
||||
export const isPipelineParserConfig = (
|
||||
parserConfig: Record<string, any> | undefined,
|
||||
): boolean => {
|
||||
if (!parserConfig || typeof parserConfig !== 'object') {
|
||||
return false;
|
||||
}
|
||||
return Object.keys(parserConfig).some((key) => key.includes(':'));
|
||||
};
|
||||
|
||||
/**
|
||||
* Extracts Raptor configuration with extra fields merged into ext.
|
||||
* @param raptorConfig - The raptor configuration object
|
||||
|
||||
@@ -39,7 +39,10 @@ import {
|
||||
useGetPaginationWithRouter,
|
||||
useHandleSearchChange,
|
||||
} from './logic-hooks';
|
||||
import { extractParserConfigExt } from './parser-config-utils';
|
||||
import {
|
||||
extractParserConfigExt,
|
||||
isPipelineParserConfig,
|
||||
} from './parser-config-utils';
|
||||
import {
|
||||
useGetKnowledgeSearchParams,
|
||||
useSetPaginationParams,
|
||||
@@ -502,6 +505,66 @@ export const useSetDocumentParser = () => {
|
||||
return { setDocumentParser: mutateAsync, data, loading };
|
||||
};
|
||||
|
||||
/**
|
||||
* Go-backend variant of useSetDocumentParser. The Go document endpoint takes
|
||||
* `parser_id` (instead of the legacy `chunk_method`) and expects the
|
||||
* pipeline-shaped parser_config (keyed by operator id) to be sent as-is.
|
||||
* Keep it parallel to the Python version — the original hook stays untouched
|
||||
* and can be dropped once the Python backend is retired.
|
||||
*/
|
||||
export const useSetDocumentPipelineParser = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const {
|
||||
data,
|
||||
isPending: loading,
|
||||
mutateAsync,
|
||||
} = useMutation({
|
||||
mutationKey: [DocumentApiAction.SetDocumentParser, 'pipeline'],
|
||||
mutationFn: async ({
|
||||
parserId,
|
||||
pipelineId,
|
||||
documentId,
|
||||
datasetId,
|
||||
parserConfig,
|
||||
}: {
|
||||
parserId: string;
|
||||
pipelineId: string;
|
||||
documentId: string;
|
||||
datasetId: string;
|
||||
parserConfig?: IChangeParserConfigRequestBody;
|
||||
}) => {
|
||||
const updateData: Record<string, unknown> = {
|
||||
parser_id: parserId,
|
||||
pipeline_id: pipelineId,
|
||||
};
|
||||
|
||||
|
||||
if (parserConfig) {
|
||||
updateData.parser_config = isPipelineParserConfig(parserConfig)
|
||||
? parserConfig
|
||||
: extractParserConfigExt(parserConfig);
|
||||
}
|
||||
|
||||
const { data } = await changeDocumentParser(
|
||||
datasetId,
|
||||
documentId,
|
||||
updateData,
|
||||
);
|
||||
if (data.code === 0) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: [DocumentApiAction.FetchDocumentList],
|
||||
});
|
||||
|
||||
message.success(i18n.t('message.modified'));
|
||||
}
|
||||
return data.code;
|
||||
},
|
||||
});
|
||||
|
||||
return { setDocumentPipelineParser: mutateAsync, data, loading };
|
||||
};
|
||||
|
||||
export const useSetDocumentMeta = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
|
||||
@@ -57,7 +57,10 @@ import {
|
||||
useGetPaginationWithRouter,
|
||||
useHandleSearchChange,
|
||||
} from './logic-hooks';
|
||||
import { extractParserConfigExt } from './parser-config-utils';
|
||||
import {
|
||||
extractParserConfigExt,
|
||||
isPipelineParserConfig,
|
||||
} from './parser-config-utils';
|
||||
import { useSetPaginationParams } from './route-hook';
|
||||
|
||||
export const enum KnowledgeApiAction {
|
||||
@@ -263,15 +266,6 @@ export const useDeleteKnowledge = () => {
|
||||
return { data, loading, deleteKnowledge: mutateAsync };
|
||||
};
|
||||
|
||||
function isPipelineParserConfig(
|
||||
parserConfig: Record<string, any> | undefined,
|
||||
): boolean {
|
||||
if (!parserConfig || typeof parserConfig !== 'object') {
|
||||
return false;
|
||||
}
|
||||
return Object.keys(parserConfig).some((key) => key.includes(':'));
|
||||
}
|
||||
|
||||
export const useUpdateKnowledge = (shouldFetchList = false) => {
|
||||
const knowledgeBaseId = useKnowledgeBaseId();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
98
web/src/hooks/use-pipeline-operator.ts
Normal file
98
web/src/hooks/use-pipeline-operator.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import { useFetchPipelineDslByPipelineId } from '@/hooks/use-agent-request';
|
||||
import { RAGFlowNodeType } from '@/interfaces/database/agent';
|
||||
import {
|
||||
buildParserConfigFromNodes,
|
||||
buildPipelineOperatorNodes,
|
||||
} from '@/utils/pipeline-operator';
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { UseFormReturn } from 'react-hook-form';
|
||||
|
||||
export const usePipelineOperatorNodes = (
|
||||
pipelineId?: string,
|
||||
pipelineParserConfig?: Record<string, any>,
|
||||
isBuiltin = false,
|
||||
) => {
|
||||
const { dsl, loading } = useFetchPipelineDslByPipelineId(
|
||||
pipelineId,
|
||||
isBuiltin,
|
||||
);
|
||||
|
||||
const operatorNodes = useMemo(() => {
|
||||
return buildPipelineOperatorNodes(dsl, pipelineParserConfig);
|
||||
}, [dsl, pipelineParserConfig]);
|
||||
|
||||
return { operatorNodes, loading };
|
||||
};
|
||||
|
||||
/**
|
||||
* Resets parser_config when the selected pipeline changes, so stale configs
|
||||
* from the previous pipeline are never submitted. Once the new pipeline's
|
||||
* DSL has loaded, parser_config is seeded with the DSL defaults (i.e. what
|
||||
* the operator tabs display).
|
||||
*
|
||||
* The very first pipeline seen is treated as the initial load: the form was
|
||||
* already reset with the saved parser_config on mount, so it is left
|
||||
* untouched.
|
||||
*/
|
||||
export const useResetParserConfigOnPipelineChange = (
|
||||
form: UseFormReturn<any>,
|
||||
pipelineId: string | undefined,
|
||||
savedPipelineId: string | undefined,
|
||||
operatorNodes: RAGFlowNodeType[],
|
||||
) => {
|
||||
const previousPipelineIdRef = useRef<string>();
|
||||
|
||||
useEffect(() => {
|
||||
if (!pipelineId) {
|
||||
// Selection cleared (e.g. parse type switched): drop configs that
|
||||
// belonged to the previously selected pipeline.
|
||||
if (previousPipelineIdRef.current) {
|
||||
previousPipelineIdRef.current = '';
|
||||
form.setValue('parser_config', {});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const isInitialLoad =
|
||||
previousPipelineIdRef.current === undefined &&
|
||||
pipelineId === savedPipelineId;
|
||||
if (isInitialLoad || previousPipelineIdRef.current === pipelineId) {
|
||||
previousPipelineIdRef.current = pipelineId;
|
||||
return;
|
||||
}
|
||||
|
||||
if (operatorNodes.length === 0) {
|
||||
// The new pipeline's DSL is still loading — clear the previous
|
||||
// pipeline's configs right away; defaults are seeded once it arrives.
|
||||
form.setValue('parser_config', {});
|
||||
return;
|
||||
}
|
||||
|
||||
previousPipelineIdRef.current = pipelineId;
|
||||
form.setValue('parser_config', buildParserConfigFromNodes(operatorNodes));
|
||||
}, [form, pipelineId, savedPipelineId, operatorNodes]);
|
||||
};
|
||||
|
||||
export const useActiveTab = (operatorNodes: RAGFlowNodeType[]) => {
|
||||
const [activeTab, setActiveTab] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
if (operatorNodes.length > 0) {
|
||||
const firstTab =
|
||||
(operatorNodes[0].data as Record<string, any>)?.operatorId ||
|
||||
operatorNodes[0].data?.label ||
|
||||
'';
|
||||
const validTabs = operatorNodes.map(
|
||||
(node) =>
|
||||
(node.data as Record<string, any>)?.operatorId ||
|
||||
node.data?.label ||
|
||||
'',
|
||||
);
|
||||
setActiveTab((prev) => (validTabs.includes(prev) ? prev : firstTab));
|
||||
} else {
|
||||
setActiveTab('');
|
||||
}
|
||||
}, [operatorNodes]);
|
||||
|
||||
return { activeTab, setActiveTab };
|
||||
};
|
||||
Reference in New Issue
Block a user