Compare commits

..
5 Commits
Author SHA1 Message Date
Dr.Lt.Data bcbed07560 refactor: change type name NOISE to NOISE_IMAGE. 2024-12-20 14:58:38 +09:00
Dr.Lt.Data 685c5c0d00 Merge pull request #198 from stormwulfren/main
Zipped Prompts Parsing Enhancements
2024-12-19 18:43:45 +09:00
Ren Black 697f12fbdb Merge pull request #1 from stormwulfren/feat/zippedPromptsQoL
Enhance zipped prompt parsing
2024-12-18 13:12:10 +00:00
Ren Black e8817bc348 Enhance zipped prompt parsing
- Added 'count' to emits of LoadPromptsFromDir and LoadPromptsFromFile nodes. Represents the total number of extracted prompts in the batch.
- Modified regex pattern for prompt parsing to include an optional 'name' field. If 'name' is not present, the existing behaviour of using the filename is emitted instead. Additionally, 'positive', 'negative' and 'name' can be presented in arbitrary order.
2024-12-18 13:09:40 +00:00
Dr.Lt.Data 9c6065af6d feat: Is Cached (Inspire) node is added.
https://github.com/ltdrdata/ComfyUI-Inspire-Pack/issues/190#issuecomment-2507871877
2024-12-01 01:26:36 +09:00
9 changed files with 154 additions and 30 deletions
+2
View File
@@ -2,6 +2,7 @@
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`.
* 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.
@@ -147,6 +148,7 @@ This repository offers various extension nodes for ComfyUI. Nodes here have diff
* When `key_opt` is empty, the `ckpt_name` is set as the cache key. The cache key output can be used for deletion purposes with Remove Back End.
* This node resolves the issue of reloading checkpoints during workflow switching.
* `Stable Cascade Checkpoint Loader (Inspire)`: This node provides a feature that allows you to load the `stage_b` and `stage_c` checkpoints of Stable Cascade at once, and it also provides a backend caching feature, optionally.
* `Is Cached (Inspire)`: Returns whether the cache exists.
### Conditioning - Nodes for conditionings
* `Concat Conditionings with Multiplier (Inspire)`: Concatenating an arbitrary number of Conditionings while applying a multiplier for each Conditioning. The multiplier depends on `comfy_PoP`, so [comfy_PoP](https://github.com/picturesonpictures/comfy_PoP) must be installed.
+1 -1
View File
@@ -7,7 +7,7 @@
import importlib
version_code = [1, 8]
version_code = [1, 9, 1]
version_str = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '')
print(f"### Loading: ComfyUI-Inspire-Pack ({version_str})")
+2 -2
View File
@@ -162,7 +162,7 @@ class KSamplerAdvanced_inspire:
"optional":
{
"variation_method": (["linear", "slerp"],),
"noise_opt": ("NOISE",),
"noise_opt": ("NOISE_IMAGE",),
"scheduler_func_opt": ("SCHEDULER_FUNC",),
}
}
@@ -253,7 +253,7 @@ class KSamplerAdvanced_inspire_pipe:
},
"optional":
{
"noise_opt": ("NOISE",),
"noise_opt": ("NOISE_IMAGE",),
"scheduler_func_opt": ("SCHEDULER_FUNC",),
}
}
+75 -2
View File
@@ -1,5 +1,6 @@
import json
import os
from .libs import common
import folder_paths
import nodes
@@ -478,6 +479,74 @@ class StableCascade_CheckpointLoader:
return b_model, b_vae, c_model, c_vae, clip_vision, clip, key_b, key_c
class IsCached:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"key": ("STRING", {"multiline": False}),
},
"hidden": {
"unique_id": "UNIQUE_ID"
}
}
RETURN_TYPES = ("BOOLEAN", )
FUNCTION = "doit"
CATEGORY = "InspirePack/Backend"
@staticmethod
def IS_CHANGED(key, unique_id):
return common.is_changed(unique_id, key in cache)
def doit(self, key, unique_id):
return (key in cache,)
# WIP: not properly working, yet
class CacheBridge:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"value": (any_typ,),
"mode": ("BOOLEAN", {"default": True, "label_off": "cached", "label_on": "passthrough"}),
},
"hidden": {
"unique_id": "UNIQUE_ID"
}
}
RETURN_TYPES = (any_typ, )
RETURN_NAMES = ("value",)
FUNCTION = "doit"
CATEGORY = "InspirePack/Backend"
@staticmethod
def IS_CHANGED(value, mode, unique_id):
if not mode and unique_id in common.changed_cache:
return common.not_changed_value(unique_id)
else:
return common.changed_value(unique_id)
def doit(self, value, mode, unique_id):
if not mode:
# cache mode
if unique_id not in common.changed_cache:
common.changed_cache[unique_id] = value
common.changed_count_cache[unique_id] = 0
return (common.changed_cache[unique_id],)
else:
common.changed_cache[unique_id] = value
common.changed_count_cache[unique_id] = 0
return (common.changed_cache[unique_id],)
NODE_CLASS_MAPPINGS = {
"CacheBackendData //Inspire": CacheBackendData,
"CacheBackendDataNumberKey //Inspire": CacheBackendDataNumberKey,
@@ -489,7 +558,9 @@ NODE_CLASS_MAPPINGS = {
"RemoveBackendDataNumberKey //Inspire": RemoveBackendDataNumberKey,
"ShowCachedInfo //Inspire": ShowCachedInfo,
"CheckpointLoaderSimpleShared //Inspire": CheckpointLoaderSimpleShared,
"StableCascade_CheckpointLoader //Inspire": StableCascade_CheckpointLoader
"StableCascade_CheckpointLoader //Inspire": StableCascade_CheckpointLoader,
"IsCached //Inspire": IsCached,
# "CacheBridge //Inspire": CacheBridge,
}
NODE_DISPLAY_NAME_MAPPINGS = {
@@ -503,5 +574,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"RemoveBackendDataNumberKey //Inspire": "Remove Backend Data [NumberKey] (Inspire)",
"ShowCachedInfo //Inspire": "Show Cached Info (Inspire)",
"CheckpointLoaderSimpleShared //Inspire": "Shared Checkpoint Loader (Inspire)",
"StableCascade_CheckpointLoader //Inspire": "Stable Cascade Checkpoint Loader (Inspire)"
"StableCascade_CheckpointLoader //Inspire": "Stable Cascade Checkpoint Loader (Inspire)",
"IsCached //Inspire": "Is Cached (Inspire)",
# "CacheBridge //Inspire": "Cache Bridge (Inspire)"
}
+17
View File
@@ -6,6 +6,7 @@ from enum import Enum
from . import prompt_support
from aiohttp import web
from . import backend_support
from .libs import common
max_seed = 2**32 - 1
@@ -354,6 +355,21 @@ def force_reset_useless_params(json_data):
return json_data
def clear_unused_node_changed_cache(json_data):
prompt = json_data['prompt']
unused = []
for x in common.changed_cache.keys():
if x not in prompt:
unused.append(x)
for x in unused:
del common.changed_cache[x]
del common.changed_count_cache[x]
return json_data
def onprompt(json_data):
prompt_support.list_counter_map = {}
@@ -367,6 +383,7 @@ def onprompt(json_data):
populate_wildcards(json_data)
force_reset_useless_params(json_data)
clear_unused_node_changed_cache(json_data)
return json_data
+27
View File
@@ -12,3 +12,30 @@ def impact_sampling(*args, **kwargs):
raise Exception(f"[ERROR] You need to install 'ComfyUI-Impact-Pack'")
return nodes.NODE_CLASS_MAPPINGS['RegionalSampler'].separated_sample(*args, **kwargs)
changed_count_cache = {}
changed_cache = {}
def changed_value(uid):
v = changed_count_cache.get(uid, 0)
changed_count_cache[uid] = v + 1
return v + 1
def not_changed_value(uid):
return changed_count_cache.get(uid, 0)
def is_changed(uid, value):
if uid not in changed_cache or changed_cache[uid] != value:
res = changed_value(uid)
else:
res = not_changed_value(uid)
changed_cache[uid] = value
print(f"keys: {changed_cache.keys()}")
return res
+25 -20
View File
@@ -63,7 +63,8 @@ class LoadPromptsFromDir:
}
}
RETURN_TYPES = ("ZIPPED_PROMPT",)
RETURN_TYPES = ("ZIPPED_PROMPT", "INT")
RETURN_NAMES = ("zipped_prompt", "count")
OUTPUT_IS_LIST = (True,)
FUNCTION = "doit"
@@ -125,20 +126,21 @@ class LoadPromptsFromDir:
prompt_list = re.split(r'\n\s*-+\s*\n', prompt_data)
for prompt in prompt_list:
pattern = r"positive:(.*?)(?:\n*|$)negative:(.*)"
pattern = r"^(?:(?:positive:(?P<positive>.*?)|negative:(?P<negative>.*?)|name:(?P<name>.*?))\n*)+$"
matches = re.search(pattern, prompt, re.DOTALL)
if matches:
positive_text = matches.group(1).strip()
negative_text = matches.group(2).strip()
result_tuple = (positive_text, negative_text, file_name)
positive_text = matches.group('positive').strip()
negative_text = matches.group('negative').strip()
name_text = matches.group('name').strip() if matches.group('name') else file_name
result_tuple = (positive_text, negative_text, name_text)
prompts.append(result_tuple)
else:
print(f"[WARN] LoadPromptsFromDir: invalid prompt format in '{file_name}'")
except Exception as e:
print(f"[ERROR] LoadPromptsFromDir: an error occurred while processing '{file_name}': {str(e)}\nNOTE: Only files with UTF-8 encoding are supported.")
return (prompts, )
return (prompts, len(prompts),)
class LoadPromptsFromFile:
@@ -166,7 +168,8 @@ class LoadPromptsFromFile:
}
}
RETURN_TYPES = ("ZIPPED_PROMPT",)
RETURN_TYPES = ("ZIPPED_PROMPT", "INT")
RETURN_NAMES = ("zipped_prompt", "count")
OUTPUT_IS_LIST = (True,)
FUNCTION = "doit"
@@ -228,22 +231,23 @@ class LoadPromptsFromFile:
prompt_list = re.split(r'\n\s*-+\s*\n', prompt_data)
pattern = r"positive:(.*?)(?:\n*|$)negative:(.*)"
pattern = r"^(?:(?:positive:(?P<positive>.*?)|negative:(?P<negative>.*?)|name:(?P<name>.*?))\n*)+$"
for p in prompt_list:
matches = re.search(pattern, p, re.DOTALL)
if matches:
positive_text = matches.group(1).strip()
negative_text = matches.group(2).strip()
result_tuple = (positive_text, negative_text, prompt_file)
positive_text = matches.group('positive').strip()
negative_text = matches.group('negative').strip()
name_text = matches.group('name').strip() if matches.group('name') else prompt_file
result_tuple = (positive_text, negative_text, name_text)
prompts.append(result_tuple)
else:
print(f"[WARN] LoadPromptsFromFile: invalid prompt format in '{prompt_file}'")
except Exception as e:
print(f"[ERROR] LoadPromptsFromFile: an error occurred while processing '{prompt_file}': {str(e)}\nNOTE: Only files with UTF-8 encoding are supported.")
return (prompts, )
return (prompts, len(prompts),)
class LoadSinglePromptFromFile:
@@ -306,13 +310,14 @@ class LoadSinglePromptFromFile:
except Exception:
prompt = prompt_list[-1]
pattern = r"positive:(.*?)(?:\n*|$)negative:(.*)"
pattern = r"^(?:(?:positive:(?P<positive>.*?)|negative:(?P<negative>.*?)|name:(?P<name>.*?))\n*)+$"
matches = re.search(pattern, prompt, re.DOTALL)
if matches:
positive_text = matches.group(1).strip()
negative_text = matches.group(2).strip()
result_tuple = (positive_text, negative_text, prompt_file)
positive_text = matches.group('positive').strip()
negative_text = matches.group('negative').strip()
name_text = matches.group('name').strip() if matches.group('name') else prompt_file
result_tuple = (positive_text, negative_text, name_text)
prompts.append(result_tuple)
else:
print(f"[WARN] LoadSinglePromptFromFile: invalid prompt format in '{prompt_file}'")
@@ -682,7 +687,7 @@ class SeedExplorer:
}
}
RETURN_TYPES = ("NOISE",)
RETURN_TYPES = ("NOISE_IMAGE",)
FUNCTION = "doit"
CATEGORY = "InspirePack/Prompt"
@@ -757,15 +762,15 @@ class CompositeNoise:
def INPUT_TYPES(s):
return {
"required": {
"destination": ("NOISE",),
"source": ("NOISE",),
"destination": ("NOISE_IMAGE",),
"source": ("NOISE_IMAGE",),
"mode": (["center", "left-top", "right-top", "left-bottom", "right-bottom", "xy"], ),
"x": ("INT", {"default": 0, "min": 0, "max": nodes.MAX_RESOLUTION, "step": 8}),
"y": ("INT", {"default": 0, "min": 0, "max": nodes.MAX_RESOLUTION, "step": 8}),
},
}
RETURN_TYPES = ("NOISE",)
RETURN_TYPES = ("NOISE_IMAGE",)
FUNCTION = "doit"
CATEGORY = "InspirePack/Prompt"
+4 -4
View File
@@ -460,7 +460,7 @@ class RegionalSeedExplorerMask:
"required": {
"mask": ("MASK",),
"noise": ("NOISE",),
"noise": ("NOISE_IMAGE",),
"seed_prompt": ("STRING", {"multiline": True, "dynamicPrompts": False, "pysssss.autocomplete": False}),
"enable_additional": ("BOOLEAN", {"default": True, "label_on": "true", "label_off": "false"}),
"additional_seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
@@ -471,7 +471,7 @@ class RegionalSeedExplorerMask:
{"variation_method": (["linear", "slerp"],), }
}
RETURN_TYPES = ("NOISE",)
RETURN_TYPES = ("NOISE_IMAGE",)
FUNCTION = "doit"
CATEGORY = "InspirePack/Regional"
@@ -517,7 +517,7 @@ class RegionalSeedExplorerColorMask:
"color_mask": ("IMAGE",),
"mask_color": ("STRING", {"multiline": False, "default": "#FFFFFF"}),
"noise": ("NOISE",),
"noise": ("NOISE_IMAGE",),
"seed_prompt": ("STRING", {"multiline": True, "dynamicPrompts": False, "pysssss.autocomplete": False}),
"enable_additional": ("BOOLEAN", {"default": True, "label_on": "true", "label_off": "false"}),
"additional_seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}),
@@ -528,7 +528,7 @@ class RegionalSeedExplorerColorMask:
{"variation_method": (["linear", "slerp"],), }
}
RETURN_TYPES = ("NOISE", "MASK")
RETURN_TYPES = ("NOISE_IMAGE", "MASK")
FUNCTION = "doit"
CATEGORY = "InspirePack/Regional"
+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.8"
version = "1.9.1"
license = { file = "LICENSE" }
dependencies = ["matplotlib", "cachetools"]