Compare commits

..
31 Commits
Author SHA1 Message Date
yolain 1616dd6602 Upgrade v1.3.1 to ComfyRegistry 2025-06-29 11:43:22 +08:00
yolain 282eedfea6 Rewrite drawNodeWidget and fix the GroupNode preview issue 2025-06-28 18:37:56 +08:00
yolain 17b163e234 Fix typo in EN tooltip for Nodes Map sidebar icon #816 2025-06-26 16:43:19 +08:00
Laegel 501d97bb5c chore: Now able to store metadata in ImageChooser (#813) 2025-06-23 16:22:23 +08:00
WathomeBo de92038f88 Update util.py (#809)
补充了用于选择lora模型的 setLoraName
2025-06-17 12:19:42 +08:00
Thomas Ward 530333d72d Update logic.py: properly handle overwrite mode (#807)
In low-level `OPEN` logic at the system, there are two modes of opening files for writing: `WRITE` which clobbers existing file data, and `APPEND` which allows appending of data.

In the current code, using `if not overwrite: pass` does nothing to define if you're actually appending or overwriting the file in your selection, and instead you should define the file open mode based on analysis of whether you have `overwrite` set to True or not.

This code patch does this.

(discovered as a result of helping someone via the ComfyUI discord)
2025-06-17 12:19:27 +08:00
yolain 041f49540c Forced override of drawNodeWidget for nodes containing hidden widget on the official theme #801 2025-06-14 14:22:54 +08:00
MakinoHaruka 71c7865d2d locale typo (#797) 2025-06-05 10:55:11 +08:00
yolain c7fbf05970 Implement error handling for all frontend hijack attempts. If EasyUse fails (e.g., due to official frontend changes), fall back to the native callback function. 2025-06-04 23:28:45 +08:00
yolain 2986a01469 When using the easy theme to draw node components, the draw method removed from front-end v1.21.3 is supplemented #793 2025-06-03 13:27:18 +08:00
yolain fa7c5d8b4d Fix ImagePreviewWidget can not display image in v1.21.3 frontend 2025-06-01 15:35:52 +08:00
Mike KinneyandMike Kinney 1d8db7510b Update XY Plot Labels (#792)
* Add lora weight to XY title axis. Trim lora desc.

* Add weights to lora names in xyPlots. Re-add because original lost in git merge mistake.

* Only add common label, if it's not an axis type.

* Remove bad comment.

---------

Co-authored-by: Mike Kinney <mike.kinney@valorepartners.com>
2025-06-01 13:15:55 +08:00
yolain 7ef0612ce7 Fix stepping changes not working in new front-end versions #789 2025-05-27 18:04:15 +08:00
yolain 7ff4790493 Fix update node height only if the node is preSamplingcustom listening for scheduler changes #788 2025-05-27 12:26:39 +08:00
yolain 640ef31625 Fix uniform width didn't work when sizes were inconsistent 2025-05-26 13:24:09 +08:00
yolain e4ac947d96 Fix precision issues with nodes related to float numbers #779 2025-05-22 11:06:52 +08:00
yolain d287e28e5c Fix fluxLoader using widget options instead of getting ckpt_names globally #772 2025-05-19 12:42:36 +08:00
yolain f33c17f762 Fix fluxLoader duplicate fetching of node information #772 2025-05-19 11:02:56 +08:00
yolain e07b8cc7bf Fix widgets being hidden in connections 2025-05-18 13:34:42 +08:00
yolain 6abe07bb79 Merge pull request #766 from mekinney/bugfix-xyplot-optional-lora
Use previously generated model/clip for next loaded lora
2025-05-15 16:27:31 +08:00
Mike Kinney 7fbd03bda7 Merge branch 'main' into bugfix-xyplot-optional-lora 2025-05-14 07:20:08 -07:00
Mike Kinney 9cc2ac02da Use previously generated model/clip for next loaded lora 2025-05-14 06:27:36 -07:00
Mike Kinney 2f2a3035a2 Merge pull request #3 from mekinney/bug-xyplot-save-model-and-clip-when-processing-lora-stack-in-xyplot
Update clip and model when adding loras
2025-05-13 16:52:23 -07:00
Mike Kinney 5d8f0a3b0a Update clip and model when adding loras 2025-05-13 16:49:49 -07:00
Mike Kinney 8aadd72494 Merge pull request #2 from mekinney/Change-Load-LORA-formatting-to-2-digits
Updated formatting for load lora for strength displays to 3 digits
2025-05-13 07:05:24 -07:00
Mike Kinney fceec754a4 Updated formatting for load lora for strength displays to 3 digits 2025-05-13 07:03:59 -07:00
Mike Kinney 419b7c985c Merge pull request #1 from mekinney/XYPlot-Footer
Add core XYPlot Footer
2025-05-13 06:51:23 -07:00
Mike Kinney ce62fc73da Add core XYPlot Footer 2025-05-13 06:35:45 -07:00
yolain 4f31641da3 Adding text truncation to widgets of type text 2025-05-13 12:35:31 +08:00
yolain deec62ab76 Set the minimum height of the initial display when imageChooser is paused. #755 2025-05-12 11:43:44 +08:00
yolain 5c8cdb58c7 Add easy seedList node (It's useful for in loops) 2025-05-11 00:43:27 +08:00
15 changed files with 246 additions and 55 deletions
-1
View File
@@ -515,7 +515,6 @@ git clone https://github.com/yolain/ComfyUI-Easy-Use
**Comfyui-Easy-Use** 是一个 GPL 许可的开源项目。为了项目取得更好、可持续的发展,我希望能够获得更多的支持。 如果我的自定义节点为您的一天增添了价值,请考虑喝杯咖啡来进一步补充能量! 💖感谢您的支持,每一杯咖啡都是我创作的动力!
- [BiliBili充电](https://space.bilibili.com/1840885116)
- [爱发电](https://afdian.com/a/yolain)
- [Wechat/Alipay](https://github.com/user-attachments/assets/803469bd-ed6a-4fab-932d-50e5088a2d03)
感谢您的捐助,我将用这些费用来租用 GPU 或购买其他 GPT 服务,以便更好地调试和完善 ComfyUI-Easy-Use 功能
+6 -1
View File
@@ -47,6 +47,12 @@ Double-click install.bat to install the required dependencies
## 📜 Changelog
**v1.3.1**
- Rewrite drawNodeWidget and fix the GroupNode preview issue.
- Updated some features of XYPlot by [mekinney](https://github.com/mekinney)
- Add `easy seedList` node (It's useful for in loops)
**v1.3.0**
- Set loop nodes maximum number of inputs and outputs to 20
@@ -499,7 +505,6 @@ If my custom nodes has added value to your day, consider indulging in a coffee t
💖You can support me in any of the following ways:
- [BiliBili](https://space.bilibili.com/1840885116)
- [Afdian](https://afdian.com/a/yolain)
- [Wechat / Alipay](https://github.com/user-attachments/assets/803469bd-ed6a-4fab-932d-50e5088a2d03)
## 🌟Stargazers
+1 -1
View File
@@ -1,4 +1,4 @@
__version__ = "1.3.0"
__version__ = "1.3.1"
import yaml
import json
+31 -2
View File
@@ -1756,6 +1756,35 @@
}
}
},
"easy seedList": {
"display_name": "随机种列表",
"description": "可用于for循环的随机数种子列表,通过与easy forLoopStart节点的索引与easy indexAny节点相连接可实现在循环中使用不同种子值进行采样",
"inputs": {
"min_num": {
"name": "最小值"
},
"max_num": {
"name": "最大值"
},
"method": {
"name": "生成方式"
},
"total": {
"name": "总量"
},
"seed": {
"name": "列表序号"
}
},
"outputs": {
"0": {
"name": "随机种"
},
"1": {
"name": "总量"
}
}
},
"easy globalSeed": {
"display_name": "全局随机种",
"inputs": {
@@ -6365,7 +6394,7 @@
"name": "高度"
},
"scale": {
"name": "缩放洗漱"
"name": "缩放系数"
},
"flip_w/h": {
"name": "翻转宽高"
@@ -6708,4 +6737,4 @@
}
}
}
}
}
+5 -1
View File
@@ -351,7 +351,7 @@ class easyLoader:
lora_path = None
if lora_path is not None:
log_node_info("Load LORA",f"{lora_name}: {model_strength}, {clip_strength}, LBW={lbw}, A={lbw_a}, B={lbw_b}")
log_node_info("Load LORA",f"{lora_name}: model={model_strength:.3f}, clip={clip_strength:.3f}, LBW={lbw}, A={lbw_a}, B={lbw_b}")
if lbw:
lbw = lora["lbw"]
lbw_a = lora["lbw_a"]
@@ -432,10 +432,13 @@ class easyLoader:
clip_vision = None
lora_stack = []
# Check for model override
can_load_lora = True
# 判断是否存在 模型或Lora叠加xyplot, 若存在优先缓存第一个模型
# Determine whether there is a model or Lora overlapping xyplot, and if there is, prioritize caching the first model.
xy_model_id = next((x for x in prompt if str(prompt[x]["class_type"]) in ["easy XYInputs: ModelMergeBlocks",
"easy XYInputs: Checkpoint"]), None)
# This will find nodes that aren't actively connected to anything, and skip loading lora's for them.
xy_lora_id = next((x for x in prompt if str(prompt[x]["class_type"]) == "easy XYInputs: Lora"), None)
if xy_lora_id is not None:
can_load_lora = False
@@ -461,6 +464,7 @@ class easyLoader:
if optional_lora_stack is not None and can_load_lora:
for lora in optional_lora_stack:
# This is a subtle bit of code because it uses the model created by the last call, and passes it to the next call.
lora = {"lora_name": lora[0], "model": model, "clip": clip, "model_strength": lora[1],
"clip_strength": lora[2]}
model, clip = self.load_lora(lora)
+90 -15
View File
@@ -8,6 +8,7 @@ from .log import log_node_warn
from ..modules.layer_diffuse import LayerDiffuse
from ..config import RESOURCES_DIR
from nodes import CLIPTextEncode
import pprint
try:
from comfy_extras.nodes_flux import FluxGuidance
except:
@@ -52,7 +53,7 @@ class easyXYPlot():
plot_image_vars[value_type] = value
if value_type in ["seed", "Seeds++ Batch"]:
value_label = f"{value}"
value_label = f"seed: {value}"
else:
value_label = f"{value_type}: {value}"
@@ -63,7 +64,9 @@ class easyXYPlot():
arr = value.split(',')
model_name = os.path.basename(os.path.splitext(arr[0])[0])
trigger_words = ' ' + arr[3] if value_type == 'Lora' and len(arr[3]) > 2 else ''
value_label = f"{model_name}{trigger_words}"
lora_weight = float(arr[1]) if value_type == 'Lora' and len(arr) > 1 else 0
lora_weight_desc = f"({lora_weight:.2f})" if lora_weight > 0 else ''
value_label = f"{model_name[:30]}{lora_weight_desc} {trigger_words}"
if value_type in ["ModelMergeBlocks"]:
if ":" in value:
@@ -118,24 +121,32 @@ class easyXYPlot():
def calculate_background_dimensions(self):
border_size = int((self.max_width // 8) * 1.5) if self.y_type != "None" or self.x_type != "None" else 0
bg_width = self.num_cols * (self.max_width + self.grid_spacing) - self.grid_spacing + border_size * (
self.y_type != "None")
bg_height = self.num_rows * (self.max_height + self.grid_spacing) - self.grid_spacing + border_size * (
self.x_type != "None")
# Add space at the bottom of the image for common informaiton about the image
bg_height = bg_height + (border_size*2)
# print(f"Grid Size: width = {bg_width} height = {bg_height} border_size = {border_size}")
x_offset_initial = border_size if self.y_type != "None" else 0
y_offset = border_size if self.x_type != "None" else 0
return bg_width, bg_height, x_offset_initial, y_offset
def adjust_font_size(self, text, initial_font_size, label_width):
font = self.get_font(initial_font_size, self.custom_font)
text_width = font.getbbox(text)
# pprint.pp(f"Initial font size: {initial_font_size}, text: {text}, text_width: {text_width}")
if text_width and text_width[2]:
text_width = text_width[2]
scaling_factor = 0.9
if text_width > (label_width * scaling_factor):
# print(f"Adjusting font size from {initial_font_size} to fit text width {text_width} into label width {label_width} scaling_factor {scaling_factor}")
return int(initial_font_size * (label_width / text_width) * scaling_factor)
else:
return initial_font_size
@@ -144,15 +155,22 @@ class easyXYPlot():
_, _, width, height = d.textbbox((0, 0), text=text, font=font)
return width, height
def create_label(self, img, text, initial_font_size, is_x_label=True, max_font_size=70, min_font_size=10):
label_width = img.width if is_x_label else img.height
def create_label(self, img, text, initial_font_size, is_x_label=True, max_font_size=70, min_font_size=10, label_width=0, label_height=0):
# if the label_width is specified, leave it along. Otherwise do the old logic.
if label_width == 0:
label_width = img.width if is_x_label else img.height
text_lines = text.split('\n')
longest_line = max(text_lines, key=len)
# Adjust font size
font_size = self.adjust_font_size(text, initial_font_size, label_width)
font_size = self.adjust_font_size(longest_line, initial_font_size, label_width)
font_size = min(max_font_size, font_size) # Ensure font isn't too large
font_size = max(min_font_size, font_size) # Ensure font isn't too small
label_height = int(font_size * 1.5) if is_x_label else font_size
if label_height == 0:
label_height = int(font_size * 1.5) if is_x_label else font_size
label_bg = Image.new('RGBA', (label_width, label_height), color=(255, 255, 255, 0))
d = ImageDraw.Draw(label_bg)
@@ -166,7 +184,7 @@ class easyXYPlot():
text = text + '...'
# Compute text width and height for multi-line text
text_lines = text.split('\n')
text_widths, text_heights = zip(*[self.textsize(d, line, font=font) for line in text_lines])
max_text_width = max(text_widths)
total_text_height = sum(text_heights)
@@ -195,8 +213,7 @@ class easyXYPlot():
clip = clip if clip is not None else plot_image_vars["clip"]
steps = plot_image_vars['steps'] if "steps" in plot_image_vars else 1
sd_version = get_sd_version(plot_image_vars['model'])
sd_version = get_sd_version(plot_image_vars['model'])
# 高级用法
if plot_image_vars["x_node_type"] == "advanced" or plot_image_vars["y_node_type"] == "advanced":
if self.x_type == "Seeds++ Batch" or self.y_type == "Seeds++ Batch":
@@ -347,17 +364,24 @@ class easyXYPlot():
# Lora
if self.x_type == "Lora" or self.y_type == "Lora":
# print(f"Lora: {x_value} {y_value}")
model = model if model is not None else plot_image_vars["model"]
clip = clip if clip is not None else plot_image_vars["clip"]
xy_values = x_value if self.x_type == "Lora" else y_value
lora_name, lora_model_strength, lora_clip_strength, _ = xy_values.split(",")
lora_stack = [{"lora_name": lora_name, "model": model, "clip" :clip, "model_strength": float(lora_model_strength), "clip_strength": float(lora_clip_strength)}]
# print(f"new_lora_stack: {new_lora_stack}")
if 'lora_stack' in plot_image_vars:
lora_stack = lora_stack + plot_image_vars['lora_stack']
if lora_stack is not None and lora_stack != []:
for lora in lora_stack:
# Each generation of the model, must use the reference to previously created model / clip objects.
lora['model'] = model
lora['clip'] = clip
model, clip = self.easyCache.load_lora(lora)
# 提示词
@@ -464,6 +488,7 @@ class easyXYPlot():
plot_image_vars['negative_weight_interpretation'], w_max=1.0,
apply_to_pooled="enable", a1111_prompt_style=a1111_prompt_style, steps=steps)
model = model if model is not None else plot_image_vars["model"]
vae = vae if vae is not None else plot_image_vars["vae"]
positive = positive if positive is not None else plot_image_vars["positive_cond"]
@@ -582,11 +607,10 @@ class easyXYPlot():
return self.latents_plot
def plot_images_and_labels(self):
# Calculate the background dimensions
def plot_images_and_labels(self, plot_image_vars):
bg_width, bg_height, x_offset_initial, y_offset = self.calculate_background_dimensions()
# Create the white background image
background = Image.new('RGBA', (int(bg_width), int(bg_height)), color=(255, 255, 255, 255))
output_image = []
@@ -618,4 +642,55 @@ class easyXYPlot():
y_offset += img.height + self.grid_spacing
return (self.sampler.pil2tensor(background), output_image)
# lookup used models in the image
common_label = ""
# Update to add a function to do the heavy lifting. Parameters are plot_image_vars name, label to use, names of the axis,
# pprint.pp(plot_image_vars)
# We don't process LORAs here because there can be multiple of them.
labels = [
{"id": "ckpt_name", "id_desc": "ckpt", "axis_type" : "Checkpoint"},
{"id": "vae_name", "id_desc": '', "axis_type" : "vae_name"},
{"id": "sampler_name", "id_desc": "sampler", "axis_type" : "Sampler"},
{"id": "scheduler", "id_desc": '', "axis_type" : "Scheduler"},
{"id": "steps", "id_desc": '', "axis_type" : "Steps"},
{"id": "Flux Guidance", "id_desc": 'guidance', "axis_type" : "Flux Guidance"},
{"id": "seed", "id_desc": '', "axis_type" : "Seeds++ Batch"}
]
for item in labels:
# Only add the label if it's not one of the axis
# print(f"Checking item: {item['id']} axis_type {item['axis_type']} x_type: {self.x_type} y_type: {self.y_type}")
if self.x_type != item['axis_type'] and self.y_type != item['axis_type']:
common_label += self.add_common_label(item['id'], plot_image_vars, item['id_desc'])
common_label += f"\n"
if plot_image_vars['lora_stack'] is not None and plot_image_vars['lora_stack'] != []:
# print(f"lora_stack: {plot_image_vars['lora_stack']}")
for lora in plot_image_vars['lora_stack']:
lora_name = lora['lora_name']
lora_weight = lora['model_strength']
if lora_name is not None and len(lora_name) > 0 and lora_weight > 0:
common_label += f"LORA: {lora_name} weight: {lora_weight:.2f} \n"
common_label = common_label.strip()
if len(common_label) > 0:
label_height = background.height - y_offset
label_bg = self.create_label(background, common_label, int(48 * background.width / 512), label_width=background.width, label_height=label_height)
label_x = (background.width - label_bg.width) // 2
label_y = y_offset
# print(f"Adding common label: {common_label} x = {label_x} y = {label_y}")
background.alpha_composite(label_bg, (label_x, label_y))
return (self.sampler.pil2tensor(background), output_image)
def add_common_label(self, tag, plot_image_vars, description = ''):
label = ''
if description == '': description = tag
if tag in plot_image_vars and plot_image_vars[tag] is not None and plot_image_vars[tag] != 'None':
label += f"{description}: {plot_image_vars[tag]} "
# print(f"add_common_label: {tag} description: {description} label: {label}" )
return label
+20 -13
View File
@@ -1057,7 +1057,12 @@ class imageChooser(PreviewImage):
images_in = torch.cat(kwargs.pop('images'))
self.batch = images_in.shape[0]
for x in kwargs: kwargs[x] = kwargs[x][0]
result = self.save_images(images=images_in, prompt=prompt)
try:
pnginfo = extra_pnginfo[0]
except:
pnginfo = None
result = self.save_images(images=images_in, prompt=prompt, extra_pnginfo=pnginfo)
images = result['ui']['images']
PromptServer.instance.send_sync("easyuse-image-choose", {"id": id, "urls": images})
@@ -1964,7 +1969,7 @@ class makeImageForICRepaint:
b = torch.full([batch_size, height, width, 1], ((color) & 0xFF) / 0xFF)
return torch.cat((r, g, b), dim=-1)
def resize_image_and_mask(self, image, mask, w, h ):
def resize_image_and_mask(self, image, mask, w, h ,fit='fill'):
ret_images = []
ret_masks = []
_mask = Image.new('L', size=(w, h), color='black')
@@ -1972,12 +1977,12 @@ class makeImageForICRepaint:
if image is not None and len(image) > 0:
for i in image:
_image = tensor2pil(i).convert('RGB')
_image = fit_resize_image(_image, w, h, 'fill', Image.LANCZOS, '#000000')
_image = fit_resize_image(_image, w, h, fit, Image.LANCZOS, '#000000')
ret_images.append(pil2tensor(_image))
if mask is not None and len(mask) > 0:
for m in mask:
_mask = tensor2pil(m).convert('L')
_mask = fit_resize_image(_mask, w, h, 'fill', Image.LANCZOS).convert('L')
_mask = fit_resize_image(_mask, w, h, fit, Image.LANCZOS).convert('L')
ret_masks.append(image2mask(_mask))
if len(ret_images) > 0 and len(ret_masks) > 0:
@@ -2017,16 +2022,18 @@ class makeImageForICRepaint:
image, mask, context_mask = None, None, None
# resize
if img1_h != img2_h and img1_w != img2_w:
if img1_h != img2_h or img1_w != img2_w:
width, height = img2_w, img2_h
if direction == 'left-right' and img1_h != img2_h:
scale_factor = img2_h / img1_h
width = round(img1_w * scale_factor)
elif direction == 'top-bottom' and img1_w != img2_w:
scale_factor = img2_w / img1_w
height = round(img1_h * scale_factor)
image_1, mask_1 = self.resize_image_and_mask(image_1, mask_1, width, height)
fit = 'crop'
if method != 'uniform width':
if direction == 'left-right' and img1_h != img2_h:
scale_factor = img2_h / img1_h
width = round(img1_w * scale_factor)
elif direction == 'top-bottom' and img1_w != img2_w:
scale_factor = img2_w / img1_w
height = round(img1_h * scale_factor)
fit = 'fill'
image_1, mask_1 = self.resize_image_and_mask(image_1, mask_1, width, height, fit)
if mask_1 is None:
mask_1 = torch.full((1, image_1.shape[1], image_1.shape[2]), 0, dtype=torch.float32, device="cpu")
+17 -15
View File
@@ -166,7 +166,7 @@ class Float:
@classmethod
def INPUT_TYPES(s):
return {
"required": {"value": ("FLOAT", {"default": 0, "step": 0.01, "min": -999999, "max": 999999, })},
"required": {"value": ("FLOAT", {"default": 0, "step": 0.01, "min":-0xffffffffffffffff, "max": 0xffffffffffffffff, })},
}
RETURN_TYPES = ("FLOAT",)
@@ -175,7 +175,7 @@ class Float:
CATEGORY = "EasyUse/Logic/Type"
def execute(self, value):
return (value,)
return (round(value, 3),)
# 浮点数范围
@@ -239,9 +239,9 @@ class RangeFloat:
error_if_mismatched_list_args(locals())
getcontext().prec = 12
start = [Decimal(s) for s in start]
stop = [Decimal(s) for s in stop]
step = [Decimal(s) for s in step]
start = [round(Decimal(s),2) for s in start]
stop = [round(Decimal(s),2) for s in stop]
step = [round(Decimal(s),2) for s in step]
ranges = []
range_sizes = []
@@ -573,17 +573,17 @@ class mathFloatOperation:
def float_math_operation(self, a, b, operation):
if operation == "add":
return (a + b,)
return (round(a + b,3),)
elif operation == "subtract":
return (a - b,)
return (round(a - b,3),)
elif operation == "multiply":
return (a * b,)
return (round(a * b,3),)
elif operation == "divide":
return (a / b,)
return (round(a / b,3),)
elif operation == "modulo":
return (a % b,)
return (round(a % b,3),)
elif operation == "power":
return (a ** b,)
return (round(a ** b,3),)
class mathStringOperation:
@@ -1607,8 +1607,10 @@ class saveText:
if not os.path.exists(output_file_path):
os.makedirs(output_file_path)
if not overwrite:
pass
if overwrite:
file_mode = "w"
else:
file_mode = "a"
log_node_info("Save Text", f"Saving to {filepath}")
@@ -1617,13 +1619,13 @@ class saveText:
for i in text.split("\n"):
text_list.append(i.strip())
with open(filepath, "w", newline="", encoding='utf-8') as csv_file:
with open(filepath, file_mode, newline="", encoding='utf-8') as csv_file:
csv_writer = csv.writer(csv_file)
# Write each line as a separate row in the CSV file
for line in text_list:
csv_writer.writerow([line])
else:
with open(filepath, "w", newline="", encoding='utf-8') as text_file:
with open(filepath, file_mode, newline="", encoding='utf-8') as text_file:
for line in text:
text_file.write(line)
+1 -1
View File
@@ -513,7 +513,7 @@ class samplerFull:
samp_samples = {"samples": latents_plot}
images, image_list = sampleXYplot.plot_images_and_labels()
images, image_list = sampleXYplot.plot_images_and_labels(plot_image_vars)
# Generate output_images
output_images = torch.stack([tensor.squeeze() for tensor in image_list])
+51
View File
@@ -1,4 +1,6 @@
from ..config import MAX_SEED_NUM
import hashlib
import random
class easySeed:
@classmethod
@@ -19,6 +21,53 @@ class easySeed:
def doit(self, seed=0, prompt=None, extra_pnginfo=None, my_unique_id=None):
return seed,
class seedList:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"min_num": ("INT", {"default": 0, "min": 0, "max": MAX_SEED_NUM}),
"max_num": ("INT", {"default": MAX_SEED_NUM, "min": 0 }),
"method": (["random", "increment", "decrement"], {"default": "random"}),
"total": ("INT", {"default": 1, "min": 1, "max": 100000}),
"seed": ("INT", {"default": 0, "min": 0, "max": MAX_SEED_NUM,}),
},
"hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO", "my_unique_id": "UNIQUE_ID"},
}
RETURN_TYPES = ("INT", "INT")
RETURN_NAMES = ("seed", "total")
FUNCTION = "doit"
DESCRIPTION = "Random number seed that can be used in a for loop, by connecting index and easy indexAny node to realize different seed values in the loop."
CATEGORY = "EasyUse/Seed"
def doit(self, min_num, max_num, method, total, seed=0, prompt=None, extra_pnginfo=None, my_unique_id=None):
random.seed(seed)
seed_list = []
if min_num > max_num:
min_num, max_num = max_num, min_num
for i in range(total):
if method == 'random':
s = random.randint(min_num, max_num)
elif method == 'increment':
s = min_num + i
if s > max_num:
s = max_num
elif method == 'decrement':
s = max_num - i
if s < min_num:
s = min_num
seed_list.append(s)
return seed_list, total
@classmethod
def IS_CHANGED(s, seed, **kwargs):
m = hashlib.sha256()
m.update(seed)
return m.digest().hex()
# 全局随机种
class globalSeed:
@classmethod
@@ -46,10 +95,12 @@ class globalSeed:
NODE_CLASS_MAPPINGS = {
"easy seed": easySeed,
"easy seedList": seedList,
"easy globalSeed": globalSeed,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"easy seed": "EasySeed",
"easy seedList": "EasySeedList",
"easy globalSeed": "EasyGlobalSeed",
}
+20 -1
View File
@@ -106,6 +106,23 @@ class setControlName:
def set_name(self, controlnet_name):
return (controlnet_name,)
class setLoraName:
@classmethod
def INPUT_TYPES(cls):
return {"required": {
"lora_name": (folder_paths.get_filename_list("loras"),),
}
}
RETURN_TYPES = (AlwaysEqualProxy('*'),)
RETURN_NAMES = ("lora_name",)
FUNCTION = "set_name"
CATEGORY = "EasyUse/Util"
def set_name(self, lora_name):
return (lora_name,)
NODE_CLASS_MAPPINGS = {
@@ -113,6 +130,7 @@ NODE_CLASS_MAPPINGS = {
"easy sliderControl": sliderControl,
"easy ckptNames": setCkptName,
"easy controlnetNames": setControlName,
"easy loraNames": setLoraName,
}
NODE_DISPLAY_NAME_MAPPINGS = {
@@ -120,4 +138,5 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"easy sliderControl": "Easy Slider Control",
"easy ckptNames": "Ckpt Names",
"easy controlnetNames": "ControlNet Names",
}
"easy loraNames": "Lora Names",
}
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "comfyui-easy-use"
description = "To enhance the usability of ComfyUI, optimizations and integrations have been implemented for several commonly used nodes."
version = "1.3.0"
version = "1.3.1"
license = { file = "LICENSE" }
dependencies = ["diffusers", "accelerate", "clip_interrogator>=0.6.0", "sentencepiece", "lark", "onnxruntime", "spandrel", "opencv-python", "matplotlib", "peft"]
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