aleph65 commited on
Commit
3a92475
·
verified ·
1 Parent(s): 233b9a9

convert_workflow.py: resolve unwired promoted subgraph inputs from sibling widget defaults

Browse files
workflows/scripts/convert_workflow.py CHANGED
@@ -28,6 +28,13 @@ SUBGRAPH_INPUT_ID = -10
28
  SUBGRAPH_OUTPUT_ID = -20
29
 
30
 
 
 
 
 
 
 
 
31
  class Scope:
32
  """One graph namespace: either the root workflow or a subgraph instance."""
33
 
@@ -85,9 +92,13 @@ class Converter:
85
  # ones live in proxyWidgets instead), so match by name, not slot index
86
  name = self.subgraph_defs[instance["type"]]["inputs"][origin_slot]["name"]
87
  entry = next((i for i in instance.get("inputs", []) if i["name"] == name), None)
88
- if entry is None:
89
- return None # unwired promoted widget: inner node keeps its own value
90
- return self.resolve(parent_scope, entry.get("link"))
 
 
 
 
91
 
92
  node = scope.nodes[origin_id]
93
  ntype = node["type"]
@@ -117,6 +128,25 @@ class Converter:
117
 
118
  return (scope.fid(origin_id), origin_slot)
119
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  def widget_inputs(self, node):
121
  """Map a node's widgets_values onto named inputs using /object_info order."""
122
  if "Power Lora Loader" in node["type"]:
@@ -188,7 +218,11 @@ class Converter:
188
  inputs = self.widget_inputs(node)
189
  for inp in node.get("inputs", []):
190
  source = self.resolve(scope, inp.get("link"))
191
- if source is not None:
 
 
 
 
192
  inputs[inp["name"]] = list(source)
193
  elif inp.get("link") is not None and not inp.get("widget"):
194
  print(f"warning: {scope.fid(nid)} ({ntype}) input {inp['name']!r} "
 
28
  SUBGRAPH_OUTPUT_ID = -20
29
 
30
 
31
+ class WidgetDefault:
32
+ """Literal carried across an unwired promoted subgraph input."""
33
+
34
+ def __init__(self, value):
35
+ self.value = value
36
+
37
+
38
  class Scope:
39
  """One graph namespace: either the root workflow or a subgraph instance."""
40
 
 
92
  # ones live in proxyWidgets instead), so match by name, not slot index
93
  name = self.subgraph_defs[instance["type"]]["inputs"][origin_slot]["name"]
94
  entry = next((i for i in instance.get("inputs", []) if i["name"] == name), None)
95
+ if entry is not None and entry.get("link") is not None:
96
+ return self.resolve(parent_scope, entry["link"])
97
+ # unwired promoted widget: the UI backs it with the widget of the
98
+ # first interior node this boundary slot fans out to, so inputs
99
+ # without a widget of their own (e.g. math variables) still get a
100
+ # value -- mirror that lookup here
101
+ return self._boundary_default(scope, origin_slot)
102
 
103
  node = scope.nodes[origin_id]
104
  ntype = node["type"]
 
128
 
129
  return (scope.fid(origin_id), origin_slot)
130
 
131
+ def _boundary_default(self, scope, origin_slot):
132
+ """Widget value backing an unwired promoted subgraph input, taken from
133
+ the first fan-out target of the slot that has that widget itself."""
134
+ for _, (oid, oslot, tid, tslot) in sorted(scope.links.items()):
135
+ if oid != SUBGRAPH_INPUT_ID or oslot != origin_slot:
136
+ continue
137
+ target = scope.nodes.get(tid)
138
+ if (target is None or target.get("mode", 0) in (2, 4)
139
+ or target["type"] in self.subgraph_defs
140
+ or target["type"] not in self.oi):
141
+ continue
142
+ if tslot >= len(target.get("inputs", [])):
143
+ continue
144
+ widgets = self.widget_inputs(target)
145
+ name = target["inputs"][tslot]["name"]
146
+ if name in widgets:
147
+ return WidgetDefault(widgets[name])
148
+ return None
149
+
150
  def widget_inputs(self, node):
151
  """Map a node's widgets_values onto named inputs using /object_info order."""
152
  if "Power Lora Loader" in node["type"]:
 
218
  inputs = self.widget_inputs(node)
219
  for inp in node.get("inputs", []):
220
  source = self.resolve(scope, inp.get("link"))
221
+ if isinstance(source, WidgetDefault):
222
+ # the node's own widget value (if any) already won via
223
+ # widget_inputs; only fill inputs that have none
224
+ inputs.setdefault(inp["name"], source.value)
225
+ elif source is not None:
226
  inputs[inp["name"]] = list(source)
227
  elif inp.get("link") is not None and not inp.get("widget"):
228
  print(f"warning: {scope.fid(nid)} ({ntype}) input {inp['name']!r} "