Skip to content

Commit 9359c03

Browse files
psychedelicioushipsterusername
authored andcommitted
feat(ui): use zod-less workflow builder when appropriate
1 parent 598241e commit 9359c03

File tree

3 files changed

+75
-33
lines changed

3 files changed

+75
-33
lines changed

invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedNodes.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { enqueueRequested } from 'app/store/actions';
22
import { buildNodesGraph } from 'features/nodes/util/graph/buildNodesGraph';
3-
import { buildWorkflow } from 'features/nodes/util/workflow/buildWorkflow';
3+
import {
4+
buildWorkflowRight,
5+
} from 'features/nodes/util/workflow/buildWorkflow';
46
import { queueApi } from 'services/api/endpoints/queue';
57
import type { BatchConfig } from 'services/api/types';
68

@@ -15,14 +17,16 @@ export const addEnqueueRequestedNodes = () => {
1517
const { nodes, edges } = state.nodes;
1618
const workflow = state.workflow;
1719
const graph = buildNodesGraph(state.nodes);
18-
const builtWorkflow = buildWorkflow({
20+
const builtWorkflow = buildWorkflowRight({
1921
nodes,
2022
edges,
2123
workflow,
2224
});
2325

24-
// embedded workflows don't have an id
25-
delete builtWorkflow.id;
26+
if (builtWorkflow) {
27+
// embedded workflows don't have an id
28+
delete builtWorkflow.id;
29+
}
2630

2731
const batchConfig: BatchConfig = {
2832
batch: {

invokeai/frontend/web/src/features/nodes/hooks/useWorkflowWatcher.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import { useAppSelector } from 'app/store/storeHooks';
22
import type { WorkflowV2 } from 'features/nodes/types/workflow';
33
import type { BuildWorkflowArg } from 'features/nodes/util/workflow/buildWorkflow';
4-
import { buildWorkflow } from 'features/nodes/util/workflow/buildWorkflow';
4+
import { buildWorkflowFast } from 'features/nodes/util/workflow/buildWorkflow';
55
import { debounce } from 'lodash-es';
66
import { atom } from 'nanostores';
77
import { useEffect } from 'react';
88

99
export const $builtWorkflow = atom<WorkflowV2 | null>(null);
1010

1111
const debouncedBuildWorkflow = debounce((arg: BuildWorkflowArg) => {
12-
$builtWorkflow.set(buildWorkflow(arg));
12+
$builtWorkflow.set(buildWorkflowFast(arg));
1313
}, 300);
1414

1515
export const useWorkflowWatcher = () => {

invokeai/frontend/web/src/features/nodes/util/workflow/buildWorkflow.ts

Lines changed: 65 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ import { logger } from 'app/logging/logger';
22
import { parseify } from 'common/util/serialize';
33
import type { NodesState, WorkflowsState } from 'features/nodes/store/types';
44
import { isInvocationNode, isNotesNode } from 'features/nodes/types/invocation';
5-
import type { WorkflowV2 } from 'features/nodes/types/workflow';
6-
import { zWorkflowEdge, zWorkflowNode } from 'features/nodes/types/workflow';
5+
import { type WorkflowV2, zWorkflowV2 } from 'features/nodes/types/workflow';
76
import i18n from 'i18n';
87
import { cloneDeep, omit } from 'lodash-es';
98
import { fromZodError } from 'zod-validation-error';
@@ -16,46 +15,85 @@ export type BuildWorkflowArg = {
1615

1716
export type BuildWorkflowFunction = (arg: BuildWorkflowArg) => WorkflowV2;
1817

19-
export const buildWorkflow: BuildWorkflowFunction = ({
18+
export const buildWorkflowFast: BuildWorkflowFunction = ({
2019
nodes,
2120
edges,
2221
workflow,
23-
}) => {
22+
}: BuildWorkflowArg): WorkflowV2 => {
2423
const clonedWorkflow = omit(cloneDeep(workflow), 'isTouched');
25-
const clonedNodes = cloneDeep(nodes);
26-
const clonedEdges = cloneDeep(edges);
2724

2825
const newWorkflow: WorkflowV2 = {
2926
...clonedWorkflow,
3027
nodes: [],
3128
edges: [],
3229
};
3330

34-
clonedNodes
35-
.filter((n) => isInvocationNode(n) || isNotesNode(n)) // Workflows only contain invocation and notes nodes
36-
.forEach((node) => {
37-
const result = zWorkflowNode.safeParse(node);
38-
if (!result.success) {
39-
const { message } = fromZodError(result.error, {
40-
prefix: i18n.t('nodes.unableToParseNode'),
41-
});
42-
logger('nodes').warn({ node: parseify(node) }, message);
43-
return;
44-
}
45-
newWorkflow.nodes.push(result.data);
46-
});
31+
nodes.forEach((node) => {
32+
if (isInvocationNode(node) && node.type) {
33+
newWorkflow.nodes.push({
34+
id: node.id,
35+
type: node.type,
36+
data: cloneDeep(node.data),
37+
position: { ...node.position },
38+
width: node.width,
39+
height: node.height,
40+
});
41+
} else if (isNotesNode(node) && node.type) {
42+
newWorkflow.nodes.push({
43+
id: node.id,
44+
type: node.type,
45+
data: cloneDeep(node.data),
46+
position: { ...node.position },
47+
width: node.width,
48+
height: node.height,
49+
});
50+
}
51+
});
4752

48-
clonedEdges.forEach((edge) => {
49-
const result = zWorkflowEdge.safeParse(edge);
50-
if (!result.success) {
51-
const { message } = fromZodError(result.error, {
52-
prefix: i18n.t('nodes.unableToParseEdge'),
53+
edges.forEach((edge) => {
54+
if (edge.type === 'default' && edge.sourceHandle && edge.targetHandle) {
55+
newWorkflow.edges.push({
56+
id: edge.id,
57+
type: edge.type,
58+
source: edge.source,
59+
target: edge.target,
60+
sourceHandle: edge.sourceHandle,
61+
targetHandle: edge.targetHandle,
62+
});
63+
} else if (edge.type === 'collapsed') {
64+
newWorkflow.edges.push({
65+
id: edge.id,
66+
type: edge.type,
67+
source: edge.source,
68+
target: edge.target,
5369
});
54-
logger('nodes').warn({ edge: parseify(edge) }, message);
55-
return;
5670
}
57-
newWorkflow.edges.push(result.data);
5871
});
5972

6073
return newWorkflow;
6174
};
75+
76+
export const buildWorkflowRight = ({
77+
nodes,
78+
edges,
79+
workflow,
80+
}: BuildWorkflowArg): WorkflowV2 | null => {
81+
const newWorkflowUnsafe = {
82+
...workflow,
83+
nodes,
84+
edges,
85+
};
86+
87+
const result = zWorkflowV2.safeParse(newWorkflowUnsafe);
88+
89+
if (!result.success) {
90+
const { message } = fromZodError(result.error, {
91+
prefix: i18n.t('nodes.unableToParseNode'),
92+
});
93+
94+
logger('nodes').warn({ workflow: parseify(newWorkflowUnsafe) }, message);
95+
return null;
96+
}
97+
98+
return result.data;
99+
};

0 commit comments

Comments
 (0)