diff --git a/packages/global/core/workflow/constants.ts b/packages/global/core/workflow/constants.ts index 0ca64623f..b02fc83b0 100644 --- a/packages/global/core/workflow/constants.ts +++ b/packages/global/core/workflow/constants.ts @@ -256,9 +256,9 @@ export enum NodeOutputKeyEnum { // loop loopArray = 'loopArray', - // loop start loopStartInput = 'loopStartInput', + loopArrayIndex = 'loopArrayIndex', // form input formInputResult = 'formInputResult' diff --git a/packages/global/core/workflow/template/system/loop/loopStart.ts b/packages/global/core/workflow/template/system/loop/loopStart.ts index 96ded8e69..3a41a8b78 100644 --- a/packages/global/core/workflow/template/system/loop/loopStart.ts +++ b/packages/global/core/workflow/template/system/loop/loopStart.ts @@ -1,8 +1,13 @@ -import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../../../node/constant'; +import { + FlowNodeInputTypeEnum, + FlowNodeOutputTypeEnum, + FlowNodeTypeEnum +} from '../../../node/constant'; import { FlowNodeTemplateType } from '../../../type/node.d'; import { FlowNodeTemplateTypeEnum, NodeInputKeyEnum, + NodeOutputKeyEnum, WorkflowIOValueTypeEnum } from '../../../constants'; import { getHandleConfig } from '../../utils'; @@ -30,5 +35,13 @@ export const LoopStartNode: FlowNodeTemplateType = { value: '' } ], - outputs: [] + outputs: [ + { + id: NodeOutputKeyEnum.loopArrayIndex, + key: NodeOutputKeyEnum.loopArrayIndex, + label: i18nT('workflow:Array_element_index'), + type: FlowNodeOutputTypeEnum.static, + valueType: WorkflowIOValueTypeEnum.number + } + ] }; diff --git a/packages/service/core/workflow/dispatch/loop/runLoop.ts b/packages/service/core/workflow/dispatch/loop/runLoop.ts index eb0b8b57e..d94038c9d 100644 --- a/packages/service/core/workflow/dispatch/loop/runLoop.ts +++ b/packages/service/core/workflow/dispatch/loop/runLoop.ts @@ -43,6 +43,7 @@ export const dispatchLoop = async (props: Props): Promise => { let totalPoints = 0; let newVariables: Record = props.variables; + let index = 0; for await (const item of loopInputArray.filter(Boolean)) { runtimeNodes.forEach((node) => { if ( @@ -50,14 +51,21 @@ export const dispatchLoop = async (props: Props): Promise => { node.flowNodeType === FlowNodeTypeEnum.loopStart ) { node.isEntry = true; - node.inputs = node.inputs.map((input) => - input.key === NodeInputKeyEnum.loopStartInput - ? { - ...input, - value: item - } - : input - ); + node.inputs = node.inputs.map((input) => { + if (input.key === NodeInputKeyEnum.loopStartInput) { + return { + ...input, + value: item + }; + } else if (input.key === NodeInputKeyEnum.loopStartInput) { + return { + ...input, + value: index++ + }; + } else { + return input; + } + }); } }); const response = await dispatchWorkFlow({ diff --git a/packages/web/i18n/en/workflow.json b/packages/web/i18n/en/workflow.json index 4b54ff34f..9112f3a26 100644 --- a/packages/web/i18n/en/workflow.json +++ b/packages/web/i18n/en/workflow.json @@ -1,5 +1,6 @@ { "Array_element": "Array element", + "Array_element_index": "Index", "Code": "Code", "Confirm_sync_node": "It will be updated to the latest node configuration and fields that do not exist in the template will be deleted (including all custom fields).\n\nIf the fields are complex, it is recommended that you copy a node first and then update the original node to facilitate parameter copying.", "Node.Open_Node_Course": "Open node course", diff --git a/packages/web/i18n/zh/workflow.json b/packages/web/i18n/zh/workflow.json index e5f964d0d..1c54c3d8e 100644 --- a/packages/web/i18n/zh/workflow.json +++ b/packages/web/i18n/zh/workflow.json @@ -1,5 +1,6 @@ { "Array_element": "数组元素", + "Array_element_index": "下标", "Code": "代码", "Confirm_sync_node": "将会更新至最新的节点配置,不存在模板中的字段将会被删除(包括所有自定义字段)。\n如果字段较为复杂,建议您先复制一份节点,再更新原来的节点,便于参数复制。", "Node.Open_Node_Course": "查看节点教程", diff --git a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/Loop/NodeLoop.tsx b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/Loop/NodeLoop.tsx index 1fed1610b..2d7060e89 100644 --- a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/Loop/NodeLoop.tsx +++ b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/Loop/NodeLoop.tsx @@ -43,15 +43,11 @@ const NodeLoop = ({ data, selected }: NodeProps) => { const { resetParentNodeSizeAndPosition } = useWorkflow(); - const loopInputArray = useMemo( - () => inputs.find((input) => input.key === NodeInputKeyEnum.loopInputArray), - [inputs] - ); - - const { nodeWidth, nodeHeight } = useMemo(() => { + const { nodeWidth, nodeHeight, loopInputArray } = useMemo(() => { return { nodeWidth: inputs.find((input) => input.key === NodeInputKeyEnum.nodeWidth)?.value, - nodeHeight: inputs.find((input) => input.key === NodeInputKeyEnum.nodeHeight)?.value + nodeHeight: inputs.find((input) => input.key === NodeInputKeyEnum.nodeHeight)?.value, + loopInputArray: inputs.find((input) => input.key === NodeInputKeyEnum.loopInputArray) }; }, [inputs]); diff --git a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/Loop/NodeLoopStart.tsx b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/Loop/NodeLoopStart.tsx index f3d4b0f1d..b418425ee 100644 --- a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/Loop/NodeLoopStart.tsx +++ b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/Loop/NodeLoopStart.tsx @@ -8,11 +8,15 @@ import { WorkflowContext } from '../../../context'; import { NodeInputKeyEnum, NodeOutputKeyEnum, + toolValueTypeList, WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants'; import { Box, Flex, Table, TableContainer, Tbody, Td, Th, Thead, Tr } from '@chakra-ui/react'; import React, { useEffect, useMemo } from 'react'; -import { FlowNodeOutputTypeEnum } from '@fastgpt/global/core/workflow/node/constant'; +import { + FlowNodeOutputTypeEnum, + FlowValueTypeMap +} from '@fastgpt/global/core/workflow/node/constant'; import MyIcon from '@fastgpt/web/components/common/Icon'; const typeMap = { @@ -24,7 +28,7 @@ const typeMap = { const NodeLoopStart = ({ data, selected }: NodeProps) => { const { t } = useTranslation(); - const { nodeId } = data; + const { nodeId, outputs } = data; const { nodeList, onChangeNode } = useContextSelector(WorkflowContext, (v) => v); const loopStartNode = useMemo( @@ -94,23 +98,21 @@ const NodeLoopStart = ({ data, selected }: NodeProps) => { debug: true }} > - - {!loopItemInputType ? ( - - ) : ( - - - - - - - - - - - + + + +
- {t('workflow:Variable_name')} - {t('common:core.workflow.Value type')}
+ + + + + + + + {outputs.map((output) => ( + - + {output.valueType && } - -
+ {t('workflow:Variable_name')} + {t('common:core.workflow.Value type')}
) => { mr={1} color={'primary.600'} /> - {t('workflow:Array_element')} + {t(output.label)} {loopItemInputType}{FlowValueTypeMap[output.valueType]?.label}
-
-
- )} + ))} + + + +
); - }, [data, loopItemInputType, selected, t]); + }, [data, outputs, selected, t]); return Render; };