146 lines
4.3 KiB
JavaScript
146 lines
4.3 KiB
JavaScript
import { DATA_TYPES } from './constants.js';
|
|
|
|
function getInputName(handleId) {
|
|
return handleId.split('::')[1];
|
|
}
|
|
|
|
function getOutputSlot(handleId) {
|
|
return parseInt(handleId.split('::')[1], 10);
|
|
}
|
|
|
|
function resolveExecutionEdge(edge) {
|
|
const original = edge?.data?.groupProxyOriginal;
|
|
if (!original) return edge;
|
|
return {
|
|
...edge,
|
|
source: original.source || edge.source,
|
|
sourceHandle: original.sourceHandle || edge.sourceHandle,
|
|
target: original.target || edge.target,
|
|
targetHandle: original.targetHandle || edge.targetHandle,
|
|
};
|
|
}
|
|
|
|
export function getConnectedNodeIds(edges) {
|
|
const connectedNodeIds = new Set();
|
|
for (const edge of edges) {
|
|
const resolved = resolveExecutionEdge(edge);
|
|
connectedNodeIds.add(resolved.source);
|
|
connectedNodeIds.add(resolved.target);
|
|
}
|
|
return connectedNodeIds;
|
|
}
|
|
|
|
function isPreviewLoadNode(node) {
|
|
return ['Image', 'ImageDemo'].includes(node?.data?.className);
|
|
}
|
|
|
|
function hasPreviewLoadSelection(node) {
|
|
if (node?.data?.className === 'Image') {
|
|
return !!String(node.data?.widgetValues?.filename || '').trim();
|
|
}
|
|
if (node?.data?.className === 'ImageDemo') {
|
|
return !!String(node.data?.widgetValues?.name || '').trim();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function getRunnableNodeIds(nodes, edges) {
|
|
const connectedNodeIds = getConnectedNodeIds(edges);
|
|
|
|
const runnableNodeIds = new Set(connectedNodeIds);
|
|
for (const node of nodes) {
|
|
if (connectedNodeIds.has(node.id)) continue;
|
|
if (isPreviewLoadNode(node) && hasPreviewLoadSelection(node)) {
|
|
runnableNodeIds.add(node.id);
|
|
}
|
|
}
|
|
|
|
return runnableNodeIds;
|
|
}
|
|
|
|
export function serializeExecutionGraph(nodes, edges, { excludeManualTrigger = false } = {}) {
|
|
const runnableNodeIds = getRunnableNodeIds(nodes, edges);
|
|
const prompt = {};
|
|
|
|
for (const node of nodes) {
|
|
if (!runnableNodeIds.has(node.id)) continue;
|
|
|
|
const { className, definition, widgetValues, runtimeValues } = node.data;
|
|
if (className === 'Group') continue;
|
|
if (!definition) continue;
|
|
if (excludeManualTrigger && definition.manual_trigger) continue;
|
|
|
|
const inputs = {};
|
|
const valueBag = { ...(widgetValues || {}), ...(runtimeValues || {}) };
|
|
|
|
const allWidgets = {
|
|
...(definition.input.required || {}),
|
|
...(definition.input.optional || {}),
|
|
};
|
|
for (const [name, spec] of Object.entries(allWidgets)) {
|
|
const [type] = Array.isArray(spec) ? spec : [spec];
|
|
if (DATA_TYPES.has(type)) continue;
|
|
if (type === 'BUTTON') continue;
|
|
if (valueBag[name] !== undefined) {
|
|
inputs[name] = valueBag[name];
|
|
}
|
|
}
|
|
|
|
const incoming = edges
|
|
.map(resolveExecutionEdge)
|
|
.filter((edge) => edge.target === node.id);
|
|
for (const edge of incoming) {
|
|
const inputName = getInputName(edge.targetHandle);
|
|
const outputSlot = getOutputSlot(edge.sourceHandle);
|
|
inputs[inputName] = [edge.source, outputSlot];
|
|
}
|
|
|
|
prompt[node.id] = { class_type: className, inputs };
|
|
}
|
|
|
|
return prompt;
|
|
}
|
|
|
|
export function getAutoRunnableNodes(nodes, edges) {
|
|
const runnableNodeIds = getRunnableNodeIds(nodes, edges);
|
|
return nodes.filter((node) => runnableNodeIds.has(node.id));
|
|
}
|
|
|
|
export function hasBlockingAutoRunInput(node, edges) {
|
|
const def = node.data?.definition;
|
|
if (!def || def.manual_trigger) return false;
|
|
|
|
const required = def.input.required || {};
|
|
for (const [name, spec] of Object.entries(required)) {
|
|
const [type, opts] = Array.isArray(spec) ? spec : [spec, {}];
|
|
const hiddenByConnectedInput = (() => {
|
|
const raw = opts?.hide_when_input_connected;
|
|
if (!raw) return false;
|
|
const inputs = Array.isArray(raw) ? raw : [raw];
|
|
return inputs.some((inputName) => edges.some(
|
|
(edge) => {
|
|
const resolved = resolveExecutionEdge(edge);
|
|
return resolved.target === node.id && getInputName(resolved.targetHandle) === String(inputName);
|
|
}
|
|
));
|
|
})();
|
|
|
|
if (hiddenByConnectedInput) continue;
|
|
|
|
if (type === 'FILE_PICKER' || type === 'FOLDER_PICKER') {
|
|
if (!node.data.widgetValues?.[name]) return true;
|
|
continue;
|
|
}
|
|
if (!DATA_TYPES.has(type)) continue;
|
|
const hasEdge = edges.some(
|
|
(edge) => {
|
|
const resolved = resolveExecutionEdge(edge);
|
|
return resolved.target === node.id && getInputName(resolved.targetHandle) === name;
|
|
}
|
|
);
|
|
if (!hasEdge) return true;
|
|
}
|
|
|
|
return false;
|
|
}
|