Upload graph_builder.py with huggingface_hub
Browse files- graph_builder.py +123 -0
graph_builder.py
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json, os
|
| 2 |
+
OI = json.load(open("/tmp/oi.json", encoding="utf-8"))
|
| 3 |
+
OUT = "/workspace/pack_jsons"
|
| 4 |
+
os.makedirs(OUT, exist_ok=True)
|
| 5 |
+
|
| 6 |
+
# pack class -> OFM brand title
|
| 7 |
+
PACK = {
|
| 8 |
+
"NanoBananaAIO": "OFM Image and Video Edit AIO",
|
| 9 |
+
"GeminiPromptNode": "OFM Prompt Generator",
|
| 10 |
+
"PromptSelectorNodeMonthly": "OFM Prompt Selector",
|
| 11 |
+
"SeedreamNode": "OFM Seedream Edit",
|
| 12 |
+
"DirectoryImageLoaderNode": "OFM Directory Image Loader",
|
| 13 |
+
"LoadAPIKeysNode": "OFM Load API Keys",
|
| 14 |
+
"VideoFrameExtractorNode": "OFM Video Frame Extractor",
|
| 15 |
+
"MetadataRemoveNodeMonthly": "OFM Remove Metadata",
|
| 16 |
+
"SaveAsPhonePhotoNodeMonthly": "OFM Save as Phone Photo",
|
| 17 |
+
"LoraCaptionGeneratorNode": "OFM Lora Caption Generator",
|
| 18 |
+
"AiorBustVideoLoader": "OFM Video Loader",
|
| 19 |
+
"Aiorbust_Renoise": "OFM Renoise",
|
| 20 |
+
"Aiorbust_Camera_Look": "OFM Camera Look",
|
| 21 |
+
"Aiorbust_Apply_LUT": "OFM Apply LUT",
|
| 22 |
+
}
|
| 23 |
+
LINK_T = {"IMAGE", "MASK", "LATENT", "CONDITIONING", "MODEL", "VAE", "CLIP", "AUDIO"}
|
| 24 |
+
|
| 25 |
+
def schema(t):
|
| 26 |
+
info = OI.get(t)
|
| 27 |
+
if not info:
|
| 28 |
+
return None
|
| 29 |
+
inp = info.get("input", {})
|
| 30 |
+
widgets = [] # (name, default) -> widgets_values
|
| 31 |
+
link_inputs = [] # (name, type) -> input slots needing wiring
|
| 32 |
+
for sec in ("required", "optional"):
|
| 33 |
+
for name, spec in inp.get(sec, {}).items():
|
| 34 |
+
tp = spec[0]
|
| 35 |
+
o = spec[1] if len(spec) > 1 and isinstance(spec[1], dict) else {}
|
| 36 |
+
if isinstance(tp, list):
|
| 37 |
+
widgets.append((name, tp[0] if tp else ""))
|
| 38 |
+
elif tp == "STRING":
|
| 39 |
+
widgets.append((name, o.get("default", "")))
|
| 40 |
+
elif tp == "INT":
|
| 41 |
+
widgets.append((name, o.get("default", 0)))
|
| 42 |
+
elif tp == "FLOAT":
|
| 43 |
+
widgets.append((name, o.get("default", 0.0)))
|
| 44 |
+
elif tp == "BOOLEAN":
|
| 45 |
+
widgets.append((name, o.get("default", False)))
|
| 46 |
+
elif tp in LINK_T:
|
| 47 |
+
link_inputs.append((name, tp))
|
| 48 |
+
# unknown custom types -> skip (rare)
|
| 49 |
+
onames = info.get("output_name") or info.get("output", [])
|
| 50 |
+
otypes = info.get("output", [])
|
| 51 |
+
outs = list(zip(onames, otypes))
|
| 52 |
+
return widgets, link_inputs, outs
|
| 53 |
+
|
| 54 |
+
def build(t, title):
|
| 55 |
+
s = schema(t)
|
| 56 |
+
if not s:
|
| 57 |
+
return None
|
| 58 |
+
widgets, link_inputs, outs = s
|
| 59 |
+
nodes, links = [], []
|
| 60 |
+
nid, lid = 1, 1
|
| 61 |
+
# LoadImage for each IMAGE input
|
| 62 |
+
src = {}
|
| 63 |
+
y = 60
|
| 64 |
+
for (iname, itype) in link_inputs:
|
| 65 |
+
if itype == "IMAGE":
|
| 66 |
+
nodes.append({"id": nid, "type": "LoadImage", "pos": [60, y], "size": [300, 314], "flags": {},
|
| 67 |
+
"order": len(nodes), "mode": 0, "inputs": [],
|
| 68 |
+
"outputs": [{"name": "IMAGE", "type": "IMAGE", "links": [lid], "slot_index": 0},
|
| 69 |
+
{"name": "MASK", "type": "MASK", "links": None}],
|
| 70 |
+
"properties": {"Node name for S&R": "LoadImage"}, "widgets_values": ["example.png", "image"]})
|
| 71 |
+
src[iname] = (nid, 0, lid); lid += 1; nid += 1; y += 360
|
| 72 |
+
main_id = nid; nid += 1
|
| 73 |
+
main_inputs = []
|
| 74 |
+
for slot, (iname, itype) in enumerate(link_inputs):
|
| 75 |
+
if iname in src:
|
| 76 |
+
snid, sslot, l = src[iname]
|
| 77 |
+
main_inputs.append({"name": iname, "type": itype, "link": l})
|
| 78 |
+
links.append([l, snid, sslot, main_id, slot, itype])
|
| 79 |
+
else:
|
| 80 |
+
main_inputs.append({"name": iname, "type": itype, "link": None})
|
| 81 |
+
main_outputs = []
|
| 82 |
+
out_link = {}
|
| 83 |
+
for oslot, (oname, otype) in enumerate(outs):
|
| 84 |
+
l = None
|
| 85 |
+
if otype in ("IMAGE", "STRING"):
|
| 86 |
+
l = lid; out_link[oslot] = (l, otype, oname); lid += 1
|
| 87 |
+
main_outputs.append({"name": oname, "type": otype, "links": [l] if l else None, "slot_index": oslot})
|
| 88 |
+
nodes.append({"id": main_id, "type": t, "title": title, "pos": [460, 120], "size": [400, 340], "flags": {},
|
| 89 |
+
"order": len(nodes), "mode": 0, "inputs": main_inputs, "outputs": main_outputs,
|
| 90 |
+
"properties": {"Node name for S&R": t}, "widgets_values": [w[1] for w in widgets]})
|
| 91 |
+
# sink per IMAGE/STRING output
|
| 92 |
+
y2 = 120
|
| 93 |
+
for oslot, (l, otype, oname) in out_link.items():
|
| 94 |
+
if otype == "IMAGE":
|
| 95 |
+
nodes.append({"id": nid, "type": "SaveImage", "pos": [920, y2], "size": [320, 300], "flags": {},
|
| 96 |
+
"order": len(nodes), "mode": 0, "inputs": [{"name": "images", "type": "IMAGE", "link": l}],
|
| 97 |
+
"outputs": [], "properties": {}, "widgets_values": ["OFM_" + t]})
|
| 98 |
+
links.append([l, main_id, oslot, nid, 0, "IMAGE"]); nid += 1; y2 += 340
|
| 99 |
+
elif otype == "STRING":
|
| 100 |
+
nodes.append({"id": nid, "type": "ShowText|pysssss", "title": "OFM — текст", "pos": [920, y2],
|
| 101 |
+
"size": [380, 200], "flags": {}, "order": len(nodes), "mode": 0,
|
| 102 |
+
"inputs": [{"name": "text", "type": "STRING", "link": l, "widget": {"name": "text"}}],
|
| 103 |
+
"outputs": [{"name": "STRING", "type": "STRING", "links": None, "shape": 6}],
|
| 104 |
+
"properties": {"Node name for S&R": "ShowText|pysssss"}, "widgets_values": [""]})
|
| 105 |
+
links.append([l, main_id, oslot, nid, 0, "STRING"]); nid += 1; y2 += 240
|
| 106 |
+
# note
|
| 107 |
+
nodes.append({"id": nid, "type": "Note", "title": title, "pos": [60, 10], "size": [560, 90], "flags": {},
|
| 108 |
+
"order": len(nodes), "mode": 0, "inputs": [], "outputs": [], "properties": {},
|
| 109 |
+
"widgets_values": [title + " — впиши API-ключ в ноде и Queue. Облачные ноды GPU не требуют."]})
|
| 110 |
+
return {"last_node_id": nid, "last_link_id": lid - 1, "nodes": nodes, "links": links,
|
| 111 |
+
"groups": [], "config": {}, "extra": {}, "version": 0.4}
|
| 112 |
+
|
| 113 |
+
done = []
|
| 114 |
+
for t, title in PACK.items():
|
| 115 |
+
g = build(t, title)
|
| 116 |
+
if g:
|
| 117 |
+
fn = f"{OUT}/OFM_{t}.json"
|
| 118 |
+
json.dump(g, open(fn, "w", encoding="utf-8"), ensure_ascii=False, indent=1)
|
| 119 |
+
done.append(t)
|
| 120 |
+
print("BUILT", t, "nodes=" + str(len(g["nodes"])), flush=True)
|
| 121 |
+
else:
|
| 122 |
+
print("SKIP (not loaded)", t, flush=True)
|
| 123 |
+
print(f"GRAPHS_DONE {len(done)}/{len(PACK)}", flush=True)
|