mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-01-19 19:00:21 +08:00
Merge branch 'comfyanonymous:master' into feature/blockweights
This commit is contained in:
commit
f6b10bb71c
@ -88,3 +88,8 @@ class Example:
|
|||||||
NODE_CLASS_MAPPINGS = {
|
NODE_CLASS_MAPPINGS = {
|
||||||
"Example": Example
|
"Example": Example
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# A dictionary that contains the friendly/humanly readable titles for the nodes
|
||||||
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||||
|
"Example": "Example Node"
|
||||||
|
}
|
||||||
|
|||||||
50
nodes.py
50
nodes.py
@ -1181,6 +1181,54 @@ NODE_CLASS_MAPPINGS = {
|
|||||||
"DiffusersLoader": DiffusersLoader,
|
"DiffusersLoader": DiffusersLoader,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||||
|
# Sampling
|
||||||
|
"KSampler": "KSampler",
|
||||||
|
"KSamplerAdvanced": "KSampler (Advanced)",
|
||||||
|
# Loaders
|
||||||
|
"CheckpointLoader": "Load Checkpoint (With Config)",
|
||||||
|
"CheckpointLoaderSimple": "Load Checkpoint",
|
||||||
|
"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):
|
def load_custom_node(module_path):
|
||||||
module_name = os.path.basename(module_path)
|
module_name = os.path.basename(module_path)
|
||||||
if os.path.isfile(module_path):
|
if os.path.isfile(module_path):
|
||||||
@ -1196,6 +1244,8 @@ def load_custom_node(module_path):
|
|||||||
module_spec.loader.exec_module(module)
|
module_spec.loader.exec_module(module)
|
||||||
if hasattr(module, "NODE_CLASS_MAPPINGS") and getattr(module, "NODE_CLASS_MAPPINGS") is not None:
|
if hasattr(module, "NODE_CLASS_MAPPINGS") and getattr(module, "NODE_CLASS_MAPPINGS") is not None:
|
||||||
NODE_CLASS_MAPPINGS.update(module.NODE_CLASS_MAPPINGS)
|
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:
|
else:
|
||||||
print(f"Skip {module_path} module for custom nodes due to the lack of NODE_CLASS_MAPPINGS.")
|
print(f"Skip {module_path} module for custom nodes due to the lack of NODE_CLASS_MAPPINGS.")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@ -47,7 +47,7 @@
|
|||||||
" !git pull\n",
|
" !git pull\n",
|
||||||
"\n",
|
"\n",
|
||||||
"!echo -= Install dependencies =-\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"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -177,7 +177,8 @@ class PromptServer():
|
|||||||
info['input'] = obj_class.INPUT_TYPES()
|
info['input'] = obj_class.INPUT_TYPES()
|
||||||
info['output'] = obj_class.RETURN_TYPES
|
info['output'] = obj_class.RETURN_TYPES
|
||||||
info['output_name'] = obj_class.RETURN_NAMES if hasattr(obj_class, 'RETURN_NAMES') else info['output']
|
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['description'] = ''
|
||||||
info['category'] = 'sd'
|
info['category'] = 'sd'
|
||||||
if hasattr(obj_class, 'CATEGORY'):
|
if hasattr(obj_class, 'CATEGORY'):
|
||||||
|
|||||||
@ -21,28 +21,74 @@ const colorPalettes = {
|
|||||||
"MODEL": "#B39DDB", // light lavender-purple
|
"MODEL": "#B39DDB", // light lavender-purple
|
||||||
"STYLE_MODEL": "#C2FFAE", // light green-yellow
|
"STYLE_MODEL": "#C2FFAE", // light green-yellow
|
||||||
"VAE": "#FF6E6E", // bright red
|
"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": {
|
"solarized": {
|
||||||
"id": "palette_2",
|
"id": "solarized",
|
||||||
"name": "Palette 2",
|
"name": "Solarized",
|
||||||
"colors": {
|
"colors": {
|
||||||
"node_slot": {
|
"node_slot": {
|
||||||
"CLIP": "#556B2F", // Dark Olive Green
|
"CLIP": "#859900", // Green
|
||||||
"CLIP_VISION": "#4B0082", // Indigo
|
"CLIP_VISION": "#6c71c4", // Indigo
|
||||||
"CLIP_VISION_OUTPUT": "#006400", // Green
|
"CLIP_VISION_OUTPUT": "#859900", // Green
|
||||||
"CONDITIONING": "#FF1493", // Deep Pink
|
"CONDITIONING": "#d33682", // Magenta
|
||||||
"CONTROL_NET": "#8B4513", // Saddle Brown
|
"CONTROL_NET": "#cb4b16", // Orange
|
||||||
"IMAGE": "#8B0000", // Dark Red
|
"IMAGE": "#dc322f", // Red
|
||||||
"LATENT": "#00008B", // Dark Blue
|
"LATENT": "#268bd2", // Blue
|
||||||
"MASK": "#2F4F4F", // Dark Slate Grey
|
"MASK": "#073642", // Base02
|
||||||
"MODEL": "#FF8C00", // Dark Orange
|
"MODEL": "#cb4b16", // Orange
|
||||||
"STYLE_MODEL": "#004A4A", // Sherpa Blue
|
"STYLE_MODEL": "#073642", // Base02
|
||||||
"UPSCALE_MODEL": "#4A004A", // Tyrian Purple
|
"UPSCALE_MODEL": "#6c71c4", // Indigo
|
||||||
"VAE": "#4F394F", // Loulou
|
"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",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -192,8 +238,20 @@ app.registerExtension({
|
|||||||
if (colorPalette.colors) {
|
if (colorPalette.colors) {
|
||||||
if (colorPalette.colors.node_slot) {
|
if (colorPalette.colors.node_slot) {
|
||||||
Object.assign(app.canvas.default_connection_color_byType, colorPalette.colors.node_slot);
|
Object.assign(app.canvas.default_connection_color_byType, colorPalette.colors.node_slot);
|
||||||
app.canvas.draw(true, true);
|
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
|
||||||
|
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)) {
|
||||||
|
LiteGraph[key] = colorPalette.colors.litegraph_base[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
app.canvas.draw(true, true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
184
web/extensions/core/nodeTemplates.js
Normal file
184
web/extensions/core/nodeTemplates.js
Normal file
@ -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;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
@ -7481,8 +7481,8 @@ LGraphNode.prototype.executeAction = function(action)
|
|||||||
clientY_rel = e.clientY;
|
clientY_rel = e.clientY;
|
||||||
}
|
}
|
||||||
|
|
||||||
// e.deltaX = clientX_rel - this.last_mouse_position[0];
|
e.deltaX = clientX_rel - this.last_mouse_position[0];
|
||||||
// e.deltaY = clientY_rel- this.last_mouse_position[1];
|
e.deltaY = clientY_rel- this.last_mouse_position[1];
|
||||||
|
|
||||||
this.last_mouse_position[0] = clientX_rel;
|
this.last_mouse_position[0] = clientX_rel;
|
||||||
this.last_mouse_position[1] = clientY_rel;
|
this.last_mouse_position[1] = clientY_rel;
|
||||||
@ -9923,7 +9923,14 @@ LGraphNode.prototype.executeAction = function(action)
|
|||||||
case "number":
|
case "number":
|
||||||
case "combo":
|
case "combo":
|
||||||
var old_value = w.value;
|
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)
|
if(event.deltaX)
|
||||||
w.value += event.deltaX * 0.1 * (w.options.step || 1);
|
w.value += event.deltaX * 0.1 * (w.options.step || 1);
|
||||||
if ( w.options.min != null && w.value < w.options.min ) {
|
if ( w.options.min != null && w.value < w.options.min ) {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { ComfyWidgets } from "./widgets.js";
|
import { ComfyWidgets } from "./widgets.js";
|
||||||
import { ComfyUI } from "./ui.js";
|
import { ComfyUI, $el } from "./ui.js";
|
||||||
import { api } from "./api.js";
|
import { api } from "./api.js";
|
||||||
import { defaultGraph } from "./defaultGraph.js";
|
import { defaultGraph } from "./defaultGraph.js";
|
||||||
import { getPngMetadata, importA1111 } from "./pnginfo.js";
|
import { getPngMetadata, importA1111 } from "./pnginfo.js";
|
||||||
@ -835,7 +835,7 @@ class ComfyApp {
|
|||||||
app.#invokeExtensionsAsync("nodeCreated", this);
|
app.#invokeExtensionsAsync("nodeCreated", this);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: nodeData.name,
|
title: nodeData.display_name || nodeData.name,
|
||||||
comfyClass: nodeData.name,
|
comfyClass: nodeData.name,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -864,12 +864,62 @@ class ComfyApp {
|
|||||||
graphData = structuredClone(defaultGraph);
|
graphData = structuredClone(defaultGraph);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Patch T2IAdapterLoader to ControlNetLoader since they are the same node now
|
const missingNodeTypes = [];
|
||||||
for (let n of graphData.nodes) {
|
for (let n of graphData.nodes) {
|
||||||
|
// Patch T2IAdapterLoader to ControlNetLoader since they are the same node now
|
||||||
if (n.type == "T2IAdapterLoader") n.type = "ControlNetLoader";
|
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);
|
try {
|
||||||
|
this.graph.configure(graphData);
|
||||||
|
} catch (error) {
|
||||||
|
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.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
|
||||||
|
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(0,0,0,0.2)",
|
||||||
|
},
|
||||||
|
textContent: error.stack || "No stacktrace available",
|
||||||
|
}),
|
||||||
|
...errorHint,
|
||||||
|
]).outerHTML
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (const node of this.graph._nodes) {
|
for (const node of this.graph._nodes) {
|
||||||
const size = node.computeSize();
|
const size = node.computeSize();
|
||||||
@ -893,6 +943,14 @@ class ComfyApp {
|
|||||||
|
|
||||||
this.#invokeExtensions("loadedGraphNode", node);
|
this.#invokeExtensions("loadedGraphNode", node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (missingNodeTypes.length) {
|
||||||
|
this.ui.dialog.show(
|
||||||
|
`When loading the graph, the following node types were not found: <ul>${Array.from(new Set(missingNodeTypes)).map(
|
||||||
|
(t) => `<li>${t}</li>`
|
||||||
|
).join("")}</ul>Nodes that have failed to load will show as red on the graph.`
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -13,7 +13,7 @@ export const defaultGraph = {
|
|||||||
inputs: [{ name: "clip", type: "CLIP", link: 5 }],
|
inputs: [{ name: "clip", type: "CLIP", link: 5 }],
|
||||||
outputs: [{ name: "CONDITIONING", type: "CONDITIONING", links: [6], slot_index: 0 }],
|
outputs: [{ name: "CONDITIONING", type: "CONDITIONING", links: [6], slot_index: 0 }],
|
||||||
properties: {},
|
properties: {},
|
||||||
widgets_values: ["bad hands"],
|
widgets_values: ["text, watermark"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 6,
|
id: 6,
|
||||||
@ -26,7 +26,7 @@ export const defaultGraph = {
|
|||||||
inputs: [{ name: "clip", type: "CLIP", link: 3 }],
|
inputs: [{ name: "clip", type: "CLIP", link: 3 }],
|
||||||
outputs: [{ name: "CONDITIONING", type: "CONDITIONING", links: [4], slot_index: 0 }],
|
outputs: [{ name: "CONDITIONING", type: "CONDITIONING", links: [4], slot_index: 0 }],
|
||||||
properties: {},
|
properties: {},
|
||||||
widgets_values: ["masterpiece best quality girl"],
|
widgets_values: ["beautiful scenery nature glass bottle landscape, , purple galaxy bottle,"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 5,
|
id: 5,
|
||||||
@ -56,7 +56,7 @@ export const defaultGraph = {
|
|||||||
],
|
],
|
||||||
outputs: [{ name: "LATENT", type: "LATENT", links: [7], slot_index: 0 }],
|
outputs: [{ name: "LATENT", type: "LATENT", links: [7], slot_index: 0 }],
|
||||||
properties: {},
|
properties: {},
|
||||||
widgets_values: [8566257, true, 20, 8, "euler", "normal", 1],
|
widgets_values: [156680208700286, true, 20, 8, "euler", "normal", 1],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 8,
|
id: 8,
|
||||||
|
|||||||
@ -32,8 +32,9 @@ export function getPngMetadata(file) {
|
|||||||
}
|
}
|
||||||
const keyword = String.fromCharCode(...pngData.slice(offset + 8, keyword_end));
|
const keyword = String.fromCharCode(...pngData.slice(offset + 8, keyword_end));
|
||||||
// Get the text
|
// Get the text
|
||||||
const text = String.fromCharCode(...pngData.slice(keyword_end + 1, offset + 8 + length));
|
const contentArraySegment = pngData.slice(keyword_end + 1, offset + 8 + length);
|
||||||
txt_chunks[keyword] = text;
|
const contentJson = Array.from(contentArraySegment).map(s=>String.fromCharCode(s)).join('')
|
||||||
|
txt_chunks[keyword] = contentJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += 12 + length;
|
offset += 12 + length;
|
||||||
|
|||||||
@ -8,14 +8,18 @@ export function $el(tag, propsOrChildren, children) {
|
|||||||
if (Array.isArray(propsOrChildren)) {
|
if (Array.isArray(propsOrChildren)) {
|
||||||
element.append(...propsOrChildren);
|
element.append(...propsOrChildren);
|
||||||
} else {
|
} else {
|
||||||
const parent = propsOrChildren.parent;
|
const { parent, $: cb, dataset, style } = propsOrChildren;
|
||||||
delete propsOrChildren.parent;
|
delete propsOrChildren.parent;
|
||||||
const cb = propsOrChildren.$;
|
|
||||||
delete propsOrChildren.$;
|
delete propsOrChildren.$;
|
||||||
|
delete propsOrChildren.dataset;
|
||||||
|
delete propsOrChildren.style;
|
||||||
|
|
||||||
if (propsOrChildren.style) {
|
if (style) {
|
||||||
Object.assign(element.style, propsOrChildren.style);
|
Object.assign(element.style, style);
|
||||||
delete propsOrChildren.style;
|
}
|
||||||
|
|
||||||
|
if (dataset) {
|
||||||
|
Object.assign(element.dataset, dataset);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.assign(element, propsOrChildren);
|
Object.assign(element, propsOrChildren);
|
||||||
@ -145,7 +149,7 @@ function dragElement(dragEl, settings) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("resize", () => {
|
window.addEventListener("resize", () => {
|
||||||
ensureInBounds();
|
ensureInBounds();
|
||||||
});
|
});
|
||||||
|
|
||||||
function closeDragElement() {
|
function closeDragElement() {
|
||||||
@ -155,26 +159,33 @@ function dragElement(dragEl, settings) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ComfyDialog {
|
export class ComfyDialog {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.element = $el("div.comfy-modal", { parent: document.body }, [
|
this.element = $el("div.comfy-modal", { parent: document.body }, [
|
||||||
$el("div.comfy-modal-content", [
|
$el("div.comfy-modal-content", [$el("p", { $: (p) => (this.textElement = p) }), ...this.createButtons()]),
|
||||||
$el("p", { $: (p) => (this.textElement = p) }),
|
|
||||||
$el("button", {
|
|
||||||
type: "button",
|
|
||||||
textContent: "Close",
|
|
||||||
onclick: () => this.close(),
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createButtons() {
|
||||||
|
return [
|
||||||
|
$el("button", {
|
||||||
|
type: "button",
|
||||||
|
textContent: "Close",
|
||||||
|
onclick: () => this.close(),
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
this.element.style.display = "none";
|
this.element.style.display = "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
show(html) {
|
show(html) {
|
||||||
this.textElement.innerHTML = html;
|
if (typeof html === "string") {
|
||||||
|
this.textElement.innerHTML = html;
|
||||||
|
} else {
|
||||||
|
this.textElement.replaceChildren(html);
|
||||||
|
}
|
||||||
this.element.style.display = "flex";
|
this.element.style.display = "flex";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -202,7 +202,8 @@ button.comfy-queue-btn {
|
|||||||
margin: 6px 0 !important;
|
margin: 6px 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comfy-modal.comfy-settings {
|
.comfy-modal.comfy-settings,
|
||||||
|
.comfy-modal.comfy-manage-templates {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
color: #999;
|
color: #999;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user