File size: 8,284 Bytes
681fa96
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
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 && !nd.properties.rejects_ue_links) {
                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 }