File size: 3,145 Bytes
baac5bb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import { app } from "../../scripts/app.js";

function mimicNode(node, target, slot) {
  const getWidget = (widget) => {
    if (typeof widget.origType === "undefined") return widget;
    const newWidget = new Proxy(widget, {
      has(target, prop) {
        return prop in target && prop !== "origType" && prop !== "computeSize";
      },
      get(target, prop) {
        if (prop.startsWith("orig") || prop === "computeSize") {
          return undefined;
        } else if (prop === "type") {
          return target.origType;
        } else if (prop === "name") {
          return inputName;
        } else {
          return target[prop];
        }
      },
      set(target, prop, value) {
        target[prop] = value;
        return true;
      }
    });
    return newWidget;
  }
  const input = target.inputs[slot];
  const inputName = node.inputs.length > 0 ? node.inputs[0].name : node.widgets[0].name;
  if (typeof input.widget === "undefined") {  // This is an input
    node.inputs = [{ ...input, name: inputName }];
    node.widgets = [];
  } else {  // This is a widget
    node.widgets = [getWidget(target.widgets.find(w => w.name === input.name))];
    node.inputs = [];
    node.size = node.computeSize();
    requestAnimationFrame(() => {
      if (node.onResize) {
        node.onResize(node.size);
      }
    });
  }
}

app.registerExtension({
	name: "Comfy.DynamicInput",
  dynamicNodes: ["CPackInputAny", "CPackInputFile"],

	async beforeRegisterNodeDef(nodeType, nodeData) {
    if (!this.dynamicNodes.includes(nodeData.name)) return;

    nodeType.prototype.onConnectOutput = function () {
      if (this.outputs[0].links?.length > 0) return false;
      const target = arguments[3];
      if (this.type === "CPackInputFile" && !["COMBO", "STRING"].includes(target.inputs[arguments[4]].type))
        return false;
      mimicNode(this, target, arguments[4]);
      this.title = target.inputs[arguments[4]].name;
    }
  },

  async setup(app) {
    app.graph.nodes.forEach((node) => {
      if (!this.dynamicNodes.includes(node.type)) return;
      if (node.outputs.length > 0 && node.outputs[0].links.length > 0) {
        const link = node.graph.links[node.outputs[0].links[0]];
        mimicNode(node, app.graph.getNodeById(link.target_id), link.target_slot);
      }
    })
  },

  async init(app) {
    const originalToPrompt = app.graphToPrompt;
    const self = this;
    app.graphToPrompt = async function(graph = app.graph, clean = true) {
      const { workflow, output } = await originalToPrompt(graph, clean);
      Object.entries(output).forEach(([id, nodeData]) => {
        if (!nodeData.class_type.startsWith("CPackInput")) return;
        const node = graph.getNodeById(parseInt(id));
        if (!nodeData["_meta"]) {
          nodeData["_meta"] = { title: node.title };
        }
        if (node.widgets.length === 0) return;
        const widget = node.widgets[0];
        nodeData["_meta"] = { ...nodeData["_meta"], options: widget.options };
      });
      return { workflow, output };
    };
  }
});