Count disconnected frontend nodes in upstream check

Closes #103
This commit is contained in:
space-nuko
2023-06-01 12:54:27 -05:00
parent 634d16a182
commit afd3c05d0b
3 changed files with 72 additions and 68 deletions

View File

@@ -4,8 +4,8 @@
import Accordion from "./gradio/app/Accordion.svelte"; import Accordion from "./gradio/app/Accordion.svelte";
import uiState from '$lib/stores/uiState'; import uiState from '$lib/stores/uiState';
import type { ComfyNodeDefInputType } from "$lib/ComfyNodeDef"; import type { ComfyNodeDefInputType } from "$lib/ComfyNodeDef";
import type { INodeInputSlot, LGraphNode, Subgraph } from "@litegraph-ts/core"; import type { INodeInputSlot, LGraphNode, LLink, Subgraph } from "@litegraph-ts/core";
import { UpstreamNodeLocator } from "./ComfyPromptSerializer"; import { UpstreamNodeLocator, getUpstreamLink } from "./ComfyPromptSerializer";
import JsonView from "./JsonView.svelte"; import JsonView from "./JsonView.svelte";
export let app: ComfyApp; export let app: ComfyApp;
@@ -35,7 +35,7 @@
const node = app.lCanvas.graph.getNodeByIdRecursive(error.nodeID); const node = app.lCanvas.graph.getNodeByIdRecursive(error.nodeID);
const inputIndex =node.findInputSlotIndexByName(error.input.name); const inputIndex = node.findInputSlotIndexByName(error.input.name);
if (inputIndex === -1) { if (inputIndex === -1) {
return return
} }
@@ -43,7 +43,10 @@
// TODO multiple tags? // TODO multiple tags?
const tag: string | null = error.queueEntry.extraData.extra_pnginfo.comfyBoxPrompt.subgraphs[0]; const tag: string | null = error.queueEntry.extraData.extra_pnginfo.comfyBoxPrompt.subgraphs[0];
const test = (node: LGraphNode) => (node as any).isBackendNode const test = (node: LGraphNode, currentLink: LLink) => {
const [nextGraph, nextLink, nextInputSlot, nextNode] = getUpstreamLink(node, currentLink)
return nextLink == null;
};
const nodeLocator = new UpstreamNodeLocator(test) const nodeLocator = new UpstreamNodeLocator(test)
const [_, foundLink, foundInputSlot, foundPrevNode] = nodeLocator.locateUpstream(node, inputIndex, tag); const [_, foundLink, foundInputSlot, foundPrevNode] = nodeLocator.locateUpstream(node, inputIndex, tag);

View File

@@ -71,13 +71,9 @@ export function isActiveBackendNode(node: LGraphNode, tag: string | null = null)
return true; return true;
} }
type UpstreamResult = [LGraph | null, LLink | null, number | null, LGraphNode | null]; export type UpstreamResult = [LGraph | null, LLink | null, number | null, LGraphNode | null];
export class UpstreamNodeLocator { function followSubgraph(subgraph: Subgraph, link: LLink): UpstreamResult {
constructor(private isTheTargetNode: (node: LGraphNode) => boolean) {
}
private followSubgraph(subgraph: Subgraph, link: LLink): UpstreamResult {
if (link.origin_id != subgraph.id) if (link.origin_id != subgraph.id)
throw new Error("Invalid link and graph output!") throw new Error("Invalid link and graph output!")
@@ -87,9 +83,9 @@ export class UpstreamNodeLocator {
const nextLink = innerGraphOutput.getInputLink(0) const nextLink = innerGraphOutput.getInputLink(0)
return [innerGraphOutput.graph, nextLink, 0, innerGraphOutput]; return [innerGraphOutput.graph, nextLink, 0, innerGraphOutput];
} }
private followGraphInput(graphInput: GraphInput, link: LLink): UpstreamResult { function followGraphInput(graphInput: GraphInput, link: LLink): UpstreamResult {
if (link.origin_id != graphInput.id) if (link.origin_id != graphInput.id)
throw new Error("Invalid link and graph input!") throw new Error("Invalid link and graph input!")
@@ -103,16 +99,16 @@ export class UpstreamNodeLocator {
const nextLink = outerSubgraph.getInputLink(outerInputIndex) const nextLink = outerSubgraph.getInputLink(outerInputIndex)
return [outerSubgraph.graph, nextLink, outerInputIndex, outerSubgraph]; return [outerSubgraph.graph, nextLink, outerInputIndex, outerSubgraph];
} }
private getUpstreamLink(parent: LGraphNode, currentLink: LLink): UpstreamResult { export function getUpstreamLink(parent: LGraphNode, currentLink: LLink): UpstreamResult {
if (parent.is(Subgraph)) { if (parent.is(Subgraph)) {
console.debug("FollowSubgraph") console.debug("FollowSubgraph")
return this.followSubgraph(parent, currentLink); return followSubgraph(parent, currentLink);
} }
else if (parent.is(GraphInput)) { else if (parent.is(GraphInput)) {
console.debug("FollowGraphInput") console.debug("FollowGraphInput")
return this.followGraphInput(parent, currentLink); return followGraphInput(parent, currentLink);
} }
else if ("getUpstreamLink" in parent) { else if ("getUpstreamLink" in parent) {
const link = (parent as ComfyGraphNode).getUpstreamLink(); const link = (parent as ComfyGraphNode).getUpstreamLink();
@@ -127,6 +123,10 @@ export class UpstreamNodeLocator {
} }
console.warn("[graphToPrompt] Frontend node does not support getUpstreamLink", parent.type) console.warn("[graphToPrompt] Frontend node does not support getUpstreamLink", parent.type)
return [null, null, null, null]; return [null, null, null, null];
}
export class UpstreamNodeLocator {
constructor(private isTheTargetNode: (node: LGraphNode, currentLink: LLink) => boolean) {
} }
/* /*
@@ -146,8 +146,8 @@ export class UpstreamNodeLocator {
let currentInputSlot = inputIndex; let currentInputSlot = inputIndex;
let currentNode = fromNode; let currentNode = fromNode;
const shouldFollowParent = (parent: LGraphNode) => { const shouldFollowParent = (parent: LGraphNode, currentLink: LLink) => {
return isActiveNode(parent, tag) && !this.isTheTargetNode(parent); return isActiveNode(parent, tag) && !this.isTheTargetNode(parent, currentLink);
} }
// If there are non-target nodes between us and another // If there are non-target nodes between us and another
@@ -156,8 +156,8 @@ export class UpstreamNodeLocator {
// will simply follow their single input, while branching // will simply follow their single input, while branching
// nodes have conditional logic that determines which link // nodes have conditional logic that determines which link
// to follow backwards. // to follow backwards.
while (shouldFollowParent(parent)) { while (shouldFollowParent(parent, currentLink)) {
const [nextGraph, nextLink, nextInputSlot, nextNode] = this.getUpstreamLink(parent, currentLink); const [nextGraph, nextLink, nextInputSlot, nextNode] = getUpstreamLink(parent, currentLink);
currentInputSlot = nextInputSlot; currentInputSlot = nextInputSlot;
currentNode = nextNode; currentNode = nextNode;
@@ -183,7 +183,7 @@ export class UpstreamNodeLocator {
} }
} }
if (!isActiveNode(parent, tag) || !this.isTheTargetNode(parent) || currentLink == null) if (!isActiveNode(parent, tag) || !this.isTheTargetNode(parent, currentLink) || currentLink == null)
return [null, currentLink, currentInputSlot, currentNode]; return [null, currentLink, currentInputSlot, currentNode];
return [parent, currentLink, currentInputSlot, currentNode] return [parent, currentLink, currentInputSlot, currentNode]

View File

@@ -3,7 +3,7 @@ import ComfyGraphNode, { type ComfyGraphNodeProperties } from "./ComfyGraphNode"
import { Watch } from "@litegraph-ts/nodes-basic"; import { Watch } from "@litegraph-ts/nodes-basic";
import { nextLetter } from "$lib/utils"; import { nextLetter } from "$lib/utils";
export type PickFirstMode = "anyActiveLink" | "truthy" | "dataNonNull" export type PickFirstMode = "anyActiveLink" | "dataTruthy" | "dataNonNull"
export interface ComfyPickFirstNodeProperties extends ComfyGraphNodeProperties { export interface ComfyPickFirstNodeProperties extends ComfyGraphNodeProperties {
mode: PickFirstMode mode: PickFirstMode
@@ -12,7 +12,7 @@ export interface ComfyPickFirstNodeProperties extends ComfyGraphNodeProperties {
export default class ComfyPickFirstNode extends ComfyGraphNode { export default class ComfyPickFirstNode extends ComfyGraphNode {
override properties: ComfyPickFirstNodeProperties = { override properties: ComfyPickFirstNodeProperties = {
tags: [], tags: [],
mode: "dataNonNull" mode: "anyActiveLink"
} }
static slotLayout: SlotLayout = { static slotLayout: SlotLayout = {
@@ -36,7 +36,7 @@ export default class ComfyPickFirstNode extends ComfyGraphNode {
super(title); super(title);
this.displayWidget = this.addWidget("text", "Value", "") this.displayWidget = this.addWidget("text", "Value", "")
this.displayWidget.disabled = true; this.displayWidget.disabled = true;
this.modeWidget = this.addWidget("combo", "Mode", this.properties.mode, null, { property: "mode", values: ["anyActiveLink", "truthy", "dataNonNull"] }) this.modeWidget = this.addWidget("combo", "Mode", this.properties.mode, null, { property: "mode", values: ["anyActiveLink", "dataTruthy", "dataNonNull"] })
} }
override onDrawBackground(ctx: CanvasRenderingContext2D) { override onDrawBackground(ctx: CanvasRenderingContext2D) {
@@ -45,7 +45,7 @@ export default class ComfyPickFirstNode extends ComfyGraphNode {
} }
if (this.selected === -1) { if (this.selected === -1) {
// Draw an X // Draw an X indicating nothing matched the selection criteria
const y = LiteGraph.NODE_SLOT_HEIGHT + 6; const y = LiteGraph.NODE_SLOT_HEIGHT + 6;
ctx.lineWidth = 5; ctx.lineWidth = 5;
ctx.strokeStyle = "red"; ctx.strokeStyle = "red";
@@ -60,6 +60,7 @@ export default class ComfyPickFirstNode extends ComfyGraphNode {
ctx.stroke(); ctx.stroke();
} }
else { else {
// Draw an arrow pointing to the selected input
ctx.fillStyle = "#AFB"; ctx.fillStyle = "#AFB";
const y = (this.selected) * LiteGraph.NODE_SLOT_HEIGHT + 6; const y = (this.selected) * LiteGraph.NODE_SLOT_HEIGHT + 6;
ctx.beginPath(); ctx.beginPath();
@@ -130,7 +131,7 @@ export default class ComfyPickFirstNode extends ComfyGraphNode {
else { else {
if (this.properties.mode === "dataNonNull") if (this.properties.mode === "dataNonNull")
return link.data != null; return link.data != null;
else if (this.properties.mode === "truthy") else if (this.properties.mode === "dataTruthy")
return Boolean(link.data) return Boolean(link.data)
else // anyActiveLink else // anyActiveLink
return true; return true;