From 5bcbc007ddeb5a784925c6c2c457ef0e2a9354b7 Mon Sep 17 00:00:00 2001 From: City <125218114+city96@users.noreply.github.com> Date: Thu, 30 Mar 2023 23:13:58 +0200 Subject: [PATCH 01/27] Add human-readable names for nodes --- nodes.py | 48 ++++++++++++++++++++++++++++++++++++++++++++++ server.py | 3 ++- web/scripts/app.js | 2 +- 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/nodes.py b/nodes.py index 6fb7f0175..538787555 100644 --- a/nodes.py +++ b/nodes.py @@ -1018,6 +1018,54 @@ NODE_CLASS_MAPPINGS = { "VAEEncodeTiled": VAEEncodeTiled, } +NODE_DISPLAY_NAME_MAPPINGS = { + # Sampling + "KSampler": "KSampler", + "KSamplerAdvanced": "KSampler (Advanced)", + # Loaders + "CheckpointLoader": "Load Checkpoint", + "CheckpointLoaderSimple": "Load Checkpoint (Simple)", + "VAELoader": "Load VAE", + "LoraLoader": "Load LoRA", + "CLIPLoader": "Load CLIP", + "ControlNetLoader": "Load ControlNet Model", + "DiffControlNetLoader": "Load ControlNet Model (diff)", + "StyleModelLoader": "Load Style Model", + "CLIPVisionLoader": "Load CLIP Vision", + "UpscaleModelLoader": "Load Upscale Model", + # Conditioning + "CLIPVisionEncode": "CLIP Vision Encode", + "StyleModelApply": "Apply Style Model", + "CLIPTextEncode": "CLIP Text Encode (Prompt)", + "CLIPSetLastLayer": "CLIP Set Last Layer", + "ConditioningCombine": "Conditioning (Combine)", + "ConditioningSetArea": "Conditioning (Set Area)", + "ControlNetApply": "Apply ControlNet", + # Latent + "VAEEncodeForInpaint": "VAE Encode (for Inpainting)", + "SetLatentNoiseMask": "Set Latent Noise Mask", + "VAEDecode": "VAE Decode", + "VAEEncode": "VAE Encode", + "LatentRotate": "Rotate Latent", + "LatentFlip": "Flip Latent", + "LatentCrop": "Crop Latent", + "EmptyLatentImage": "Empty Latent Image", + "LatentUpscale": "Upscale Latent", + "LatentComposite": "Latent Composite", + # Image + "SaveImage": "Save Image", + "PreviewImage": "Preview Image", + "LoadImage": "Load Image", + "LoadImageMask": "Load Image (as Mask)", + "ImageScale": "Upscale Image", + "ImageUpscaleWithModel": "Upscale Image (using Model)", + "ImageInvert": "Invert Image", + "ImagePadForOutpaint": "Pad Image for Outpainting", + # _for_testing + "VAEDecodeTiled": "VAE Decode (Tiled)", + "VAEEncodeTiled": "VAE Encode (Tiled)", +} + def load_custom_node(module_path): module_name = os.path.basename(module_path) if os.path.isfile(module_path): diff --git a/server.py b/server.py index 80fb2dc72..2e6fc1a28 100644 --- a/server.py +++ b/server.py @@ -153,7 +153,8 @@ class PromptServer(): info['input'] = obj_class.INPUT_TYPES() info['output'] = obj_class.RETURN_TYPES info['output_name'] = obj_class.RETURN_NAMES if hasattr(obj_class, 'RETURN_NAMES') else info['output'] - info['name'] = x #TODO + info['name'] = x + info['display_name'] = nodes.NODE_DISPLAY_NAME_MAPPINGS[x] if x in nodes.NODE_DISPLAY_NAME_MAPPINGS.keys() else x info['description'] = '' info['category'] = 'sd' if hasattr(obj_class, 'CATEGORY'): diff --git a/web/scripts/app.js b/web/scripts/app.js index b29981091..125ce17ae 100644 --- a/web/scripts/app.js +++ b/web/scripts/app.js @@ -777,7 +777,7 @@ class ComfyApp { app.#invokeExtensionsAsync("nodeCreated", this); }, { - title: nodeData.name, + title: nodeData.display_name, comfyClass: nodeData.name, } ); From e6e30ee7cbf88c731b34f8ef52832920567940b6 Mon Sep 17 00:00:00 2001 From: City <125218114+city96@users.noreply.github.com> Date: Fri, 31 Mar 2023 00:54:35 +0200 Subject: [PATCH 02/27] Fallback for node title --- web/scripts/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/scripts/app.js b/web/scripts/app.js index 125ce17ae..404d87cb6 100644 --- a/web/scripts/app.js +++ b/web/scripts/app.js @@ -777,7 +777,7 @@ class ComfyApp { app.#invokeExtensionsAsync("nodeCreated", this); }, { - title: nodeData.display_name, + title: nodeData.display_name || nodeData.name, comfyClass: nodeData.name, } ); From 9ac95e6ac7a16283ab5f0710fdda15be3b5a5e50 Mon Sep 17 00:00:00 2001 From: City <125218114+city96@users.noreply.github.com> Date: Fri, 31 Mar 2023 07:05:17 +0200 Subject: [PATCH 03/27] Add human-readable name support for custom nodes --- custom_nodes/example_node.py.example | 5 +++++ nodes.py | 2 ++ 2 files changed, 7 insertions(+) diff --git a/custom_nodes/example_node.py.example b/custom_nodes/example_node.py.example index 1bb1a5a37..d2f6e3332 100644 --- a/custom_nodes/example_node.py.example +++ b/custom_nodes/example_node.py.example @@ -84,3 +84,8 @@ class Example: NODE_CLASS_MAPPINGS = { "Example": Example } + +# A dictionary that contains the friendly/humanly readable titles for the nodes +NODE_DISPLAY_NAME_MAPPINGS = { + "Example": "Example Node" +} diff --git a/nodes.py b/nodes.py index 538787555..da71dfc04 100644 --- a/nodes.py +++ b/nodes.py @@ -1081,6 +1081,8 @@ def load_custom_node(module_path): module_spec.loader.exec_module(module) if hasattr(module, "NODE_CLASS_MAPPINGS") and getattr(module, "NODE_CLASS_MAPPINGS") is not None: NODE_CLASS_MAPPINGS.update(module.NODE_CLASS_MAPPINGS) + if hasattr(module, "NODE_DISPLAY_NAME_MAPPINGS") and getattr(module, "NODE_DISPLAY_NAME_MAPPINGS") is not None: + NODE_DISPLAY_NAME_MAPPINGS.update(module.NODE_DISPLAY_NAME_MAPPINGS) else: print(f"Skip {module_path} module for custom nodes due to the lack of NODE_CLASS_MAPPINGS.") except Exception as e: From 2d7ad41142a941f7d82e166869bb1e8372a559ac Mon Sep 17 00:00:00 2001 From: EllangoK Date: Fri, 7 Apr 2023 19:42:03 -0400 Subject: [PATCH 04/27] colorPalette sets LiteGraph colors --- web/extensions/core/colorPalette.js | 34 +++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/web/extensions/core/colorPalette.js b/web/extensions/core/colorPalette.js index e54bc2a38..8e542b5c2 100644 --- a/web/extensions/core/colorPalette.js +++ b/web/extensions/core/colorPalette.js @@ -21,8 +21,31 @@ const colorPalettes = { "MODEL": "#B39DDB", // light lavender-purple "STYLE_MODEL": "#C2FFAE", // light green-yellow "VAE": "#FF6E6E", // bright red - } - } + }, + "litegraph_base": { + "NODE_TITLE_COLOR": "#999", + "NODE_SELECTED_TITLE_COLOR": "#FFF", + "NODE_TEXT_SIZE": 14, + "NODE_TEXT_COLOR": "#AAA", + "NODE_SUBTEXT_SIZE": 12, + "NODE_DEFAULT_COLOR": "#333", + "NODE_DEFAULT_BGCOLOR": "#353535", + "NODE_DEFAULT_BOXCOLOR": "#666", + "NODE_DEFAULT_SHAPE": "box", + "NODE_BOX_OUTLINE_COLOR": "#FFF", + "DEFAULT_SHADOW_COLOR": "rgba(0,0,0,0.5)", + "DEFAULT_GROUP_FONT": 24, + + "WIDGET_BGCOLOR": "#222", + "WIDGET_OUTLINE_COLOR": "#666", + "WIDGET_TEXT_COLOR": "#DDD", + "WIDGET_SECONDARY_TEXT_COLOR": "#999", + + "LINK_COLOR": "#9A9", + "EVENT_LINK_COLOR": "#A86", + "CONNECTING_LINK_COLOR": "#AFA", + }, + }, }, "palette_2": { "id": "palette_2", @@ -194,6 +217,13 @@ app.registerExtension({ Object.assign(app.canvas.default_connection_color_byType, colorPalette.colors.node_slot); app.canvas.draw(true, true); } + if (colorPalette.colors.litegraph_base) { + for (const key in colorPalette.colors.litegraph_base) { + if (colorPalette.colors.litegraph_base.hasOwnProperty(key) && LiteGraph.hasOwnProperty(key)) { + LiteGraph[key] = colorPalette.colors.litegraph_base[key]; + } + } + } } }; From 7bce83aa0394a01c6624e7d1a5763653e52e6eb6 Mon Sep 17 00:00:00 2001 From: EllangoK Date: Fri, 7 Apr 2023 20:12:24 -0400 Subject: [PATCH 05/27] fixes NODE_TITLE_COLOR not being set --- web/extensions/core/colorPalette.js | 60 +++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/web/extensions/core/colorPalette.js b/web/extensions/core/colorPalette.js index 8e542b5c2..d212602c6 100644 --- a/web/extensions/core/colorPalette.js +++ b/web/extensions/core/colorPalette.js @@ -47,25 +47,48 @@ const colorPalettes = { }, }, }, - "palette_2": { - "id": "palette_2", - "name": "Palette 2", + "solarized": { + "id": "solarized", + "name": "Solarized", "colors": { "node_slot": { - "CLIP": "#556B2F", // Dark Olive Green - "CLIP_VISION": "#4B0082", // Indigo - "CLIP_VISION_OUTPUT": "#006400", // Green - "CONDITIONING": "#FF1493", // Deep Pink - "CONTROL_NET": "#8B4513", // Saddle Brown - "IMAGE": "#8B0000", // Dark Red - "LATENT": "#00008B", // Dark Blue - "MASK": "#2F4F4F", // Dark Slate Grey - "MODEL": "#FF8C00", // Dark Orange - "STYLE_MODEL": "#004A4A", // Sherpa Blue - "UPSCALE_MODEL": "#4A004A", // Tyrian Purple - "VAE": "#4F394F", // Loulou - } - } + "CLIP": "#859900", // Green + "CLIP_VISION": "#6c71c4", // Indigo + "CLIP_VISION_OUTPUT": "#859900", // Green + "CONDITIONING": "#d33682", // Magenta + "CONTROL_NET": "#cb4b16", // Orange + "IMAGE": "#dc322f", // Red + "LATENT": "#268bd2", // Blue + "MASK": "#073642", // Base02 + "MODEL": "#cb4b16", // Orange + "STYLE_MODEL": "#073642", // Base02 + "UPSCALE_MODEL": "#6c71c4", // Indigo + "VAE": "#586e75", // Base1 + }, + "litegraph_base": { + "NODE_TITLE_COLOR": "#fdf6e3", + "NODE_SELECTED_TITLE_COLOR": "#b58900", + "NODE_TEXT_SIZE": 14, + "NODE_TEXT_COLOR": "#657b83", + "NODE_SUBTEXT_SIZE": 12, + "NODE_DEFAULT_COLOR": "#586e75", + "NODE_DEFAULT_BGCOLOR": "#073642", + "NODE_DEFAULT_BOXCOLOR": "#839496", + "NODE_DEFAULT_SHAPE": "box", + "NODE_BOX_OUTLINE_COLOR": "#fdf6e3", + "DEFAULT_SHADOW_COLOR": "rgba(0,0,0,0.5)", + "DEFAULT_GROUP_FONT": 24, + + "WIDGET_BGCOLOR": "#002b36", + "WIDGET_OUTLINE_COLOR": "#839496", + "WIDGET_TEXT_COLOR": "#fdf6e3", + "WIDGET_SECONDARY_TEXT_COLOR": "#93a1a1", + + "LINK_COLOR": "#2aa198", + "EVENT_LINK_COLOR": "#268bd2", + "CONNECTING_LINK_COLOR": "#859900", + }, + }, } }; @@ -218,6 +241,9 @@ app.registerExtension({ app.canvas.draw(true, true); } if (colorPalette.colors.litegraph_base) { + // Everything updates correctly in the loop, except the Node Title for some reason + app.canvas.node_title_color = colorPalette.colors.litegraph_base.NODE_TITLE_COLOR; + for (const key in colorPalette.colors.litegraph_base) { if (colorPalette.colors.litegraph_base.hasOwnProperty(key) && LiteGraph.hasOwnProperty(key)) { LiteGraph[key] = colorPalette.colors.litegraph_base[key]; From 463792f06826227c711a5b2e729cafbe5b8e6ce8 Mon Sep 17 00:00:00 2001 From: comfyanonymous Date: Fri, 7 Apr 2023 23:07:19 -0400 Subject: [PATCH 06/27] Allow dragging again. --- web/lib/litegraph.core.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/web/lib/litegraph.core.js b/web/lib/litegraph.core.js index 066f51938..c3efa22a9 100644 --- a/web/lib/litegraph.core.js +++ b/web/lib/litegraph.core.js @@ -7481,8 +7481,8 @@ LGraphNode.prototype.executeAction = function(action) clientY_rel = e.clientY; } - // e.deltaX = clientX_rel - this.last_mouse_position[0]; - // e.deltaY = clientY_rel- this.last_mouse_position[1]; + e.deltaX = clientX_rel - this.last_mouse_position[0]; + e.deltaY = clientY_rel- this.last_mouse_position[1]; this.last_mouse_position[0] = clientX_rel; this.last_mouse_position[1] = clientY_rel; @@ -9923,7 +9923,14 @@ LGraphNode.prototype.executeAction = function(action) case "number": case "combo": var old_value = w.value; - if (event.type == LiteGraph.pointerevents_method+"move" && w.type == "number") { + var delta = x < 40 ? -1 : x > widget_width - 40 ? 1 : 0; + var allow_scroll = true; + if (delta) { + if (x > -3 && x < widget_width + 3) { + allow_scroll = false; + } + } + if (allow_scroll && event.type == LiteGraph.pointerevents_method+"move" && w.type == "number") { if(event.deltaX) w.value += event.deltaX * 0.1 * (w.options.step || 1); if ( w.options.min != null && w.value < w.options.min ) { From ebd7f9bf80213a44a8e2cadc75875a4b980991e5 Mon Sep 17 00:00:00 2001 From: comfyanonymous Date: Sat, 8 Apr 2023 01:10:15 -0400 Subject: [PATCH 07/27] Change the default prompt to something more impressive. --- web/scripts/defaultGraph.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/scripts/defaultGraph.js b/web/scripts/defaultGraph.js index 967377ad6..9b3cb4a7e 100644 --- a/web/scripts/defaultGraph.js +++ b/web/scripts/defaultGraph.js @@ -13,7 +13,7 @@ export const defaultGraph = { inputs: [{ name: "clip", type: "CLIP", link: 5 }], outputs: [{ name: "CONDITIONING", type: "CONDITIONING", links: [6], slot_index: 0 }], properties: {}, - widgets_values: ["bad hands"], + widgets_values: ["text, watermark"], }, { id: 6, @@ -26,7 +26,7 @@ export const defaultGraph = { inputs: [{ name: "clip", type: "CLIP", link: 3 }], outputs: [{ name: "CONDITIONING", type: "CONDITIONING", links: [4], slot_index: 0 }], properties: {}, - widgets_values: ["masterpiece best quality girl"], + widgets_values: ["beautiful scenery nature glass bottle landscape, , purple galaxy bottle,"], }, { id: 5, @@ -56,7 +56,7 @@ export const defaultGraph = { ], outputs: [{ name: "LATENT", type: "LATENT", links: [7], slot_index: 0 }], properties: {}, - widgets_values: [8566257, true, 20, 8, "euler", "normal", 1], + widgets_values: [156680208700286, true, 20, 8, "euler", "normal", 1], }, { id: 8, From 5bb1358dd66a310793a1ea1a8cfcb037618fe37e Mon Sep 17 00:00:00 2001 From: EllangoK Date: Sat, 8 Apr 2023 09:28:35 -0400 Subject: [PATCH 08/27] manual set default link color --- web/extensions/core/colorPalette.js | 3 +- web/scripts/test.js | 71 +++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 web/scripts/test.js diff --git a/web/extensions/core/colorPalette.js b/web/extensions/core/colorPalette.js index d212602c6..30a984607 100644 --- a/web/extensions/core/colorPalette.js +++ b/web/extensions/core/colorPalette.js @@ -238,11 +238,11 @@ app.registerExtension({ if (colorPalette.colors) { if (colorPalette.colors.node_slot) { Object.assign(app.canvas.default_connection_color_byType, colorPalette.colors.node_slot); - app.canvas.draw(true, true); } if (colorPalette.colors.litegraph_base) { // Everything updates correctly in the loop, except the Node Title for some reason app.canvas.node_title_color = colorPalette.colors.litegraph_base.NODE_TITLE_COLOR; + app.canvas.default_link_color = colorPalette.colors.litegraph_base.LINK_COLOR; for (const key in colorPalette.colors.litegraph_base) { if (colorPalette.colors.litegraph_base.hasOwnProperty(key) && LiteGraph.hasOwnProperty(key)) { @@ -250,6 +250,7 @@ app.registerExtension({ } } } + app.canvas.draw(true, true); } }; diff --git a/web/scripts/test.js b/web/scripts/test.js new file mode 100644 index 000000000..55f8dfb69 --- /dev/null +++ b/web/scripts/test.js @@ -0,0 +1,71 @@ +(function() { + var LGraphCanvas = LiteGraph.LGraphCanvas; + var LGraph = LiteGraph.LGraph; + + // Save the original renderLink function + var originalRenderLink = LGraphCanvas.prototype.renderLink; + + // Save the original connect function + var originalConnect = LGraph.prototype.connect; + + // Override the connect function + LGraph.prototype.connect = function ( + origin_slot, + target_slot, + options + ) { + var origin_id = origin_slot[0]; + var target_id = target_slot[0]; + + var origin_node = this.getNodeById(origin_id); + var target_node = this.getNodeById(target_id); + + + if (origin_node && target_node) { + var output_slot = origin_slot[1]; + var output_slot_info = origin_node.getOutputInfo(output_slot); + + + console.log(output_slot_info) + if (output_slot_info) { + options = options || {}; + options.color = output_slot_info.label_color || null; + } + } + + return originalConnect.call(this, origin_slot, target_slot, options); + }; + + // Override the renderLink function + LGraphCanvas.prototype.renderLink = function ( + ctx, + a, + b, + link, + skip_border, + flow, + color, + start_dir, + end_dir, + num_sublines + ) { + if (link && link.color) { + color = link.color; + } + + // Call the original renderLink function with the new color + originalRenderLink.call( + this, + ctx, + a, + b, + link, + skip_border, + flow, + color, + start_dir, + end_dir, + num_sublines + ); + }; +})(); From 357c0753f8b911202ea2cdd6d92a4d73cdfd58e4 Mon Sep 17 00:00:00 2001 From: pythongosssss <125205205+pythongosssss@users.noreply.github.com> Date: Sat, 8 Apr 2023 14:38:45 +0100 Subject: [PATCH 09/27] Support dataset when creating elements Allow dialog to show element and override buttons --- web/scripts/ui.js | 47 +++++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/web/scripts/ui.js b/web/scripts/ui.js index 6999c0a73..09861c440 100644 --- a/web/scripts/ui.js +++ b/web/scripts/ui.js @@ -8,14 +8,18 @@ export function $el(tag, propsOrChildren, children) { if (Array.isArray(propsOrChildren)) { element.append(...propsOrChildren); } else { - const parent = propsOrChildren.parent; + const { parent, $: cb, dataset, style } = propsOrChildren; delete propsOrChildren.parent; - const cb = propsOrChildren.$; delete propsOrChildren.$; + delete propsOrChildren.dataset; + delete propsOrChildren.style; - if (propsOrChildren.style) { - Object.assign(element.style, propsOrChildren.style); - delete propsOrChildren.style; + if (style) { + Object.assign(element.style, style); + } + + if (dataset) { + Object.assign(element.dataset, dataset); } Object.assign(element, propsOrChildren); @@ -76,7 +80,7 @@ function dragElement(dragEl, settings) { dragEl.style.left = newPosX + "px"; dragEl.style.right = "unset"; } - + dragEl.style.top = newPosY + "px"; dragEl.style.bottom = "unset"; @@ -145,7 +149,7 @@ function dragElement(dragEl, settings) { } window.addEventListener("resize", () => { - ensureInBounds(); + ensureInBounds(); }); function closeDragElement() { @@ -155,26 +159,33 @@ function dragElement(dragEl, settings) { } } -class ComfyDialog { +export class ComfyDialog { constructor() { this.element = $el("div.comfy-modal", { parent: document.body }, [ - $el("div.comfy-modal-content", [ - $el("p", { $: (p) => (this.textElement = p) }), - $el("button", { - type: "button", - textContent: "Close", - onclick: () => this.close(), - }), - ]), + $el("div.comfy-modal-content", [$el("p", { $: (p) => (this.textElement = p) }), ...this.createButtons()]), ]); } + createButtons() { + return [ + $el("button", { + type: "button", + textContent: "Close", + onclick: () => this.close(), + }), + ]; + } + close() { this.element.style.display = "none"; } show(html) { - this.textElement.innerHTML = html; + if (typeof html === "string") { + this.textElement.innerHTML = html; + } else { + this.textElement.replaceChildren(html); + } this.element.style.display = "flex"; } } @@ -419,7 +430,7 @@ export class ComfyUI { type: "boolean", defaultValue: true, }); - + const fileInput = $el("input", { type: "file", accept: ".json,image/png", From 1acd2ef5d2695fcb1ae065e9aa1f1a1b2a0c6098 Mon Sep 17 00:00:00 2001 From: pythongosssss <125205205+pythongosssss@users.noreply.github.com> Date: Sat, 8 Apr 2023 14:39:10 +0100 Subject: [PATCH 10/27] Adds menu for adding + managing node templates --- web/extensions/core/nodeTemplates.js | 184 +++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 web/extensions/core/nodeTemplates.js diff --git a/web/extensions/core/nodeTemplates.js b/web/extensions/core/nodeTemplates.js new file mode 100644 index 000000000..69d09cde8 --- /dev/null +++ b/web/extensions/core/nodeTemplates.js @@ -0,0 +1,184 @@ +import { app } from "/scripts/app.js"; +import { ComfyDialog, $el } from "/scripts/ui.js"; + +// Adds the ability to save and add multiple nodes as a template +// To save: +// Select multiple nodes (ctrl + drag to select a region or ctrl+click individual nodes) +// Right click the canvas +// Save Node Template -> give it a name +// +// To add: +// Right click the canvas +// Node templates -> click the one to add +// +// To delete/rename: +// Right click the canvas +// Node templates -> Manage + +const id = "Comfy.NodeTemplates"; + +class ManageTemplates extends ComfyDialog { + constructor() { + super(); + this.element.classList.add("comfy-manage-templates"); + this.templates = this.load(); + } + + createButtons() { + const btns = super.createButtons(); + btns[0].textContent = "Cancel"; + btns.unshift( + $el("button", { + type: "button", + textContent: "Save", + onclick: () => this.save(), + }) + ); + return btns; + } + + load() { + const templates = localStorage.getItem(id); + if (templates) { + return JSON.parse(templates); + } else { + return []; + } + } + + save() { + // Find all visible inputs and save them as our new list + const inputs = this.element.querySelectorAll("input"); + const updated = []; + + for (let i = 0; i < inputs.length; i++) { + const input = inputs[i]; + if (input.parentElement.style.display !== "none") { + const t = this.templates[i]; + t.name = input.value.trim() || input.getAttribute("data-name"); + updated.push(t); + } + } + + this.templates = updated; + this.store(); + this.close(); + } + + store() { + localStorage.setItem(id, JSON.stringify(this.templates)); + } + + show() { + // Show list of template names + delete button + super.show( + $el( + "div", + { + style: { + display: "grid", + gridTemplateColumns: "1fr auto", + gap: "5px", + }, + }, + this.templates.flatMap((t) => { + let nameInput; + return [ + $el( + "label", + { + textContent: "Name: ", + }, + [ + $el("input", { + value: t.name, + dataset: { name: t.name }, + $: (el) => (nameInput = el), + }), + ] + ), + $el("button", { + textContent: "Delete", + style: { + fontSize: "12px", + color: "red", + fontWeight: "normal", + }, + onclick: (e) => { + nameInput.value = ""; + e.target.style.display = "none"; + e.target.previousElementSibling.style.display = "none"; + }, + }), + ]; + }) + ) + ); + } +} + +app.registerExtension({ + name: id, + setup() { + const manage = new ManageTemplates(); + + const clipboardAction = (cb) => { + // We use the clipboard functions but dont want to overwrite the current user clipboard + // Restore it after we've run our callback + const old = localStorage.getItem("litegrapheditor_clipboard"); + cb(); + localStorage.setItem("litegrapheditor_clipboard", old); + }; + + const orig = LGraphCanvas.prototype.getCanvasMenuOptions; + LGraphCanvas.prototype.getCanvasMenuOptions = function () { + const options = orig.apply(this, arguments); + + options.push(null); + options.push({ + content: `Save Selected as Template`, + disabled: !Object.keys(app.canvas.selected_nodes || {}).length, + callback: () => { + const name = prompt("Enter name"); + if (!name || !name.trim()) return; + + clipboardAction(() => { + app.canvas.copyToClipboard(); + manage.templates.push({ + name, + data: localStorage.getItem("litegrapheditor_clipboard"), + }); + manage.store(); + }); + }, + }); + + // Map each template to a menu item + const subItems = manage.templates.map((t) => ({ + content: t.name, + callback: () => { + clipboardAction(() => { + localStorage.setItem("litegrapheditor_clipboard", t.data); + app.canvas.pasteFromClipboard(); + }); + }, + })); + + if (subItems.length) { + subItems.push(null, { + content: "Manage", + callback: () => manage.show(), + }); + + options.push({ + content: "Node Templates", + submenu: { + options: subItems, + }, + }); + } + + return options; + }; + }, +}); From fe93261456784c498b1a3def7d062ad9b5767da6 Mon Sep 17 00:00:00 2001 From: pythongosssss <125205205+pythongosssss@users.noreply.github.com> Date: Sat, 8 Apr 2023 14:48:15 +0100 Subject: [PATCH 11/27] Add style update --- web/style.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/style.css b/web/style.css index 27bb83bb3..afea3a8b8 100644 --- a/web/style.css +++ b/web/style.css @@ -202,7 +202,8 @@ button.comfy-queue-btn { margin: 6px 0 !important; } -.comfy-modal.comfy-settings { +.comfy-modal.comfy-settings, +.comfy-modal.comfy-manage-templates { text-align: center; font-family: sans-serif; color: #999; From cceb530395741f0eac67b367acd831fea0dbc925 Mon Sep 17 00:00:00 2001 From: pythongosssss <125205205+pythongosssss@users.noreply.github.com> Date: Sat, 8 Apr 2023 14:50:57 +0100 Subject: [PATCH 12/27] Adds warning when loading graph with nodes you dont have --- web/scripts/app.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/web/scripts/app.js b/web/scripts/app.js index a687eb5c2..695d4a5d0 100644 --- a/web/scripts/app.js +++ b/web/scripts/app.js @@ -864,9 +864,15 @@ class ComfyApp { graphData = structuredClone(defaultGraph); } - // Patch T2IAdapterLoader to ControlNetLoader since they are the same node now + let missingNodeTypes = []; for (let n of graphData.nodes) { + // Patch T2IAdapterLoader to ControlNetLoader since they are the same node now if (n.type == "T2IAdapterLoader") n.type = "ControlNetLoader"; + + // Find missing node types + if (!(n.type in LiteGraph.registered_node_types)) { + missingNodeTypes.push(n.type); + } } this.graph.configure(graphData); @@ -893,6 +899,14 @@ class ComfyApp { this.#invokeExtensions("loadedGraphNode", node); } + + if (missingNodeTypes.length) { + this.ui.dialog.show( + `When loading the graph, the following node types were not found:
    ${missingNodeTypes.map( + (t) => `
  • ${t}
  • ` + )}
Nodes that have failed to load will show as red on the graph.` + ); + } } /** From aad71add699a136eb865f89db8bb6a350d49b417 Mon Sep 17 00:00:00 2001 From: pythongosssss <125205205+pythongosssss@users.noreply.github.com> Date: Sat, 8 Apr 2023 14:52:24 +0100 Subject: [PATCH 13/27] const --- web/scripts/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/scripts/app.js b/web/scripts/app.js index 695d4a5d0..dee4f65ac 100644 --- a/web/scripts/app.js +++ b/web/scripts/app.js @@ -864,7 +864,7 @@ class ComfyApp { graphData = structuredClone(defaultGraph); } - let missingNodeTypes = []; + const missingNodeTypes = []; for (let n of graphData.nodes) { // Patch T2IAdapterLoader to ControlNetLoader since they are the same node now if (n.type == "T2IAdapterLoader") n.type = "ControlNetLoader"; From 620c0f937665a1001f61195a666565bfab28103a Mon Sep 17 00:00:00 2001 From: EllangoK Date: Sat, 8 Apr 2023 10:43:04 -0400 Subject: [PATCH 14/27] link color is set to nodeType color --- web/extensions/core/colorPalette.js | 59 ++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/web/extensions/core/colorPalette.js b/web/extensions/core/colorPalette.js index 30a984607..3c0300bf0 100644 --- a/web/extensions/core/colorPalette.js +++ b/web/extensions/core/colorPalette.js @@ -240,7 +240,7 @@ app.registerExtension({ Object.assign(app.canvas.default_connection_color_byType, colorPalette.colors.node_slot); } if (colorPalette.colors.litegraph_base) { - // Everything updates correctly in the loop, except the Node Title for some reason + // Everything updates correctly in the loop, except the Node Title and Link Color for some reason app.canvas.node_title_color = colorPalette.colors.litegraph_base.NODE_TITLE_COLOR; app.canvas.default_link_color = colorPalette.colors.litegraph_base.LINK_COLOR; @@ -250,6 +250,63 @@ app.registerExtension({ } } } + + (function(colorPalette) { + var LGraphCanvas = LiteGraph.LGraphCanvas; + var LGraph = LiteGraph.LGraph; + + // Save the original renderLink function + var originalRenderLink = LGraphCanvas.prototype.renderLink; + + // Override the renderLink function + LGraphCanvas.prototype.renderLink = function ( + ctx, + a, + b, + link, + skip_border, + flow, + color, + start_dir, + end_dir, + num_sublines + ) { + if (link && link.color) { + color = link.color; + } + if (link) { + const inputNode = this.graph.getNodeById(link.origin_id); + const outputNode = this.graph.getNodeById(link.target_id); + + let data = null; + if (inputNode.outputs.length > 1) { + data = outputNode.inputs[0]; + } else { + data = inputNode.outputs[0]; + } + let nodeType = data.type; + color = "#" + Math.floor(Math.random() * 16777215).toString(16); + + color = colorPalette.colors.node_slot[nodeType]; + } + + // Call the original renderLink function with the new color + originalRenderLink.call( + this, + ctx, + a, + b, + link, + skip_border, + flow, + color, + start_dir, + end_dir, + num_sublines + ); + }; + })(colorPalette); + app.canvas.draw(true, true); } }; From 6b638c965b6fec1c88947212792dc299acf67b36 Mon Sep 17 00:00:00 2001 From: EllangoK Date: Sat, 8 Apr 2023 10:47:15 -0400 Subject: [PATCH 15/27] matches entry for correct link color --- web/extensions/core/colorPalette.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/web/extensions/core/colorPalette.js b/web/extensions/core/colorPalette.js index 3c0300bf0..e84bf6c0e 100644 --- a/web/extensions/core/colorPalette.js +++ b/web/extensions/core/colorPalette.js @@ -284,7 +284,20 @@ app.registerExtension({ } else { data = inputNode.outputs[0]; } - let nodeType = data.type; + + const matchingEntry = inputNode.outputs.find(output => { + return outputNode.inputs.some(input => input.type === output.type); + }); + + console.log("matchingEntry: ", matchingEntry) + + const inputTypes = inputNode.outputs.map(output => output.type); + console.log("Input types:", inputTypes); + + const outputTypes = outputNode.inputs.map(input => input.type); + console.log("Output types:", outputTypes); + + let nodeType = matchingEntry.type; color = "#" + Math.floor(Math.random() * 16777215).toString(16); color = colorPalette.colors.node_slot[nodeType]; From 0d358b95665a4a2c3edbdf2a4e51920e4c773fb1 Mon Sep 17 00:00:00 2001 From: EllangoK Date: Sat, 8 Apr 2023 10:59:34 -0400 Subject: [PATCH 16/27] cleanup customizeRenderLink --- web/extensions/core/colorPalette.js | 127 +++++++++++++--------------- 1 file changed, 57 insertions(+), 70 deletions(-) diff --git a/web/extensions/core/colorPalette.js b/web/extensions/core/colorPalette.js index e84bf6c0e..2189e3c29 100644 --- a/web/extensions/core/colorPalette.js +++ b/web/extensions/core/colorPalette.js @@ -250,76 +250,7 @@ app.registerExtension({ } } } - - (function(colorPalette) { - var LGraphCanvas = LiteGraph.LGraphCanvas; - var LGraph = LiteGraph.LGraph; - - // Save the original renderLink function - var originalRenderLink = LGraphCanvas.prototype.renderLink; - - // Override the renderLink function - LGraphCanvas.prototype.renderLink = function ( - ctx, - a, - b, - link, - skip_border, - flow, - color, - start_dir, - end_dir, - num_sublines - ) { - if (link && link.color) { - color = link.color; - } - if (link) { - const inputNode = this.graph.getNodeById(link.origin_id); - const outputNode = this.graph.getNodeById(link.target_id); - - let data = null; - if (inputNode.outputs.length > 1) { - data = outputNode.inputs[0]; - } else { - data = inputNode.outputs[0]; - } - - const matchingEntry = inputNode.outputs.find(output => { - return outputNode.inputs.some(input => input.type === output.type); - }); - - console.log("matchingEntry: ", matchingEntry) - - const inputTypes = inputNode.outputs.map(output => output.type); - console.log("Input types:", inputTypes); - - const outputTypes = outputNode.inputs.map(input => input.type); - console.log("Output types:", outputTypes); - - let nodeType = matchingEntry.type; - color = "#" + Math.floor(Math.random() * 16777215).toString(16); - - color = colorPalette.colors.node_slot[nodeType]; - } - - // Call the original renderLink function with the new color - originalRenderLink.call( - this, - ctx, - a, - b, - link, - skip_border, - flow, - color, - start_dir, - end_dir, - num_sublines - ); - }; - })(colorPalette); - + customizeRenderLink(colorPalette); app.canvas.draw(true, true); } }; @@ -476,3 +407,59 @@ app.registerExtension({ }); }, }); + +function customizeRenderLink(colorPalette) { + var LGraphCanvas = LiteGraph.LGraphCanvas; + + function getLinkColor(link, inputNode, outputNode, colorPalette) { + let color = null; + if (link && link.color) { + color = link.color; + } else if (link) { + const matchingEntry = inputNode.outputs.find((output) => { + return outputNode.inputs.some((input) => input.type === output.type); + }); + + if (matchingEntry) { + let nodeType = matchingEntry.type; + color = colorPalette.colors.node_slot[nodeType]; + } + } + return color; + } + + var originalRenderLink = LGraphCanvas.prototype.renderLink; + + LGraphCanvas.prototype.renderLink = function( + ctx, + a, + b, + link, + skip_border, + flow, + color, + start_dir, + end_dir, + num_sublines + ) { + if (link) { + const inputNode = this.graph.getNodeById(link.origin_id); + const outputNode = this.graph.getNodeById(link.target_id); + color = getLinkColor(link, inputNode, outputNode, colorPalette); + } + + originalRenderLink.call( + this, + ctx, + a, + b, + link, + skip_border, + flow, + color, + start_dir, + end_dir, + num_sublines + ); + }; +} \ No newline at end of file From e76890dcb4e8e8e8521d80d7b216d1bc410bbe4d Mon Sep 17 00:00:00 2001 From: Filipe Date: Sat, 8 Apr 2023 12:00:03 -0300 Subject: [PATCH 17/27] Fix large workflow pnginfo import --- web/scripts/pnginfo.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/web/scripts/pnginfo.js b/web/scripts/pnginfo.js index 580030d81..31f470739 100644 --- a/web/scripts/pnginfo.js +++ b/web/scripts/pnginfo.js @@ -32,8 +32,9 @@ export function getPngMetadata(file) { } const keyword = String.fromCharCode(...pngData.slice(offset + 8, keyword_end)); // Get the text - const text = String.fromCharCode(...pngData.slice(keyword_end + 1, offset + 8 + length)); - txt_chunks[keyword] = text; + const contentArraySegment = pngData.slice(keyword_end + 1, offset + 8 + length); + const contentJson = Array.from(contentArraySegment).map(s=>String.fromCharCode(s)).join('') + txt_chunks[keyword] = contentJson; } offset += 12 + length; From 327e49da42a76aa84d86e7236b95e5490e860a37 Mon Sep 17 00:00:00 2001 From: EllangoK Date: Sat, 8 Apr 2023 11:13:27 -0400 Subject: [PATCH 18/27] remove test render link file --- web/extensions/core/colorPalette.js | 2 +- web/scripts/test.js | 71 ----------------------------- 2 files changed, 1 insertion(+), 72 deletions(-) delete mode 100644 web/scripts/test.js diff --git a/web/extensions/core/colorPalette.js b/web/extensions/core/colorPalette.js index 2189e3c29..a04a422b9 100644 --- a/web/extensions/core/colorPalette.js +++ b/web/extensions/core/colorPalette.js @@ -462,4 +462,4 @@ function customizeRenderLink(colorPalette) { num_sublines ); }; -} \ No newline at end of file +} diff --git a/web/scripts/test.js b/web/scripts/test.js deleted file mode 100644 index 55f8dfb69..000000000 --- a/web/scripts/test.js +++ /dev/null @@ -1,71 +0,0 @@ -(function() { - var LGraphCanvas = LiteGraph.LGraphCanvas; - var LGraph = LiteGraph.LGraph; - - // Save the original renderLink function - var originalRenderLink = LGraphCanvas.prototype.renderLink; - - // Save the original connect function - var originalConnect = LGraph.prototype.connect; - - // Override the connect function - LGraph.prototype.connect = function ( - origin_slot, - target_slot, - options - ) { - var origin_id = origin_slot[0]; - var target_id = target_slot[0]; - - var origin_node = this.getNodeById(origin_id); - var target_node = this.getNodeById(target_id); - - - if (origin_node && target_node) { - var output_slot = origin_slot[1]; - var output_slot_info = origin_node.getOutputInfo(output_slot); - - - console.log(output_slot_info) - if (output_slot_info) { - options = options || {}; - options.color = output_slot_info.label_color || null; - } - } - - return originalConnect.call(this, origin_slot, target_slot, options); - }; - - // Override the renderLink function - LGraphCanvas.prototype.renderLink = function ( - ctx, - a, - b, - link, - skip_border, - flow, - color, - start_dir, - end_dir, - num_sublines - ) { - if (link && link.color) { - color = link.color; - } - - // Call the original renderLink function with the new color - originalRenderLink.call( - this, - ctx, - a, - b, - link, - skip_border, - flow, - color, - start_dir, - end_dir, - num_sublines - ); - }; -})(); From 79ff7d67a5562891dec5e952b1340dffda17289d Mon Sep 17 00:00:00 2001 From: pythongosssss <125205205+pythongosssss@users.noreply.github.com> Date: Sat, 8 Apr 2023 16:23:57 +0100 Subject: [PATCH 19/27] Add error handling around initial load of workflow --- web/scripts/app.js | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/web/scripts/app.js b/web/scripts/app.js index a687eb5c2..c2ba74b3a 100644 --- a/web/scripts/app.js +++ b/web/scripts/app.js @@ -1,5 +1,5 @@ import { ComfyWidgets } from "./widgets.js"; -import { ComfyUI } from "./ui.js"; +import { ComfyUI, $el } from "./ui.js"; import { api } from "./api.js"; import { defaultGraph } from "./defaultGraph.js"; import { getPngMetadata, importA1111 } from "./pnginfo.js"; @@ -869,7 +869,42 @@ class ComfyApp { if (n.type == "T2IAdapterLoader") n.type = "ControlNetLoader"; } - this.graph.configure(graphData); + try { + this.graph.configure(graphData); + } catch (error) { + let errorHint = ""; + // Try extracting filename to see if it was caused by an extension + const filename = error.fileName || (error.stack || "").match(/\/([\/\w-_\.]+\.js):(\d*):(\d*)/)?.[1]; + const pos = (filename || "").indexOf("/extensions/"); + if (pos > -1) { + errorHint = "This may be due to the following extension: " + filename.substring(pos + 12); + } + + // Show dialog to let the user know something went wrong loading the data + this.ui.dialog.show( + $el("div", [ + $el("p", { textContent: "Loading aborted due to error reloading workflow data" }), + $el("pre", { + style: { padding: "5px", backgroundColor: "rgba(255,0,0,0.2)" }, + textContent: error.toString(), + }), + $el("pre", { + style: { + padding: "5px", + color: "#ccc", + fontSize: "10px", + maxHeight: "50vh", + overflow: "auto", + backgroundColor: "rgba(255,0,0,0.2)", + }, + textContent: error.stack || "No stacktrace available", + }), + $el("span", { textContent: errorHint, style: { fontWeight: "bold" } }), + ]).outerHTML + ); + + return; + } for (const node of this.graph._nodes) { const size = node.computeSize(); From 12f9bfe8951d001b978dec0bd9a288dd39e80400 Mon Sep 17 00:00:00 2001 From: pythongosssss <125205205+pythongosssss@users.noreply.github.com> Date: Sat, 8 Apr 2023 16:31:10 +0100 Subject: [PATCH 20/27] Better filename check --- web/scripts/app.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/scripts/app.js b/web/scripts/app.js index c2ba74b3a..deb31f229 100644 --- a/web/scripts/app.js +++ b/web/scripts/app.js @@ -873,11 +873,11 @@ class ComfyApp { this.graph.configure(graphData); } catch (error) { let errorHint = ""; - // Try extracting filename to see if it was caused by an extension - const filename = error.fileName || (error.stack || "").match(/\/([\/\w-_\.]+\.js):(\d*):(\d*)/)?.[1]; + // Try extracting filename to see if it was caused by an extension script + const filename = error.fileName || (error.stack || "").match(/(\/extensions\/.*\.js)/)?.[1]; const pos = (filename || "").indexOf("/extensions/"); if (pos > -1) { - errorHint = "This may be due to the following extension: " + filename.substring(pos + 12); + errorHint = "This may be due to the following script: " + filename.substring(pos + 12); } // Show dialog to let the user know something went wrong loading the data From b78ebfcf9ddf757a5e807130c723a72460d6f2dd Mon Sep 17 00:00:00 2001 From: pythongosssss <125205205+pythongosssss@users.noreply.github.com> Date: Sat, 8 Apr 2023 16:37:09 +0100 Subject: [PATCH 21/27] Improve error UI --- web/scripts/app.js | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/web/scripts/app.js b/web/scripts/app.js index deb31f229..a8729fb4f 100644 --- a/web/scripts/app.js +++ b/web/scripts/app.js @@ -872,12 +872,21 @@ class ComfyApp { try { this.graph.configure(graphData); } catch (error) { - let errorHint = ""; + let errorHint = []; // Try extracting filename to see if it was caused by an extension script const filename = error.fileName || (error.stack || "").match(/(\/extensions\/.*\.js)/)?.[1]; const pos = (filename || "").indexOf("/extensions/"); if (pos > -1) { - errorHint = "This may be due to the following script: " + filename.substring(pos + 12); + errorHint.push( + $el("span", { textContent: "This may be due to the following script:" }), + $el("br"), + $el("span", { + style: { + fontWeight: "bold", + }, + textContent: filename.substring(pos), + }) + ); } // Show dialog to let the user know something went wrong loading the data @@ -895,14 +904,14 @@ class ComfyApp { fontSize: "10px", maxHeight: "50vh", overflow: "auto", - backgroundColor: "rgba(255,0,0,0.2)", + backgroundColor: "rgba(0,0,0,0.2)", }, textContent: error.stack || "No stacktrace available", }), - $el("span", { textContent: errorHint, style: { fontWeight: "bold" } }), + ...errorHint, ]).outerHTML ); - + return; } From 92e912c065c866054ff38eeca4045c6ee4e23f47 Mon Sep 17 00:00:00 2001 From: pythongosssss <125205205+pythongosssss@users.noreply.github.com> Date: Sat, 8 Apr 2023 16:55:09 +0100 Subject: [PATCH 22/27] Fix multiple missing --- web/scripts/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/scripts/app.js b/web/scripts/app.js index dee4f65ac..10019ce82 100644 --- a/web/scripts/app.js +++ b/web/scripts/app.js @@ -902,9 +902,9 @@ class ComfyApp { if (missingNodeTypes.length) { this.ui.dialog.show( - `When loading the graph, the following node types were not found:
    ${missingNodeTypes.map( + `When loading the graph, the following node types were not found:
      ${Array.from(new Set(missingNodeTypes)).map( (t) => `
    • ${t}
    • ` - )}
    Nodes that have failed to load will show as red on the graph.` + ).join("")}
Nodes that have failed to load will show as red on the graph.` ); } } From d9220a0bd6f60ad06e73a4d631bbc63ec8592c1c Mon Sep 17 00:00:00 2001 From: EllangoK Date: Sat, 8 Apr 2023 11:55:27 -0400 Subject: [PATCH 23/27] link colors change after palette swap didn't work previously as same function was defined repeatedly --- web/extensions/core/colorPalette.js | 39 ++++++++++++++++------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/web/extensions/core/colorPalette.js b/web/extensions/core/colorPalette.js index a04a422b9..c1473b93f 100644 --- a/web/extensions/core/colorPalette.js +++ b/web/extensions/core/colorPalette.js @@ -238,6 +238,7 @@ app.registerExtension({ if (colorPalette.colors) { if (colorPalette.colors.node_slot) { Object.assign(app.canvas.default_connection_color_byType, colorPalette.colors.node_slot); + customizeRenderLink(colorPalette); } if (colorPalette.colors.litegraph_base) { // Everything updates correctly in the loop, except the Node Title and Link Color for some reason @@ -250,7 +251,6 @@ app.registerExtension({ } } } - customizeRenderLink(colorPalette); app.canvas.draw(true, true); } }; @@ -411,24 +411,28 @@ app.registerExtension({ function customizeRenderLink(colorPalette) { var LGraphCanvas = LiteGraph.LGraphCanvas; - function getLinkColor(link, inputNode, outputNode, colorPalette) { - let color = null; - if (link && link.color) { - color = link.color; - } else if (link) { - const matchingEntry = inputNode.outputs.find((output) => { - return outputNode.inputs.some((input) => input.type === output.type); - }); + if (!LGraphCanvas.prototype.getLinkColor) { + LGraphCanvas.prototype.getLinkColor = function(link, inputNode, outputNode, colorPalette) { + let color = null; + if (link && link.color) { + color = link.color; + } else if (link) { + const matchingEntry = inputNode.outputs.find((output) => { + return outputNode.inputs.some((input) => input.type === output.type); + }); - if (matchingEntry) { - let nodeType = matchingEntry.type; - color = colorPalette.colors.node_slot[nodeType]; + if (matchingEntry) { + let nodeType = matchingEntry.type; + color = colorPalette.colors.node_slot[nodeType]; + } } - } - return color; + return color; + }; } - var originalRenderLink = LGraphCanvas.prototype.renderLink; + if (!LGraphCanvas.prototype.originalRenderLink) { + LGraphCanvas.prototype.originalRenderLink = LGraphCanvas.prototype.renderLink; + } LGraphCanvas.prototype.renderLink = function( ctx, @@ -445,10 +449,11 @@ function customizeRenderLink(colorPalette) { if (link) { const inputNode = this.graph.getNodeById(link.origin_id); const outputNode = this.graph.getNodeById(link.target_id); - color = getLinkColor(link, inputNode, outputNode, colorPalette); + color = this.getLinkColor(link, inputNode, outputNode, colorPalette); } - originalRenderLink.call( + // call the original renderLink function + this.originalRenderLink.call( this, ctx, a, From 53fba56ee5fa48261d8caec46927c34923a168fd Mon Sep 17 00:00:00 2001 From: EllangoK Date: Sat, 8 Apr 2023 13:18:23 -0400 Subject: [PATCH 24/27] assign link_type_colors directly --- web/extensions/core/colorPalette.js | 63 +---------------------------- 1 file changed, 1 insertion(+), 62 deletions(-) diff --git a/web/extensions/core/colorPalette.js b/web/extensions/core/colorPalette.js index c1473b93f..a08d46684 100644 --- a/web/extensions/core/colorPalette.js +++ b/web/extensions/core/colorPalette.js @@ -238,7 +238,7 @@ app.registerExtension({ if (colorPalette.colors) { if (colorPalette.colors.node_slot) { Object.assign(app.canvas.default_connection_color_byType, colorPalette.colors.node_slot); - customizeRenderLink(colorPalette); + Object.assign(LGraphCanvas.link_type_colors, colorPalette.colors.node_slot); } if (colorPalette.colors.litegraph_base) { // Everything updates correctly in the loop, except the Node Title and Link Color for some reason @@ -407,64 +407,3 @@ app.registerExtension({ }); }, }); - -function customizeRenderLink(colorPalette) { - var LGraphCanvas = LiteGraph.LGraphCanvas; - - if (!LGraphCanvas.prototype.getLinkColor) { - LGraphCanvas.prototype.getLinkColor = function(link, inputNode, outputNode, colorPalette) { - let color = null; - if (link && link.color) { - color = link.color; - } else if (link) { - const matchingEntry = inputNode.outputs.find((output) => { - return outputNode.inputs.some((input) => input.type === output.type); - }); - - if (matchingEntry) { - let nodeType = matchingEntry.type; - color = colorPalette.colors.node_slot[nodeType]; - } - } - return color; - }; - } - - if (!LGraphCanvas.prototype.originalRenderLink) { - LGraphCanvas.prototype.originalRenderLink = LGraphCanvas.prototype.renderLink; - } - - LGraphCanvas.prototype.renderLink = function( - ctx, - a, - b, - link, - skip_border, - flow, - color, - start_dir, - end_dir, - num_sublines - ) { - if (link) { - const inputNode = this.graph.getNodeById(link.origin_id); - const outputNode = this.graph.getNodeById(link.target_id); - color = this.getLinkColor(link, inputNode, outputNode, colorPalette); - } - - // call the original renderLink function - this.originalRenderLink.call( - this, - ctx, - a, - b, - link, - skip_border, - flow, - color, - start_dir, - end_dir, - num_sublines - ); - }; -} From 24d53992c61650bc2919acc06fbfbb625468bde8 Mon Sep 17 00:00:00 2001 From: comfyanonymous Date: Sat, 8 Apr 2023 15:53:01 -0400 Subject: [PATCH 25/27] Rename. --- nodes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nodes.py b/nodes.py index 63cf5e448..14a73bcd7 100644 --- a/nodes.py +++ b/nodes.py @@ -1109,8 +1109,8 @@ NODE_DISPLAY_NAME_MAPPINGS = { "KSampler": "KSampler", "KSamplerAdvanced": "KSampler (Advanced)", # Loaders - "CheckpointLoader": "Load Checkpoint", - "CheckpointLoaderSimple": "Load Checkpoint (Simple)", + "CheckpointLoader": "Load Checkpoint (With Config)", + "CheckpointLoaderSimple": "Load Checkpoint", "VAELoader": "Load VAE", "LoraLoader": "Load LoRA", "CLIPLoader": "Load CLIP", From 90581684b49ce2da94c2b5939d442dcbbc6b2331 Mon Sep 17 00:00:00 2001 From: comfyanonymous Date: Sat, 8 Apr 2023 19:25:34 -0400 Subject: [PATCH 26/27] Update notebook. --- notebooks/comfyui_colab.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notebooks/comfyui_colab.ipynb b/notebooks/comfyui_colab.ipynb index 3e59fbde7..d17f9877d 100644 --- a/notebooks/comfyui_colab.ipynb +++ b/notebooks/comfyui_colab.ipynb @@ -47,7 +47,7 @@ " !git pull\n", "\n", "!echo -= Install dependencies =-\n", - "!pip install xformers -r requirements.txt --extra-index-url https://download.pytorch.org/whl/cu118" + "!pip install xformers!=0.0.18 -r requirements.txt --extra-index-url https://download.pytorch.org/whl/cu118" ] }, { From 1e1875f674f47742cd8cb650b8e29b2b60cc2a2b Mon Sep 17 00:00:00 2001 From: comfyanonymous Date: Sun, 9 Apr 2023 01:31:47 -0400 Subject: [PATCH 27/27] Print xformers version and warning about 0.0.18 --- comfy/model_management.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/comfy/model_management.py b/comfy/model_management.py index 2407140fd..8303cb437 100644 --- a/comfy/model_management.py +++ b/comfy/model_management.py @@ -45,6 +45,8 @@ try: except: OOM_EXCEPTION = Exception +XFORMERS_VERSION = "" +XFORMERS_ENABLED_VAE = True if args.disable_xformers: XFORMERS_IS_AVAILABLE = False else: @@ -52,6 +54,17 @@ else: import xformers import xformers.ops XFORMERS_IS_AVAILABLE = True + try: + XFORMERS_VERSION = xformers.version.__version__ + print("xformers version:", XFORMERS_VERSION) + if XFORMERS_VERSION.startswith("0.0.18"): + print() + print("WARNING: This version of xformers has a major bug where you will get black images when generating high resolution images.") + print("Please downgrade or upgrade xformers to a different version.") + print() + XFORMERS_ENABLED_VAE = False + except: + pass except: XFORMERS_IS_AVAILABLE = False @@ -223,13 +236,8 @@ def xformers_enabled_vae(): enabled = xformers_enabled() if not enabled: return False - try: - #0.0.18 has a bug where Nan is returned when inputs are too big (1152x1920 res images and above) - if xformers.version.__version__ == "0.0.18": - return False - except: - pass - return enabled + + return XFORMERS_ENABLED_VAE def pytorch_attention_enabled(): return ENABLE_PYTORCH_ATTENTION