import json, os OI = json.load(open("/tmp/oi.json", encoding="utf-8")) OUT = "/workspace/pack_jsons" os.makedirs(OUT, exist_ok=True) # pack class -> OFM brand title PACK = { "NanoBananaAIO": "OFM Image and Video Edit AIO", "GeminiPromptNode": "OFM Prompt Generator", "PromptSelectorNodeMonthly": "OFM Prompt Selector", "SeedreamNode": "OFM Seedream Edit", "DirectoryImageLoaderNode": "OFM Directory Image Loader", "LoadAPIKeysNode": "OFM Load API Keys", "VideoFrameExtractorNode": "OFM Video Frame Extractor", "MetadataRemoveNodeMonthly": "OFM Remove Metadata", "SaveAsPhonePhotoNodeMonthly": "OFM Save as Phone Photo", "LoraCaptionGeneratorNode": "OFM Lora Caption Generator", "AiorBustVideoLoader": "OFM Video Loader", "Aiorbust_Renoise": "OFM Renoise", "Aiorbust_Camera_Look": "OFM Camera Look", "Aiorbust_Apply_LUT": "OFM Apply LUT", } LINK_T = {"IMAGE", "MASK", "LATENT", "CONDITIONING", "MODEL", "VAE", "CLIP", "AUDIO"} def schema(t): info = OI.get(t) if not info: return None inp = info.get("input", {}) widgets = [] # (name, default) -> widgets_values link_inputs = [] # (name, type) -> input slots needing wiring for sec in ("required", "optional"): for name, spec in inp.get(sec, {}).items(): tp = spec[0] o = spec[1] if len(spec) > 1 and isinstance(spec[1], dict) else {} if isinstance(tp, list): widgets.append((name, tp[0] if tp else "")) elif tp == "STRING": widgets.append((name, o.get("default", ""))) elif tp == "INT": widgets.append((name, o.get("default", 0))) elif tp == "FLOAT": widgets.append((name, o.get("default", 0.0))) elif tp == "BOOLEAN": widgets.append((name, o.get("default", False))) elif tp in LINK_T: link_inputs.append((name, tp)) # unknown custom types -> skip (rare) onames = info.get("output_name") or info.get("output", []) otypes = info.get("output", []) outs = list(zip(onames, otypes)) return widgets, link_inputs, outs def build(t, title): s = schema(t) if not s: return None widgets, link_inputs, outs = s nodes, links = [], [] nid, lid = 1, 1 # LoadImage for each IMAGE input src = {} y = 60 for (iname, itype) in link_inputs: if itype == "IMAGE": nodes.append({"id": nid, "type": "LoadImage", "pos": [60, y], "size": [300, 314], "flags": {}, "order": len(nodes), "mode": 0, "inputs": [], "outputs": [{"name": "IMAGE", "type": "IMAGE", "links": [lid], "slot_index": 0}, {"name": "MASK", "type": "MASK", "links": None}], "properties": {"Node name for S&R": "LoadImage"}, "widgets_values": ["example.png", "image"]}) src[iname] = (nid, 0, lid); lid += 1; nid += 1; y += 360 main_id = nid; nid += 1 main_inputs = [] for slot, (iname, itype) in enumerate(link_inputs): if iname in src: snid, sslot, l = src[iname] main_inputs.append({"name": iname, "type": itype, "link": l}) links.append([l, snid, sslot, main_id, slot, itype]) else: main_inputs.append({"name": iname, "type": itype, "link": None}) main_outputs = [] out_link = {} for oslot, (oname, otype) in enumerate(outs): l = None if otype in ("IMAGE", "STRING"): l = lid; out_link[oslot] = (l, otype, oname); lid += 1 main_outputs.append({"name": oname, "type": otype, "links": [l] if l else None, "slot_index": oslot}) nodes.append({"id": main_id, "type": t, "title": title, "pos": [460, 120], "size": [400, 340], "flags": {}, "order": len(nodes), "mode": 0, "inputs": main_inputs, "outputs": main_outputs, "properties": {"Node name for S&R": t}, "widgets_values": [w[1] for w in widgets]}) # sink per IMAGE/STRING output y2 = 120 for oslot, (l, otype, oname) in out_link.items(): if otype == "IMAGE": nodes.append({"id": nid, "type": "SaveImage", "pos": [920, y2], "size": [320, 300], "flags": {}, "order": len(nodes), "mode": 0, "inputs": [{"name": "images", "type": "IMAGE", "link": l}], "outputs": [], "properties": {}, "widgets_values": ["OFM_" + t]}) links.append([l, main_id, oslot, nid, 0, "IMAGE"]); nid += 1; y2 += 340 elif otype == "STRING": nodes.append({"id": nid, "type": "ShowText|pysssss", "title": "OFM — текст", "pos": [920, y2], "size": [380, 200], "flags": {}, "order": len(nodes), "mode": 0, "inputs": [{"name": "text", "type": "STRING", "link": l, "widget": {"name": "text"}}], "outputs": [{"name": "STRING", "type": "STRING", "links": None, "shape": 6}], "properties": {"Node name for S&R": "ShowText|pysssss"}, "widgets_values": [""]}) links.append([l, main_id, oslot, nid, 0, "STRING"]); nid += 1; y2 += 240 # note nodes.append({"id": nid, "type": "Note", "title": title, "pos": [60, 10], "size": [560, 90], "flags": {}, "order": len(nodes), "mode": 0, "inputs": [], "outputs": [], "properties": {}, "widgets_values": [title + " — впиши API-ключ в ноде и Queue. Облачные ноды GPU не требуют."]}) return {"last_node_id": nid, "last_link_id": lid - 1, "nodes": nodes, "links": links, "groups": [], "config": {}, "extra": {}, "version": 0.4} done = [] for t, title in PACK.items(): g = build(t, title) if g: fn = f"{OUT}/OFM_{t}.json" json.dump(g, open(fn, "w", encoding="utf-8"), ensure_ascii=False, indent=1) done.append(t) print("BUILT", t, "nodes=" + str(len(g["nodes"])), flush=True) else: print("SKIP (not loaded)", t, flush=True) print(f"GRAPHS_DONE {len(done)}/{len(PACK)}", flush=True)