Fix: Fixed the issue where the drop-down box could not be displayed after selecting a large model #9869 (#10205)

### What problem does this PR solve?

Fix: Fixed the issue where the drop-down box could not be displayed
after selecting a large model #9869

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
balibabu
2025-09-22 17:16:34 +08:00
committed by GitHub
parent 476852e8f1
commit 73c33bc8d2
17 changed files with 180 additions and 205 deletions

View File

@ -3,7 +3,7 @@ import { useTranslate } from '@/hooks/common-hooks';
import { useSelectLlmOptionsByModelType } from '@/hooks/llm-hooks'; import { useSelectLlmOptionsByModelType } from '@/hooks/llm-hooks';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { camelCase } from 'lodash'; import { camelCase } from 'lodash';
import { useMemo } from 'react'; import { ReactNode, useMemo } from 'react';
import { useFormContext } from 'react-hook-form'; import { useFormContext } from 'react-hook-form';
import { SelectWithSearch } from './originui/select-with-search'; import { SelectWithSearch } from './originui/select-with-search';
import { import {
@ -23,10 +23,12 @@ export function LayoutRecognizeFormField({
name = 'parser_config.layout_recognize', name = 'parser_config.layout_recognize',
horizontal = true, horizontal = true,
optionsWithoutLLM, optionsWithoutLLM,
label,
}: { }: {
name?: string; name?: string;
horizontal?: boolean; horizontal?: boolean;
optionsWithoutLLM?: { value: string; label: string }[]; optionsWithoutLLM?: { value: string; label: string }[];
label?: ReactNode;
}) { }) {
const form = useFormContext(); const form = useFormContext();
@ -81,7 +83,7 @@ export function LayoutRecognizeFormField({
['w-1/4']: horizontal, ['w-1/4']: horizontal,
})} })}
> >
{t('layoutRecognize')} {label || t('layoutRecognize')}
</FormLabel> </FormLabel>
<div className={horizontal ? 'w-3/4' : 'w-full'}> <div className={horizontal ? 'w-3/4' : 'w-full'}>
<FormControl> <FormControl>

View File

@ -49,6 +49,22 @@ export type SelectWithSearchFlagProps = {
placeholder?: string; placeholder?: string;
}; };
function findLabelWithoutOptions(
options: SelectWithSearchFlagOptionType[],
value: string,
) {
return options.find((opt) => opt.value === value)?.label || '';
}
function findLabelWithOptions(
options: SelectWithSearchFlagOptionType[],
value: string,
) {
return options
.map((group) => group?.options?.find((item) => item.value === value))
.filter(Boolean)[0]?.label;
}
export const SelectWithSearch = forwardRef< export const SelectWithSearch = forwardRef<
React.ElementRef<typeof Button>, React.ElementRef<typeof Button>,
SelectWithSearchFlagProps SelectWithSearchFlagProps
@ -69,6 +85,28 @@ export const SelectWithSearch = forwardRef<
const [open, setOpen] = useState<boolean>(false); const [open, setOpen] = useState<boolean>(false);
const [value, setValue] = useState<string>(''); const [value, setValue] = useState<string>('');
const selectLabel = useMemo(() => {
if (options.every((x) => x.options === undefined)) {
return findLabelWithoutOptions(options, value);
} else if (options.every((x) => Array.isArray(x.options))) {
return findLabelWithOptions(options, value);
} else {
// Some have options, some don't
const optionsWithOptions = options.filter((x) =>
Array.isArray(x.options),
);
const optionsWithoutOptions = options.filter(
(x) => x.options === undefined,
);
const label = findLabelWithOptions(optionsWithOptions, value);
if (label) {
return label;
}
return findLabelWithoutOptions(optionsWithoutOptions, value);
}
}, [options, value]);
const handleSelect = useCallback( const handleSelect = useCallback(
(val: string) => { (val: string) => {
setValue(val); setValue(val);
@ -90,16 +128,7 @@ export const SelectWithSearch = forwardRef<
useEffect(() => { useEffect(() => {
setValue(val); setValue(val);
}, [val]); }, [val]);
const selectLabel = useMemo(() => {
const optionTemp = options[0];
if (optionTemp?.options) {
return options
.map((group) => group?.options?.find((item) => item.value === value))
.filter(Boolean)[0]?.label;
} else {
return options.find((opt) => opt.value === value)?.label || '';
}
}, [options, value]);
return ( return (
<Popover open={open} onOpenChange={setOpen}> <Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild> <PopoverTrigger asChild>

View File

@ -1694,6 +1694,7 @@ This delimiter is used to split the input text into several text pieces echo of
searchMethod: 'Search method', searchMethod: 'Search method',
filenameEmbdWeight: 'Filename embd weight', filenameEmbdWeight: 'Filename embd weight',
begin: 'File', begin: 'File',
parserMethod: 'Parser method',
}, },
}, },
}; };

View File

@ -1604,6 +1604,7 @@ General实体和关系提取提示来自 GitHub - microsoft/graphrag基于
searchMethod: '搜索方法', searchMethod: '搜索方法',
filenameEmbdWeight: '文件名嵌入权重', filenameEmbdWeight: '文件名嵌入权重',
begin: '文件', begin: '文件',
parserMethod: '解析方法',
}, },
}, },
}; };

View File

@ -30,6 +30,7 @@ import { useBeforeDelete } from '../hooks/use-before-delete';
import { useMoveNote } from '../hooks/use-move-note'; import { useMoveNote } from '../hooks/use-move-note';
import { useDropdownManager } from './context'; import { useDropdownManager } from './context';
import { useRunDataflow } from '../hooks/use-run-dataflow';
import { import {
useHideFormSheetOnNodeDeletion, useHideFormSheetOnNodeDeletion,
useShowDrawer, useShowDrawer,
@ -152,6 +153,8 @@ function DataFlowCanvas({ drawerVisible, hideDrawer }: IProps) {
hideModal: hideLogSheet, hideModal: hideLogSheet,
} = useSetModalState(); } = useSetModalState();
const { run, loading: running, messageId } = useRunDataflow(showLogSheet!);
const onConnect = (connection: Connection) => { const onConnect = (connection: Connection) => {
originalOnConnect(connection); originalOnConnect(connection);
isConnectedRef.current = true; isConnectedRef.current = true;
@ -300,10 +303,13 @@ function DataFlowCanvas({ drawerVisible, hideDrawer }: IProps) {
{runVisible && ( {runVisible && (
<RunSheet <RunSheet
hideModal={hideRunOrChatDrawer} hideModal={hideRunOrChatDrawer}
showModal={showLogSheet} run={run}
loading={running}
></RunSheet> ></RunSheet>
)} )}
{logSheetVisible && <LogSheet hideModal={hideLogSheet}></LogSheet>} {logSheetVisible && (
<LogSheet hideModal={hideLogSheet} messageId={messageId}></LogSheet>
)}
</div> </div>
); );
} }

View File

@ -227,7 +227,7 @@ export enum FileType {
Email = 'email', Email = 'email',
TextMarkdown = 'text&markdown', TextMarkdown = 'text&markdown',
Docx = 'word', Docx = 'word',
PowerPoint = 'ppt', PowerPoint = 'slides',
Video = 'video', Video = 'video',
Audio = 'audio', Audio = 'audio',
} }

View File

@ -1,3 +1,4 @@
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 } from '@/components/llm-setting-items/llm-form-field';
import { import {
@ -46,11 +47,13 @@ export function ParserMethodFormField({
prefix, prefix,
optionsWithoutLLM, optionsWithoutLLM,
}: CommonProps & { optionsWithoutLLM?: { value: string; label: string }[] }) { }: CommonProps & { optionsWithoutLLM?: { value: string; label: string }[] }) {
const { t } = useTranslation();
return ( return (
<LayoutRecognizeFormField <LayoutRecognizeFormField
name={buildFieldNameWithPrefix(`parse_method`, prefix)} name={buildFieldNameWithPrefix(`parse_method`, prefix)}
horizontal={false} horizontal={false}
optionsWithoutLLM={optionsWithoutLLM} optionsWithoutLLM={optionsWithoutLLM}
label={t('dataflow.parserMethod')}
></LayoutRecognizeFormField> ></LayoutRecognizeFormField>
); );
} }
@ -62,3 +65,22 @@ export function LargeModelFormField({ prefix }: CommonProps) {
></LLMFormField> ></LLMFormField>
); );
} }
export function LanguageFormField({ prefix }: CommonProps) {
const { t } = useTranslation();
return (
<RAGFlowFormItem
name={buildFieldNameWithPrefix(`lang`, prefix)}
label={t('dataflow.lang')}
>
{(field) => (
<SelectWithSearch
options={crossLanguageOptions}
value={field.value}
onChange={field.onChange}
></SelectWithSearch>
)}
</RAGFlowFormItem>
);
}

View File

@ -1,10 +1,11 @@
import { buildOptions } from '@/utils/form'; import { buildOptions } from '@/utils/form';
import { isEmpty } from 'lodash'; import { isEmpty } from 'lodash';
import { useEffect } from 'react'; import { useEffect, useMemo } from 'react';
import { useFormContext } from 'react-hook-form'; import { useFormContext, useWatch } from 'react-hook-form';
import { ImageParseMethod } from '../../constant'; import { ImageParseMethod } from '../../constant';
import { ParserMethodFormField } from './common-form-fields'; import { LanguageFormField, ParserMethodFormField } from './common-form-fields';
import { CommonProps } from './interface'; import { CommonProps } from './interface';
import { useSetInitialLanguage } from './use-set-initial-language';
import { buildFieldNameWithPrefix } from './utils'; import { buildFieldNameWithPrefix } from './utils';
const options = buildOptions(ImageParseMethod); const options = buildOptions(ImageParseMethod);
@ -13,6 +14,14 @@ export function ImageFormFields({ prefix }: CommonProps) {
const form = useFormContext(); const form = useFormContext();
const parseMethodName = buildFieldNameWithPrefix('parse_method', prefix); const parseMethodName = buildFieldNameWithPrefix('parse_method', prefix);
const parseMethod = useWatch({
name: parseMethodName,
});
const languageShown = useMemo(() => {
return !isEmpty(parseMethod) && parseMethod !== ImageParseMethod.OCR;
}, [parseMethod]);
useEffect(() => { useEffect(() => {
if (isEmpty(form.getValues(parseMethodName))) { if (isEmpty(form.getValues(parseMethodName))) {
form.setValue(parseMethodName, ImageParseMethod.OCR, { form.setValue(parseMethodName, ImageParseMethod.OCR, {
@ -22,12 +31,15 @@ export function ImageFormFields({ prefix }: CommonProps) {
} }
}, [form, parseMethodName]); }, [form, parseMethodName]);
useSetInitialLanguage({ prefix, languageShown });
return ( return (
<> <>
<ParserMethodFormField <ParserMethodFormField
prefix={prefix} prefix={prefix}
optionsWithoutLLM={options} optionsWithoutLLM={options}
></ParserMethodFormField> ></ParserMethodFormField>
{languageShown && <LanguageFormField prefix={prefix}></LanguageFormField>}
</> </>
); );
} }

View File

@ -33,7 +33,9 @@ import { VideoFormFields } from './video-form-fields';
const outputList = buildOutputList(initialParserValues.outputs); const outputList = buildOutputList(initialParserValues.outputs);
const FileFormatOptions = buildOptions(FileType); const FileFormatOptions = buildOptions(FileType).filter(
(x) => x.value !== FileType.Video, // Temporarily hide the video option
);
const FileFormatWidgetMap = { const FileFormatWidgetMap = {
[FileType.PDF]: PdfFormFields, [FileType.PDF]: PdfFormFields,
@ -105,7 +107,7 @@ function ParserItem({ name, index, fieldLength, remove }: ParserItemProps) {
return ( return (
<section <section
className={cn('space-y-5 px-5 py-2.5 rounded-md', { className={cn('space-y-5 py-2.5 rounded-md', {
'bg-state-error-5': isHovering, 'bg-state-error-5': isHovering,
})} })}
> >

View File

@ -1,17 +1,13 @@
import { crossLanguageOptions } from '@/components/cross-language-form-field';
import { ParseDocumentType } from '@/components/layout-recognize-form-field'; import { ParseDocumentType } from '@/components/layout-recognize-form-field';
import { SelectWithSearch } from '@/components/originui/select-with-search';
import { RAGFlowFormItem } from '@/components/ragflow-form';
import { isEmpty } from 'lodash'; import { isEmpty } from 'lodash';
import { useEffect, useMemo } from 'react'; import { useEffect, useMemo } from 'react';
import { useFormContext, useWatch } from 'react-hook-form'; import { useFormContext, useWatch } from 'react-hook-form';
import { useTranslation } from 'react-i18next'; import { LanguageFormField, ParserMethodFormField } from './common-form-fields';
import { ParserMethodFormField } from './common-form-fields';
import { CommonProps } from './interface'; import { CommonProps } from './interface';
import { useSetInitialLanguage } from './use-set-initial-language';
import { buildFieldNameWithPrefix } from './utils'; import { buildFieldNameWithPrefix } from './utils';
export function PdfFormFields({ prefix }: CommonProps) { export function PdfFormFields({ prefix }: CommonProps) {
const { t } = useTranslation();
const form = useFormContext(); const form = useFormContext();
const parseMethodName = buildFieldNameWithPrefix('parse_method', prefix); const parseMethodName = buildFieldNameWithPrefix('parse_method', prefix);
@ -19,7 +15,6 @@ export function PdfFormFields({ prefix }: CommonProps) {
const parseMethod = useWatch({ const parseMethod = useWatch({
name: parseMethodName, name: parseMethodName,
}); });
const lang = form.getValues(buildFieldNameWithPrefix('lang', prefix));
const languageShown = useMemo(() => { const languageShown = useMemo(() => {
return ( return (
@ -29,18 +24,7 @@ export function PdfFormFields({ prefix }: CommonProps) {
); );
}, [parseMethod]); }, [parseMethod]);
useEffect(() => { useSetInitialLanguage({ prefix, languageShown });
if (languageShown && isEmpty(lang)) {
form.setValue(
buildFieldNameWithPrefix('lang', prefix),
crossLanguageOptions[0].value,
{
shouldValidate: true,
shouldDirty: true,
},
);
}
}, [form, lang, languageShown, prefix]);
useEffect(() => { useEffect(() => {
if (isEmpty(form.getValues(parseMethodName))) { if (isEmpty(form.getValues(parseMethodName))) {
@ -54,20 +38,7 @@ export function PdfFormFields({ prefix }: CommonProps) {
return ( return (
<> <>
<ParserMethodFormField prefix={prefix}></ParserMethodFormField> <ParserMethodFormField prefix={prefix}></ParserMethodFormField>
{languageShown && ( {languageShown && <LanguageFormField prefix={prefix}></LanguageFormField>}
<RAGFlowFormItem
name={buildFieldNameWithPrefix(`lang`, prefix)}
label={t('dataflow.lang')}
>
{(field) => (
<SelectWithSearch
options={crossLanguageOptions}
value={field.value}
onChange={field.onChange}
></SelectWithSearch>
)}
</RAGFlowFormItem>
)}
</> </>
); );
} }

View File

@ -0,0 +1,29 @@
import { crossLanguageOptions } from '@/components/cross-language-form-field';
import { isEmpty } from 'lodash';
import { useEffect } from 'react';
import { useFormContext } from 'react-hook-form';
import { buildFieldNameWithPrefix } from './utils';
export function useSetInitialLanguage({
prefix,
languageShown,
}: {
prefix: string;
languageShown: boolean;
}) {
const form = useFormContext();
const lang = form.getValues(buildFieldNameWithPrefix('lang', prefix));
useEffect(() => {
if (languageShown && isEmpty(lang)) {
form.setValue(
buildFieldNameWithPrefix('lang', prefix),
crossLanguageOptions[0].value,
{
shouldValidate: true,
shouldDirty: true,
},
);
}
}, [form, lang, languageShown, prefix]);
}

View File

@ -9,7 +9,6 @@ import {
useMemo, useMemo,
useState, useState,
} from 'react'; } from 'react';
import { Operator } from '../constant';
import useGraphStore from '../store'; import useGraphStore from '../store';
import { getAgentNodeTools } from '../utils'; import { getAgentNodeTools } from '../utils';
@ -77,13 +76,10 @@ export const useHandleNodeNameChange = ({
data: any; data: any;
}) => { }) => {
const [name, setName] = useState<string>(''); const [name, setName] = useState<string>('');
const { updateNodeName, nodes, getOperatorTypeFromId } = useGraphStore( const { updateNodeName, nodes } = useGraphStore((state) => state);
(state) => state,
);
const previousName = data?.name; const previousName = data?.name;
const isToolNode = getOperatorTypeFromId(id) === Operator.Tool;
const { handleToolNameBlur, previousToolName } = useHandleTooNodeNameChange({ const { previousToolName } = useHandleTooNodeNameChange({
id, id,
name, name,
setName, setName,
@ -109,12 +105,12 @@ export const useHandleNodeNameChange = ({
}, []); }, []);
useEffect(() => { useEffect(() => {
setName(isToolNode ? previousToolName : previousName); setName(previousName);
}, [isToolNode, previousName, previousToolName]); }, [previousName, previousToolName]);
return { return {
name, name,
handleNameBlur: isToolNode ? handleToolNameBlur : handleNameBlur, handleNameBlur: handleNameBlur,
handleNameChange, handleNameChange,
}; };
}; };

View File

@ -1,12 +1,14 @@
import { useSendMessageBySSE } from '@/hooks/use-send-message'; import { useSendMessageBySSE } from '@/hooks/use-send-message';
import api from '@/utils/api'; import api from '@/utils/api';
import { useCallback } from 'react'; import { get } from 'lodash';
import { useCallback, useState } from 'react';
import { useParams } from 'umi'; import { useParams } from 'umi';
import { useSaveGraphBeforeOpeningDebugDrawer } from './use-save-graph'; import { useSaveGraphBeforeOpeningDebugDrawer } from './use-save-graph';
export function useRunDataflow(showLogSheet: () => void) { export function useRunDataflow(showLogSheet: () => void) {
const { send } = useSendMessageBySSE(api.runCanvas); const { send } = useSendMessageBySSE(api.runCanvas);
const { id } = useParams(); const { id } = useParams();
const [messageId, setMessageId] = useState();
const { handleRun: saveGraph, loading } = const { handleRun: saveGraph, loading } =
useSaveGraphBeforeOpeningDebugDrawer(showLogSheet!); useSaveGraphBeforeOpeningDebugDrawer(showLogSheet!);
@ -22,12 +24,21 @@ export function useRunDataflow(showLogSheet: () => void) {
files: [fileResponseData.file], files: [fileResponseData.file],
}); });
if (res && res?.response.status === 200 && res?.data?.code === 0) { if (res && res?.response.status === 200 && get(res, 'data.code') === 0) {
// fetch canvas // fetch canvas
const msgId = get(res, 'data.data.message_id');
if (msgId) {
setMessageId(msgId);
}
return msgId;
} }
}, },
[id, saveGraph, send], [id, saveGraph, send],
); );
return { run, loading: loading }; return { run, loading: loading, messageId };
} }
export type RunDataflowType = ReturnType<typeof useRunDataflow>;

View File

@ -8,7 +8,9 @@ import {
TimelineSeparator, TimelineSeparator,
TimelineTitle, TimelineTitle,
} from '@/components/originui/timeline'; } from '@/components/originui/timeline';
import { useFetchMessageTrace } from '@/hooks/use-agent-request';
import { Aperture } from 'lucide-react'; import { Aperture } from 'lucide-react';
import { useEffect } from 'react';
const items = [ const items = [
{ {
@ -48,7 +50,24 @@ const items = [
}, },
]; ];
export function DataflowTimeline() { export type DataflowTimelineProps = { messageId: string };
interface DataflowTrace {
datetime: string;
elapsed_time: number;
message: string;
progress: number;
timestamp: number;
}
export function DataflowTimeline({ messageId }: DataflowTimelineProps) {
const { setMessageId, data } = useFetchMessageTrace(false);
useEffect(() => {
if (messageId) {
setMessageId(messageId);
}
}, [messageId, setMessageId]);
return ( return (
<Timeline> <Timeline>
{items.map((item) => ( {items.map((item) => (

View File

@ -8,18 +8,18 @@ import { IModalProps } from '@/interfaces/common';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { NotebookText } from 'lucide-react'; import { NotebookText } from 'lucide-react';
import 'react18-json-view/src/style.css'; import 'react18-json-view/src/style.css';
import { DataflowTimeline } from './dataflow-timeline'; import { DataflowTimeline, DataflowTimelineProps } from './dataflow-timeline';
type LogSheetProps = IModalProps<any>; type LogSheetProps = IModalProps<any> & DataflowTimelineProps;
export function LogSheet({ hideModal }: LogSheetProps) { export function LogSheet({ hideModal, messageId }: LogSheetProps) {
return ( return (
<Sheet open onOpenChange={hideModal} modal={false}> <Sheet open onOpenChange={hideModal} modal={false}>
<SheetContent className={cn('top-20 right-[620px]')}> <SheetContent className={cn('top-20 right-[620px]')}>
<SheetHeader> <SheetHeader>
<SheetTitle className="flex items-center gap-1"> <SheetTitle className="flex items-center gap-1">
<NotebookText className="size-4" /> <NotebookText className="size-4" />
<DataflowTimeline></DataflowTimeline> <DataflowTimeline messageId={messageId}></DataflowTimeline>
</SheetTitle> </SheetTitle>
</SheetHeader> </SheetHeader>
<section className="max-h-[82vh] overflow-auto mt-6"></section> <section className="max-h-[82vh] overflow-auto mt-6"></section>

View File

@ -7,13 +7,14 @@ import {
import { IModalProps } from '@/interfaces/common'; import { IModalProps } from '@/interfaces/common';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useRunDataflow } from '../hooks/use-run-dataflow'; import { RunDataflowType } from '../hooks/use-run-dataflow';
import { UploaderForm } from './uploader'; import { UploaderForm } from './uploader';
const RunSheet = ({ hideModal, showModal: showLogSheet }: IModalProps<any>) => { type RunSheetProps = IModalProps<any> &
const { t } = useTranslation(); Pick<RunDataflowType, 'run' | 'loading'>;
const { run, loading } = useRunDataflow(showLogSheet!); const RunSheet = ({ hideModal, run, loading }: RunSheetProps) => {
const { t } = useTranslation();
return ( return (
<Sheet onOpenChange={hideModal} open modal={false}> <Sheet onOpenChange={hideModal} open modal={false}>

View File

@ -1,22 +1,10 @@
import { import { IAgentForm } from '@/interfaces/database/agent';
IAgentForm,
ICategorizeItem,
ICategorizeItemResult,
} from '@/interfaces/database/agent';
import { DSLComponents, RAGFlowNodeType } from '@/interfaces/database/flow'; import { DSLComponents, RAGFlowNodeType } from '@/interfaces/database/flow';
import { removeUselessFieldsFromValues } from '@/utils/form'; import { removeUselessFieldsFromValues } from '@/utils/form';
import { Edge, Node, XYPosition } from '@xyflow/react'; import { Edge, Node, XYPosition } from '@xyflow/react';
import { FormInstance, FormListFieldData } from 'antd'; import { FormInstance, FormListFieldData } from 'antd';
import { humanId } from 'human-id'; import { humanId } from 'human-id';
import { import { curry, get, intersectionWith, isEmpty, isEqual, sample } from 'lodash';
curry,
get,
intersectionWith,
isEmpty,
isEqual,
omit,
sample,
} from 'lodash';
import pipe from 'lodash/fp/pipe'; import pipe from 'lodash/fp/pipe';
import isObject from 'lodash/isObject'; import isObject from 'lodash/isObject';
import { import {
@ -30,7 +18,7 @@ import {
import { HierarchicalMergerFormSchemaType } from './form/hierarchical-merger-form'; import { HierarchicalMergerFormSchemaType } from './form/hierarchical-merger-form';
import { ParserFormSchemaType } from './form/parser-form'; import { ParserFormSchemaType } from './form/parser-form';
import { SplitterFormSchemaType } from './form/splitter-form'; import { SplitterFormSchemaType } from './form/splitter-form';
import { BeginQuery, IPosition } from './interface'; import { IPosition } from './interface';
const buildComponentDownstreamOrUpstream = ( const buildComponentDownstreamOrUpstream = (
edges: Edge[], edges: Edge[],
@ -122,6 +110,7 @@ function transformParserParams(params: ParserFormSchemaType) {
filteredSetup = { filteredSetup = {
...filteredSetup, ...filteredSetup,
parse_method: cur.parse_method, parse_method: cur.parse_method,
lang: cur.lang,
}; };
break; break;
case FileType.Email: case FileType.Email:
@ -308,10 +297,6 @@ export const getOtherFieldValues = (
x !== form.getFieldValue([formListName, field.name, latestField]), x !== form.getFieldValue([formListName, field.name, latestField]),
); );
export const generateSwitchHandleText = (idx: number) => {
return `Case ${idx + 1}`;
};
export const getNodeDragHandle = (nodeType?: string) => { export const getNodeDragHandle = (nodeType?: string) => {
return nodeType === Operator.Note ? '.note-drag-handle' : undefined; return nodeType === Operator.Note ? '.note-drag-handle' : undefined;
}; };
@ -400,40 +385,6 @@ export const needsSingleStepDebugging = (label: string) => {
return !NoDebugOperatorsList.some((x) => (label as Operator) === x); return !NoDebugOperatorsList.some((x) => (label as Operator) === x);
}; };
// Get the coordinates of the node relative to the Iteration node
export function getRelativePositionToIterationNode(
nodes: RAGFlowNodeType[],
position?: XYPosition, // relative position
) {
if (!position) {
return;
}
const iterationNodes = nodes.filter(
(node) => node.data.label === Operator.Iteration,
);
for (const iterationNode of iterationNodes) {
const {
position: { x, y },
width,
height,
} = iterationNode;
const halfWidth = (width || 0) / 2;
if (
position.x >= x - halfWidth &&
position.x <= x + halfWidth &&
position.y >= y &&
position.y <= y + (height || 0)
) {
return {
parentId: iterationNode.id,
position: { x: position.x - x + halfWidth, y: position.y - y },
};
}
}
}
export const generateDuplicateNode = ( export const generateDuplicateNode = (
position?: XYPosition, position?: XYPosition,
label?: string, label?: string,
@ -468,71 +419,11 @@ export function convertToObjectArray(list: Array<string | number | boolean>) {
return list.map((x) => ({ value: x })); return list.map((x) => ({ value: x }));
} }
/**
* convert the following object into a list
*
* {
"product_related": {
"description": "The question is about product usage, appearance and how it works.",
"examples": "Why it always beaming?\nHow to install it onto the wall?\nIt leaks, what to do?",
"to": "generate:0"
}
}
*/
export const buildCategorizeListFromObject = (
categorizeItem: ICategorizeItemResult,
) => {
// Categorize's to field has two data sources, with edges as the data source.
// Changes in the edge or to field need to be synchronized to the form field.
return Object.keys(categorizeItem)
.reduce<Array<ICategorizeItem>>((pre, cur) => {
// synchronize edge data to the to field
pre.push({
name: cur,
...categorizeItem[cur],
examples: convertToObjectArray(categorizeItem[cur].examples),
});
return pre;
}, [])
.sort((a, b) => a.index - b.index);
};
/**
* Convert the list in the following form into an object
* {
"items": [
{
"name": "Categorize 1",
"description": "111",
"examples": ["ddd"],
"to": "Retrieval:LazyEelsStick"
}
]
}
*/
export const buildCategorizeObjectFromList = (list: Array<ICategorizeItem>) => {
return list.reduce<ICategorizeItemResult>((pre, cur) => {
if (cur?.name) {
pre[cur.name] = {
...omit(cur, 'name', 'examples'),
examples: convertToStringArray(cur.examples) as string[],
};
}
return pre;
}, {});
};
export function getAgentNodeTools(agentNode?: RAGFlowNodeType) { export function getAgentNodeTools(agentNode?: RAGFlowNodeType) {
const tools: IAgentForm['tools'] = get(agentNode, 'data.form.tools', []); const tools: IAgentForm['tools'] = get(agentNode, 'data.form.tools', []);
return tools; return tools;
} }
export function getAgentNodeMCP(agentNode?: RAGFlowNodeType) {
const tools: IAgentForm['mcp'] = get(agentNode, 'data.form.mcp', []);
return tools;
}
export function mapEdgeMouseEvent( export function mapEdgeMouseEvent(
edges: Edge[], edges: Edge[],
edgeId: string, edgeId: string,
@ -552,21 +443,3 @@ export function mapEdgeMouseEvent(
return nextEdges; return nextEdges;
} }
export function buildBeginQueryWithObject(
inputs: Record<string, BeginQuery>,
values: BeginQuery[],
) {
const nextInputs = Object.keys(inputs).reduce<Record<string, BeginQuery>>(
(pre, key) => {
const item = values.find((x) => x.key === key);
if (item) {
pre[key] = { ...item };
}
return pre;
},
{},
);
return nextInputs;
}