Skip to content

Commit

Permalink
loop-node
Browse files Browse the repository at this point in the history
  • Loading branch information
newfish-cmyk committed Sep 12, 2024
1 parent 35798de commit 2da6357
Show file tree
Hide file tree
Showing 18 changed files with 327 additions and 97 deletions.
12 changes: 10 additions & 2 deletions packages/global/core/workflow/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,12 @@ export enum NodeInputKeyEnum {
// loop
loopInputArray = 'loopInputArray',
loopFlow = 'loopFlow',
loopOutputArray = 'loopOutputArray'

// loop start
loopArrayElement = 'loopArrayElement',

// loop end
loopOutputArrayElement = 'loopOutputArrayElement'
}

export enum NodeOutputKeyEnum {
Expand Down Expand Up @@ -187,7 +192,10 @@ export enum NodeOutputKeyEnum {
selectResult = 'selectResult',

// loop
loopArray = 'loopArray'
loopArray = 'loopArray',

// loop start
loopArrayElement = 'loopArrayElement'
}

export enum VariableInputEnum {
Expand Down
10 changes: 10 additions & 0 deletions packages/global/core/workflow/runtime/type.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,16 @@ export type DispatchNodeResponseType = {

// update var
updateVarResult?: any[];

// loop start
loopInputElement?: any;
// loop end
loopOutputElement?: any;

// loop
loopResult?: any[];
loopInput?: any[];
loopDetail?: ChatHistoryItemResType[];
};

export type DispatchNodeResultType<T = {}> = {
Expand Down
6 changes: 4 additions & 2 deletions packages/global/core/workflow/template/system/loop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ export const LoopNode: FlowNodeTemplateType = {
renderTypeList: [FlowNodeInputTypeEnum.reference],
valueType: WorkflowIOValueTypeEnum.arrayAny,
required: true,
label: i18nT('workflow:loop_input_array')
label: i18nT('workflow:loop_input_array'),
value: []
},
{
key: NodeInputKeyEnum.loopFlow,
Expand All @@ -39,7 +40,8 @@ export const LoopNode: FlowNodeTemplateType = {
label: '',
value: {
width: 0,
height: 0
height: 0,
childNodes: []
}
}
],
Expand Down
4 changes: 2 additions & 2 deletions packages/global/core/workflow/template/system/loopEnd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ export const LoopEndNode: FlowNodeTemplateType = {
version: '4811',
inputs: [
{
key: NodeInputKeyEnum.loopOutputArray,
key: NodeInputKeyEnum.loopOutputArrayElement,
renderTypeList: [FlowNodeInputTypeEnum.reference],
valueType: WorkflowIOValueTypeEnum.arrayAny,
valueType: WorkflowIOValueTypeEnum.any,
label: '',
required: true,
value: []
Expand Down
19 changes: 16 additions & 3 deletions packages/global/core/workflow/template/system/loopStart.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { FlowNodeTypeEnum } from '../../node/constant';
import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '../../node/constant';
import { FlowNodeTemplateType } from '../../type/node.d';
import { FlowNodeTemplateTypeEnum } from '../../constants';
import {
FlowNodeTemplateTypeEnum,
NodeInputKeyEnum,
WorkflowIOValueTypeEnum
} from '../../constants';
import { getHandleConfig } from '../utils';
import { i18nT } from '../../../../../web/i18n/utils';

Expand All @@ -16,6 +20,15 @@ export const LoopStartNode: FlowNodeTemplateType = {
forbidDelete: true,
showStatus: false,
version: '4811',
inputs: [],
inputs: [
{
key: NodeInputKeyEnum.loopArrayElement,
renderTypeList: [FlowNodeInputTypeEnum.hidden],
valueType: WorkflowIOValueTypeEnum.any,
label: '',
required: true,
value: ''
}
],
outputs: []
};
6 changes: 6 additions & 0 deletions packages/service/core/workflow/dispatch/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ import {
UserSelectInteractive
} from '@fastgpt/global/core/workflow/template/system/userSelect/type';
import { dispatchRunAppNode } from './plugin/runApp';
import { dispatchLoop } from './tools/runLoop';
import { dispatchLoopEnd } from './tools/runLoopEnd';
import { dispatchLoopStart } from './tools/runLoopStart';

const callbackMap: Record<FlowNodeTypeEnum, Function> = {
[FlowNodeTypeEnum.workflowStart]: dispatchWorkflowStart,
Expand All @@ -91,6 +94,9 @@ const callbackMap: Record<FlowNodeTypeEnum, Function> = {
[FlowNodeTypeEnum.customFeedback]: dispatchCustomFeedback,
[FlowNodeTypeEnum.readFiles]: dispatchReadFiles,
[FlowNodeTypeEnum.userSelect]: dispatchUserSelect,
[FlowNodeTypeEnum.loop]: dispatchLoop,
[FlowNodeTypeEnum.loopStart]: dispatchLoopStart,
[FlowNodeTypeEnum.loopEnd]: dispatchLoopEnd,

// none
[FlowNodeTypeEnum.systemConfig]: dispatchSystemConfig,
Expand Down
67 changes: 67 additions & 0 deletions packages/service/core/workflow/dispatch/tools/runLoop.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import { FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant';
import {
DispatchNodeResultType,
ModuleDispatchProps
} from '@fastgpt/global/core/workflow/runtime/type';
import { dispatchWorkFlow } from '..';
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
import { ChatHistoryItemResType } from '@fastgpt/global/core/chat/type';

type Props = ModuleDispatchProps<{
[NodeInputKeyEnum.loopInputArray]: Array<any>;
[NodeInputKeyEnum.loopFlow]: { childNodes: Array<string> };
}>;
type Response = DispatchNodeResultType<{
[NodeOutputKeyEnum.loopArray]: any[];
}>;

export const dispatchLoop = async (props: Props): Promise<Response> => {
const { params, runtimeNodes } = props;
const {
loopInputArray,
loopFlow: { childNodes }
} = params;
const runNodes = runtimeNodes.filter((node) => childNodes.includes(node.nodeId));
const outputArray = [];
const loopDetail: ChatHistoryItemResType[] = [];

for (const element of loopInputArray) {
const response = await dispatchWorkFlow({
...props,
runtimeNodes: runNodes.map((node) =>
node.flowNodeType === FlowNodeTypeEnum.loopStart
? {
...node,
isEntry: true,
inputs: node.inputs.map((input) =>
input.key === NodeInputKeyEnum.loopArrayElement
? {
...input,
value: element
}
: input
)
}
: {
...node,
isEntry: false
}
)
});
const loopOutputElement = response.flowResponses.find(
(res) => res.moduleType === FlowNodeTypeEnum.loopEnd
)?.loopOutputElement;
outputArray.push(loopOutputElement);
loopDetail.push(...response.flowResponses);
}

return {
[DispatchNodeResponseKeyEnum.nodeResponse]: {
loopInput: loopInputArray,
loopResult: outputArray,
loopDetail: loopDetail
},
[NodeOutputKeyEnum.loopArray]: outputArray
};
};
21 changes: 21 additions & 0 deletions packages/service/core/workflow/dispatch/tools/runLoopEnd.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
import {
DispatchNodeResultType,
ModuleDispatchProps
} from '@fastgpt/global/core/workflow/runtime/type';

type Props = ModuleDispatchProps<{
[NodeInputKeyEnum.loopOutputArrayElement]: any;
}>;
type Response = DispatchNodeResultType<{}>;

export const dispatchLoopEnd = async (props: Props): Promise<Response> => {
const { params } = props;

return {
[DispatchNodeResponseKeyEnum.nodeResponse]: {
loopOutputElement: params.loopOutputArrayElement
}
};
};
24 changes: 24 additions & 0 deletions packages/service/core/workflow/dispatch/tools/runLoopStart.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { NodeInputKeyEnum, NodeOutputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
import {
DispatchNodeResultType,
ModuleDispatchProps
} from '@fastgpt/global/core/workflow/runtime/type';

type Props = ModuleDispatchProps<{
[NodeInputKeyEnum.loopArrayElement]: any;
}>;
type Response = DispatchNodeResultType<{
[NodeOutputKeyEnum.loopArrayElement]: any;
}>;

export const dispatchLoopStart = async (props: Props): Promise<Response> => {
const { params } = props;

return {
[DispatchNodeResponseKeyEnum.nodeResponse]: {
loopInputElement: params.loopArrayElement
},
[NodeOutputKeyEnum.loopArrayElement]: params.loopArrayElement
};
};
8 changes: 6 additions & 2 deletions packages/web/i18n/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,11 @@
"search using reRank": "Result Re-Rank",
"text output": "Text Output",
"update_var_result": "Variable Update Result (Displays Multiple Variable Update Results in Order)",
"user_select_result": "User Selection Result"
"user_select_result": "User Selection Result",
"loop_input": "Loop Input Array",
"loop_output": "Loop Output Array",
"loop_input_element": "Loop Input Element",
"loop_output_element": "Loop Output Element"
},
"retry": "Regenerate",
"tts": {
Expand Down Expand Up @@ -1482,4 +1486,4 @@
"verification": "Verification",
"xx_search_result": "{{key}} Search Results",
"yes": "Yes"
}
}
8 changes: 6 additions & 2 deletions packages/web/i18n/zh/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,11 @@
"search using reRank": "结果重排",
"text output": "文本输出",
"update_var_result": "变量更新结果(按顺序展示多个变量更新结果)",
"user_select_result": "用户选择结果"
"user_select_result": "用户选择结果",
"loop_input": "输入数组",
"loop_output": "输出数组",
"loop_input_element": "输入数组元素",
"loop_output_element": "输出数组元素"
},
"retry": "重新生成",
"tts": {
Expand Down Expand Up @@ -1482,4 +1486,4 @@
"verification": "验证",
"xx_search_result": "{{key}} 的搜索结果",
"yes": ""
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import Markdown from '@/components/Markdown';
import { QuoteList } from '../ChatContainer/ChatBox/components/QuoteModal';
import { DatasetSearchModeMap } from '@fastgpt/global/core/dataset/constants';
import { formatNumber } from '@fastgpt/global/common/math/tools';
import { useI18n } from '@/web/context/I18n';
import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip';
import Avatar from '@fastgpt/web/components/common/Avatar';
import { useSystem } from '@fastgpt/web/hooks/useSystem';
Expand Down Expand Up @@ -40,6 +39,7 @@ export const WholeResponseContent = ({
showDetail: boolean;
}) => {
const { t } = useTranslation();
console.log('activeModule', activeModule);

// Auto scroll to top
const ContentRef = useRef<HTMLDivElement>(null);
Expand Down Expand Up @@ -337,6 +337,22 @@ export const WholeResponseContent = ({
label={t('common:core.chat.response.update_var_result')}
value={activeModule?.updateVarResult}
/>

{/* loop */}
<Row label={t('common:core.chat.response.loop_input')} value={activeModule?.loopInput} />
<Row label={t('common:core.chat.response.loop_output')} value={activeModule?.loopResult} />

{/* loopStart */}
<Row
label={t('common:core.chat.response.loop_input_element')}
value={activeModule?.loopInputElement}
/>

{/* loopEnd */}
<Row
label={t('common:core.chat.response.loop_output_element')}
value={activeModule?.loopOutputElement}
/>
</Box>
) : null;
};
Expand Down Expand Up @@ -525,6 +541,9 @@ export const ResponseBox = React.memo(function ResponseBox({
if (Array.isArray(item.pluginDetail)) {
helper(item.pluginDetail);
}
if (Array.isArray(item.loopDetail)) {
helper(item.loopDetail);
}
}
});
}
Expand Down Expand Up @@ -552,9 +571,10 @@ export const ResponseBox = React.memo(function ResponseBox({
function pretreatmentResponse(res: ChatHistoryItemResType[]): sideTabItemType[] {
return res.map((item) => {
let children: sideTabItemType[] = [];
if (!!(item?.toolDetail || item?.pluginDetail)) {
if (!!(item?.toolDetail || item?.pluginDetail || item?.loopDetail)) {
if (item?.toolDetail) children.push(...pretreatmentResponse(item?.toolDetail));
if (item?.pluginDetail) children.push(...pretreatmentResponse(item?.pluginDetail));
if (item?.loopDetail) children.push(...pretreatmentResponse(item?.loopDetail));
}

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,8 @@ const RenderList = React.memo(function RenderList({
},
position: { x: mouseX, y: mouseY },
selected: true,
zIndex: templateNode.flowNodeType === FlowNodeTypeEnum.loop ? -1001 : 0
zIndex: templateNode.flowNodeType === FlowNodeTypeEnum.loop ? -1001 : 0,
t
});
const newNodes = [newNode];

Expand All @@ -503,12 +504,14 @@ const RenderList = React.memo(function RenderList({
const startNode = nodeTemplate2FlowNode({
template: loopStartNode,
position: { x: mouseX + 60, y: mouseY + 280 },
parentNodeId: newNode.id
parentNodeId: newNode.id,
t
});
const endNode = nodeTemplate2FlowNode({
template: { ...loopEndNode },
template: loopEndNode,
position: { x: mouseX + 420, y: mouseY + 680 },
parentNodeId: newNode.id
parentNodeId: newNode.id,
t
});

newNodes.push(startNode, endNode);
Expand Down
Loading

0 comments on commit 2da6357

Please sign in to comment.