Compare commits

...
20 Commits
Author SHA1 Message Date
Dr.Lt.DataandClaude d23db9aa54 feat: Impact Pack progressive on-demand wildcard loading support
Add compatibility with Impact Pack's progressive on-demand wildcard loading system.
Wildcard selector now displays loading status indicators:
- 🔵 On-Demand mode: Shows loaded wildcard count
- 🟢 Full Cache mode: All wildcards loaded

Changes:
- Import Impact Pack's get_wildcard_label(), is_wildcard_label(), load_wildcard_status()
- Add fallback functions for backward compatibility
- Update WildcardEncode and MakeBasicPipe nodes with dynamic status display
- Add async callbacks to reload status after wildcard selection

Backward compatible with older Impact Pack versions.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 02:01:35 +09:00
Dr.Lt.Data 9c875a75d1 fixed: Canny_Preprocessor_wrapper - compatibility patch
https://github.com/ltdrdata/ComfyUI-Inspire-Pack/issues/259
2025-10-10 01:02:40 +09:00
Dr.Lt.Data b551b01f97 fixed: TripleCLIPLoader compatibility patch
https://github.com/ltdrdata/ComfyUI-Inspire-Pack/issues/261
https://github.com/comfyanonymous/ComfyUI/pull/10162
2025-10-09 11:43:48 +09:00
Dr.Lt.Data 6b2ca017a1 modified: Improved the behavior so that the core scheduler is retrieved dynamically instead of statically.
- Some nodepacks also insert custom schedulers into the scheduler.
2025-10-01 00:57:04 +09:00
Dr.Lt.Data 1aef2c57e3 Merge pull request #258 from rgthree/fix-queue-selected-nodes
Ensure to pass additional arguments through api.queuePrompt (fixes "Queue Selected Nodes")
2025-09-08 08:09:14 +09:00
Regis Gaughan, III c1449422e5 Ensure to pass additional arguments through api.queuePrompt (fixes "Queue Selected Nodes") 2025-09-06 21:35:45 -04:00
Dr.Lt.Data 04223778ea feat: extra schedulers - support OSS Chroma 2025-07-15 12:28:45 +09:00
Dr.Lt.Data 3fc749d6ba feat: Load Image Batch/List from Dir - sort_method is added
https://github.com/ltdrdata/ComfyUI-Inspire-Pack/issues/233
2025-06-17 22:05:16 +09:00
Dr.Lt.Data c2ccf7f879 Merge pull request #240 from LevelPixel/patch-1
Return an empty list from RetrieveBackendData rather than throwing a runtime error
2025-06-12 17:05:51 +09:00
Level Pixel 8e99bebdfe Update backend_support.py - Return an empty list rather than throwing a runtime error
Return an empty list rather than throwing a runtime error
2025-06-10 06:51:57 +06:00
Dr.Lt.Data 8814b8901a modified: support case-insensitive matching for prompt loader
https://github.com/ltdrdata/ComfyUI-Inspire-Pack/issues/239#issuecomment-2952226907
2025-06-09 06:30:31 +09:00
Dr.Lt.Data 291d3dd13f Merge pull request #230 from wzgrx/patch-1
Update requirements.txt
2025-05-17 16:57:27 +09:00
wzgrx 5619e51b01 Update requirements.txt 2025-05-17 09:28:41 +08:00
Dr.Lt.Data 0f38db4180 feat: support OSS scheduler based on Impact Sampler 2025-04-13 10:31:17 +09:00
Dr.Lt.Data e2d18c21ba feat: IPAdapterModelHelper - add SDXL FaceID Plus v2
https://github.com/ltdrdata/ComfyUI-Inspire-Pack/issues/224
2025-04-05 18:01:42 +09:00
Dr.Lt.Data 13fda9df3f Merge pull request #222 from eltociear/patch-1
docs: update README.md
2025-04-05 01:08:25 +09:00
Ikko Eltociear Ashimine 035f37d1d1 docs: update README.md
minor fix
2025-03-31 00:31:42 +09:00
Dr.Lt.Data 9d179f0193 Merge pull request #220 from ComfyNodePRs/update-publish-yaml
Update Github Action for Publishing to Comfy Registry
2025-03-29 00:32:18 +09:00
Dr.Lt.Data 5891049f2b feat: DropList node is added
https://github.com/ltdrdata/ComfyUI-Inspire-Pack/issues/219
2025-03-25 23:59:53 +09:00
snomiao f64211c3f3 chore(publish): update GitHub Actions workflow for node publishing
- Add permissions for writing issues
- Update publish-node-action to use version v1
- Add condition to run job only for 'ltdrdata' repository owner
2025-01-21 08:42:07 +00:00
16 changed files with 219 additions and 54 deletions
+6 -2
View File
@@ -7,15 +7,19 @@ on:
paths:
- "pyproject.toml"
permissions:
issues: write
jobs:
publish-node:
name: Publish Custom Node to registry
runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'ltdrdata' }}
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Publish Custom Node
uses: Comfy-Org/publish-node-action@main
uses: Comfy-Org/publish-node-action@v1
with:
## Add your own personal access token to your Github Repository secrets and reference it here.
personal_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }}
personal_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }}
+4 -2
View File
@@ -2,7 +2,8 @@
This repository offers various extension nodes for ComfyUI. Nodes here have different characteristics compared to those in the ComfyUI Impact Pack. The Impact Pack has become too large now...
## Notice:
* v1.9.1 To avoid confusion with the `NOISE` type in core, the type name has been changed to `NOISE_IMAGE`.
* V1.18: To use the 'OSS' Scheduler, please update to ComfyUI version 0.3.28 or later (April 13th or newer) and Impact Pack version V8.11 or higher.
* V1.9.1 To avoid confusion with the `NOISE` type in core, the type name has been changed to `NOISE_IMAGE`.
* V0.73 The Variation Seed feature is added to Regional Prompt nodes, and it is only compatible with versions Impact Pack V5.10 and above.
* V0.69 incompatible with the outdated **ComfyUI IPAdapter Plus**. (A version dated March 24th or later is required.)
* V0.64 add sigma_factor to RegionalPrompt... nodes required Impact Pack V4.76 or later.
@@ -172,7 +173,8 @@ This repository offers various extension nodes for ComfyUI. Nodes here have diff
* `Float Range (Inspire)`: Create a float list that increases the value by `step` from `start` to `stop`. A list as large as the maximum limit is created, and when `ensure_end` is enabled, the last value of the list becomes the stop value.
* `Worklist To Item List (Inspire)`: The list in ComfyUI allows for repeated execution of a sub-workflow. This groups these repetitions (a.k.a. list) into a single ITEM_LIST output. ITEM_LIST can then be used in ForeachList.
* `▶Foreach List (Inspire)`: A starting node for performing iterative tasks by retrieving items one by one from the ITEM_LIST.\nGenerate a new intermediate_output using item and intermediate_output as inputs, then connect it to ForeachListEnd.\nNOTE:If initial_input is omitted, the first item in item_list is used as the initial value, and the processing starts from the second item in item_list.
* `Foreach List◀ (Inspire)`: A end node for performing iterative tasks by retrieving items one by one from the ITEM_LIST.\nNOTE:Directly connect the outputs of ForeachListBegin to 'flow_control' and 'remained_list'.
* `Foreach List◀ (Inspire)`: An end node for performing iterative tasks by retrieving items one by one from the ITEM_LIST.\nNOTE:Directly connect the outputs of ForeachListBegin to 'flow_control' and 'remained_list'.
* `Drop List (Inspire)`: Removes all items from the ITEM_LIST. If the ITEM_LIST generated through this node is passed to ForeachListEnd, the process is immediately terminated.
### Util - Utilities
* `ToIPAdapterPipe (Inspire)`, `FromIPAdapterPipe (Inspire)`: These nodes assists in conveniently using the bundled ipadapter_model, clip_vision, and model required for applying IPAdapter.
+1 -11
View File
@@ -8,7 +8,7 @@
import importlib
import logging
version_code = [1, 15]
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})")
@@ -39,13 +39,3 @@ for module_name in node_list:
WEB_DIRECTORY = "./js"
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS", "WEB_DIRECTORY"]
try:
import cm_global
cm_global.register_extension('ComfyUI-Inspire-Pack',
{'version': version_code,
'name': 'Inspire Pack',
'nodes': set(NODE_CLASS_MAPPINGS.keys()),
'description': 'This extension provides various nodes to support Lora Block Weight and the Impact Pack. Provides many easily applicable regional features and applications for Variation Seed.', })
except:
pass
+4 -4
View File
@@ -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}),
+8 -2
View File
@@ -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
View File
@@ -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 -3
View File
@@ -1,5 +1,3 @@
import traceback
import comfy
import nodes
from . import utils
@@ -7,7 +5,11 @@ import logging
from server import PromptServer
SCHEDULERS = comfy.samplers.KSampler.SCHEDULERS + ['AYS SDXL', 'AYS SD1', 'AYS SVD', "GITS[coeff=1.2]"]
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):
+37 -3
View File
@@ -1,3 +1,5 @@
import logging
from comfy_execution.graph_utils import GraphBuilder, is_link
from .libs.utils import any_typ
from .libs.common import update_node_status, ListWrapper
@@ -165,10 +167,13 @@ class ForeachListEnd:
self.collect_contained(child_id, upstream, contained)
def doit(self, flow_control, remained_list, intermediate_output, dynprompt, unique_id):
if remained_list.aux[1] is None:
remained_list.aux = (remained_list.aux[0], unique_id)
if hasattr(remained_list, "aux"):
if remained_list.aux[1] is None:
remained_list.aux = (remained_list.aux[0], unique_id)
update_node_status(remained_list.aux[1], f"{(remained_list.aux[0]-len(remained_list))}/{remained_list.aux[0]} steps", (remained_list.aux[0]-len(remained_list))/remained_list.aux[0])
update_node_status(remained_list.aux[1], f"{(remained_list.aux[0]-len(remained_list))}/{remained_list.aux[0]} steps", (remained_list.aux[0]-len(remained_list))/remained_list.aux[0])
else:
logging.warning("[Inspire Pack] ForeachListEnd: `remained_list` did not come from ForeachList.")
if len(remained_list) == 0:
return (intermediate_output,)
@@ -217,11 +222,39 @@ class ForeachListEnd:
}
class DropItems:
@classmethod
def INPUT_TYPES(s):
return {
"required": { "item_list": ("ITEM_LIST", {"tooltip":"Directly connect the output of ForeachListBegin, the starting node of the iteration."}), },
}
RETURN_TYPES = (any_typ,)
RETURN_NAMES = ("ITEM_LIST",)
OUTPUT_TOOLTIPS = ("This is the final output value.",)
FUNCTION = "doit"
DESCRIPTION = ""
CATEGORY = "InspirePack/List"
def doit(self, item_list):
l = ListWrapper([])
if hasattr(item_list, 'aux'):
l.aux = item_list.aux
else:
logging.warning("[Inspire Pack] DropItems: `item_list` did not come from ForeachList.")
return (l,)
NODE_CLASS_MAPPINGS = {
"FloatRange //Inspire": FloatRange,
"WorklistToItemList //Inspire": WorklistToItemList,
"ForeachListBegin //Inspire": ForeachListBegin,
"ForeachListEnd //Inspire": ForeachListEnd,
"DropItems //Inspire": DropItems,
}
NODE_DISPLAY_NAME_MAPPINGS = {
@@ -229,4 +262,5 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"WorklistToItemList //Inspire": "Worklist To Item List (Inspire)",
"ForeachListBegin //Inspire": "▶Foreach List (Inspire)",
"ForeachListEnd //Inspire": "Foreach List◀ (Inspire)",
"DropItems //Inspire": "Drop Items (Inspire)",
}
+1
View File
@@ -30,6 +30,7 @@ model_preset = {
"SD1.5 FaceID Portrait v11": ("ip-adapter-faceid-portrait-v11_sd15", "CLIP-ViT-H-14-laion2B-s32B-b79K", None, True),
"SD1.5 FaceID Portrait": ("ip-adapter-faceid-portrait_sd15", "CLIP-ViT-H-14-laion2B-s32B-b79K", None, True),
"SDXL FaceID": ("ip-adapter-faceid_sdxl", "CLIP-ViT-H-14-laion2B-s32B-b79K", "ip-adapter-faceid_sdxl_lora", True),
"SDXL FaceID Plus v2": ("ip-adapter-faceid-plusv2_sdxl", "CLIP-ViT-H-14-laion2B-s32B-b79K", "ip-adapter-faceid-plusv2_sdxl_lora", True),
"SDXL FaceID Portrait": ("ip-adapter-faceid-portrait_sdxl", "CLIP-ViT-H-14-laion2B-s32B-b79K", None, True),
"SDXL FaceID Portrait unnorm": ("ip-adapter-faceid-portrait_sdxl_unnorm", "CLIP-ViT-H-14-laion2B-s32B-b79K", None, True),
"Kolors FaceID Plus": ("Kolors-IP-Adapter-FaceID-Plus", "clip-vit-large-patch14-336", None, True),
+36 -3
View File
@@ -130,7 +130,7 @@ class LoadPromptsFromDir:
for prompt in prompt_list:
pattern = r"^(?:(?:positive:(?P<positive>.*?)|negative:(?P<negative>.*?)|name:(?P<name>.*?))\n*)+$"
matches = re.search(pattern, prompt, re.DOTALL)
matches = re.search(pattern, prompt, re.DOTALL | re.IGNORECASE)
if matches:
positive_text = matches.group('positive').strip()
@@ -487,13 +487,44 @@ class GlobalSeed:
return {}
class SeedLogger:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
"seeds": ("STRING", {"multiline": True, "dynamicPrompts": False, "control_after_generate": False}),
"limit": ("INT", {"default": 5, "min": 0, "max": 0xffffffffffffffff}),
},
"hidden": {"unique_id": "UNIQUE_ID"}
}
RETURN_TYPES = ()
FUNCTION = "doit"
CATEGORY = "InspirePack/Prompt"
OUTPUT_NODE = True
def doit(self, seed, seeds: str, limit, unique_id):
if limit > 0:
lines = seeds.split('\n')
res = str(seed) + '\n' + '\n'.join(lines[:limit-1])
else:
res = str(seed) + '\n' + seeds
PromptServer.instance.send_sync("inspire-node-feedback", {"node_id": unique_id, "widget_name": "seeds", "type": "text", "data": res})
return {}
class GlobalSampler:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"sampler_name": (comfy.samplers.KSampler.SAMPLERS, ),
"scheduler": (common.SCHEDULERS, ),
"scheduler": (common.get_schedulers(), ),
}
}
@@ -993,6 +1024,7 @@ NODE_CLASS_MAPPINGS = {
"ZipPrompt //Inspire": ZipPrompt,
"PromptExtractor //Inspire": PromptExtractor,
"GlobalSeed //Inspire": GlobalSeed,
"SeedLogger //Inspire": SeedLogger,
"GlobalSampler //Inspire": GlobalSampler,
"BindImageListPromptList //Inspire": BindImageListPromptList,
"WildcardEncode //Inspire": WildcardEncodeInspire,
@@ -1004,7 +1036,7 @@ NODE_CLASS_MAPPINGS = {
"MakeBasicPipe //Inspire": MakeBasicPipe,
"RemoveControlNet //Inspire": RemoveControlNet,
"RemoveControlNetFromRegionalPrompts //Inspire": RemoveControlNetFromRegionalPrompts,
"CompositeNoise //Inspire": CompositeNoise
"CompositeNoise //Inspire": CompositeNoise,
}
NODE_DISPLAY_NAME_MAPPINGS = {
@@ -1015,6 +1047,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"ZipPrompt //Inspire": "Zip Prompt (Inspire)",
"PromptExtractor //Inspire": "Prompt Extractor (Inspire)",
"GlobalSeed //Inspire": "Global Seed (Inspire)",
"SeedLogger //Inspire": "Seed Logger (Inspire)",
"GlobalSampler //Inspire": "Global Sampler (Inspire)",
"BindImageListPromptList //Inspire": "Bind [ImageList, PromptList] (Inspire)",
"WildcardEncode //Inspire": "Wildcard Encode (Inspire)",
+2 -2
View File
@@ -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}),
+2 -2
View File
@@ -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", ),
+6 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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.15"
version = "1.23"
license = { file = "LICENSE" }
dependencies = ["matplotlib", "cachetools"]
+1 -1
View File
@@ -1,5 +1,5 @@
matplotlib
cachetools
numpy<2
numpy
webcolors
opencv-python