Workflow deep and workflow connection performance (#2664)

* feat: Workflow dispatch deep

* perf: workflow connection
This commit is contained in:
Archer
2024-09-10 16:57:59 +08:00
committed by GitHub
parent 7473be5922
commit aeba79267a
21 changed files with 274 additions and 1300 deletions

View File

@@ -36,3 +36,6 @@ HOME_URL=/
# 日志等级: debug, info, warn, error
LOG_LEVEL=debug
STORE_LOG_LEVEL=warn
# 工作流最大运行次数,避免极端的死循环情况
WORKFLOW_MAX_RUN_TIMES=500

View File

@@ -27,6 +27,7 @@ import {
import { StoreNodeItemType } from '@fastgpt/global/core/workflow/type/node';
import { getWorkflowResponseWrite } from '@fastgpt/service/core/workflow/dispatch/utils';
import { getNanoid } from '@fastgpt/global/common/string/tools';
import { WORKFLOW_MAX_RUN_TIMES } from '@fastgpt/service/core/workflow/constants';
export type Props = {
messages: ChatCompletionMessageParam[];
@@ -120,7 +121,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
chatConfig,
histories: chatMessages,
stream: true,
maxRunTimes: 200,
maxRunTimes: WORKFLOW_MAX_RUN_TIMES,
workflowStreamResponse: workflowResponseWrite
});

View File

@@ -9,6 +9,7 @@ import { PostWorkflowDebugProps, PostWorkflowDebugResponse } from '@/global/core
import { NextAPI } from '@/service/middleware/entry';
import { ReadPermissionVal } from '@fastgpt/global/support/permission/constant';
import { defaultApp } from '@/web/core/app/constants';
import { WORKFLOW_MAX_RUN_TIMES } from '@fastgpt/service/core/workflow/constants';
async function handler(
req: NextApiRequest,
@@ -57,7 +58,7 @@ async function handler(
chatConfig: defaultApp.chatConfig,
histories: [],
stream: false,
maxRunTimes: 200
maxRunTimes: WORKFLOW_MAX_RUN_TIMES
});
pushChatUsage({

View File

@@ -59,6 +59,7 @@ import { getSystemTime } from '@fastgpt/global/common/time/timezone';
import { rewriteNodeOutputByHistories } from '@fastgpt/global/core/workflow/runtime/utils';
import { getWorkflowResponseWrite } from '@fastgpt/service/core/workflow/dispatch/utils';
import { getPluginRunUserQuery } from '@fastgpt/service/core/workflow/utils';
import { WORKFLOW_MAX_RUN_TIMES } from '@fastgpt/service/core/workflow/constants';
type FastGptWebChatProps = {
chatId?: string; // undefined: get histories from messages, '': new chat, 'xxxxx': get histories from db
@@ -264,7 +265,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
chatConfig,
histories: newHistories,
stream,
maxRunTimes: 200,
maxRunTimes: WORKFLOW_MAX_RUN_TIMES,
workflowStreamResponse: workflowResponseWrite
});
}

View File

@@ -11,88 +11,98 @@ export const ConnectionSourceHandle = ({ nodeId }: { nodeId: string }) => {
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
const edges = useContextSelector(WorkflowContext, (v) => v.edges);
const node = useMemo(() => nodeList.find((node) => node.nodeId === nodeId), [nodeList, nodeId]);
const { showSourceHandle, RightHandle, LeftHandlee, TopHandlee, BottomHandlee } = useMemo(() => {
const node = nodeList.find((node) => node.nodeId === nodeId);
/* not node/not connecting node, hidden */
const showSourceHandle = useMemo(() => {
if (!node) return false;
if (connectingEdge && connectingEdge.nodeId !== nodeId) return false;
return true;
}, [connectingEdge, node, nodeId]);
/* not node/not connecting node, hidden */
const showSourceHandle = (() => {
if (!node) return false;
if (connectingEdge && connectingEdge.nodeId !== nodeId) return false;
return true;
})();
const RightHandle = useMemo(() => {
const handleId = getHandleId(nodeId, 'source', Position.Right);
const rightTargetConnected = edges.some(
(edge) => edge.targetHandle === getHandleId(nodeId, 'target', Position.Right)
);
const RightHandle = (() => {
const handleId = getHandleId(nodeId, 'source', Position.Right);
const rightTargetConnected = edges.some(
(edge) => edge.targetHandle === getHandleId(nodeId, 'target', Position.Right)
);
if (!node || !node?.sourceHandle?.right || rightTargetConnected) return null;
if (!node || !node?.sourceHandle?.right || rightTargetConnected) return null;
return (
<SourceHandle
nodeId={nodeId}
handleId={handleId}
position={Position.Right}
translate={[2, 0]}
/>
);
}, [edges, node, nodeId]);
const LeftHandlee = useMemo(() => {
const leftTargetConnected = edges.some(
(edge) => edge.targetHandle === getHandleId(nodeId, 'target', Position.Left)
);
if (!node || !node?.sourceHandle?.left || leftTargetConnected) return null;
return (
<SourceHandle
nodeId={nodeId}
handleId={handleId}
position={Position.Right}
translate={[2, 0]}
/>
);
})();
const LeftHandlee = (() => {
const leftTargetConnected = edges.some(
(edge) => edge.targetHandle === getHandleId(nodeId, 'target', Position.Left)
);
if (!node || !node?.sourceHandle?.left || leftTargetConnected) return null;
const handleId = getHandleId(nodeId, 'source', Position.Left);
const handleId = getHandleId(nodeId, 'source', Position.Left);
return (
<SourceHandle
nodeId={nodeId}
handleId={handleId}
position={Position.Left}
translate={[-6, 0]}
/>
);
}, [edges, node, nodeId]);
const TopHandlee = useMemo(() => {
if (
edges.some(
(edge) => edge.target === nodeId && edge.targetHandle === NodeOutputKeyEnum.selectedTools
return (
<SourceHandle
nodeId={nodeId}
handleId={handleId}
position={Position.Left}
translate={[-6, 0]}
/>
);
})();
const TopHandlee = (() => {
if (
edges.some(
(edge) => edge.target === nodeId && edge.targetHandle === NodeOutputKeyEnum.selectedTools
)
)
)
return null;
return null;
const handleId = getHandleId(nodeId, 'source', Position.Top);
const topTargetConnected = edges.some(
(edge) => edge.targetHandle === getHandleId(nodeId, 'target', Position.Top)
);
if (!node || !node?.sourceHandle?.top || topTargetConnected) return null;
const handleId = getHandleId(nodeId, 'source', Position.Top);
const topTargetConnected = edges.some(
(edge) => edge.targetHandle === getHandleId(nodeId, 'target', Position.Top)
);
if (!node || !node?.sourceHandle?.top || topTargetConnected) return null;
return (
<SourceHandle
nodeId={nodeId}
handleId={handleId}
position={Position.Top}
translate={[0, -2]}
/>
);
}, [edges, node, nodeId]);
const BottomHandlee = useMemo(() => {
const handleId = getHandleId(nodeId, 'source', Position.Bottom);
const targetConnected = edges.some(
(edge) => edge.targetHandle === getHandleId(nodeId, 'target', Position.Bottom)
);
if (!node || !node?.sourceHandle?.bottom || targetConnected) return null;
return (
<SourceHandle
nodeId={nodeId}
handleId={handleId}
position={Position.Top}
translate={[0, -2]}
/>
);
})();
const BottomHandlee = (() => {
const handleId = getHandleId(nodeId, 'source', Position.Bottom);
const targetConnected = edges.some(
(edge) => edge.targetHandle === getHandleId(nodeId, 'target', Position.Bottom)
);
if (!node || !node?.sourceHandle?.bottom || targetConnected) return null;
return (
<SourceHandle
nodeId={nodeId}
handleId={handleId}
position={Position.Bottom}
translate={[0, 2]}
/>
);
}, [edges, node, nodeId]);
return (
<SourceHandle
nodeId={nodeId}
handleId={handleId}
position={Position.Bottom}
translate={[0, 2]}
/>
);
})();
return {
showSourceHandle,
RightHandle,
LeftHandlee,
TopHandlee,
BottomHandlee
};
}, [connectingEdge, edges, nodeId, nodeList]);
return showSourceHandle ? (
<>
@@ -104,74 +114,96 @@ export const ConnectionSourceHandle = ({ nodeId }: { nodeId: string }) => {
) : null;
};
export const ConnectionTargetHandle = ({ nodeId }: { nodeId: string }) => {
export const ConnectionTargetHandle = React.memo(function ConnectionTargetHandle({
nodeId
}: {
nodeId: string;
}) {
const connectingEdge = useContextSelector(WorkflowContext, (ctx) => ctx.connectingEdge);
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
const edges = useContextSelector(WorkflowContext, (v) => v.edges);
const node = useMemo(() => nodeList.find((node) => node.nodeId === nodeId), [nodeList, nodeId]);
const { showHandle, LeftHandle, rightHandle, topHandle, bottomHandle } = useMemo(() => {
const node = nodeList.find((node) => node.nodeId === nodeId);
const connectingNode = nodeList.find((node) => node.nodeId === connectingEdge?.nodeId);
const showHandle = useMemo(() => {
if (!node) return false;
if (connectingEdge && connectingEdge.nodeId === nodeId) return false;
return true;
}, [connectingEdge, node, nodeId]);
const sourceEdges = edges.filter((edge) => edge.target === connectingNode?.nodeId);
const connectingNodeSourceNodeIds = sourceEdges.map((edge) => edge.source);
const LeftHandle = useMemo(() => {
if (!node || !node?.targetHandle?.left) return null;
const showHandle = (() => {
if (!node) return false;
// Unable to connect oneself
if (connectingEdge && connectingEdge.nodeId === nodeId) return false;
// Unable to connect to the source node
if (connectingNodeSourceNodeIds.includes(nodeId)) return false;
return true;
})();
const handleId = getHandleId(nodeId, 'target', Position.Left);
const LeftHandle = (() => {
if (!node || !node?.targetHandle?.left) return null;
return (
<TargetHandle
nodeId={nodeId}
handleId={handleId}
position={Position.Left}
translate={[-2, 0]}
/>
);
}, [node, nodeId]);
const rightHandle = useMemo(() => {
if (!node || !node?.targetHandle?.right) return null;
const handleId = getHandleId(nodeId, 'target', Position.Left);
const handleId = getHandleId(nodeId, 'target', Position.Right);
return (
<TargetHandle
nodeId={nodeId}
handleId={handleId}
position={Position.Left}
translate={[-2, 0]}
/>
);
})();
const rightHandle = (() => {
if (!node || !node?.targetHandle?.right) return null;
return (
<TargetHandle
nodeId={nodeId}
handleId={handleId}
position={Position.Right}
translate={[2, 0]}
/>
);
}, [node, nodeId]);
const topHandle = useMemo(() => {
if (!node || !node?.targetHandle?.top) return null;
const handleId = getHandleId(nodeId, 'target', Position.Right);
const handleId = getHandleId(nodeId, 'target', Position.Top);
return (
<TargetHandle
nodeId={nodeId}
handleId={handleId}
position={Position.Right}
translate={[2, 0]}
/>
);
})();
const topHandle = (() => {
if (!node || !node?.targetHandle?.top) return null;
return (
<TargetHandle
nodeId={nodeId}
handleId={handleId}
position={Position.Top}
translate={[0, -2]}
/>
);
}, [node, nodeId]);
const bottomHandle = useMemo(() => {
if (!node || !node?.targetHandle?.bottom) return null;
const handleId = getHandleId(nodeId, 'target', Position.Top);
const handleId = getHandleId(nodeId, 'target', Position.Bottom);
return (
<TargetHandle
nodeId={nodeId}
handleId={handleId}
position={Position.Top}
translate={[0, -2]}
/>
);
})();
const bottomHandle = (() => {
if (!node || !node?.targetHandle?.bottom) return null;
return (
<TargetHandle
nodeId={nodeId}
handleId={handleId}
position={Position.Bottom}
translate={[0, 2]}
/>
);
}, [node, nodeId]);
const handleId = getHandleId(nodeId, 'target', Position.Bottom);
return (
<TargetHandle
nodeId={nodeId}
handleId={handleId}
position={Position.Bottom}
translate={[0, 2]}
/>
);
})();
return {
showHandle,
LeftHandle,
rightHandle,
topHandle,
bottomHandle
};
}, [connectingEdge, edges, nodeId, nodeList]);
return showHandle ? (
<>
@@ -181,7 +213,7 @@ export const ConnectionTargetHandle = ({ nodeId }: { nodeId: string }) => {
{bottomHandle}
</>
) : null;
};
});
export default function Dom() {
return <></>;

View File

@@ -248,6 +248,14 @@ const NodeCard = (props: Props) => {
onChangeNode,
toast
]);
const RenderHandle = useMemo(() => {
return (
<>
<ConnectionSourceHandle nodeId={nodeId} />
<ConnectionTargetHandle nodeId={nodeId} />
</>
);
}, [nodeId]);
return (
<Box
@@ -283,8 +291,7 @@ const NodeCard = (props: Props) => {
<NodeDebugResponse nodeId={nodeId} debugResult={debugResult} />
{Header}
{children}
<ConnectionSourceHandle nodeId={nodeId} />
<ConnectionTargetHandle nodeId={nodeId} />
{RenderHandle}
<EditTitleModal maxLength={20} />
</Box>

View File

@@ -13,6 +13,7 @@ import {
import { UsageSourceEnum } from '@fastgpt/global/support/wallet/usage/constants';
import { addLog } from '@fastgpt/service/common/system/log';
import { MongoApp } from '@fastgpt/service/core/app/schema';
import { WORKFLOW_MAX_RUN_TIMES } from '@fastgpt/service/core/workflow/constants';
import { dispatchWorkFlow } from '@fastgpt/service/core/workflow/dispatch';
export const getScheduleTriggerApp = async () => {
@@ -55,7 +56,7 @@ export const getScheduleTriggerApp = async () => {
chatConfig: defaultApp.chatConfig,
histories: [],
stream: false,
maxRunTimes: 200
maxRunTimes: WORKFLOW_MAX_RUN_TIMES
});
pushChatUsage({
appName: app.name,