Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d23db9aa54 | ||
|
|
9c875a75d1 | ||
|
|
b551b01f97 | ||
|
|
6b2ca017a1 | ||
|
|
1aef2c57e3 | ||
|
|
c1449422e5 | ||
|
|
04223778ea | ||
|
|
3fc749d6ba | ||
|
|
c2ccf7f879 | ||
|
|
8e99bebdfe |
+1
-1
@@ -8,7 +8,7 @@
|
||||
import importlib
|
||||
import logging
|
||||
|
||||
version_code = [1, 19, 1]
|
||||
version_code = [1, 23]
|
||||
version_str = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '')
|
||||
logging.info(f"### Loading: ComfyUI-Inspire-Pack ({version_str})")
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ class KSampler_inspire:
|
||||
"steps": ("INT", {"default": 20, "min": 1, "max": 10000}),
|
||||
"cfg": ("FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0}),
|
||||
"sampler_name": (comfy.samplers.KSampler.SAMPLERS, ),
|
||||
"scheduler": (common.SCHEDULERS, ),
|
||||
"scheduler": (common.get_schedulers(), ),
|
||||
"positive": ("CONDITIONING", ),
|
||||
"negative": ("CONDITIONING", ),
|
||||
"latent_image": ("LATENT", ),
|
||||
@@ -169,7 +169,7 @@ class KSamplerAdvanced_inspire:
|
||||
"steps": ("INT", {"default": 20, "min": 1, "max": 10000}),
|
||||
"cfg": ("FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step":0.5, "round": 0.01}),
|
||||
"sampler_name": (comfy.samplers.KSampler.SAMPLERS, ),
|
||||
"scheduler": (common.SCHEDULERS, ),
|
||||
"scheduler": (common.get_schedulers(), ),
|
||||
"positive": ("CONDITIONING", ),
|
||||
"negative": ("CONDITIONING", ),
|
||||
"latent_image": ("LATENT", ),
|
||||
@@ -227,7 +227,7 @@ class KSampler_inspire_pipe:
|
||||
"steps": ("INT", {"default": 20, "min": 1, "max": 10000}),
|
||||
"cfg": ("FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0}),
|
||||
"sampler_name": (comfy.samplers.KSampler.SAMPLERS, ),
|
||||
"scheduler": (common.SCHEDULERS, ),
|
||||
"scheduler": (common.get_schedulers(), ),
|
||||
"latent_image": ("LATENT", ),
|
||||
"denoise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
|
||||
"noise_mode": (supported_noise_modes,),
|
||||
@@ -265,7 +265,7 @@ class KSamplerAdvanced_inspire_pipe:
|
||||
"steps": ("INT", {"default": 20, "min": 1, "max": 10000}),
|
||||
"cfg": ("FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step":0.5, "round": 0.01}),
|
||||
"sampler_name": (comfy.samplers.KSampler.SAMPLERS, ),
|
||||
"scheduler": (common.SCHEDULERS, ),
|
||||
"scheduler": (common.get_schedulers(), ),
|
||||
"latent_image": ("LATENT", ),
|
||||
"start_at_step": ("INT", {"default": 0, "min": 0, "max": 10000}),
|
||||
"end_at_step": ("INT", {"default": 10000, "min": 0, "max": 10000}),
|
||||
|
||||
@@ -189,7 +189,7 @@ class RetrieveBackendData:
|
||||
|
||||
if v is None:
|
||||
logging.warning(f"[RetrieveBackendData] '{key}' is unregistered key.")
|
||||
return (None,)
|
||||
return ([None],)
|
||||
|
||||
is_list, data = v[1]
|
||||
|
||||
@@ -521,7 +521,13 @@ class LoadTextEncoderShared:
|
||||
logging.error("[LoadTextEncoderShared] Currently, the triple text encoder is only supported in `sd3`.")
|
||||
raise ValueError("Currently, the triple text encoder is only supported in `sd3`.")
|
||||
|
||||
res = nodes.NODE_CLASS_MAPPINGS["TripleCLIPLoader"]().load_clip(model_name1, model_name2, model_name3)[0]
|
||||
tcloader = nodes.NODE_CLASS_MAPPINGS["TripleCLIPLoader"]()
|
||||
if hasattr(tcloader, 'execute'):
|
||||
# node v3
|
||||
res = tcloader.execute(model_name1, model_name2, model_name3)[0]
|
||||
else:
|
||||
# legacy compatibility
|
||||
res = tcloader.load_clip(model_name1, model_name2, model_name3)[0]
|
||||
|
||||
elif model_name2 != "None" or model_name3 != "None": # dual text encoder
|
||||
second_model = model_name2 if model_name2 != "None" else model_name3
|
||||
|
||||
+48
-4
@@ -15,6 +15,48 @@ from .libs.utils import ByPassTypeTuple, empty_pil_tensor, empty_latent
|
||||
from PIL import Image
|
||||
import numpy as np
|
||||
import logging
|
||||
import re
|
||||
|
||||
|
||||
def extract_first_number(s):
|
||||
match = re.search(r'\d+', s)
|
||||
return int(match.group()) if match else float('inf')
|
||||
|
||||
|
||||
sort_methods = [
|
||||
"None",
|
||||
"Alphabetical (ASC)",
|
||||
"Alphabetical (DESC)",
|
||||
"Numerical (ASC)",
|
||||
"Numerical (DESC)",
|
||||
"Datetime (ASC)",
|
||||
"Datetime (DESC)"
|
||||
]
|
||||
|
||||
|
||||
def sort_by(items, base_path='.', method=None):
|
||||
def fullpath(x): return os.path.join(base_path, x)
|
||||
|
||||
def get_timestamp(path):
|
||||
try:
|
||||
return os.path.getmtime(path)
|
||||
except FileNotFoundError:
|
||||
return float('-inf')
|
||||
|
||||
if method == "Alphabetical (ASC)":
|
||||
return sorted(items)
|
||||
elif method == "Alphabetical (DESC)":
|
||||
return sorted(items, reverse=True)
|
||||
elif method == "Numerical (ASC)":
|
||||
return sorted(items, key=lambda x: extract_first_number(os.path.splitext(x)[0]))
|
||||
elif method == "Numerical (DESC)":
|
||||
return sorted(items, key=lambda x: extract_first_number(os.path.splitext(x)[0]), reverse=True)
|
||||
elif method == "Datetime (ASC)":
|
||||
return sorted(items, key=lambda x: get_timestamp(fullpath(x)))
|
||||
elif method == "Datetime (DESC)":
|
||||
return sorted(items, key=lambda x: get_timestamp(fullpath(x)), reverse=True)
|
||||
else:
|
||||
return items
|
||||
|
||||
|
||||
class LoadImagesFromDirBatch:
|
||||
@@ -28,6 +70,7 @@ class LoadImagesFromDirBatch:
|
||||
"image_load_cap": ("INT", {"default": 0, "min": 0, "step": 1}),
|
||||
"start_index": ("INT", {"default": 0, "min": -1, "max": 0xffffffffffffffff, "step": 1}),
|
||||
"load_always": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}),
|
||||
"sort_method": (sort_methods,),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +86,7 @@ class LoadImagesFromDirBatch:
|
||||
else:
|
||||
return hash(frozenset(kwargs))
|
||||
|
||||
def load_images(self, directory: str, image_load_cap: int = 0, start_index: int = 0, load_always=False):
|
||||
def load_images(self, directory: str, image_load_cap: int = 0, start_index: int = 0, load_always=False, sort_method=None):
|
||||
if not os.path.isdir(directory):
|
||||
raise FileNotFoundError(f"Directory '{directory} cannot be found.'")
|
||||
dir_files = os.listdir(directory)
|
||||
@@ -56,7 +99,7 @@ class LoadImagesFromDirBatch:
|
||||
valid_extensions.extend('.jxl')
|
||||
dir_files = [f for f in dir_files if any(f.lower().endswith(ext) for ext in valid_extensions)]
|
||||
|
||||
dir_files = sorted(dir_files)
|
||||
dir_files = sort_by(dir_files, directory, sort_method)
|
||||
dir_files = [os.path.join(directory, x) for x in dir_files]
|
||||
|
||||
# start at start_index
|
||||
@@ -133,6 +176,7 @@ class LoadImagesFromDirList:
|
||||
"image_load_cap": ("INT", {"default": 0, "min": 0, "step": 1}),
|
||||
"start_index": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff, "step": 1}),
|
||||
"load_always": ("BOOLEAN", {"default": False, "label_on": "enabled", "label_off": "disabled"}),
|
||||
"sort_method": (sort_methods,),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,7 +195,7 @@ class LoadImagesFromDirList:
|
||||
else:
|
||||
return hash(frozenset(kwargs))
|
||||
|
||||
def load_images(self, directory: str, image_load_cap: int = 0, start_index: int = 0, load_always=False):
|
||||
def load_images(self, directory: str, image_load_cap: int = 0, start_index: int = 0, load_always=False, sort_method=None):
|
||||
if not os.path.isdir(directory):
|
||||
raise FileNotFoundError(f"Directory '{directory}' cannot be found.")
|
||||
dir_files = os.listdir(directory)
|
||||
@@ -164,7 +208,7 @@ class LoadImagesFromDirList:
|
||||
valid_extensions.extend('.jxl')
|
||||
dir_files = [f for f in dir_files if any(f.lower().endswith(ext) for ext in valid_extensions)]
|
||||
|
||||
dir_files = sorted(dir_files)
|
||||
dir_files = sort_by(dir_files, directory, sort_method)
|
||||
dir_files = [os.path.join(directory, x) for x in dir_files]
|
||||
|
||||
# start at start_index
|
||||
|
||||
@@ -5,7 +5,11 @@ import logging
|
||||
from server import PromptServer
|
||||
|
||||
|
||||
SCHEDULERS = comfy.samplers.KSampler.SCHEDULERS + ['AYS SDXL', 'AYS SD1', 'AYS SVD', "GITS[coeff=1.2]", 'OSS FLUX', 'OSS Wan']
|
||||
ADDITIONAL_SCHEDULERS = ['AYS SDXL', 'AYS SD1', 'AYS SVD', 'GITS[coeff=1.2]', 'LTXV[default]', 'OSS FLUX', 'OSS Wan', 'OSS Chroma']
|
||||
|
||||
|
||||
def get_schedulers():
|
||||
return list(comfy.samplers.SCHEDULER_HANDLERS) + ADDITIONAL_SCHEDULERS
|
||||
|
||||
|
||||
def impact_sampling(*args, **kwargs):
|
||||
|
||||
@@ -524,7 +524,7 @@ class GlobalSampler:
|
||||
return {
|
||||
"required": {
|
||||
"sampler_name": (comfy.samplers.KSampler.SAMPLERS, ),
|
||||
"scheduler": (common.SCHEDULERS, ),
|
||||
"scheduler": (common.get_schedulers(), ),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ class RegionalPromptSimple:
|
||||
"mask": ("MASK",),
|
||||
"cfg": ("FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0}),
|
||||
"sampler_name": (comfy.samplers.KSampler.SAMPLERS,),
|
||||
"scheduler": (common.SCHEDULERS,),
|
||||
"scheduler": (common.get_schedulers(),),
|
||||
"wildcard_prompt": ("STRING", {"multiline": True, "dynamicPrompts": False, "placeholder": "wildcard prompt"}),
|
||||
"controlnet_in_pipe": ("BOOLEAN", {"default": False, "label_on": "Keep", "label_off": "Override"}),
|
||||
"sigma_factor": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}),
|
||||
@@ -107,7 +107,7 @@ class RegionalPromptColorMask:
|
||||
"mask_color": ("STRING", {"multiline": False, "default": "#FFFFFF"}),
|
||||
"cfg": ("FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0}),
|
||||
"sampler_name": (comfy.samplers.KSampler.SAMPLERS,),
|
||||
"scheduler": (common.SCHEDULERS,),
|
||||
"scheduler": (common.get_schedulers(),),
|
||||
"wildcard_prompt": ("STRING", {"multiline": True, "dynamicPrompts": False, "placeholder": "wildcard prompt"}),
|
||||
"controlnet_in_pipe": ("BOOLEAN", {"default": False, "label_on": "Keep", "label_off": "Override"}),
|
||||
"sigma_factor": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01}),
|
||||
|
||||
@@ -16,7 +16,7 @@ class KSampler_progress(a1111_compat.KSampler_inspire):
|
||||
"steps": ("INT", {"default": 20, "min": 1, "max": 10000}),
|
||||
"cfg": ("FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0}),
|
||||
"sampler_name": (comfy.samplers.KSampler.SAMPLERS, ),
|
||||
"scheduler": (common.SCHEDULERS, ),
|
||||
"scheduler": (common.get_schedulers(), ),
|
||||
"positive": ("CONDITIONING", ),
|
||||
"negative": ("CONDITIONING", ),
|
||||
"latent_image": ("LATENT", ),
|
||||
@@ -79,7 +79,7 @@ class KSamplerAdvanced_progress(a1111_compat.KSamplerAdvanced_inspire):
|
||||
"steps": ("INT", {"default": 20, "min": 1, "max": 10000}),
|
||||
"cfg": ("FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step":0.5, "round": 0.01}),
|
||||
"sampler_name": (comfy.samplers.KSampler.SAMPLERS, ),
|
||||
"scheduler": (common.SCHEDULERS, ),
|
||||
"scheduler": (common.get_schedulers(), ),
|
||||
"positive": ("CONDITIONING", ),
|
||||
"negative": ("CONDITIONING", ),
|
||||
"latent_image": ("LATENT", ),
|
||||
|
||||
@@ -301,7 +301,12 @@ class Canny_Preprocessor_wrapper:
|
||||
|
||||
def apply(self, image, mask=None):
|
||||
obj = nodes.NODE_CLASS_MAPPINGS['Canny']()
|
||||
return obj.detect_edge(image, self.low_threshold, self.high_threshold)[0]
|
||||
if hasattr(obj, 'execute'):
|
||||
# node v3
|
||||
return obj.execute(image, self.low_threshold, self.high_threshold)[0]
|
||||
else:
|
||||
# legacy compatibility
|
||||
return obj.detect_edge(image, self.low_threshold, self.high_threshold)[0]
|
||||
|
||||
|
||||
class OpenPose_Preprocessor_Provider_for_SEGS:
|
||||
|
||||
+57
-13
@@ -2,15 +2,45 @@ import { ComfyApp, app } from "../../scripts/app.js";
|
||||
import { api } from "../../scripts/api.js";
|
||||
|
||||
let get_wildcards_list;
|
||||
let get_wildcard_label;
|
||||
let is_wildcard_label;
|
||||
let load_wildcard_status;
|
||||
|
||||
try {
|
||||
const ImpactPack = await import("../ComfyUI-Impact-Pack/impact-pack.js");
|
||||
console.log("[Inspire Pack] Impact Pack module loaded:", ImpactPack);
|
||||
get_wildcards_list = ImpactPack.get_wildcards_list;
|
||||
get_wildcard_label = ImpactPack.get_wildcard_label;
|
||||
is_wildcard_label = ImpactPack.is_wildcard_label;
|
||||
load_wildcard_status = ImpactPack.load_wildcard_status;
|
||||
console.log("[Inspire Pack] Functions imported:", {
|
||||
get_wildcards_list: !!get_wildcards_list,
|
||||
get_wildcard_label: !!get_wildcard_label,
|
||||
is_wildcard_label: !!is_wildcard_label,
|
||||
load_wildcard_status: !!load_wildcard_status
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
console.error("[Inspire Pack] Failed to import Impact Pack module:", error);
|
||||
}
|
||||
catch (error) {}
|
||||
|
||||
// fallback
|
||||
// Fallback for get_wildcards_list
|
||||
if(!get_wildcards_list) {
|
||||
get_wildcards_list = () => { return ["Impact Pack isn't installed or is outdated."]; }
|
||||
console.warn("[Inspire Pack] get_wildcards_list not available. Using fallback.");
|
||||
get_wildcards_list = () => {
|
||||
return ["Impact Pack isn't installed or needs browser cache refresh."];
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback for on-demand features (backward compatibility with older Impact Pack)
|
||||
if(!get_wildcard_label) {
|
||||
get_wildcard_label = () => { return "Select the Wildcard to add to the text"; };
|
||||
}
|
||||
if(!is_wildcard_label) {
|
||||
is_wildcard_label = (value) => { return value === "Select the Wildcard to add to the text"; };
|
||||
}
|
||||
if(!load_wildcard_status) {
|
||||
load_wildcard_status = async () => {}; // No-op for older versions
|
||||
}
|
||||
|
||||
let pb_cache = {};
|
||||
@@ -62,19 +92,23 @@ app.registerExtension({
|
||||
});
|
||||
|
||||
// wildcard
|
||||
node.widgets[combo_id+1].callback = (value, canvas, node, pos, e) => {
|
||||
node.widgets[combo_id+1].callback = async (value, canvas, node, pos, e) => {
|
||||
if(wildcard_text_widget.value != '')
|
||||
wildcard_text_widget.value += ', '
|
||||
|
||||
wildcard_text_widget.value += node._wildcard_value;
|
||||
|
||||
// Reload wildcard status to update loaded count (Impact Pack staged feature)
|
||||
await load_wildcard_status();
|
||||
app.canvas.setDirty(true);
|
||||
}
|
||||
|
||||
Object.defineProperty(node.widgets[combo_id+1], "value", {
|
||||
set: (value) => {
|
||||
if (value !== "Select the Wildcard to add to the text")
|
||||
if (!is_wildcard_label(value))
|
||||
node._wildcard_value = value;
|
||||
},
|
||||
get: () => { return "Select the Wildcard to add to the text"; }
|
||||
get: () => { return get_wildcard_label(); }
|
||||
});
|
||||
|
||||
Object.defineProperty(node.widgets[combo_id+1].options, "values", {
|
||||
@@ -86,7 +120,10 @@ app.registerExtension({
|
||||
|
||||
// Preventing validation errors from occurring in any situation.
|
||||
node.widgets[combo_id].serializeValue = () => { return "Select the LoRA to add to the text"; }
|
||||
node.widgets[combo_id+1].serializeValue = () => { return "Select the Wildcard to add to the text"; }
|
||||
node.widgets[combo_id+1].serializeValue = () => {
|
||||
// Always serialize as the default label (not the dynamic on-demand label)
|
||||
return "Select the Wildcard to add to the text";
|
||||
}
|
||||
|
||||
// wildcard populating
|
||||
populated_text_widget.inputEl.disabled = true;
|
||||
@@ -145,7 +182,7 @@ app.registerExtension({
|
||||
get: () => { return "Select the LoRA to add to the text"; }
|
||||
});
|
||||
|
||||
node.widgets[combo_id+1].callback = (value, canvas, node, pos, e) => {
|
||||
node.widgets[combo_id+1].callback = async (value, canvas, node, pos, e) => {
|
||||
let w = null;
|
||||
if(direction_widget.value) {
|
||||
w = pos_wildcard_text_widget;
|
||||
@@ -158,14 +195,18 @@ app.registerExtension({
|
||||
w.value += ', '
|
||||
|
||||
w.value += node._wildcard_value;
|
||||
|
||||
// Reload wildcard status to update loaded count (Impact Pack staged feature)
|
||||
await load_wildcard_status();
|
||||
app.canvas.setDirty(true);
|
||||
}
|
||||
|
||||
Object.defineProperty(node.widgets[combo_id+1], "value", {
|
||||
set: (value) => {
|
||||
if (value !== "Select the Wildcard to add to the text")
|
||||
if (!is_wildcard_label(value))
|
||||
node._wildcard_value = value;
|
||||
},
|
||||
get: () => { return "Select the Wildcard to add to the text"; }
|
||||
get: () => { return get_wildcard_label(); }
|
||||
});
|
||||
|
||||
Object.defineProperty(node.widgets[combo_id+1].options, "values", {
|
||||
@@ -177,7 +218,10 @@ app.registerExtension({
|
||||
|
||||
// Preventing validation errors from occurring in any situation.
|
||||
node.widgets[combo_id].serializeValue = () => { return "Select the LoRA to add to the text"; }
|
||||
node.widgets[combo_id+1].serializeValue = () => { return "Select the Wildcard to add to the text"; }
|
||||
node.widgets[combo_id+1].serializeValue = () => {
|
||||
// Always serialize as the default label (not the dynamic on-demand label)
|
||||
return "Select the Wildcard to add to the text";
|
||||
}
|
||||
|
||||
// wildcard populating
|
||||
pos_populated_text_widget.inputEl.disabled = true;
|
||||
@@ -270,7 +314,7 @@ app.registerExtension({
|
||||
|
||||
|
||||
const original_queuePrompt = api.queuePrompt;
|
||||
async function queuePrompt_with_widget_idxs(number, { output, workflow }) {
|
||||
async function queuePrompt_with_widget_idxs(number, { output, workflow }, ...args) {
|
||||
workflow.widget_idx_map = {};
|
||||
|
||||
for(let i in app.graph._nodes_by_id) {
|
||||
@@ -289,7 +333,7 @@ async function queuePrompt_with_widget_idxs(number, { output, workflow }) {
|
||||
}
|
||||
}
|
||||
|
||||
return await original_queuePrompt.call(api, number, { output, workflow });
|
||||
return await original_queuePrompt.call(api, number, { output, workflow }, ...args);
|
||||
}
|
||||
|
||||
api.queuePrompt = queuePrompt_with_widget_idxs;
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
[project]
|
||||
name = "comfyui-inspire-pack"
|
||||
description = "This extension provides various nodes to support Lora Block Weight, Regional Nodes, Backend Cache, Prompt Utils, List Utils, Noise(Seed) Utils, ... and the Impact Pack."
|
||||
version = "1.19.1"
|
||||
version = "1.23"
|
||||
license = { file = "LICENSE" }
|
||||
dependencies = ["matplotlib", "cachetools"]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user