Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
727295b52e | ||
|
|
6c23f7691d | ||
|
|
6248f31402 | ||
|
|
cb0b652703 | ||
|
|
9c4fa5fb27 | ||
|
|
759b4d0dc9 | ||
|
|
a65fd56b7f | ||
|
|
47d981eca2 |
@@ -344,9 +344,9 @@ mmdet_skip = False
|
||||
3. `cd ComfyUI-Impact-Pack`
|
||||
4. (optional) `git clone https://github.com/ltdrdata/ComfyUI-Impact-Subpack impact_subpack`
|
||||
* Impact Pack will automatically download subpack during its initial launch.
|
||||
5. (optional) `python install.py`
|
||||
5. (optional) `python install-manual.py`
|
||||
* Impact Pack will automatically install its dependencies during its initial launch.
|
||||
* For the portable version, you should execute the command `..\..\..\python_embeded\python.exe install.py` to run the installation script.
|
||||
* For the portable version, you should execute the command `..\..\..\python_embeded\python.exe install-manual.py` to run the installation script.
|
||||
6. Restart ComfyUI
|
||||
|
||||
* NOTE1: If an error occurs during the installation process, please refer to [Troubleshooting Page](troubleshooting/TROUBLESHOOTING.md) for assistance.
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import subprocess
|
||||
import threading
|
||||
import locale
|
||||
import traceback
|
||||
|
||||
|
||||
if sys.argv[0] == 'install.py':
|
||||
sys.path.append('.') # for portable version
|
||||
|
||||
|
||||
impact_path = os.path.join(os.path.dirname(__file__), "modules")
|
||||
subpack_path = os.path.join(os.path.dirname(__file__), "impact_subpack")
|
||||
subpack_repo = "https://github.com/ltdrdata/ComfyUI-Impact-Subpack"
|
||||
|
||||
|
||||
comfy_path = os.environ.get('COMFYUI_PATH')
|
||||
if comfy_path is None:
|
||||
print(f"\n[bold yellow]WARN: The `COMFYUI_PATH` environment variable is not set. Assuming `{os.path.dirname(__file__)}/../../` as the ComfyUI path.[/bold yellow]", file=sys.stderr)
|
||||
comfy_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
|
||||
model_path = os.environ.get('COMFYUI_MODEL_PATH')
|
||||
if model_path is None:
|
||||
try:
|
||||
import folder_paths
|
||||
model_path = folder_paths.models_dir
|
||||
except:
|
||||
pass
|
||||
|
||||
if model_path is None:
|
||||
model_path = os.path.abspath(os.path.join(comfy_path, 'models'))
|
||||
print(f"\n[bold yellow]WARN: The `COMFYUI_MODEL_PATH` environment variable is not set. Assuming `{model_path}` as the ComfyUI path.[/bold yellow]", file=sys.stderr)
|
||||
|
||||
|
||||
sys.path.append(impact_path)
|
||||
sys.path.append(comfy_path)
|
||||
|
||||
|
||||
# ---
|
||||
def handle_stream(stream, is_stdout):
|
||||
stream.reconfigure(encoding=locale.getpreferredencoding(), errors='replace')
|
||||
|
||||
for msg in stream:
|
||||
if is_stdout:
|
||||
print(msg, end="", file=sys.stdout)
|
||||
else:
|
||||
print(msg, end="", file=sys.stderr)
|
||||
|
||||
|
||||
def process_wrap(cmd_str, cwd=None, handler=None, env=None):
|
||||
print(f"[Impact Pack] EXECUTE: {cmd_str} in '{cwd}'")
|
||||
process = subprocess.Popen(cmd_str, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env, text=True, bufsize=1)
|
||||
|
||||
if handler is None:
|
||||
handler = handle_stream
|
||||
|
||||
stdout_thread = threading.Thread(target=handler, args=(process.stdout, True))
|
||||
stderr_thread = threading.Thread(target=handler, args=(process.stderr, False))
|
||||
|
||||
stdout_thread.start()
|
||||
stderr_thread.start()
|
||||
|
||||
stdout_thread.join()
|
||||
stderr_thread.join()
|
||||
|
||||
return process.wait()
|
||||
# ---
|
||||
|
||||
|
||||
try:
|
||||
import platform
|
||||
import folder_paths
|
||||
from torchvision.datasets.utils import download_url
|
||||
import impact.config
|
||||
|
||||
print("### ComfyUI-Impact-Pack: Check dependencies")
|
||||
def ensure_subpack():
|
||||
import git
|
||||
if os.path.exists(subpack_path):
|
||||
try:
|
||||
repo = git.Repo(subpack_path)
|
||||
repo.remotes.origin.pull()
|
||||
except:
|
||||
traceback.print_exc()
|
||||
if platform.system() == 'Windows':
|
||||
print(f"[ComfyUI-Impact-Pack] Please turn off ComfyUI and remove '{subpack_path}' and restart ComfyUI.")
|
||||
else:
|
||||
shutil.rmtree(subpack_path)
|
||||
git.Repo.clone_from(subpack_repo, subpack_path)
|
||||
else:
|
||||
git.Repo.clone_from(subpack_repo, subpack_path)
|
||||
|
||||
|
||||
def install():
|
||||
subpack_install_script = os.path.join(subpack_path, "install.py")
|
||||
|
||||
print(f"### ComfyUI-Impact-Pack: Updating subpack")
|
||||
ensure_subpack() # The installation of the subpack must take place before ensure_pip. cv2 triggers a permission error.
|
||||
|
||||
new_env = os.environ.copy()
|
||||
new_env["COMFYUI_PATH"] = comfy_path
|
||||
new_env["COMFYUI_MODEL_PATH"] = model_path
|
||||
|
||||
if os.path.exists(subpack_install_script):
|
||||
if not is_requirements_installed(os.path.join(subpack_path, 'requirements.txt')):
|
||||
process_wrap(pip_install + ['-r', 'requirements.txt'], cwd=subpack_path)
|
||||
|
||||
process_wrap([sys.executable, 'install.py'], cwd=subpack_path, env=new_env)
|
||||
else:
|
||||
print(f"### ComfyUI-Impact-Pack: (Install Failed) Subpack\nFile not found: `{subpack_install_script}`")
|
||||
|
||||
# Download model
|
||||
print("### ComfyUI-Impact-Pack: Check basic models")
|
||||
sam_path = os.path.join(model_path, "sams")
|
||||
onnx_path = os.path.join(model_path, "onnx")
|
||||
|
||||
if not os.path.exists(os.path.join(os.path.dirname(__file__), '..', 'skip_download_model')):
|
||||
if not impact.config.get_config()['mmdet_skip']:
|
||||
bbox_path = os.path.join(model_path, "mmdets", "bbox")
|
||||
if not os.path.exists(bbox_path):
|
||||
os.makedirs(bbox_path)
|
||||
|
||||
if not os.path.exists(os.path.join(bbox_path, "mmdet_anime-face_yolov3.pth")):
|
||||
download_url("https://huggingface.co/dustysys/ddetailer/resolve/main/mmdet/bbox/mmdet_anime-face_yolov3.pth", bbox_path)
|
||||
|
||||
if not os.path.exists(os.path.join(bbox_path, "mmdet_anime-face_yolov3.py")):
|
||||
download_url("https://raw.githubusercontent.com/Bing-su/dddetailer/master/config/mmdet_anime-face_yolov3.py", bbox_path)
|
||||
|
||||
if not os.path.exists(os.path.join(sam_path, "sam_vit_b_01ec64.pth")):
|
||||
download_url("https://dl.fbaipublicfiles.com/segment_anything/sam_vit_b_01ec64.pth", sam_path)
|
||||
|
||||
if not os.path.exists(onnx_path):
|
||||
print(f"### ComfyUI-Impact-Pack: onnx model directory created ({onnx_path})")
|
||||
os.mkdir(onnx_path)
|
||||
|
||||
impact.config.write_config()
|
||||
|
||||
install()
|
||||
|
||||
except Exception as e:
|
||||
print("[ERROR] ComfyUI-Impact-Pack: Dependency installation has failed. Please install manually.")
|
||||
traceback.print_exc()
|
||||
+7
-3
@@ -353,7 +353,7 @@ app.registerExtension({
|
||||
}
|
||||
|
||||
this.outputs[0].type = origin_type;
|
||||
this.outputs[0].name = origin_type;
|
||||
this.outputs[0].name = 'output1';
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -483,8 +483,12 @@ app.registerExtension({
|
||||
|
||||
if(this.inputs[0].type == '*'){
|
||||
const node = app.graph.getNodeById(link_info.origin_id);
|
||||
let origin_type = node.outputs[link_info.origin_slot].type;
|
||||
|
||||
let origin_type = node.outputs[link_info.origin_slot]?.type;
|
||||
if(link_info.target_slot == 0 && this.inputs.length > 1) {
|
||||
origin_type = this.inputs[1].type;
|
||||
node.connect(link_info.origin_slot, node.id, 'input1');
|
||||
}
|
||||
|
||||
if(origin_type == '*') {
|
||||
this.disconnectInput(link_info.target_slot);
|
||||
return;
|
||||
|
||||
@@ -20,7 +20,8 @@ class PreviewBridge:
|
||||
"image": ("STRING", {"default": ""}),
|
||||
},
|
||||
"optional": {
|
||||
"block": ("BOOLEAN", {"default": False, "label_on": "if_empty_mask", "label_off": "never", "tooltip": "is_empty_mask: If the mask is empty, the execution is stopped.\nnever: The execution is never stopped."})
|
||||
"block": ("BOOLEAN", {"default": False, "label_on": "if_empty_mask", "label_off": "never", "tooltip": "is_empty_mask: If the mask is empty, the execution is stopped.\nnever: The execution is never stopped."}),
|
||||
"restore_mask": (["never", "always", "if_same_size"], {"tooltip": "if_same_size: If the changed input image is the same size as the previous image, restore using the last saved mask\nalways: Whenever the input image changes, always restore using the last saved mask\nnever: Do not restore the mask.\n`restore_mask` has higher priority than `block`"}),
|
||||
},
|
||||
"hidden": {"unique_id": "UNIQUE_ID", "extra_pnginfo": "EXTRA_PNGINFO"},
|
||||
}
|
||||
@@ -75,7 +76,7 @@ class PreviewBridge:
|
||||
|
||||
return image, mask.unsqueeze(0), ui_item
|
||||
|
||||
def doit(self, images, image, unique_id, block=False, prompt=None, extra_pnginfo=None):
|
||||
def doit(self, images, image, unique_id, block=False, restore_mask="never", prompt=None, extra_pnginfo=None):
|
||||
need_refresh = False
|
||||
|
||||
if unique_id not in core.preview_bridge_cache:
|
||||
@@ -88,10 +89,25 @@ class PreviewBridge:
|
||||
pixels, mask, path_item = PreviewBridge.load_image(image)
|
||||
image = [path_item]
|
||||
else:
|
||||
res = nodes.PreviewImage().save_images(images, filename_prefix="PreviewBridge/PB-", prompt=prompt, extra_pnginfo=extra_pnginfo)
|
||||
if restore_mask != "never":
|
||||
mask = core.preview_bridge_last_mask_cache.get(unique_id)
|
||||
if mask is None or (restore_mask != "always" and mask.shape[1:] != images.shape[1:3]):
|
||||
mask = None
|
||||
else:
|
||||
mask = None
|
||||
|
||||
if mask is None:
|
||||
mask = torch.zeros((64, 64), dtype=torch.float32, device="cpu")
|
||||
res = nodes.PreviewImage().save_images(images, filename_prefix="PreviewBridge/PB-", prompt=prompt, extra_pnginfo=extra_pnginfo)
|
||||
else:
|
||||
masked_images = tensor_convert_rgba(images)
|
||||
resized_mask = resize_mask(mask, (images.shape[1], images.shape[2])).unsqueeze(3)
|
||||
resized_mask = 1 - resized_mask
|
||||
tensor_putalpha(masked_images, resized_mask)
|
||||
res = nodes.PreviewImage().save_images(masked_images, filename_prefix="PreviewBridge/PB-", prompt=prompt, extra_pnginfo=extra_pnginfo)
|
||||
|
||||
image2 = res['ui']['images']
|
||||
pixels = images
|
||||
mask = torch.zeros((64, 64), dtype=torch.float32, device="cpu")
|
||||
|
||||
path = os.path.join(folder_paths.get_temp_directory(), 'PreviewBridge', image2[0]['filename'])
|
||||
core.set_previewbridge_image(unique_id, path, image2[0])
|
||||
@@ -103,7 +119,7 @@ class PreviewBridge:
|
||||
|
||||
is_empty_mask = torch.all(mask == 0)
|
||||
|
||||
if block and is_empty_mask and core.is_execution_model_version_supported:
|
||||
if block and is_empty_mask and core.is_execution_model_version_supported():
|
||||
from comfy_execution.graph import ExecutionBlocker
|
||||
result = ExecutionBlocker(None), ExecutionBlocker(None)
|
||||
elif block and is_empty_mask:
|
||||
@@ -112,6 +128,9 @@ class PreviewBridge:
|
||||
else:
|
||||
result = pixels, mask
|
||||
|
||||
if not is_empty_mask:
|
||||
core.preview_bridge_last_mask_cache[unique_id] = mask
|
||||
|
||||
return {
|
||||
"ui": {"images": image},
|
||||
"result": result,
|
||||
@@ -196,7 +215,8 @@ class PreviewBridgeLatent:
|
||||
},
|
||||
"optional": {
|
||||
"vae_opt": ("VAE", ),
|
||||
"block": ("BOOLEAN", {"default": False, "label_on": "if_empty_mask", "label_off": "never", "tooltip": "is_empty_mask: If the mask is empty, the execution is stopped.\nnever: The execution is never stopped. Instead, it returns a white mask."})
|
||||
"block": ("BOOLEAN", {"default": False, "label_on": "if_empty_mask", "label_off": "never", "tooltip": "is_empty_mask: If the mask is empty, the execution is stopped.\nnever: The execution is never stopped. Instead, it returns a white mask."}),
|
||||
"restore_mask": (["never", "always", "if_same_size"], {"tooltip": "if_same_size: If the changed input latent is the same size as the previous latent, restore using the last saved mask\nalways: Whenever the input latent changes, always restore using the last saved mask\nnever: Do not restore the mask.\n`restore_mask` has higher priority than `block`\nIf the input latent already has a mask, do not restore mask."}),
|
||||
},
|
||||
"hidden": {"unique_id": "UNIQUE_ID", "prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"},
|
||||
}
|
||||
@@ -252,7 +272,7 @@ class PreviewBridgeLatent:
|
||||
|
||||
return image, mask, ui_item
|
||||
|
||||
def doit(self, latent, image, preview_method, vae_opt=None, block=False, unique_id=None, prompt=None, extra_pnginfo=None):
|
||||
def doit(self, latent, image, preview_method, vae_opt=None, block=False, unique_id=None, restore_mask='never', prompt=None, extra_pnginfo=None):
|
||||
latent_channels = latent['samples'].shape[1]
|
||||
preview_method_channels = 16 if 'SD3' in preview_method or 'SC-Prior' in preview_method or 'FLUX.1' in preview_method or 'TAEF1' == preview_method else 4
|
||||
|
||||
@@ -311,13 +331,28 @@ class PreviewBridgeLatent:
|
||||
'type': 'temp',
|
||||
}]
|
||||
|
||||
is_empty_mask = torch.all(mask == 1)
|
||||
is_empty_mask = False
|
||||
else:
|
||||
mask = torch.ones(latent['samples'].shape[2:], dtype=torch.float32, device="cpu").unsqueeze(0)
|
||||
res = nodes.PreviewImage().save_images(decoded_image, filename_prefix="PreviewBridge/PBL-", prompt=prompt, extra_pnginfo=extra_pnginfo)
|
||||
if restore_mask != "never":
|
||||
mask = core.preview_bridge_last_mask_cache.get(unique_id)
|
||||
if mask is None or (restore_mask != "always" and mask.shape[1:] != decoded_image.shape[1:3]):
|
||||
mask = None
|
||||
else:
|
||||
mask = None
|
||||
|
||||
if mask is None:
|
||||
mask = torch.ones(latent['samples'].shape[2:], dtype=torch.float32, device="cpu").unsqueeze(0)
|
||||
res = nodes.PreviewImage().save_images(decoded_image, filename_prefix="PreviewBridge/PBL-", prompt=prompt, extra_pnginfo=extra_pnginfo)
|
||||
else:
|
||||
masked_images = tensor_convert_rgba(decoded_image)
|
||||
resized_mask = resize_mask(mask, (decoded_image.shape[1], decoded_image.shape[2])).unsqueeze(3)
|
||||
resized_mask = 1 - resized_mask
|
||||
tensor_putalpha(masked_images, resized_mask)
|
||||
res = nodes.PreviewImage().save_images(masked_images, filename_prefix="PreviewBridge/PBL-", prompt=prompt, extra_pnginfo=extra_pnginfo)
|
||||
|
||||
res_image = res['ui']['images']
|
||||
|
||||
is_empty_mask = True
|
||||
is_empty_mask = torch.all(mask == 1)
|
||||
|
||||
path = os.path.join(folder_paths.get_temp_directory(), 'PreviewBridge', res_image[0]['filename'])
|
||||
core.set_previewbridge_image(unique_id, path, res_image[0])
|
||||
@@ -327,7 +362,7 @@ class PreviewBridgeLatent:
|
||||
|
||||
res_latent = latent
|
||||
|
||||
if block and is_empty_mask and core.is_execution_model_version_supported:
|
||||
if block and is_empty_mask and core.is_execution_model_version_supported():
|
||||
from comfy_execution.graph import ExecutionBlocker
|
||||
result = ExecutionBlocker(None), ExecutionBlocker(None)
|
||||
elif block and is_empty_mask:
|
||||
@@ -336,6 +371,9 @@ class PreviewBridgeLatent:
|
||||
else:
|
||||
result = res_latent, mask
|
||||
|
||||
if not is_empty_mask:
|
||||
core.preview_bridge_last_mask_cache[unique_id] = mask
|
||||
|
||||
return {
|
||||
"ui": {"images": res_image},
|
||||
"result": result,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import configparser
|
||||
import os
|
||||
|
||||
version_code = [7, 9]
|
||||
version_code = [7, 10, 6]
|
||||
version = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '')
|
||||
|
||||
dependency_version = 23
|
||||
|
||||
@@ -41,7 +41,10 @@ SEG = namedtuple("SEG",
|
||||
pb_id_cnt = time.time()
|
||||
preview_bridge_image_id_map = {}
|
||||
preview_bridge_image_name_map = {}
|
||||
|
||||
preview_bridge_cache = {}
|
||||
preview_bridge_last_mask_cache = {}
|
||||
|
||||
current_prompt = None
|
||||
|
||||
SCHEDULERS = comfy.samplers.KSampler.SCHEDULERS + ['AYS SDXL', 'AYS SD1', 'AYS SVD', 'GITS[coeff=1.2]']
|
||||
|
||||
@@ -409,9 +409,14 @@ def gc_preview_bridge_cache(json_data):
|
||||
|
||||
for key in list(core.preview_bridge_cache.keys()):
|
||||
if key not in prompt_keys:
|
||||
print(f"key deleted: {key}")
|
||||
# print(f"key deleted [PB]: {key}")
|
||||
del core.preview_bridge_cache[key]
|
||||
|
||||
for key in list(core.preview_bridge_last_mask_cache.keys()):
|
||||
if key not in prompt_keys:
|
||||
# print(f"key deleted [PB_last_mask]: {key}")
|
||||
del core.preview_bridge_last_mask_cache[key]
|
||||
|
||||
|
||||
def workflow_imagereceiver_update(json_data):
|
||||
prompt = json_data['prompt']
|
||||
|
||||
@@ -691,7 +691,7 @@ class ImpactControlBridge:
|
||||
def doit(self, value, mode, behavior="Stop", unique_id=None, prompt=None, extra_pnginfo=None):
|
||||
global error_skip_flag
|
||||
|
||||
if core.is_execution_model_version_supported:
|
||||
if core.is_execution_model_version_supported():
|
||||
from comfy_execution.graph import ExecutionBlocker
|
||||
else:
|
||||
print("[Impact Pack] ImpactControlBridge: ComfyUI is outdated. The 'Stop' behavior cannot function properly.")
|
||||
|
||||
@@ -17,9 +17,16 @@ class GeneralSwitch:
|
||||
dyn_inputs = {"input1": (any_typ, {"lazy": True, "tooltip": "Any input. When connected, one more input slot is added."}), }
|
||||
if core.is_execution_model_version_supported():
|
||||
stack = inspect.stack()
|
||||
if stack[2].function == 'get_input_info' and stack[3].function == 'add_node':
|
||||
for x in range(2, 200):
|
||||
dyn_inputs[f"input{x}"] = (any_typ, {"lazy": True})
|
||||
if stack[2].function == 'get_input_info':
|
||||
# bypass validation
|
||||
class AllContainer:
|
||||
def __contains__(self, item):
|
||||
return True
|
||||
|
||||
def __getitem__(self, key):
|
||||
return any_typ, {"lazy": True}
|
||||
|
||||
dyn_inputs = AllContainer()
|
||||
|
||||
inputs = {"required": {
|
||||
"select": ("INT", {"default": 1, "min": 1, "max": 999999, "step": 1, "tooltip": "The input number you want to output among the inputs"}),
|
||||
@@ -163,7 +170,7 @@ class GeneralInversedSwitch:
|
||||
CATEGORY = "ImpactPack/Util"
|
||||
|
||||
def doit(self, select, prompt, unique_id, input, **kwargs):
|
||||
if core.is_execution_model_version_supported:
|
||||
if core.is_execution_model_version_supported():
|
||||
from comfy_execution.graph import ExecutionBlocker
|
||||
else:
|
||||
print("[Impact Pack] InversedSwitch: ComfyUI is outdated. The 'select_on_execution' mode cannot function properly.")
|
||||
@@ -181,7 +188,7 @@ class GeneralInversedSwitch:
|
||||
for i in range(0, cnt + 1):
|
||||
if select == i+1:
|
||||
res.append(input)
|
||||
elif core.is_execution_model_version_supported:
|
||||
elif core.is_execution_model_version_supported():
|
||||
res.append(ExecutionBlocker(None))
|
||||
else:
|
||||
res.append(None)
|
||||
|
||||
@@ -58,11 +58,11 @@ def read_wildcard_dict(wildcard_path):
|
||||
try:
|
||||
with open(file_path, 'r', encoding="ISO-8859-1") as f:
|
||||
lines = f.read().splitlines()
|
||||
wildcard_dict[key] = lines
|
||||
wildcard_dict[key] = [x for x in lines if not x.strip().startswith('#')]
|
||||
except yaml.reader.ReaderError:
|
||||
with open(file_path, 'r', encoding="UTF-8", errors="ignore") as f:
|
||||
lines = f.read().splitlines()
|
||||
wildcard_dict[key] = lines
|
||||
wildcard_dict[key] = [x for x in lines if not x.strip().startswith('#')]
|
||||
elif file.endswith('.yaml'):
|
||||
file_path = os.path.join(root, file)
|
||||
|
||||
@@ -150,7 +150,7 @@ def process(text, seed=None):
|
||||
matches = re.findall(wildcard_pattern, multi_select_pattern[1])
|
||||
if len(options) == 1 and matches:
|
||||
# count$$<single wildcard>
|
||||
options = local_wildcard_dict.get(matches[0])
|
||||
options = get_wildcard_options(multi_select_pattern[1])
|
||||
else:
|
||||
# count$$opt1|opt2|...
|
||||
options[0] = multi_select_pattern[1]
|
||||
@@ -199,6 +199,34 @@ def process(text, seed=None):
|
||||
|
||||
return replaced_string, replacements_found
|
||||
|
||||
def get_wildcard_options(string):
|
||||
pattern = r"__([\w.\-+/*\\]+?)__"
|
||||
matches = re.findall(pattern, string)
|
||||
|
||||
options = []
|
||||
|
||||
for match in matches:
|
||||
keyword = match.lower()
|
||||
keyword = wildcard_normalize(keyword)
|
||||
if keyword in local_wildcard_dict:
|
||||
options.extend(local_wildcard_dict[keyword])
|
||||
elif '*' in keyword:
|
||||
subpattern = keyword.replace('*', '.*').replace('+', '\\+')
|
||||
total_patterns = []
|
||||
found = False
|
||||
for k, v in local_wildcard_dict.items():
|
||||
if re.match(subpattern, k) is not None or re.match(subpattern, k+'/') is not None:
|
||||
total_patterns += v
|
||||
found = True
|
||||
|
||||
if found:
|
||||
options.extend(total_patterns)
|
||||
elif '/' not in keyword:
|
||||
string_fallback = string.replace(f"__{match}__", f"__*/{match}__", 1)
|
||||
options.extend(get_wildcard_options(string_fallback))
|
||||
|
||||
return options
|
||||
|
||||
def replace_wildcard(string):
|
||||
pattern = r"__([\w.\-+/*\\]+?)__"
|
||||
matches = re.findall(pattern, string)
|
||||
@@ -259,7 +287,7 @@ def process(text, seed=None):
|
||||
|
||||
|
||||
def is_numeric_string(input_str):
|
||||
return re.match(r'^-?\d+(\.\d+)?$', input_str) is not None
|
||||
return re.match(r'^-?(\d*\.?\d+|\d+\.?\d*)$', input_str) is not None
|
||||
|
||||
|
||||
def safe_float(x):
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
[project]
|
||||
name = "comfyui-impact-pack"
|
||||
description = "This extension offers various detector nodes and detailer nodes that allow you to configure a workflow that automatically enhances facial details. And provide iterative upscaler."
|
||||
version = "7.9"
|
||||
version = "7.10.6"
|
||||
license = { file = "LICENSE.txt" }
|
||||
dependencies = ["segment-anything", "scikit-image", "piexif", "transformers", "opencv-python-headless", "GitPython", "scipy>=1.11.4"]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user