Compare commits

...

8 Commits

Author SHA1 Message Date
guill 0c7c98a965 Nodes using UNIQUE_ID as input are NOT_IDEMPOTENT (#4793)
Python Linting / Run Pylint (push) Failing after 38s
Build package / Build Test (3.10) (push) Failing after 31s
Build package / Build Test (3.11) (push) Failing after 36s
Build package / Build Test (3.8) (push) Failing after 33s
Build package / Build Test (3.9) (push) Failing after 34s
As suggested by @ltdrdata, we can automatically consider nodes that take
the UNIQUE_ID hidden input to be NOT_IDEMPOTENT.
2024-09-05 19:33:02 -04:00
comfyanonymous dc2eb75b85 Update stable release workflow to latest pytorch with cuda 12.4. 2024-09-05 19:21:52 -04:00
Chenlei Hu fa34efe3bd Update frontend to v1.2.47 (#4798)
* Update web content to release v1.2.47

* Update shortcut list
2024-09-05 18:56:01 -04:00
comfyanonymous 5cbaa9e07c Mistoline flux controlnet support. 2024-09-05 00:05:17 -04:00
comfyanonymous c7427375ee Prioritize freeing partially offloaded models first. 2024-09-04 19:47:32 -04:00
comfyanonymous 22d1241a50 Add an experimental LoraSave node to extract model loras.
The model_diff input should be connected to the output of a
ModelMergeSubtract node.
2024-09-04 16:38:38 -04:00
Jedrzej Kosinski f04229b84d Add emb_patch support to UNetModel forward (#4779) 2024-09-04 14:35:15 -04:00
Silver f067ad15d1 Make live preview size a configurable launch argument (#4649)
* Make live preview size a configurable launch argument

* Remove import from testing phase

* Update cli_args.py
2024-09-03 19:16:38 -04:00
59 changed files with 8248 additions and 7338 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ on:
description: 'CUDA version'
required: true
type: string
default: "121"
default: "124"
python_minor:
description: 'Python minor version'
required: true
+2
View File
@@ -94,6 +94,8 @@ Workflow examples can be found on the [Examples page](https://comfyanonymous.git
| Alt + `+` | Canvas Zoom in |
| Alt + `-` | Canvas Zoom out |
| Ctrl + Shift + LMB + Vertical drag | Canvas Zoom in/out |
| P | Pin/Unpin selected nodes |
| Ctrl + G | Group selected nodes |
| Q | Toggle visibility of the queue |
| H | Toggle visibility of history |
| R | Refresh graph |
+2
View File
@@ -92,6 +92,8 @@ class LatentPreviewMethod(enum.Enum):
parser.add_argument("--preview-method", type=LatentPreviewMethod, default=LatentPreviewMethod.NoPreviews, help="Default preview method for sampler nodes.", action=EnumAction)
parser.add_argument("--preview-size", type=int, default=512, help="Sets the maximum preview size for sampler nodes.")
cache_group = parser.add_mutually_exclusive_group()
cache_group.add_argument("--cache-classic", action="store_true", help="Use the old style (aggressive) caching.")
cache_group.add_argument("--cache-lru", type=int, default=0, help="Use LRU caching with a maximum of N node results cached. May use more RAM/VRAM.")
+11 -5
View File
@@ -430,9 +430,9 @@ def load_controlnet_hunyuandit(controlnet_data):
control = ControlNet(control_model, compression_ratio=1, latent_format=latent_format, load_device=load_device, manual_cast_dtype=manual_cast_dtype, extra_conds=extra_conds, strength_type=StrengthType.CONSTANT)
return control
def load_controlnet_flux_xlabs(sd):
def load_controlnet_flux_xlabs_mistoline(sd, mistoline=False):
model_config, operations, load_device, unet_dtype, manual_cast_dtype, offload_device = controlnet_config(sd)
control_model = comfy.ldm.flux.controlnet.ControlNetFlux(operations=operations, device=offload_device, dtype=unet_dtype, **model_config.unet_config)
control_model = comfy.ldm.flux.controlnet.ControlNetFlux(mistoline=mistoline, operations=operations, device=offload_device, dtype=unet_dtype, **model_config.unet_config)
control_model = controlnet_load_state_dict(control_model, sd)
extra_conds = ['y', 'guidance']
control = ControlNet(control_model, load_device=load_device, manual_cast_dtype=manual_cast_dtype, extra_conds=extra_conds)
@@ -457,6 +457,10 @@ def load_controlnet_flux_instantx(sd):
control = ControlNet(control_model, compression_ratio=1, latent_format=latent_format, load_device=load_device, manual_cast_dtype=manual_cast_dtype, extra_conds=extra_conds)
return control
def convert_mistoline(sd):
return comfy.utils.state_dict_prefix_replace(sd, {"single_controlnet_blocks.": "controlnet_single_blocks."})
def load_controlnet(ckpt_path, model=None):
controlnet_data = comfy.utils.load_torch_file(ckpt_path, safe_load=True)
if 'after_proj_list.18.bias' in controlnet_data.keys(): #Hunyuan DiT
@@ -518,13 +522,15 @@ def load_controlnet(ckpt_path, model=None):
if len(leftover_keys) > 0:
logging.warning("leftover keys: {}".format(leftover_keys))
controlnet_data = new_sd
elif "controlnet_blocks.0.weight" in controlnet_data: #SD3 diffusers format
elif "controlnet_blocks.0.weight" in controlnet_data:
if "double_blocks.0.img_attn.norm.key_norm.scale" in controlnet_data:
return load_controlnet_flux_xlabs(controlnet_data)
return load_controlnet_flux_xlabs_mistoline(controlnet_data)
elif "pos_embed_input.proj.weight" in controlnet_data:
return load_controlnet_mmdit(controlnet_data)
return load_controlnet_mmdit(controlnet_data) #SD3 diffusers controlnet
elif "controlnet_x_embedder.weight" in controlnet_data:
return load_controlnet_flux_instantx(controlnet_data)
elif "controlnet_blocks.0.linear.weight" in controlnet_data: #mistoline flux
return load_controlnet_flux_xlabs_mistoline(convert_mistoline(controlnet_data), mistoline=True)
pth_key = 'control_model.zero_convs.0.0.weight'
pth = False
+74 -25
View File
@@ -1,4 +1,5 @@
#Original code can be found on: https://github.com/XLabs-AI/x-flux/blob/main/src/flux/controlnet.py
#modified to support different types of flux controlnets
import torch
import math
@@ -12,22 +13,65 @@ from .layers import (DoubleStreamBlock, EmbedND, LastLayer,
from .model import Flux
import comfy.ldm.common_dit
class MistolineCondDownsamplBlock(nn.Module):
def __init__(self, dtype=None, device=None, operations=None):
super().__init__()
self.encoder = nn.Sequential(
operations.Conv2d(3, 16, 3, padding=1, dtype=dtype, device=device),
nn.SiLU(),
operations.Conv2d(16, 16, 1, dtype=dtype, device=device),
nn.SiLU(),
operations.Conv2d(16, 16, 3, padding=1, dtype=dtype, device=device),
nn.SiLU(),
operations.Conv2d(16, 16, 3, padding=1, stride=2, dtype=dtype, device=device),
nn.SiLU(),
operations.Conv2d(16, 16, 3, padding=1, dtype=dtype, device=device),
nn.SiLU(),
operations.Conv2d(16, 16, 3, padding=1, stride=2, dtype=dtype, device=device),
nn.SiLU(),
operations.Conv2d(16, 16, 3, padding=1, dtype=dtype, device=device),
nn.SiLU(),
operations.Conv2d(16, 16, 3, padding=1, stride=2, dtype=dtype, device=device),
nn.SiLU(),
operations.Conv2d(16, 16, 1, dtype=dtype, device=device),
nn.SiLU(),
operations.Conv2d(16, 16, 3, padding=1, dtype=dtype, device=device)
)
def forward(self, x):
return self.encoder(x)
class MistolineControlnetBlock(nn.Module):
def __init__(self, hidden_size, dtype=None, device=None, operations=None):
super().__init__()
self.linear = operations.Linear(hidden_size, hidden_size, dtype=dtype, device=device)
self.act = nn.SiLU()
def forward(self, x):
return self.act(self.linear(x))
class ControlNetFlux(Flux):
def __init__(self, latent_input=False, num_union_modes=0, image_model=None, dtype=None, device=None, operations=None, **kwargs):
def __init__(self, latent_input=False, num_union_modes=0, mistoline=False, image_model=None, dtype=None, device=None, operations=None, **kwargs):
super().__init__(final_layer=False, dtype=dtype, device=device, operations=operations, **kwargs)
self.main_model_double = 19
self.main_model_single = 38
self.mistoline = mistoline
# add ControlNet blocks
if self.mistoline:
control_block = lambda : MistolineControlnetBlock(self.hidden_size, dtype=dtype, device=device, operations=operations)
else:
control_block = lambda : operations.Linear(self.hidden_size, self.hidden_size, dtype=dtype, device=device)
self.controlnet_blocks = nn.ModuleList([])
for _ in range(self.params.depth):
controlnet_block = operations.Linear(self.hidden_size, self.hidden_size, dtype=dtype, device=device)
self.controlnet_blocks.append(controlnet_block)
self.controlnet_blocks.append(control_block())
self.controlnet_single_blocks = nn.ModuleList([])
for _ in range(self.params.depth_single_blocks):
self.controlnet_single_blocks.append(operations.Linear(self.hidden_size, self.hidden_size, dtype=dtype, device=device))
self.controlnet_single_blocks.append(control_block())
self.num_union_modes = num_union_modes
self.controlnet_mode_embedder = None
@@ -38,23 +82,26 @@ class ControlNetFlux(Flux):
self.latent_input = latent_input
self.pos_embed_input = operations.Linear(self.in_channels, self.hidden_size, bias=True, dtype=dtype, device=device)
if not self.latent_input:
self.input_hint_block = nn.Sequential(
operations.Conv2d(3, 16, 3, padding=1, dtype=dtype, device=device),
nn.SiLU(),
operations.Conv2d(16, 16, 3, padding=1, dtype=dtype, device=device),
nn.SiLU(),
operations.Conv2d(16, 16, 3, padding=1, stride=2, dtype=dtype, device=device),
nn.SiLU(),
operations.Conv2d(16, 16, 3, padding=1, dtype=dtype, device=device),
nn.SiLU(),
operations.Conv2d(16, 16, 3, padding=1, stride=2, dtype=dtype, device=device),
nn.SiLU(),
operations.Conv2d(16, 16, 3, padding=1, dtype=dtype, device=device),
nn.SiLU(),
operations.Conv2d(16, 16, 3, padding=1, stride=2, dtype=dtype, device=device),
nn.SiLU(),
operations.Conv2d(16, 16, 3, padding=1, dtype=dtype, device=device)
)
if self.mistoline:
self.input_cond_block = MistolineCondDownsamplBlock(dtype=dtype, device=device, operations=operations)
else:
self.input_hint_block = nn.Sequential(
operations.Conv2d(3, 16, 3, padding=1, dtype=dtype, device=device),
nn.SiLU(),
operations.Conv2d(16, 16, 3, padding=1, dtype=dtype, device=device),
nn.SiLU(),
operations.Conv2d(16, 16, 3, padding=1, stride=2, dtype=dtype, device=device),
nn.SiLU(),
operations.Conv2d(16, 16, 3, padding=1, dtype=dtype, device=device),
nn.SiLU(),
operations.Conv2d(16, 16, 3, padding=1, stride=2, dtype=dtype, device=device),
nn.SiLU(),
operations.Conv2d(16, 16, 3, padding=1, dtype=dtype, device=device),
nn.SiLU(),
operations.Conv2d(16, 16, 3, padding=1, stride=2, dtype=dtype, device=device),
nn.SiLU(),
operations.Conv2d(16, 16, 3, padding=1, dtype=dtype, device=device)
)
def forward_orig(
self,
@@ -73,9 +120,6 @@ class ControlNetFlux(Flux):
# running on sequences img
img = self.img_in(img)
if not self.latent_input:
controlnet_cond = self.input_hint_block(controlnet_cond)
controlnet_cond = rearrange(controlnet_cond, "b c (h ph) (w pw) -> b (h w) (c ph pw)", ph=2, pw=2)
controlnet_cond = self.pos_embed_input(controlnet_cond)
img = img + controlnet_cond
@@ -131,9 +175,14 @@ class ControlNetFlux(Flux):
patch_size = 2
if self.latent_input:
hint = comfy.ldm.common_dit.pad_to_patch_size(hint, (patch_size, patch_size))
hint = rearrange(hint, "b c (h ph) (w pw) -> b (h w) (c ph pw)", ph=patch_size, pw=patch_size)
elif self.mistoline:
hint = hint * 2.0 - 1.0
hint = self.input_cond_block(hint)
else:
hint = hint * 2.0 - 1.0
hint = self.input_hint_block(hint)
hint = rearrange(hint, "b c (h ph) (w pw) -> b (h w) (c ph pw)", ph=patch_size, pw=patch_size)
bs, c, h, w = x.shape
x = comfy.ldm.common_dit.pad_to_patch_size(x, (patch_size, patch_size))
@@ -842,6 +842,11 @@ class UNetModel(nn.Module):
t_emb = timestep_embedding(timesteps, self.model_channels, repeat_only=False).to(x.dtype)
emb = self.time_embed(t_emb)
if "emb_patch" in transformer_patches:
patch = transformer_patches["emb_patch"]
for p in patch:
emb = p(emb, self.model_channels, transformer_options)
if self.num_classes is not None:
assert y.shape[0] == x.shape[0]
emb = emb + self.label_emb(y)
+1 -1
View File
@@ -426,7 +426,7 @@ def free_memory(memory_required, device, keep_loaded=[]):
shift_model = current_loaded_models[i]
if shift_model.device == device:
if shift_model not in keep_loaded:
can_unload.append((sys.getrefcount(shift_model.model), shift_model.model_memory(), i))
can_unload.append((-shift_model.model_offloaded_memory(), sys.getrefcount(shift_model.model), shift_model.model_memory(), i))
shift_model.currently_used = False
for x in sorted(can_unload):
+1 -1
View File
@@ -98,7 +98,7 @@ class CacheKeySetInputSignature(CacheKeySet):
class_type = node["class_type"]
class_def = nodes.NODE_CLASS_MAPPINGS[class_type]
signature = [class_type, self.is_changed_cache.get(node_id)]
if self.include_node_id_in_input() or (hasattr(class_def, "NOT_IDEMPOTENT") and class_def.NOT_IDEMPOTENT):
if self.include_node_id_in_input() or (hasattr(class_def, "NOT_IDEMPOTENT") and class_def.NOT_IDEMPOTENT) or "UNIQUE_ID" in class_def.INPUT_TYPES().get("hidden", {}).values():
signature.append(node_id)
inputs = node["inputs"]
for key in sorted(inputs.keys()):
+91
View File
@@ -0,0 +1,91 @@
import torch
import comfy.model_management
import comfy.utils
import folder_paths
import os
import logging
CLAMP_QUANTILE = 0.99
def extract_lora(diff, rank):
conv2d = (len(diff.shape) == 4)
kernel_size = None if not conv2d else diff.size()[2:4]
conv2d_3x3 = conv2d and kernel_size != (1, 1)
out_dim, in_dim = diff.size()[0:2]
rank = min(rank, in_dim, out_dim)
if conv2d:
if conv2d_3x3:
diff = diff.flatten(start_dim=1)
else:
diff = diff.squeeze()
U, S, Vh = torch.linalg.svd(diff.float())
U = U[:, :rank]
S = S[:rank]
U = U @ torch.diag(S)
Vh = Vh[:rank, :]
dist = torch.cat([U.flatten(), Vh.flatten()])
hi_val = torch.quantile(dist, CLAMP_QUANTILE)
low_val = -hi_val
U = U.clamp(low_val, hi_val)
Vh = Vh.clamp(low_val, hi_val)
if conv2d:
U = U.reshape(out_dim, rank, 1, 1)
Vh = Vh.reshape(rank, in_dim, kernel_size[0], kernel_size[1])
return (U, Vh)
class LoraSave:
def __init__(self):
self.output_dir = folder_paths.get_output_directory()
@classmethod
def INPUT_TYPES(s):
return {"required": {"filename_prefix": ("STRING", {"default": "loras/ComfyUI_extracted_lora"}),
"rank": ("INT", {"default": 8, "min": 1, "max": 1024, "step": 1}),
},
"optional": {"model_diff": ("MODEL",),},
}
RETURN_TYPES = ()
FUNCTION = "save"
OUTPUT_NODE = True
CATEGORY = "_for_testing"
def save(self, filename_prefix, rank, model_diff=None):
if model_diff is None:
return {}
full_output_folder, filename, counter, subfolder, filename_prefix = folder_paths.get_save_image_path(filename_prefix, self.output_dir)
output_sd = {}
prefix_key = "diffusion_model."
stored = set()
comfy.model_management.load_models_gpu([model_diff], force_patch_weights=True)
sd = model_diff.model_state_dict(filter_prefix=prefix_key)
for k in sd:
if k.endswith(".weight"):
weight_diff = sd[k]
if weight_diff.ndim < 2:
continue
try:
out = extract_lora(weight_diff, rank)
output_sd["{}.lora_up.weight".format(k[:-7])] = out[0].contiguous().half().cpu()
output_sd["{}.lora_down.weight".format(k[:-7])] = out[1].contiguous().half().cpu()
except:
logging.warning("Could not generate lora weights for key {}, is the weight difference a zero?".format(k))
output_checkpoint = f"{filename}_{counter:05}_.safetensors"
output_checkpoint = os.path.join(full_output_folder, output_checkpoint)
comfy.utils.save_torch_file(output_sd, output_checkpoint, metadata=None)
return {}
NODE_CLASS_MAPPINGS = {
"LoraSave": LoraSave
}
+1 -1
View File
@@ -9,7 +9,7 @@ import folder_paths
import comfy.utils
import logging
MAX_PREVIEW_RESOLUTION = 512
MAX_PREVIEW_RESOLUTION = args.preview_size
def preview_to_image(latent_image):
latents_ubyte = (((latent_image + 1.0) / 2.0).clamp(0, 1) # change scale from -1..1 to 0..1
+1
View File
@@ -247,6 +247,7 @@ if __name__ == "__main__":
folder_paths.add_model_folder_path("clip", os.path.join(folder_paths.get_output_directory(), "clip"))
folder_paths.add_model_folder_path("vae", os.path.join(folder_paths.get_output_directory(), "vae"))
folder_paths.add_model_folder_path("diffusion_models", os.path.join(folder_paths.get_output_directory(), "diffusion_models"))
folder_paths.add_model_folder_path("loras", os.path.join(folder_paths.get_output_directory(), "loras"))
if args.input_directory:
input_dir = os.path.abspath(args.input_directory)
+1
View File
@@ -2101,6 +2101,7 @@ def init_builtin_extra_nodes():
"nodes_controlnet.py",
"nodes_hunyuan.py",
"nodes_flux.py",
"nodes_lora_extract.py",
]
import_failed = []
-1
View File
File diff suppressed because one or more lines are too long
View File
+5 -5
View File
@@ -1,6 +1,6 @@
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
import { C as ComfyDialog, $ as $el, a as ComfyApp, b as app, L as LGraphCanvas, c as LiteGraph, d as LGraphNode, e as applyTextReplacements, f as ComfyWidgets, g as addValueControlWidgets, D as DraggableList, h as api, u as useToastStore, i as LGraphGroup } from "./index-CI3N807S.js";
import { C as ComfyDialog, $ as $el, a as ComfyApp, b as app, L as LGraphCanvas, c as LiteGraph, d as LGraphNode, e as applyTextReplacements, f as ComfyWidgets, g as addValueControlWidgets, D as DraggableList, h as api, i as LGraphGroup, u as useToastStore } from "./index-Dfv2aLsq.js";
class ClipspaceDialog extends ComfyDialog {
static {
__name(this, "ClipspaceDialog");
@@ -3650,7 +3650,7 @@ app.registerExtension({
content: "Add Group For Selected Nodes",
disabled: !Object.keys(app.canvas.selected_nodes || {}).length,
callback: /* @__PURE__ */ __name(() => {
var group2 = new LiteGraph.LGraphGroup();
const group2 = new LGraphGroup();
addNodesToGroup(group2, this.selected_nodes);
app.canvas.graph.add(group2);
this.graph.change();
@@ -5088,7 +5088,7 @@ app.registerExtension({
data = JSON.parse(data);
const nodeIds = Object.keys(app.canvas.selected_nodes);
for (let i = 0; i < nodeIds.length; i++) {
const node = app.graph.getNodeById(Number.parseInt(nodeIds[i]));
const node = app.graph.getNodeById(nodeIds[i]);
const nodeData = node?.constructor.nodeData;
let groupData = GroupNodeHandler.getGroupData(node);
if (groupData) {
@@ -5955,7 +5955,7 @@ app.registerExtension({
},
onNodeOutputsUpdated(nodeOutputs) {
for (const [nodeId, output] of Object.entries(nodeOutputs)) {
const node = app.graph.getNodeById(Number.parseInt(nodeId));
const node = app.graph.getNodeById(nodeId);
if ("audio" in output) {
const audioUIWidget = node.widgets.find(
(w) => w.name === "audioUI"
@@ -6026,4 +6026,4 @@ app.registerExtension({
};
}
});
//# sourceMappingURL=index-BD-Ia1C4.js.map
//# sourceMappingURL=index-CrROdkG4.js.map
+1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+83 -61
View File
@@ -1475,21 +1475,21 @@
width: 5rem !important;
}
.info-chip[data-v-25bd5f50] {
.info-chip[data-v-ffbfdf57] {
background: transparent;
}
.setting-item[data-v-25bd5f50] {
.setting-item[data-v-ffbfdf57] {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
}
.setting-label[data-v-25bd5f50] {
.setting-label[data-v-ffbfdf57] {
display: flex;
align-items: center;
flex: 1;
}
.setting-input[data-v-25bd5f50] {
.setting-input[data-v-ffbfdf57] {
flex: 1;
display: flex;
justify-content: flex-end;
@@ -1497,19 +1497,19 @@
}
/* Ensure PrimeVue components take full width of their container */
.setting-input[data-v-25bd5f50] .p-inputtext,
.setting-input[data-v-25bd5f50] .input-slider,
.setting-input[data-v-25bd5f50] .p-select,
.setting-input[data-v-25bd5f50] .p-togglebutton {
.setting-input[data-v-ffbfdf57] .p-inputtext,
.setting-input[data-v-ffbfdf57] .input-slider,
.setting-input[data-v-ffbfdf57] .p-select,
.setting-input[data-v-ffbfdf57] .p-togglebutton {
width: 100%;
max-width: 200px;
}
.setting-input[data-v-25bd5f50] .p-inputtext {
.setting-input[data-v-ffbfdf57] .p-inputtext {
max-width: unset;
}
/* Special case for ToggleSwitch to align it to the right */
.setting-input[data-v-25bd5f50] .p-toggleswitch {
.setting-input[data-v-ffbfdf57] .p-toggleswitch {
margin-left: auto;
}
@@ -1655,21 +1655,21 @@
margin-left: 0.5rem;
}
.comfy-error-report[data-v-12539d86] {
.comfy-error-report[data-v-a103fd62] {
display: flex;
flex-direction: column;
gap: 1rem;
}
.action-container[data-v-12539d86] {
.action-container[data-v-a103fd62] {
display: flex;
gap: 1rem;
justify-content: flex-end;
}
.wrapper-pre[data-v-12539d86] {
.wrapper-pre[data-v-a103fd62] {
white-space: pre-wrap;
word-wrap: break-word;
}
.no-results-placeholder[data-v-12539d86] {
.no-results-placeholder[data-v-a103fd62] {
padding-top: 0;
}
.lds-ring {
@@ -3158,7 +3158,7 @@ body {
overflow: hidden;
grid-template-columns: auto 1fr auto;
grid-template-rows: auto 1fr auto;
background-color: var(--bg-color);
background: var(--bg-color) var(--bg-img);
color: var(--fg-color);
min-height: -webkit-fill-available;
max-height: -webkit-fill-available;
@@ -3833,17 +3833,19 @@ audio.comfy-audio.empty-audio-widget {
box-sizing: border-box;
}
.node-title-editor[data-v-77799b26] {
.group-title-editor.node-title-editor[data-v-f0cbabc5] {
z-index: 9999;
padding: 0.25rem;
}
[data-v-77799b26] .editable-text {
[data-v-f0cbabc5] .editable-text {
width: 100%;
height: 100%;
}
[data-v-77799b26] .editable-text input {
[data-v-f0cbabc5] .editable-text input {
width: 100%;
height: 100%;
/* Override the default font size */
font-size: inherit;
}
.side-bar-button-icon {
@@ -4086,26 +4088,26 @@ audio.comfy-audio.empty-audio-widget {
color: var(--error-text);
}
.comfy-vue-node-search-container[data-v-077af1a9] {
.comfy-vue-node-search-container[data-v-d28bffc4] {
display: flex;
width: 100%;
min-width: 24rem;
align-items: center;
justify-content: center;
}
.comfy-vue-node-search-container[data-v-077af1a9] * {
.comfy-vue-node-search-container[data-v-d28bffc4] * {
pointer-events: auto;
}
.comfy-vue-node-preview-container[data-v-077af1a9] {
.comfy-vue-node-preview-container[data-v-d28bffc4] {
position: absolute;
left: -350px;
top: 50px;
}
.comfy-vue-node-search-box[data-v-077af1a9] {
.comfy-vue-node-search-box[data-v-d28bffc4] {
z-index: 10;
flex-grow: 1;
}
.option-container[data-v-077af1a9] {
.option-container[data-v-d28bffc4] {
display: flex;
width: 100%;
cursor: pointer;
@@ -4117,12 +4119,12 @@ audio.comfy-audio.empty-audio-widget {
padding-top: 0px;
padding-bottom: 0px;
}
.option-display-name[data-v-077af1a9] {
.option-display-name[data-v-d28bffc4] {
display: flex;
flex-direction: column;
font-weight: 600;
}
.option-category[data-v-077af1a9] {
.option-category[data-v-d28bffc4] {
overflow: hidden;
text-overflow: ellipsis;
font-size: 0.875rem;
@@ -4133,7 +4135,7 @@ audio.comfy-audio.empty-audio-widget {
/* Keeps the text on a single line by default */
white-space: nowrap;
}
[data-v-077af1a9] .highlight {
[data-v-d28bffc4] .highlight {
background-color: var(--p-primary-color);
color: var(--p-primary-contrast-color);
font-weight: bold;
@@ -4141,10 +4143,10 @@ audio.comfy-audio.empty-audio-widget {
padding: 0rem 0.125rem;
margin: -0.125rem 0.125rem;
}
._filter-button[data-v-077af1a9] {
._filter-button[data-v-d28bffc4] {
z-index: 10;
}
._dialog[data-v-077af1a9] {
._dialog[data-v-d28bffc4] {
min-width: 24rem;
}
@@ -4353,28 +4355,60 @@ img.galleria-image {
gap: 0.5rem;
}
.node-tree-leaf[data-v-adf5f221] {
.tree-node[data-v-d4b7b060] {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
}
.node-content[data-v-adf5f221] {
.leaf-count-badge[data-v-d4b7b060] {
margin-left: 0.5rem;
}
.node-content[data-v-d4b7b060] {
display: flex;
align-items: center;
flex-grow: 1;
}
.node-label[data-v-adf5f221] {
.leaf-label[data-v-d4b7b060] {
margin-left: 0.5rem;
}
.bookmark-button[data-v-adf5f221] {
width: unset;
padding: 0.25rem;
[data-v-d4b7b060] .editable-text span {
word-break: break-all;
}
.node-tree-folder[data-v-f2d72e9b] {
[data-v-9d3310b9] .tree-explorer-node-label {
width: 100%;
display: flex;
align-items: center;
margin-left: var(--p-tree-node-gap);
flex-grow: 1;
}
/*
* The following styles are necessary to avoid layout shift when dragging nodes over folders.
* By setting the position to relative on the parent and using an absolutely positioned pseudo-element,
* we can create a visual indicator for the drop target without affecting the layout of other elements.
*/
[data-v-9d3310b9] .p-tree-node-content:has(.tree-folder) {
position: relative;
}
[data-v-9d3310b9] .p-tree-node-content:has(.tree-folder.can-drop)::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border: 1px solid var(--p-content-color);
pointer-events: none;
}
.node-lib-node-container[data-v-3238e135] {
height: 100%;
width: 100%;
}
.bookmark-button[data-v-3238e135] {
width: unset;
padding: 0.25rem;
}
.p-selectbutton .p-button[data-v-91077f2a] {
@@ -4394,45 +4428,33 @@ img.galleria-image {
gap: 0.5rem;
}
.node-lib-tree-node-label {
display: flex;
align-items: center;
margin-left: var(--p-tree-node-gap);
flex-grow: 1;
}
.node-lib-filter-popup {
margin-left: -13px;
}
[data-v-87967891] .node-lib-search-box {
[data-v-85688f44] .node-lib-search-box {
margin-left: 1rem;
margin-right: 1rem;
margin-top: 1rem;
}
[data-v-87967891] .comfy-vue-side-bar-body {
[data-v-85688f44] .comfy-vue-side-bar-body {
background: var(--p-tree-background);
}
/*
* The following styles are necessary to avoid layout shift when dragging nodes over folders.
* By setting the position to relative on the parent and using an absolutely positioned pseudo-element,
* we can create a visual indicator for the drop target without affecting the layout of other elements.
*/
[data-v-87967891] .p-tree-node-content:has(.node-tree-folder) {
position: relative;
[data-v-85688f44] .node-lib-bookmark-tree-explorer {
padding-bottom: 2px;
}
[data-v-87967891] .p-tree-node-content:has(.node-tree-folder.can-drop)::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border: 1px solid var(--p-content-color);
pointer-events: none;
[data-v-85688f44] .node-lib-tree-explorer {
padding-top: 2px;
}
[data-v-85688f44] .p-divider {
margin: var(--comfy-tree-explorer-item-padding) 0px;
}
.spinner[data-v-8616e7a1] {
.p-tree-node-content {
padding: var(--comfy-tree-explorer-item-padding) !important;
}
.spinner[data-v-75e4840f] {
position: absolute;
inset: 0px;
display: flex;
@@ -1,6 +1,6 @@
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
import { j as createSpinner, h as api, $ as $el } from "./index-CI3N807S.js";
import { j as createSpinner, h as api, $ as $el } from "./index-Dfv2aLsq.js";
class UserSelectionScreen {
static {
__name(this, "UserSelectionScreen");
@@ -117,4 +117,4 @@ window.comfyAPI.userSelection.UserSelectionScreen = UserSelectionScreen;
export {
UserSelectionScreen
};
//# sourceMappingURL=userSelection-CyXKCVy3.js.map
//# sourceMappingURL=userSelection-DSpF-zVD.js.map
File diff suppressed because one or more lines are too long
BIN
View File
Binary file not shown.
+1 -1
View File
@@ -1,2 +1,2 @@
// Shim for extensions\core\clipspace.ts
// Shim for extensions/core/clipspace.ts
export const ClipspaceDialog = window.comfyAPI.clipspace.ClipspaceDialog;
+1 -1
View File
@@ -1,3 +1,3 @@
// Shim for extensions\core\groupNode.ts
// Shim for extensions/core/groupNode.ts
export const GroupNodeConfig = window.comfyAPI.groupNode.GroupNodeConfig;
export const GroupNodeHandler = window.comfyAPI.groupNode.GroupNodeHandler;
+1 -1
View File
@@ -1,2 +1,2 @@
// Shim for extensions\core\groupNodeManage.ts
// Shim for extensions/core/groupNodeManage.ts
export const ManageGroupDialog = window.comfyAPI.groupNodeManage.ManageGroupDialog;
+1 -1
View File
@@ -1,4 +1,4 @@
// Shim for extensions\core\widgetInputs.ts
// Shim for extensions/core/widgetInputs.ts
export const getWidgetConfig = window.comfyAPI.widgetInputs.getWidgetConfig;
export const setWidgetConfig = window.comfyAPI.widgetInputs.setWidgetConfig;
export const mergeIfValid = window.comfyAPI.widgetInputs.mergeIfValid;
+50 -50
View File
@@ -1,50 +1,50 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ComfyUI</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<!-- Browser Test Fonts -->
<!-- <link href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Noto+Color+Emoji&family=Roboto+Mono:ital,wght@0,100..700;1,100..700&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet">
<style>
* {
font-family: 'Roboto Mono', 'Noto Color Emoji';
}
</style> -->
<link rel="stylesheet" type="text/css" href="user.css" />
<link rel="stylesheet" type="text/css" href="materialdesignicons.min.css" />
<script type="module" crossorigin src="./assets/index-CI3N807S.js"></script>
<link rel="stylesheet" crossorigin href="./assets/index-_5czGnTA.css">
</head>
<body class="litegraph">
<div id="vue-app"></div>
<div id="comfy-user-selection" class="comfy-user-selection" style="display: none;">
<main class="comfy-user-selection-inner">
<h1>ComfyUI</h1>
<form>
<section>
<label>New user:
<input placeholder="Enter a username" />
</label>
</section>
<div class="comfy-user-existing">
<span class="or-separator">OR</span>
<section>
<label>
Existing user:
<select>
<option hidden disabled selected value> Select a user </option>
</select>
</label>
</section>
</div>
<footer>
<span class="comfy-user-error">&nbsp;</span>
<button class="comfy-btn comfy-user-button-next">Next</button>
</footer>
</form>
</main>
</div>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ComfyUI</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<!-- Browser Test Fonts -->
<!-- <link href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Noto+Color+Emoji&family=Roboto+Mono:ital,wght@0,100..700;1,100..700&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet">
<style>
* {
font-family: 'Roboto Mono', 'Noto Color Emoji';
}
</style> -->
<link rel="stylesheet" type="text/css" href="user.css" />
<link rel="stylesheet" type="text/css" href="materialdesignicons.min.css" />
<script type="module" crossorigin src="./assets/index-Dfv2aLsq.js"></script>
<link rel="stylesheet" crossorigin href="./assets/index-W4jP-SrU.css">
</head>
<body class="litegraph">
<div id="vue-app"></div>
<div id="comfy-user-selection" class="comfy-user-selection" style="display: none;">
<main class="comfy-user-selection-inner">
<h1>ComfyUI</h1>
<form>
<section>
<label>New user:
<input placeholder="Enter a username" />
</label>
</section>
<div class="comfy-user-existing">
<span class="or-separator">OR</span>
<section>
<label>
Existing user:
<select>
<option hidden disabled selected value> Select a user </option>
</select>
</label>
</section>
</div>
<footer>
<span class="comfy-user-error">&nbsp;</span>
<button class="comfy-btn comfy-user-button-next">Next</button>
</footer>
</form>
</main>
</div>
</body>
</html>
+1 -1
View File
@@ -1,2 +1,2 @@
// Shim for scripts\api.ts
// Shim for scripts/api.ts
export const api = window.comfyAPI.api.api;
+1 -1
View File
@@ -1,4 +1,4 @@
// Shim for scripts\app.ts
// Shim for scripts/app.ts
export const ANIM_PREVIEW_WIDGET = window.comfyAPI.app.ANIM_PREVIEW_WIDGET;
export const ComfyApp = window.comfyAPI.app.ComfyApp;
export const app = window.comfyAPI.app.app;
+1 -1
View File
@@ -1,2 +1,2 @@
// Shim for scripts\changeTracker.ts
// Shim for scripts/changeTracker.ts
export const ChangeTracker = window.comfyAPI.changeTracker.ChangeTracker;
+1 -1
View File
@@ -1,2 +1,2 @@
// Shim for scripts\defaultGraph.ts
// Shim for scripts/defaultGraph.ts
export const defaultGraph = window.comfyAPI.defaultGraph.defaultGraph;
+1 -1
View File
@@ -1,2 +1,2 @@
// Shim for scripts\domWidget.ts
// Shim for scripts/domWidget.ts
export const addDomClippingSetting = window.comfyAPI.domWidget.addDomClippingSetting;
+1 -1
View File
@@ -1,2 +1,2 @@
// Shim for scripts\logging.ts
// Shim for scripts/logging.ts
export const ComfyLogging = window.comfyAPI.logging.ComfyLogging;
+1 -1
View File
@@ -1,3 +1,3 @@
// Shim for scripts\metadata\flac.ts
// Shim for scripts/metadata/flac.ts
export const getFromFlacBuffer = window.comfyAPI.flac.getFromFlacBuffer;
export const getFromFlacFile = window.comfyAPI.flac.getFromFlacFile;
+1 -1
View File
@@ -1,3 +1,3 @@
// Shim for scripts\metadata\png.ts
// Shim for scripts/metadata/png.ts
export const getFromPngBuffer = window.comfyAPI.png.getFromPngBuffer;
export const getFromPngFile = window.comfyAPI.png.getFromPngFile;
+1 -1
View File
@@ -1,4 +1,4 @@
// Shim for scripts\pnginfo.ts
// Shim for scripts/pnginfo.ts
export const getPngMetadata = window.comfyAPI.pnginfo.getPngMetadata;
export const getFlacMetadata = window.comfyAPI.pnginfo.getFlacMetadata;
export const getWebpMetadata = window.comfyAPI.pnginfo.getWebpMetadata;
+1 -1
View File
@@ -1,4 +1,4 @@
// Shim for scripts\ui.ts
// Shim for scripts/ui.ts
export const ComfyDialog = window.comfyAPI.ui.ComfyDialog;
export const $el = window.comfyAPI.ui.$el;
export const ComfyUI = window.comfyAPI.ui.ComfyUI;
+1 -1
View File
@@ -1,2 +1,2 @@
// Shim for scripts\ui\components\asyncDialog.ts
// Shim for scripts/ui/components/asyncDialog.ts
export const ComfyAsyncDialog = window.comfyAPI.asyncDialog.ComfyAsyncDialog;
+1 -1
View File
@@ -1,2 +1,2 @@
// Shim for scripts\ui\components\button.ts
// Shim for scripts/ui/components/button.ts
export const ComfyButton = window.comfyAPI.button.ComfyButton;
+1 -1
View File
@@ -1,2 +1,2 @@
// Shim for scripts\ui\components\buttonGroup.ts
// Shim for scripts/ui/components/buttonGroup.ts
export const ComfyButtonGroup = window.comfyAPI.buttonGroup.ComfyButtonGroup;
+1 -1
View File
@@ -1,2 +1,2 @@
// Shim for scripts\ui\components\popup.ts
// Shim for scripts/ui/components/popup.ts
export const ComfyPopup = window.comfyAPI.popup.ComfyPopup;
+1 -1
View File
@@ -1,2 +1,2 @@
// Shim for scripts\ui\components\splitButton.ts
// Shim for scripts/ui/components/splitButton.ts
export const ComfySplitButton = window.comfyAPI.splitButton.ComfySplitButton;
+1 -1
View File
@@ -1,2 +1,2 @@
// Shim for scripts\ui\dialog.ts
// Shim for scripts/ui/dialog.ts
export const ComfyDialog = window.comfyAPI.dialog.ComfyDialog;
+1 -1
View File
@@ -1,2 +1,2 @@
// Shim for scripts\ui\draggableList.ts
// Shim for scripts/ui/draggableList.ts
export const DraggableList = window.comfyAPI.draggableList.DraggableList;
+1 -1
View File
@@ -1,3 +1,3 @@
// Shim for scripts\ui\imagePreview.ts
// Shim for scripts/ui/imagePreview.ts
export const calculateImageGrid = window.comfyAPI.imagePreview.calculateImageGrid;
export const createImageHost = window.comfyAPI.imagePreview.createImageHost;
+1 -1
View File
@@ -1,2 +1,2 @@
// Shim for scripts\ui\menu\index.ts
// Shim for scripts/ui/menu/index.ts
export const ComfyAppMenu = window.comfyAPI.index.ComfyAppMenu;
+1 -1
View File
@@ -1,2 +1,2 @@
// Shim for scripts\ui\menu\interruptButton.ts
// Shim for scripts/ui/menu/interruptButton.ts
export const getInterruptButton = window.comfyAPI.interruptButton.getInterruptButton;
+1 -1
View File
@@ -1,2 +1,2 @@
// Shim for scripts\ui\menu\queueButton.ts
// Shim for scripts/ui/menu/queueButton.ts
export const ComfyQueueButton = window.comfyAPI.queueButton.ComfyQueueButton;
+1 -1
View File
@@ -1,2 +1,2 @@
// Shim for scripts\ui\menu\queueOptions.ts
// Shim for scripts/ui/menu/queueOptions.ts
export const ComfyQueueOptions = window.comfyAPI.queueOptions.ComfyQueueOptions;
+1 -1
View File
@@ -1,3 +1,3 @@
// Shim for scripts\ui\menu\workflows.ts
// Shim for scripts/ui/menu/workflows.ts
export const ComfyWorkflowsMenu = window.comfyAPI.workflows.ComfyWorkflowsMenu;
export const ComfyWorkflowsContent = window.comfyAPI.workflows.ComfyWorkflowsContent;
+1 -1
View File
@@ -1,2 +1,2 @@
// Shim for scripts\ui\settings.ts
// Shim for scripts/ui/settings.ts
export const ComfySettingsDialog = window.comfyAPI.settings.ComfySettingsDialog;
+1 -1
View File
@@ -1,2 +1,2 @@
// Shim for scripts\ui\spinner.ts
// Shim for scripts/ui/spinner.ts
export const createSpinner = window.comfyAPI.spinner.createSpinner;
+1 -1
View File
@@ -1,2 +1,2 @@
// Shim for scripts\ui\toggleSwitch.ts
// Shim for scripts/ui/toggleSwitch.ts
export const toggleSwitch = window.comfyAPI.toggleSwitch.toggleSwitch;
+1 -1
View File
@@ -1,2 +1,2 @@
// Shim for scripts\ui\userSelection.ts
// Shim for scripts/ui/userSelection.ts
export const UserSelectionScreen = window.comfyAPI.userSelection.UserSelectionScreen;
+1 -1
View File
@@ -1,3 +1,3 @@
// Shim for scripts\ui\utils.ts
// Shim for scripts/ui/utils.ts
export const applyClasses = window.comfyAPI.utils.applyClasses;
export const toggleElement = window.comfyAPI.utils.toggleElement;
+1 -1
View File
@@ -1,4 +1,4 @@
// Shim for scripts\utils.ts
// Shim for scripts/utils.ts
export const clone = window.comfyAPI.utils.clone;
export const applyTextReplacements = window.comfyAPI.utils.applyTextReplacements;
export const addStylesheet = window.comfyAPI.utils.addStylesheet;
+1 -1
View File
@@ -1,4 +1,4 @@
// Shim for scripts\widgets.ts
// Shim for scripts/widgets.ts
export const updateControlWidgetLabel = window.comfyAPI.widgets.updateControlWidgetLabel;
export const addValueControlWidget = window.comfyAPI.widgets.addValueControlWidget;
export const addValueControlWidgets = window.comfyAPI.widgets.addValueControlWidgets;
+1 -1
View File
@@ -1,4 +1,4 @@
// Shim for scripts\workflows.ts
// Shim for scripts/workflows.ts
export const trimJsonExt = window.comfyAPI.workflows.trimJsonExt;
export const ComfyWorkflowManager = window.comfyAPI.workflows.ComfyWorkflowManager;
export const ComfyWorkflow = window.comfyAPI.workflows.ComfyWorkflow;