Feat: Importing data flow files from the list page #9869 (#10446)

### What problem does this PR solve?

Feat: Importing data flow files from the list page #9869

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
balibabu
2025-10-09 19:03:29 +08:00
committed by GitHub
parent f04c9e2937
commit f4324e89d9
9 changed files with 90 additions and 41 deletions

View File

@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next';
import { SelectWithSearch } from '../originui/select-with-search'; import { SelectWithSearch } from '../originui/select-with-search';
import { RAGFlowFormItem } from '../ragflow-form'; import { RAGFlowFormItem } from '../ragflow-form';
type LLMFormFieldProps = { export type LLMFormFieldProps = {
options?: any[]; options?: any[];
name?: string; name?: string;
}; };

View File

@ -52,3 +52,13 @@ export enum AgentCategory {
AgentCanvas = 'agent_canvas', AgentCanvas = 'agent_canvas',
DataflowCanvas = 'dataflow_canvas', DataflowCanvas = 'dataflow_canvas',
} }
export enum DataflowOperator {
Begin = 'File',
Note = 'Note',
Parser = 'Parser',
Tokenizer = 'Tokenizer',
Splitter = 'Splitter',
HierarchicalMerger = 'HierarchicalMerger',
Extractor = 'Extractor',
}

View File

@ -3,7 +3,6 @@ import { useHandleFilterSubmit } from '@/components/list-filter-bar/use-handle-f
import message from '@/components/ui/message'; import message from '@/components/ui/message';
import { AgentGlobals } from '@/constants/agent'; import { AgentGlobals } from '@/constants/agent';
import { import {
DSL,
IAgentLogsRequest, IAgentLogsRequest,
IAgentLogsResponse, IAgentLogsResponse,
IFlow, IFlow,
@ -295,7 +294,7 @@ export const useSetAgent = (showMessage: boolean = true) => {
mutationFn: async (params: { mutationFn: async (params: {
id?: string; id?: string;
title?: string; title?: string;
dsl?: DSL; dsl?: Record<string, any>;
avatar?: string; avatar?: string;
canvas_category?: string; canvas_category?: string;
}) => { }) => {

View File

@ -1,13 +1,20 @@
import { useToast } from '@/components/hooks/use-toast'; import { useToast } from '@/components/hooks/use-toast';
import message from '@/components/ui/message';
import { AgentCategory, DataflowOperator } from '@/constants/agent';
import { FileMimeType } from '@/constants/common'; import { FileMimeType } from '@/constants/common';
import { useSetModalState } from '@/hooks/common-hooks'; import { useSetModalState } from '@/hooks/common-hooks';
import { EmptyDsl, useSetAgent } from '@/hooks/use-agent-request'; import { EmptyDsl, useSetAgent } from '@/hooks/use-agent-request';
import { message } from 'antd'; import { Node } from '@xyflow/react';
import isEmpty from 'lodash/isEmpty'; import isEmpty from 'lodash/isEmpty';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { DataflowEmptyDsl } from './hooks/use-create-agent';
import { FormSchemaType } from './upload-agent-dialog/upload-agent-form'; import { FormSchemaType } from './upload-agent-dialog/upload-agent-form';
function hasNode(nodes: Node[], operator: DataflowOperator) {
return nodes.some((x) => x.data.label === operator);
}
export const useHandleImportJsonFile = () => { export const useHandleImportJsonFile = () => {
const { const {
visible: fileUploadVisible, visible: fileUploadVisible,
@ -32,8 +39,28 @@ export const useHandleImportJsonFile = () => {
try { try {
const graph = JSON.parse(graphStr); const graph = JSON.parse(graphStr);
if (graphStr && !isEmpty(graph) && Array.isArray(graph?.nodes)) { if (graphStr && !isEmpty(graph) && Array.isArray(graph?.nodes)) {
const dsl = { ...EmptyDsl, graph }; const nodes: Node[] = graph.nodes;
setAgent({ title: name, dsl });
let isAgent = true;
if (
hasNode(nodes, DataflowOperator.Begin) &&
hasNode(nodes, DataflowOperator.Parser)
) {
isAgent = false;
}
const dsl = isAgent
? { ...EmptyDsl, graph }
: { ...DataflowEmptyDsl, graph };
setAgent({
title: name,
dsl,
canvas_category: isAgent
? AgentCategory.AgentCanvas
: AgentCategory.DataflowCanvas,
});
hideFileUploadModal(); hideFileUploadModal();
} else { } else {
message.error(errorMessage); message.error(errorMessage);

View File

@ -1,10 +1,14 @@
import { ParseDocumentType } from '@/components/layout-recognize-form-field'; import { ParseDocumentType } from '@/components/layout-recognize-form-field';
import { initialLlmBaseValues } from '@/constants/agent'; import {
initialLlmBaseValues,
DataflowOperator as Operator,
} from '@/constants/agent';
import { import {
ChatVariableEnabledField, ChatVariableEnabledField,
variableEnabledFieldMap, variableEnabledFieldMap,
} from '@/constants/chat'; } from '@/constants/chat';
import { setInitialChatVariableEnabledFieldValue } from '@/utils/chat'; import { setInitialChatVariableEnabledFieldValue } from '@/utils/chat';
export { DataflowOperator as Operator } from '@/constants/agent';
import { import {
Circle, Circle,
@ -112,16 +116,6 @@ export enum AgentDialogueMode {
export const BeginId = 'File'; export const BeginId = 'File';
export enum Operator {
Begin = 'File',
Note = 'Note',
Parser = 'Parser',
Tokenizer = 'Tokenizer',
Splitter = 'Splitter',
HierarchicalMerger = 'HierarchicalMerger',
Extractor = 'Extractor',
}
export const SwitchLogicOperatorOptions = ['and', 'or']; export const SwitchLogicOperatorOptions = ['and', 'or'];
export const CommonOperatorList = Object.values(Operator).filter( export const CommonOperatorList = Object.values(Operator).filter(

View File

@ -1,6 +1,9 @@
import { crossLanguageOptions } from '@/components/cross-language-form-field'; import { crossLanguageOptions } from '@/components/cross-language-form-field';
import { LayoutRecognizeFormField } from '@/components/layout-recognize-form-field'; import { LayoutRecognizeFormField } from '@/components/layout-recognize-form-field';
import { LLMFormField } from '@/components/llm-setting-items/llm-form-field'; import {
LLMFormField,
LLMFormFieldProps,
} from '@/components/llm-setting-items/llm-form-field';
import { import {
SelectWithSearch, SelectWithSearch,
SelectWithSearchFlagOptionType, SelectWithSearchFlagOptionType,
@ -60,10 +63,14 @@ export function ParserMethodFormField({
); );
} }
export function LargeModelFormField({ prefix }: CommonProps) { export function LargeModelFormField({
prefix,
options,
}: CommonProps & Pick<LLMFormFieldProps, 'options'>) {
return ( return (
<LLMFormField <LLMFormField
name={buildFieldNameWithPrefix('llm_id', prefix)} name={buildFieldNameWithPrefix('llm_id', prefix)}
options={options}
></LLMFormField> ></LLMFormField>
); );
} }

View File

@ -1,13 +1,24 @@
import { LlmModelType } from '@/constants/knowledge';
import { useComposeLlmOptionsByModelTypes } from '@/hooks/llm-hooks';
import { import {
LargeModelFormField, LargeModelFormField,
OutputFormatFormFieldProps, OutputFormatFormFieldProps,
} from './common-form-fields'; } from './common-form-fields';
export function VideoFormFields({ prefix }: OutputFormatFormFieldProps) { export function VideoFormFields({ prefix }: OutputFormatFormFieldProps) {
const modelOptions = useComposeLlmOptionsByModelTypes([
LlmModelType.Chat,
LlmModelType.Image2text,
LlmModelType.Speech2text,
]);
return ( return (
<> <>
{/* Multimodal Model */} {/* Multimodal Model */}
<LargeModelFormField prefix={prefix}></LargeModelFormField> <LargeModelFormField
prefix={prefix}
options={modelOptions}
></LargeModelFormField>
</> </>
); );
} }

View File

@ -162,9 +162,9 @@ export default function DataFlow() {
onClick={handleRunAgent} onClick={handleRunAgent}
loading={running} loading={running}
> >
{running || ( <CirclePlay
<CirclePlay className={isParsing ? 'animate-spin' : ''} /> className={isParsing || isLogEmpty ? 'animate-spin' : ''}
)} />
{isParsing || running ? t('dataflow.running') : t('flow.run')} {isParsing || running ? t('dataflow.running') : t('flow.run')}
</ButtonLoading> </ButtonLoading>

View File

@ -61,24 +61,25 @@ export function LogSheet({
<SheetHeader> <SheetHeader>
<SheetTitle className="flex items-center gap-2.5"> <SheetTitle className="flex items-center gap-2.5">
<Logs className="size-4" /> {t('flow.log')} <Logs className="size-4" /> {t('flow.log')}
<Button {isCompleted && (
variant={'ghost'} <Button
disabled={!isCompleted} variant={'ghost'}
onClick={navigateToDataflowResult({ onClick={navigateToDataflowResult({
id: messageId, // 'log_id', id: messageId, // 'log_id',
[PipelineResultSearchParams.AgentId]: id, // 'agent_id', [PipelineResultSearchParams.AgentId]: id, // 'agent_id',
[PipelineResultSearchParams.DocumentId]: uploadedFileData?.id, //'doc_id', [PipelineResultSearchParams.DocumentId]: uploadedFileData?.id, //'doc_id',
[PipelineResultSearchParams.AgentTitle]: agent.title, //'title', [PipelineResultSearchParams.AgentTitle]: agent.title, //'title',
[PipelineResultSearchParams.IsReadOnly]: 'true', [PipelineResultSearchParams.IsReadOnly]: 'true',
[PipelineResultSearchParams.Type]: 'dataflow', [PipelineResultSearchParams.Type]: 'dataflow',
[PipelineResultSearchParams.CreatedBy]: [PipelineResultSearchParams.CreatedBy]:
uploadedFileData?.created_by, uploadedFileData?.created_by,
[PipelineResultSearchParams.DocumentExtension]: [PipelineResultSearchParams.DocumentExtension]:
uploadedFileData?.extension, uploadedFileData?.extension,
})} })}
> >
{t('dataflow.viewResult')} <ArrowUpRight /> {t('dataflow.viewResult')} <ArrowUpRight />
</Button> </Button>
)}
</SheetTitle> </SheetTitle>
</SheetHeader> </SheetHeader>
<section className="max-h-[82vh] overflow-auto mt-6"> <section className="max-h-[82vh] overflow-auto mt-6">