JasonSmithSO's picture
Upload 578 files
8866644 verified
import { app } from "../../../../scripts/app.js";
function links_with(p, node_id, down, up) {
const links_with = [];
p.workflow.links.forEach((l) => {
if (down && l[1]===node_id && !links_with.includes(l[3])) links_with.push(l[3])
if (up && l[3]===node_id && !links_with.includes(l[1])) links_with.push(l[1])
});
return links_with;
}
function _all_v_nodes(p, here_id) {
/*
Make a list of all downstream nodes.
*/
const downstream = [];
const to_process = [here_id]
while(to_process.length>0) {
const id = to_process.pop();
downstream.push(id);
to_process.push(
...links_with(p,id,true,false).filter((nid)=>{
return !(downstream.includes(nid) || to_process.includes(nid))
})
)
}
/*
Now all upstream nodes from any of the downstream nodes (except us).
Put us on the result list so we don't flow up through us
*/
to_process.push(...downstream.filter((n)=>{ return n!=here_id}));
const back_upstream = [here_id];
while(to_process.length>0) {
const id = to_process.pop();
back_upstream.push(id);
to_process.push(
...links_with(p,id,false,true).filter((nid)=>{
return !(back_upstream.includes(nid) || to_process.includes(nid))
})
)
}
const keep = [];
keep.push(...downstream);
keep.push(...back_upstream.filter((n)=>{return !keep.includes(n)}));
console.log(`Nodes to keep: ${keep}`);
return keep;
}
async function all_v_nodes(here_id) {
const p = structuredClone(await app.graphToPrompt());
const all_nodes = [];
p.workflow.nodes.forEach((node)=>{all_nodes.push(node.id)})
p.workflow.links = p.workflow.links.filter((l)=>{ return (all_nodes.includes(l[1]) && all_nodes.includes(l[3]))} )
return _all_v_nodes(p,here_id);
}
async function restart_from_here(here_id, go_down_to_chooser=false) {
const p = structuredClone(await app.graphToPrompt());
/*
Make a list of all nodes, and filter out links that are no longer valid
*/
const all_nodes = [];
p.workflow.nodes.forEach((node)=>{all_nodes.push(node.id)})
p.workflow.links = p.workflow.links.filter((l)=>{ return (all_nodes.includes(l[1]) && all_nodes.includes(l[3]))} )
/* Move downstream to a chooser */
if (go_down_to_chooser) {
while (!app.graph._nodes_by_id[here_id].isChooser) {
here_id = links_with(p, here_id, true, false)[0];
}
}
const keep = _all_v_nodes(p, here_id);
/*
Filter p.workflow.nodes and p.workflow.links
*/
p.workflow.nodes = p.workflow.nodes.filter((node) => {
if (node.id===here_id) node.inputs.forEach((i)=>{i.link=null}) // remove our upstream links
return (keep.includes(node.id)) // only keep keepers
})
p.workflow.links = p.workflow.links.filter((l) => {return (keep.includes(l[1]) && keep.includes(l[3]))})
/*
Filter the p.output object to only include nodes we're keeping
*/
const new_output = {}
for (const [key, value] of Object.entries(p.output)) {
if (keep.includes(parseInt(key))) new_output[key] = value;
}
/*
Filter the p.output entry for the start node to remove any list (ie link) inputs
*/
const new_inputs = {};
for (const [key, value] of Object.entries(new_output[here_id.toString()].inputs)) {
if (!Array.isArray(value)) new_inputs[key] = value;
}
new_output[here_id.toString()].inputs = new_inputs;
p.output = new_output;
// temporarily hijack graph_to_prompt with a version that restores the old one but returns this prompt
const gtp_was = app.graphToPrompt;
app.graphToPrompt = () => {
app.graphToPrompt = gtp_was;
return p;
}
app.queuePrompt(0);
}
export { restart_from_here, all_v_nodes }