import { GroupNodeHandler } from "../core/groupNode.js"; import { UseEverywhereList } from "./use_everywhere_classes.js"; import { add_ue_from_node, add_ue_from_node_in_group } from "./use_everywhere_nodes.js"; import { node_in_loop, node_is_live, is_connected, is_UEnode, Logger, get_real_node } from "./use_everywhere_utilities.js"; import { app } from "../../scripts/app.js"; class GraphAnalyser { static _instance; static instance() { if (!this._instance) this._instance = new GraphAnalyser(); return this._instance; } constructor() { this.original_graphToPrompt = app.graphToPrompt; this.ambiguity_messages = []; this.pause_depth = 0; } pause() { this.pause_depth += 1; } unpause() { this.pause_depth -= 1; } async analyse_graph(modify_and_return_prompt=false, check_for_loops=false, supress_before_queued=true) { //try { /*if (supress_before_queued) { app.graph._nodes.forEach((node) => { node.widgets?.forEach((widget) => { if (widget.beforeQueued) { widget.__beforeQueued = widget.beforeQueued; widget.beforeQueued = null; } }) if(node.seedControl && node.seedControl.lastSeedButton){ // for efficiency nodes seedControl node.seedControl.lastSeedButton.__disabled = node.seedControl.lastSeedButton.disabled node.seedControl.lastSeedButton.disabled = true } }) }*/ //return this._analyse_graph(modify_and_return_prompt, check_for_loops); /*} finally { if (supress_before_queued) { app.graph._nodes.forEach((node) => { node.widgets?.forEach((widget) => { if (widget.__beforeQueued) { widget.beforeQueued = widget.__beforeQueued; widget.__beforeQueued = null; } }) if(node.seedControl && node.seedControl.lastSeedButton){ // for efficiency nodes seedControl node.seedControl.lastSeedButton.disabled = node.seedControl.lastSeedButton.__disabled } }) } }*/ //} //async _analyse_graph(modify_and_return_prompt=false, check_for_loops=false) { if (this.pause_depth > 0) { return this.original_graphToPrompt.apply(app) } this.ambiguity_messages = []; var p; if (modify_and_return_prompt) { p = await this.original_graphToPrompt.apply(app); p = structuredClone(p); } else { p = { workflow:app.graph.serialize() } } // Create a UseEverywhereList and populate it from all live (not bypassed) nodes const ues = new UseEverywhereList(); const live_nodes = p.workflow.nodes.filter((node) => node_is_live(node)) live_nodes.filter((node) => is_UEnode(node)).forEach(node => { add_ue_from_node(ues, node); }) live_nodes.filter((node) => (get_real_node(node.id, Logger.INFORMATION) && GroupNodeHandler.isGroupNode(get_real_node(node.id)))).forEach( groupNode => { const group_data = GroupNodeHandler.getGroupData(get_real_node(groupNode.id)); group_data.nodeData.nodes.filter((node) => is_UEnode(node)).forEach(node => { add_ue_from_node_in_group(ues, node, groupNode.id, group_data); }) }) const links_added = new Set(); // Look for unconnected inputs and see if we can connect them live_nodes.filter((node) => !is_UEnode(node)).forEach(node => { const nd = get_real_node(node.id, Logger.INFORMATION); if (nd) { var gpData = GroupNodeHandler.getGroupData(nd); const isGrp = !!gpData; const o2n = isGrp ? Object.entries(gpData.oldToNewInputMap) : null; node.inputs?.forEach(input => { if (!is_connected(input) && !(node.reject_ue_connection && node.reject_ue_connection(input))) { var ue = ues.find_best_match(node, input, this.ambiguity_messages); if (ue && modify_and_return_prompt) { var effective_node = node; var effective_node_slot = -1; if (isGrp) { // the node we are looking at is a group node const in_index = node.inputs.findIndex((i)=>i==input); const inner_node_index = o2n.findIndex((l)=>Object.values(l[1]).includes(in_index)); const inner_node_slot_index = Object.values(o2n[inner_node_index][1]).findIndex((l)=>l==in_index); effective_node_slot = Object.keys(o2n[inner_node_index][1])[inner_node_slot_index]; effective_node = nd.getInnerNodes()[o2n[inner_node_index][0]]; } const upNode = get_real_node(ue.output[0]); var effective_output = [ue.output[0], ue.output[1]]; if (GroupNodeHandler.isGroupNode(upNode)) { // the upstream node is a group node const upGpData = GroupNodeHandler.getGroupData(upNode); const up_inner_node = upGpData.newToOldOutputMap[ue.output[1]].node; const up_inner_node_index = up_inner_node.index; const up_inner_node_id = upNode.getInnerNodes()[up_inner_node_index].id; const up_inner_node_slot = upGpData.newToOldOutputMap[ue.output[1]].slot; effective_output = [`${up_inner_node_id}`, up_inner_node_slot]; } if (effective_node_slot==-1) effective_node_slot = effective_node.inputs.findIndex((i)=>(i.label ? i.label : i.name)===(input.label ? input.label : input.name)); p.output[effective_node.id].inputs[effective_node.inputs[effective_node_slot].name] = effective_output; links_added.add({ "downstream":effective_node.id, "downstream_slot":effective_node_slot, "upstream":effective_output[0], "upstream_slot":effective_output[1], "controller":ue.controller.id, "type":ue.type }); } } }); } }); if (this.ambiguity_messages.length) Logger.log(Logger.PROBLEM, "Ambiguous connections", this.ambiguity_messages, Logger.CAT_AMBIGUITY); // if there are loops report them and raise an exception if (check_for_loops && app.ui.settings.getSettingValue('AE.checkloops', true)) { try { node_in_loop(live_nodes, links_added); } catch (e) { if (!e.stack) throw e; if (e.ues && e.ues.length > 0){ alert(`Loop (${e.stack}) with broadcast (${e.ues}) - not submitting workflow`); } else { alert(`Loop (${e.stack}) - not submitting workflow`); } throw new Error(`Loop Detected ${e.stack}, ${e.ues}`, {"cause":e}); } } if (modify_and_return_prompt) { [...links_added].forEach((l)=>{ p.workflow.last_link_id += 1; p.workflow.links.push([p.workflow.last_link_id, parseInt(l.upstream), l.upstream_slot, l.downstream, l.downstream_slot, l.type]) }) return p; } else return ues; } } export { GraphAnalyser }