mirror of
https://git.datalinker.icu/kijai/ComfyUI-KJNodes.git
synced 2026-05-21 11:07:17 +08:00
Merge fbd6ba21825d81d160152abd5d0c4b70cd392973 into c661baadd9683c0033cd2a6ad90157c6d099a6c2
This commit is contained in:
commit
59e53de023
636
nodes/nodes.py
636
nodes/nodes.py
@ -115,12 +115,12 @@ to a different frame count.
|
|||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
return {
|
return {
|
||||||
"required": {
|
"required": {
|
||||||
"input_str": ("STRING", {"forceInput": True,"default": "0:(0.0),\n7:(1.0),\n15:(0.0)\n"}),
|
"input_str": ("STRING", {"forceInput": True,"default": "0:(0.0),\n7:(1.0),\n15:(0.0)\n"}),
|
||||||
"old_frame_count": ("INT", {"forceInput": True,"default": 1,"min": 1, "max": 4096, "step": 1}),
|
"old_frame_count": ("INT", {"forceInput": True,"default": 1,"min": 1, "max": 4096, "step": 1}),
|
||||||
"new_frame_count": ("INT", {"forceInput": True,"default": 1,"min": 1, "max": 4096, "step": 1}),
|
"new_frame_count": ("INT", {"forceInput": True,"default": 1,"min": 1, "max": 4096, "step": 1}),
|
||||||
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
def scaleschedule(self, old_frame_count, input_str, new_frame_count):
|
def scaleschedule(self, old_frame_count, input_str, new_frame_count):
|
||||||
pattern = r'"(\d+)"\s*:\s*"(.*?)"(?:,|\Z)'
|
pattern = r'"(\d+)"\s*:\s*"(.*?)"(?:,|\Z)'
|
||||||
@ -158,11 +158,11 @@ Selects and returns the latents at the specified indices as an latent batch.
|
|||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
return {
|
return {
|
||||||
"required": {
|
"required": {
|
||||||
"latents": ("LATENT",),
|
"latents": ("LATENT",),
|
||||||
"indexes": ("STRING", {"default": "0, 1, 2", "multiline": True}),
|
"indexes": ("STRING", {"default": "0, 1, 2", "multiline": True}),
|
||||||
"latent_format": (["BCHW", "BTCHW", "BCTHW"], {"default": "BCHW"}),
|
"latent_format": (["BCHW", "BTCHW", "BCTHW"], {"default": "BCHW"}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
def indexedlatentsfrombatch(self, latents, indexes, latent_format):
|
def indexedlatentsfrombatch(self, latents, indexes, latent_format):
|
||||||
|
|
||||||
@ -197,7 +197,7 @@ class ConditioningMultiCombine:
|
|||||||
"conditioning_1": ("CONDITIONING", ),
|
"conditioning_1": ("CONDITIONING", ),
|
||||||
"conditioning_2": ("CONDITIONING", ),
|
"conditioning_2": ("CONDITIONING", ),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_TYPES = ("CONDITIONING", "INT")
|
RETURN_TYPES = ("CONDITIONING", "INT")
|
||||||
RETURN_NAMES = ("combined", "inputcount")
|
RETURN_NAMES = ("combined", "inputcount")
|
||||||
@ -276,7 +276,7 @@ class JoinStringMulti:
|
|||||||
"optional": {
|
"optional": {
|
||||||
"string_2": ("STRING", {"default": '', "forceInput": True}),
|
"string_2": ("STRING", {"default": '', "forceInput": True}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_TYPES = ("STRING",)
|
RETURN_TYPES = ("STRING",)
|
||||||
RETURN_NAMES = ("string",)
|
RETURN_NAMES = ("string",)
|
||||||
@ -316,7 +316,7 @@ class CondPassThrough:
|
|||||||
"positive": ("CONDITIONING", ),
|
"positive": ("CONDITIONING", ),
|
||||||
"negative": ("CONDITIONING", ),
|
"negative": ("CONDITIONING", ),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_TYPES = ("CONDITIONING", "CONDITIONING",)
|
RETURN_TYPES = ("CONDITIONING", "CONDITIONING",)
|
||||||
RETURN_NAMES = ("positive", "negative")
|
RETURN_NAMES = ("positive", "negative")
|
||||||
@ -339,7 +339,7 @@ class ModelPassThrough:
|
|||||||
"optional": {
|
"optional": {
|
||||||
"model": ("MODEL", ),
|
"model": ("MODEL", ),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_TYPES = ("MODEL", )
|
RETURN_TYPES = ("MODEL", )
|
||||||
RETURN_NAMES = ("model",)
|
RETURN_NAMES = ("model",)
|
||||||
@ -351,15 +351,15 @@ class ModelPassThrough:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def passthrough(self, model=None):
|
def passthrough(self, model=None):
|
||||||
return (model,)
|
return (model,)
|
||||||
|
|
||||||
def append_helper(t, mask, c, set_area_to_bounds, strength):
|
def append_helper(t, mask, c, set_area_to_bounds, strength):
|
||||||
n = [t[0], t[1].copy()]
|
n = [t[0], t[1].copy()]
|
||||||
_, h, w = mask.shape
|
_, h, w = mask.shape
|
||||||
n[1]['mask'] = mask
|
n[1]['mask'] = mask
|
||||||
n[1]['set_area_to_bounds'] = set_area_to_bounds
|
n[1]['set_area_to_bounds'] = set_area_to_bounds
|
||||||
n[1]['mask_strength'] = strength
|
n[1]['mask_strength'] = strength
|
||||||
c.append(n)
|
c.append(n)
|
||||||
|
|
||||||
class ConditioningSetMaskAndCombine:
|
class ConditioningSetMaskAndCombine:
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -606,19 +606,19 @@ class VRAM_Debug:
|
|||||||
@classmethod
|
@classmethod
|
||||||
|
|
||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
return {
|
return {
|
||||||
"required": {
|
"required": {
|
||||||
|
|
||||||
"empty_cache": ("BOOLEAN", {"default": True}),
|
"empty_cache": ("BOOLEAN", {"default": True}),
|
||||||
"gc_collect": ("BOOLEAN", {"default": True}),
|
"gc_collect": ("BOOLEAN", {"default": True}),
|
||||||
"unload_all_models": ("BOOLEAN", {"default": False}),
|
"unload_all_models": ("BOOLEAN", {"default": False}),
|
||||||
},
|
},
|
||||||
"optional": {
|
"optional": {
|
||||||
"any_input": (IO.ANY,),
|
"any_input": (IO.ANY,),
|
||||||
"image_pass": ("IMAGE",),
|
"image_pass": ("IMAGE",),
|
||||||
"model_pass": ("MODEL",),
|
"model_pass": ("MODEL",),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
RETURN_TYPES = (IO.ANY, "IMAGE","MODEL","INT", "INT",)
|
RETURN_TYPES = (IO.ANY, "IMAGE","MODEL","INT", "INT",)
|
||||||
RETURN_NAMES = ("any_output", "image_pass", "model_pass", "freemem_before", "freemem_after")
|
RETURN_NAMES = ("any_output", "image_pass", "model_pass", "freemem_before", "freemem_after")
|
||||||
@ -652,15 +652,15 @@ class SomethingToString:
|
|||||||
@classmethod
|
@classmethod
|
||||||
|
|
||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
return {
|
return {
|
||||||
"required": {
|
"required": {
|
||||||
"input": (IO.ANY, ),
|
"input": (IO.ANY, ),
|
||||||
},
|
},
|
||||||
"optional": {
|
"optional": {
|
||||||
"prefix": ("STRING", {"default": ""}),
|
"prefix": ("STRING", {"default": ""}),
|
||||||
"suffix": ("STRING", {"default": ""}),
|
"suffix": ("STRING", {"default": ""}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RETURN_TYPES = ("STRING",)
|
RETURN_TYPES = ("STRING",)
|
||||||
FUNCTION = "stringify"
|
FUNCTION = "stringify"
|
||||||
CATEGORY = "KJNodes/text"
|
CATEGORY = "KJNodes/text"
|
||||||
@ -708,31 +708,31 @@ class EmptyLatentImagePresets:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(cls):
|
def INPUT_TYPES(cls):
|
||||||
return {
|
return {
|
||||||
"required": {
|
"required": {
|
||||||
"dimensions": (
|
"dimensions": (
|
||||||
[
|
[
|
||||||
'512 x 512 (1:1)',
|
'512 x 512 (1:1)',
|
||||||
'768 x 512 (1.5:1)',
|
'768 x 512 (1.5:1)',
|
||||||
'960 x 512 (1.875:1)',
|
'960 x 512 (1.875:1)',
|
||||||
'1024 x 512 (2:1)',
|
'1024 x 512 (2:1)',
|
||||||
'1024 x 576 (1.778:1)',
|
'1024 x 576 (1.778:1)',
|
||||||
'1536 x 640 (2.4:1)',
|
'1536 x 640 (2.4:1)',
|
||||||
'1344 x 768 (1.75:1)',
|
'1344 x 768 (1.75:1)',
|
||||||
'1216 x 832 (1.46:1)',
|
'1216 x 832 (1.46:1)',
|
||||||
'1152 x 896 (1.286:1)',
|
'1152 x 896 (1.286:1)',
|
||||||
'1024 x 1024 (1:1)',
|
'1024 x 1024 (1:1)',
|
||||||
],
|
],
|
||||||
{
|
{
|
||||||
"default": '512 x 512 (1:1)'
|
"default": '512 x 512 (1:1)'
|
||||||
}),
|
}),
|
||||||
|
|
||||||
"invert": ("BOOLEAN", {"default": False}),
|
"invert": ("BOOLEAN", {"default": False}),
|
||||||
"batch_size": ("INT", {
|
"batch_size": ("INT", {
|
||||||
"default": 1,
|
"default": 1,
|
||||||
"min": 1,
|
"min": 1,
|
||||||
"max": 4096
|
"max": 4096
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_TYPES = ("LATENT", "INT", "INT")
|
RETURN_TYPES = ("LATENT", "INT", "INT")
|
||||||
@ -767,18 +767,18 @@ class EmptyLatentImageCustomPresets:
|
|||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
dimensions_dict = []
|
dimensions_dict = []
|
||||||
return {
|
return {
|
||||||
"required": {
|
"required": {
|
||||||
"dimensions": (
|
"dimensions": (
|
||||||
[f"{d['label']} - {d['value']}" for d in dimensions_dict],
|
[f"{d['label']} - {d['value']}" for d in dimensions_dict],
|
||||||
),
|
),
|
||||||
|
|
||||||
"invert": ("BOOLEAN", {"default": False}),
|
"invert": ("BOOLEAN", {"default": False}),
|
||||||
"batch_size": ("INT", {
|
"batch_size": ("INT", {
|
||||||
"default": 1,
|
"default": 1,
|
||||||
"min": 1,
|
"min": 1,
|
||||||
"max": 4096
|
"max": 4096
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_TYPES = ("LATENT", "INT", "INT")
|
RETURN_TYPES = ("LATENT", "INT", "INT")
|
||||||
@ -791,19 +791,20 @@ The choices are loaded from 'custom_dimensions.json' in the nodes folder.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def generate(self, dimensions, invert, batch_size):
|
def generate(self, dimensions, invert, batch_size):
|
||||||
from nodes import EmptyLatentImage
|
from nodes import EmptyLatentImage
|
||||||
# Split the string into label and value
|
# Split the string into label and value
|
||||||
label, value = dimensions.split(' - ')
|
label, value = dimensions.split(' - ')
|
||||||
# Split the value into width and height
|
# Split the value into width and height
|
||||||
width, height = [x.strip() for x in value.split('x')]
|
width, height = [x.strip() for x in value.split('x')]
|
||||||
|
|
||||||
if invert:
|
if invert:
|
||||||
width, height = height, width
|
width, height = height, width
|
||||||
|
|
||||||
latent = EmptyLatentImage().generate(int(width), int(height), batch_size)[0]
|
latent = EmptyLatentImage().generate(int(width), int(height), batch_size)[0]
|
||||||
|
|
||||||
return (latent, int(width), int(height),)
|
return (latent, int(width), int(height),)
|
||||||
|
|
||||||
|
# noinspection PyShadowingNames
|
||||||
class WidgetToString:
|
class WidgetToString:
|
||||||
@classmethod
|
@classmethod
|
||||||
def IS_CHANGED(cls,*,id,node_title,any_input,**kwargs):
|
def IS_CHANGED(cls,*,id,node_title,any_input,**kwargs):
|
||||||
@ -819,11 +820,11 @@ class WidgetToString:
|
|||||||
"return_all": ("BOOLEAN", {"default": False}),
|
"return_all": ("BOOLEAN", {"default": False}),
|
||||||
},
|
},
|
||||||
"optional": {
|
"optional": {
|
||||||
"any_input": (IO.ANY, ),
|
"any_input": (IO.ANY, ),
|
||||||
"node_title": ("STRING", {"multiline": False}),
|
"node_title": ("STRING", {"multiline": False}),
|
||||||
"allowed_float_decimals": ("INT", {"default": 2, "min": 0, "max": 10, "tooltip": "Number of decimal places to display for float values"}),
|
"allowed_float_decimals": ("INT", {"default": 2, "min": 0, "max": 10, "tooltip": "Number of decimal places to display for float values"}),
|
||||||
|
|
||||||
},
|
},
|
||||||
"hidden": {"extra_pnginfo": "EXTRA_PNGINFO",
|
"hidden": {"extra_pnginfo": "EXTRA_PNGINFO",
|
||||||
"prompt": "PROMPT",
|
"prompt": "PROMPT",
|
||||||
"unique_id": "UNIQUE_ID",},
|
"unique_id": "UNIQUE_ID",},
|
||||||
@ -842,54 +843,231 @@ The 'any_input' is required for making sure the node you want the value from exi
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def get_widget_value(self, id, widget_name, extra_pnginfo, prompt, unique_id, return_all=False, any_input=None, node_title="", allowed_float_decimals=2):
|
def get_widget_value(self, id, widget_name, extra_pnginfo, prompt, unique_id, return_all=False, any_input=None, node_title="", allowed_float_decimals=2):
|
||||||
|
"""
|
||||||
|
Retrieves the value of the specified widget from a node in the workflow and
|
||||||
|
returns it as a string.
|
||||||
|
|
||||||
|
If no `id` or `node_title` is provided, the method attempts to identify the
|
||||||
|
node using the `any_input` connection in the workflow. Enable node ID display
|
||||||
|
in ComfyUI's "Manager" menu to view node IDs, or use a manually edited node
|
||||||
|
title for searching. NOTE: A node does not have a title unless it is manually
|
||||||
|
edited to something other than its default value.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id (int): The unique ID of the target node. If 0, the method relies on
|
||||||
|
other methods to determine the node. TODO: change to a STRING (breaking change)
|
||||||
|
widget_name (str): The name of the widget whose value needs to be retrieved.
|
||||||
|
extra_pnginfo (dict): A dictionary containing workflow metadata, including
|
||||||
|
node connections and state.
|
||||||
|
prompt (dict): A dictionary containing node-specific data with input
|
||||||
|
settings to extract widget values.
|
||||||
|
unique_id (str): The unique identifier of the current node instance, used
|
||||||
|
to match the `any_input` connection.
|
||||||
|
return_all (bool): If True, retrieves and returns all input values from
|
||||||
|
the node, formatted as a string.
|
||||||
|
any_input (str): Optional. A link reference used to determine the node if
|
||||||
|
no `id` or `node_title` is provided.
|
||||||
|
node_title (str): Optional. The title of the node to search for. Titles
|
||||||
|
are valid only if manually assigned in ComfyUI.
|
||||||
|
allowed_float_decimals (int): The number of decimal places to which float
|
||||||
|
values should be rounded in the output.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str or tuple:
|
||||||
|
- If `return_all` is False, returns a tuple with the value of the
|
||||||
|
specified widget.
|
||||||
|
- If `return_all` is True, returns a formatted string containing all
|
||||||
|
input values for the node.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If no matching node is found for the given `id`, `node_title`,
|
||||||
|
or `any_input`.
|
||||||
|
NameError: If the specified widget does not exist in the identified node.
|
||||||
|
"""
|
||||||
workflow = extra_pnginfo["workflow"]
|
workflow = extra_pnginfo["workflow"]
|
||||||
#print(json.dumps(workflow, indent=4))
|
|
||||||
results = []
|
results = []
|
||||||
node_id = None # Initialize node_id to handle cases where no match is found
|
target_full_node_id = None # string like "5", "5:1", "5:9:6"
|
||||||
link_id = None
|
active_link_id = None
|
||||||
|
|
||||||
|
# Normalize incoming ids which may be lists/tuples (e.g., ["7:9:14", 0])
|
||||||
|
def normalize_any_id(value):
|
||||||
|
# If list/tuple, take the first element which should be the id/path
|
||||||
|
if isinstance(value, (list, tuple)) and value:
|
||||||
|
value = value[0]
|
||||||
|
# Convert ints to str
|
||||||
|
if isinstance(value, int):
|
||||||
|
return str(value)
|
||||||
|
# Pass through strings; None -> empty
|
||||||
|
return value if isinstance(value, str) else ""
|
||||||
|
|
||||||
|
id_str = normalize_any_id(id)
|
||||||
|
unique_id_str = normalize_any_id(unique_id)
|
||||||
|
|
||||||
|
# Map of (scope_key, link_id) -> full_node_id
|
||||||
|
# scope_key: '' for top-level, or the subgraph instance path for nested nodes (e.g., '5', '5:9')
|
||||||
link_to_node_map = {}
|
link_to_node_map = {}
|
||||||
|
|
||||||
for node in workflow["nodes"]:
|
# Build a map of subgraph id -> definition for quick lookup
|
||||||
if node_title:
|
defs = workflow.get("definitions", {}) or {}
|
||||||
if "title" in node:
|
subgraph_defs = {sg.get("id"): sg for sg in (defs.get("subgraphs", []) or []) if sg.get("id")}
|
||||||
if node["title"] == node_title:
|
|
||||||
node_id = node["id"]
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
print("Node title not found.")
|
|
||||||
elif id != 0:
|
|
||||||
if node["id"] == id:
|
|
||||||
node_id = id
|
|
||||||
break
|
|
||||||
elif any_input is not None:
|
|
||||||
if node["type"] == "WidgetToString" and node["id"] == int(unique_id) and not link_id:
|
|
||||||
for node_input in node["inputs"]:
|
|
||||||
if node_input["name"] == "any_input":
|
|
||||||
link_id = node_input["link"]
|
|
||||||
|
|
||||||
# Construct a map of links to node IDs for future reference
|
# Helper: register output links -> node map (scoped)
|
||||||
node_outputs = node.get("outputs", None)
|
def register_links(scope_key, node_obj, full_node_id):
|
||||||
if not node_outputs:
|
outputs = node_obj.get("outputs") or []
|
||||||
|
for out in outputs:
|
||||||
|
links = out.get("links")
|
||||||
|
if not links:
|
||||||
continue
|
continue
|
||||||
for output in node_outputs:
|
if isinstance(links, list):
|
||||||
node_links = output.get("links", None)
|
for lid in links:
|
||||||
if not node_links:
|
if lid is None:
|
||||||
continue
|
continue
|
||||||
for link in node_links:
|
link_to_node_map[(scope_key, lid)] = full_node_id
|
||||||
link_to_node_map[link] = node["id"]
|
|
||||||
if link_id and link == link_id:
|
|
||||||
break
|
|
||||||
|
|
||||||
if link_id:
|
# Recursive emitter for a subgraph instance
|
||||||
node_id = link_to_node_map.get(link_id, None)
|
# instance_path: the full path to this subgraph instance (e.g., '5' or '5:9')
|
||||||
|
def emit_subgraph_instance(sub_def, instance_path):
|
||||||
|
for snode in (sub_def.get("nodes") or []):
|
||||||
|
child_id = str(snode.get("id"))
|
||||||
|
full_id = f"{instance_path}:{child_id}"
|
||||||
|
# Yield the node with the scope of this subgraph instance
|
||||||
|
yield full_id, instance_path, snode
|
||||||
|
# If this node itself is a subgraph instance, recurse
|
||||||
|
stype = snode.get("type")
|
||||||
|
nested_def = subgraph_defs.get(stype)
|
||||||
|
if nested_def is not None:
|
||||||
|
nested_instance_path = full_id # e.g., '5:9'
|
||||||
|
for inner in emit_subgraph_instance(nested_def, nested_instance_path):
|
||||||
|
yield inner
|
||||||
|
|
||||||
if node_id is None:
|
# Master iterator: yields all nodes with their full_node_id and scope
|
||||||
raise ValueError("No matching node found for the given title or id")
|
def iter_all_nodes():
|
||||||
|
# 1) Top-level nodes
|
||||||
|
for node in workflow.get("nodes", []):
|
||||||
|
full_node_id = str(node.get("id"))
|
||||||
|
scope_key = "" # top-level link id space
|
||||||
|
yield full_node_id, scope_key, node
|
||||||
|
|
||||||
|
# 2) If a top-level node is an instance of a subgraph, emit its internal nodes
|
||||||
|
ntype = node.get("type")
|
||||||
|
sg_def = subgraph_defs.get(ntype)
|
||||||
|
if sg_def is not None:
|
||||||
|
instance_path = full_node_id # e.g., '5'
|
||||||
|
for item in emit_subgraph_instance(sg_def, instance_path):
|
||||||
|
yield item
|
||||||
|
|
||||||
|
# Helpers for id/unique_id handling
|
||||||
|
def match_id_with_fullness(candidate_full_id, requested_id):
|
||||||
|
# Exact match if the request is fully qualified
|
||||||
|
if ":" in requested_id:
|
||||||
|
return candidate_full_id == requested_id
|
||||||
|
# Otherwise, allow exact top-level id or ending with ":child"
|
||||||
|
return candidate_full_id == requested_id or candidate_full_id.endswith(f":{requested_id}")
|
||||||
|
|
||||||
|
def parent_scope_of(full_id):
|
||||||
|
parts = full_id.split(":")
|
||||||
|
return ":".join(parts[:-1]) if len(parts) > 1 else ""
|
||||||
|
|
||||||
|
def resolve_scope_from_unique_id(u_str):
|
||||||
|
# Fully qualified: everything before the last segment is the scope
|
||||||
|
if ":" in u_str:
|
||||||
|
return parent_scope_of(u_str)
|
||||||
|
|
||||||
|
# Not qualified: try to infer from prompt keys by suffix
|
||||||
|
suffix = f":{u_str}"
|
||||||
|
matches = [k for k in prompt.keys() if isinstance(k, str) and k.endswith(suffix)]
|
||||||
|
matches = list(dict.fromkeys(matches)) # dedupe
|
||||||
|
if len(matches) == 1:
|
||||||
|
return parent_scope_of(matches[0])
|
||||||
|
elif len(matches) == 0:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
f"Ambiguous unique_id '{u_str}'. Multiple subgraph instances match. "
|
||||||
|
f"Use a fully qualified id like 'parentPath:{u_str}' (e.g., '5:9:{u_str}')."
|
||||||
|
)
|
||||||
|
|
||||||
|
# First: build a complete list of nodes and the scoped link map
|
||||||
|
all_nodes = []
|
||||||
|
for full_node_id, scope_key, node in iter_all_nodes():
|
||||||
|
all_nodes.append((full_node_id, scope_key, node))
|
||||||
|
register_links(scope_key, node, full_node_id)
|
||||||
|
|
||||||
|
# Try title or id first
|
||||||
|
if node_title:
|
||||||
|
for full_node_id, _, node in all_nodes:
|
||||||
|
if "title" in node and node.get("title") == node_title:
|
||||||
|
target_full_node_id = full_node_id
|
||||||
|
break
|
||||||
|
# If title matched, do not attempt any_input fallback
|
||||||
|
any_input = None
|
||||||
|
elif id_str not in ("", "0"):
|
||||||
|
matches = [fid for fid, _, _ in all_nodes if match_id_with_fullness(fid, id_str)]
|
||||||
|
if len(matches) > 1 and ":" not in id_str and any(m != id_str for m in matches):
|
||||||
|
raise ValueError(
|
||||||
|
f"Ambiguous id '{id_str}'. Multiple nodes match across (nested) subgraphs. "
|
||||||
|
f"Use a fully qualified id like '5:9:{id_str}'."
|
||||||
|
)
|
||||||
|
target_full_node_id = matches[0] if matches else None
|
||||||
|
|
||||||
|
# Resolve via any_input + unique_id if still not found
|
||||||
|
if target_full_node_id is None and any_input is not None and unique_id_str:
|
||||||
|
# If unique_id is fully qualified, select that exact node
|
||||||
|
wts_full_id = None
|
||||||
|
if ":" in unique_id_str:
|
||||||
|
for fid, _, node in all_nodes:
|
||||||
|
if fid == unique_id_str and node.get("type") == "WidgetToString":
|
||||||
|
wts_full_id = fid
|
||||||
|
break
|
||||||
|
if wts_full_id is None:
|
||||||
|
raise ValueError(f"No WidgetToString found for unique_id '{unique_id_str}'")
|
||||||
|
found_scope_key = parent_scope_of(wts_full_id)
|
||||||
|
else:
|
||||||
|
# Infer scope from prompt keys when unqualified
|
||||||
|
found_scope_key = resolve_scope_from_unique_id(unique_id_str)
|
||||||
|
candidates = []
|
||||||
|
if found_scope_key:
|
||||||
|
candidates.append(f"{found_scope_key}:{unique_id_str}")
|
||||||
|
else:
|
||||||
|
candidates.append(unique_id_str)
|
||||||
|
|
||||||
|
for fid, scope_key, node in all_nodes:
|
||||||
|
if node.get("type") == "WidgetToString" and fid in candidates:
|
||||||
|
wts_full_id = fid
|
||||||
|
if not found_scope_key:
|
||||||
|
found_scope_key = parent_scope_of(fid)
|
||||||
|
break
|
||||||
|
|
||||||
|
if wts_full_id is None:
|
||||||
|
raise ValueError(f"No WidgetToString found for unique_id '{unique_id_str}'")
|
||||||
|
|
||||||
|
# With the WidgetToString located, read its any_input link id
|
||||||
|
wts_node = next(node for fid, _, node in all_nodes if fid == wts_full_id)
|
||||||
|
for node_input in (wts_node.get("inputs") or []):
|
||||||
|
if node_input.get("name") == "any_input":
|
||||||
|
active_link_id = node_input.get("link")
|
||||||
|
break
|
||||||
|
|
||||||
|
if active_link_id is None:
|
||||||
|
raise ValueError(f"WidgetToString '{wts_full_id}' has no 'any_input' link")
|
||||||
|
|
||||||
|
# Resolve the producer of that link within the correct scope
|
||||||
|
target_full_node_id = link_to_node_map.get((found_scope_key or "", active_link_id))
|
||||||
|
if target_full_node_id is None:
|
||||||
|
raise ValueError(
|
||||||
|
f"Could not resolve link {active_link_id} in scope '{found_scope_key}'. "
|
||||||
|
f"The subgraph clone’s links may not have been discovered."
|
||||||
|
)
|
||||||
|
|
||||||
|
if target_full_node_id is None:
|
||||||
|
raise ValueError("No matching node found for the given title, id, or any_input")
|
||||||
|
|
||||||
|
values = prompt.get(str(target_full_node_id))
|
||||||
|
if not values:
|
||||||
|
raise ValueError(f"No prompt entry found for node id: {target_full_node_id}")
|
||||||
|
|
||||||
values = prompt[str(node_id)]
|
|
||||||
if "inputs" in values:
|
if "inputs" in values:
|
||||||
if return_all:
|
if return_all:
|
||||||
# Format items based on type
|
|
||||||
formatted_items = []
|
formatted_items = []
|
||||||
for k, v in values["inputs"].items():
|
for k, v in values["inputs"].items():
|
||||||
if isinstance(v, float):
|
if isinstance(v, float):
|
||||||
@ -906,7 +1084,7 @@ The 'any_input' is required for making sure the node you want the value from exi
|
|||||||
v = str(v)
|
v = str(v)
|
||||||
return (v, )
|
return (v, )
|
||||||
else:
|
else:
|
||||||
raise NameError(f"Widget not found: {node_id}.{widget_name}")
|
raise NameError(f"Widget not found: {target_full_node_id}.{widget_name}")
|
||||||
return (', '.join(results).strip(', '), )
|
return (', '.join(results).strip(', '), )
|
||||||
|
|
||||||
class DummyOut:
|
class DummyOut:
|
||||||
@ -915,7 +1093,7 @@ class DummyOut:
|
|||||||
def INPUT_TYPES(cls):
|
def INPUT_TYPES(cls):
|
||||||
return {
|
return {
|
||||||
"required": {
|
"required": {
|
||||||
"any_input": (IO.ANY, ),
|
"any_input": (IO.ANY, ),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -973,11 +1151,11 @@ class CustomSigmas:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
return {"required":
|
return {"required":
|
||||||
{
|
{
|
||||||
"sigmas_string" :("STRING", {"default": "14.615, 6.475, 3.861, 2.697, 1.886, 1.396, 0.963, 0.652, 0.399, 0.152, 0.029","multiline": True}),
|
"sigmas_string" :("STRING", {"default": "14.615, 6.475, 3.861, 2.697, 1.886, 1.396, 0.963, 0.652, 0.399, 0.152, 0.029","multiline": True}),
|
||||||
"interpolate_to_steps": ("INT", {"default": 10,"min": 0, "max": 255, "step": 1}),
|
"interpolate_to_steps": ("INT", {"default": 10,"min": 0, "max": 255, "step": 1}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RETURN_TYPES = ("SIGMAS",)
|
RETURN_TYPES = ("SIGMAS",)
|
||||||
RETURN_NAMES = ("SIGMAS",)
|
RETURN_NAMES = ("SIGMAS",)
|
||||||
CATEGORY = "KJNodes/noise"
|
CATEGORY = "KJNodes/noise"
|
||||||
@ -1022,10 +1200,10 @@ class StringToFloatList:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
return {"required":
|
return {"required":
|
||||||
{
|
{
|
||||||
"string" :("STRING", {"default": "1, 2, 3", "multiline": True}),
|
"string" :("STRING", {"default": "1, 2, 3", "multiline": True}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RETURN_TYPES = ("FLOAT",)
|
RETURN_TYPES = ("FLOAT",)
|
||||||
RETURN_NAMES = ("FLOAT",)
|
RETURN_NAMES = ("FLOAT",)
|
||||||
CATEGORY = "KJNodes/misc"
|
CATEGORY = "KJNodes/misc"
|
||||||
@ -1045,13 +1223,13 @@ class InjectNoiseToLatent:
|
|||||||
"noise": ("LATENT",),
|
"noise": ("LATENT",),
|
||||||
"normalize": ("BOOLEAN", {"default": False}),
|
"normalize": ("BOOLEAN", {"default": False}),
|
||||||
"average": ("BOOLEAN", {"default": False}),
|
"average": ("BOOLEAN", {"default": False}),
|
||||||
},
|
},
|
||||||
"optional":{
|
"optional":{
|
||||||
"mask": ("MASK", ),
|
"mask": ("MASK", ),
|
||||||
"mix_randn_amount": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1000.0, "step": 0.001}),
|
"mix_randn_amount": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1000.0, "step": 0.001}),
|
||||||
"seed": ("INT", {"default": 123,"min": 0, "max": 0xffffffffffffffff, "step": 1}),
|
"seed": ("INT", {"default": 123,"min": 0, "max": 0xffffffffffffffff, "step": 1}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_TYPES = ("LATENT",)
|
RETURN_TYPES = ("LATENT",)
|
||||||
FUNCTION = "injectnoise"
|
FUNCTION = "injectnoise"
|
||||||
@ -1092,8 +1270,8 @@ class SoundReactive:
|
|||||||
"multiplier": ("FLOAT", {"default": 1.0, "min": 0.01, "max": 99999, "step": 0.01}),
|
"multiplier": ("FLOAT", {"default": 1.0, "min": 0.01, "max": 99999, "step": 0.01}),
|
||||||
"smoothing_factor": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
"smoothing_factor": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}),
|
||||||
"normalize": ("BOOLEAN", {"default": False}),
|
"normalize": ("BOOLEAN", {"default": False}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_TYPES = ("FLOAT","INT",)
|
RETURN_TYPES = ("FLOAT","INT",)
|
||||||
RETURN_NAMES =("sound_level", "sound_level_int",)
|
RETURN_NAMES =("sound_level", "sound_level_int",)
|
||||||
@ -1126,7 +1304,7 @@ class GenerateNoise:
|
|||||||
"multiplier": ("FLOAT", {"default": 1.0,"min": 0.0, "max": 4096, "step": 0.01}),
|
"multiplier": ("FLOAT", {"default": 1.0,"min": 0.0, "max": 4096, "step": 0.01}),
|
||||||
"constant_batch_noise": ("BOOLEAN", {"default": False}),
|
"constant_batch_noise": ("BOOLEAN", {"default": False}),
|
||||||
"normalize": ("BOOLEAN", {"default": False}),
|
"normalize": ("BOOLEAN", {"default": False}),
|
||||||
},
|
},
|
||||||
"optional": {
|
"optional": {
|
||||||
"model": ("MODEL", ),
|
"model": ("MODEL", ),
|
||||||
"sigmas": ("SIGMAS", ),
|
"sigmas": ("SIGMAS", ),
|
||||||
@ -1171,14 +1349,14 @@ def camera_embeddings(elevation, azimuth):
|
|||||||
azimuth = torch.as_tensor([azimuth])
|
azimuth = torch.as_tensor([azimuth])
|
||||||
embeddings = torch.stack(
|
embeddings = torch.stack(
|
||||||
[
|
[
|
||||||
torch.deg2rad(
|
torch.deg2rad(
|
||||||
(90 - elevation) - (90)
|
(90 - elevation) - (90)
|
||||||
), # Zero123 polar is 90-elevation
|
), # Zero123 polar is 90-elevation
|
||||||
torch.sin(torch.deg2rad(azimuth)),
|
torch.sin(torch.deg2rad(azimuth)),
|
||||||
torch.cos(torch.deg2rad(azimuth)),
|
torch.cos(torch.deg2rad(azimuth)),
|
||||||
torch.deg2rad(
|
torch.deg2rad(
|
||||||
90 - torch.full_like(elevation, 0)
|
90 - torch.full_like(elevation, 0)
|
||||||
),
|
),
|
||||||
], dim=-1).unsqueeze(1)
|
], dim=-1).unsqueeze(1)
|
||||||
|
|
||||||
return embeddings
|
return embeddings
|
||||||
@ -1204,7 +1382,7 @@ class StableZero123_BatchSchedule:
|
|||||||
"interpolation": (["linear", "ease_in", "ease_out", "ease_in_out"],),
|
"interpolation": (["linear", "ease_in", "ease_out", "ease_in_out"],),
|
||||||
"azimuth_points_string": ("STRING", {"default": "0:(0.0),\n7:(1.0),\n15:(0.0)\n", "multiline": True}),
|
"azimuth_points_string": ("STRING", {"default": "0:(0.0),\n7:(1.0),\n15:(0.0)\n", "multiline": True}),
|
||||||
"elevation_points_string": ("STRING", {"default": "0:(0.0),\n7:(0.0),\n15:(0.0)\n", "multiline": True}),
|
"elevation_points_string": ("STRING", {"default": "0:(0.0),\n7:(0.0),\n15:(0.0)\n", "multiline": True}),
|
||||||
}}
|
}}
|
||||||
|
|
||||||
RETURN_TYPES = ("CONDITIONING", "CONDITIONING", "LATENT")
|
RETURN_TYPES = ("CONDITIONING", "CONDITIONING", "LATENT")
|
||||||
RETURN_NAMES = ("positive", "negative", "latent")
|
RETURN_NAMES = ("positive", "negative", "latent")
|
||||||
@ -1337,7 +1515,7 @@ class SV3D_BatchSchedule:
|
|||||||
"interpolation": (["linear", "ease_in", "ease_out", "ease_in_out"],),
|
"interpolation": (["linear", "ease_in", "ease_out", "ease_in_out"],),
|
||||||
"azimuth_points_string": ("STRING", {"default": "0:(0.0),\n9:(180.0),\n20:(360.0)\n", "multiline": True}),
|
"azimuth_points_string": ("STRING", {"default": "0:(0.0),\n9:(180.0),\n20:(360.0)\n", "multiline": True}),
|
||||||
"elevation_points_string": ("STRING", {"default": "0:(0.0),\n9:(0.0),\n20:(0.0)\n", "multiline": True}),
|
"elevation_points_string": ("STRING", {"default": "0:(0.0),\n9:(0.0),\n20:(0.0)\n", "multiline": True}),
|
||||||
}}
|
}}
|
||||||
|
|
||||||
RETURN_TYPES = ("CONDITIONING", "CONDITIONING", "LATENT")
|
RETURN_TYPES = ("CONDITIONING", "CONDITIONING", "LATENT")
|
||||||
RETURN_NAMES = ("positive", "negative", "latent")
|
RETURN_NAMES = ("positive", "negative", "latent")
|
||||||
@ -1518,11 +1696,11 @@ https://huggingface.co/roborovski/superprompt-v1
|
|||||||
|
|
||||||
checkpoint_path = os.path.join(script_directory, "models","superprompt-v1")
|
checkpoint_path = os.path.join(script_directory, "models","superprompt-v1")
|
||||||
if not os.path.exists(checkpoint_path):
|
if not os.path.exists(checkpoint_path):
|
||||||
print(f"Downloading model to: {checkpoint_path}")
|
print(f"Downloading model to: {checkpoint_path}")
|
||||||
from huggingface_hub import snapshot_download
|
from huggingface_hub import snapshot_download
|
||||||
snapshot_download(repo_id="roborovski/superprompt-v1",
|
snapshot_download(repo_id="roborovski/superprompt-v1",
|
||||||
local_dir=checkpoint_path,
|
local_dir=checkpoint_path,
|
||||||
local_dir_use_symlinks=False)
|
local_dir_use_symlinks=False)
|
||||||
tokenizer = T5Tokenizer.from_pretrained("google/flan-t5-small", legacy=False)
|
tokenizer = T5Tokenizer.from_pretrained("google/flan-t5-small", legacy=False)
|
||||||
|
|
||||||
model = T5ForConditionalGeneration.from_pretrained(checkpoint_path, device_map=device)
|
model = T5ForConditionalGeneration.from_pretrained(checkpoint_path, device_map=device)
|
||||||
@ -1550,11 +1728,11 @@ class CameraPoseVisualizer:
|
|||||||
"use_exact_fx": ("BOOLEAN", {"default": False}),
|
"use_exact_fx": ("BOOLEAN", {"default": False}),
|
||||||
"relative_c2w": ("BOOLEAN", {"default": True}),
|
"relative_c2w": ("BOOLEAN", {"default": True}),
|
||||||
"use_viewer": ("BOOLEAN", {"default": False}),
|
"use_viewer": ("BOOLEAN", {"default": False}),
|
||||||
},
|
},
|
||||||
"optional": {
|
"optional": {
|
||||||
"cameractrl_poses": ("CAMERACTRL_POSES", {"default": None}),
|
"cameractrl_poses": ("CAMERACTRL_POSES", {"default": None}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_TYPES = ("IMAGE",)
|
RETURN_TYPES = ("IMAGE",)
|
||||||
FUNCTION = "plot"
|
FUNCTION = "plot"
|
||||||
@ -1616,7 +1794,7 @@ or a .txt file with RealEstate camera intrinsics and coordinates, in a 3D plot.
|
|||||||
|
|
||||||
for frame_idx, c2w in enumerate(c2ws):
|
for frame_idx, c2w in enumerate(c2ws):
|
||||||
self.extrinsic2pyramid(c2w, frame_idx / total_frames, hw_ratio=1/1, base_xval=base_xval,
|
self.extrinsic2pyramid(c2w, frame_idx / total_frames, hw_ratio=1/1, base_xval=base_xval,
|
||||||
zval=(fxs[frame_idx] if use_exact_fx else zval))
|
zval=(fxs[frame_idx] if use_exact_fx else zval))
|
||||||
|
|
||||||
# Create the colorbar
|
# Create the colorbar
|
||||||
cmap = mpl.cm.rainbow
|
cmap = mpl.cm.rainbow
|
||||||
@ -1652,16 +1830,16 @@ or a .txt file with RealEstate camera intrinsics and coordinates, in a 3D plot.
|
|||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
|
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
|
||||||
vertex_std = np.array([[0, 0, 0, 1],
|
vertex_std = np.array([[0, 0, 0, 1],
|
||||||
[base_xval, -base_xval * hw_ratio, zval, 1],
|
[base_xval, -base_xval * hw_ratio, zval, 1],
|
||||||
[base_xval, base_xval * hw_ratio, zval, 1],
|
[base_xval, base_xval * hw_ratio, zval, 1],
|
||||||
[-base_xval, base_xval * hw_ratio, zval, 1],
|
[-base_xval, base_xval * hw_ratio, zval, 1],
|
||||||
[-base_xval, -base_xval * hw_ratio, zval, 1]])
|
[-base_xval, -base_xval * hw_ratio, zval, 1]])
|
||||||
vertex_transformed = vertex_std @ extrinsic.T
|
vertex_transformed = vertex_std @ extrinsic.T
|
||||||
meshes = [[vertex_transformed[0, :-1], vertex_transformed[1][:-1], vertex_transformed[2, :-1]],
|
meshes = [[vertex_transformed[0, :-1], vertex_transformed[1][:-1], vertex_transformed[2, :-1]],
|
||||||
[vertex_transformed[0, :-1], vertex_transformed[2, :-1], vertex_transformed[3, :-1]],
|
[vertex_transformed[0, :-1], vertex_transformed[2, :-1], vertex_transformed[3, :-1]],
|
||||||
[vertex_transformed[0, :-1], vertex_transformed[3, :-1], vertex_transformed[4, :-1]],
|
[vertex_transformed[0, :-1], vertex_transformed[3, :-1], vertex_transformed[4, :-1]],
|
||||||
[vertex_transformed[0, :-1], vertex_transformed[4, :-1], vertex_transformed[1, :-1]],
|
[vertex_transformed[0, :-1], vertex_transformed[4, :-1], vertex_transformed[1, :-1]],
|
||||||
[vertex_transformed[1, :-1], vertex_transformed[2, :-1], vertex_transformed[3, :-1], vertex_transformed[4, :-1]]]
|
[vertex_transformed[1, :-1], vertex_transformed[2, :-1], vertex_transformed[3, :-1], vertex_transformed[4, :-1]]]
|
||||||
|
|
||||||
color = color_map if isinstance(color_map, str) else plt.cm.rainbow(color_map)
|
color = color_map if isinstance(color_map, str) else plt.cm.rainbow(color_map)
|
||||||
|
|
||||||
@ -1705,7 +1883,7 @@ class CheckpointPerturbWeights:
|
|||||||
"final_layer": ("FLOAT", {"default": 0.02, "min": 0.001, "max": 10.0, "step": 0.001}),
|
"final_layer": ("FLOAT", {"default": 0.02, "min": 0.001, "max": 10.0, "step": 0.001}),
|
||||||
"rest_of_the_blocks": ("FLOAT", {"default": 0.02, "min": 0.001, "max": 10.0, "step": 0.001}),
|
"rest_of_the_blocks": ("FLOAT", {"default": 0.02, "min": 0.001, "max": 10.0, "step": 0.001}),
|
||||||
"seed": ("INT", {"default": 123,"min": 0, "max": 0xffffffffffffffff, "step": 1}),
|
"seed": ("INT", {"default": 123,"min": 0, "max": 0xffffffffffffffff, "step": 1}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RETURN_TYPES = ("MODEL",)
|
RETURN_TYPES = ("MODEL",)
|
||||||
FUNCTION = "mod"
|
FUNCTION = "mod"
|
||||||
@ -1745,11 +1923,11 @@ class DifferentialDiffusionAdvanced():
|
|||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
return {"required": {
|
return {"required": {
|
||||||
"model": ("MODEL", ),
|
"model": ("MODEL", ),
|
||||||
"samples": ("LATENT",),
|
"samples": ("LATENT",),
|
||||||
"mask": ("MASK",),
|
"mask": ("MASK",),
|
||||||
"multiplier": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.001}),
|
"multiplier": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.001}),
|
||||||
}}
|
}}
|
||||||
RETURN_TYPES = ("MODEL", "LATENT")
|
RETURN_TYPES = ("MODEL", "LATENT")
|
||||||
FUNCTION = "apply"
|
FUNCTION = "apply"
|
||||||
CATEGORY = "_for_testing"
|
CATEGORY = "_for_testing"
|
||||||
@ -1861,16 +2039,16 @@ class DiTBlockLoraLoader:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
return {"required": {
|
return {"required": {
|
||||||
"model": ("MODEL", {"tooltip": "The diffusion model the LoRA will be applied to."}),
|
"model": ("MODEL", {"tooltip": "The diffusion model the LoRA will be applied to."}),
|
||||||
"strength_model": ("FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01, "tooltip": "How strongly to modify the diffusion model. This value can be negative."}),
|
"strength_model": ("FLOAT", {"default": 1.0, "min": -100.0, "max": 100.0, "step": 0.01, "tooltip": "How strongly to modify the diffusion model. This value can be negative."}),
|
||||||
|
|
||||||
},
|
},
|
||||||
"optional": {
|
"optional": {
|
||||||
"lora_name": (folder_paths.get_filename_list("loras"), {"tooltip": "The name of the LoRA."}),
|
"lora_name": (folder_paths.get_filename_list("loras"), {"tooltip": "The name of the LoRA."}),
|
||||||
"opt_lora_path": ("STRING", {"forceInput": True, "tooltip": "Absolute path of the LoRA."}),
|
"opt_lora_path": ("STRING", {"forceInput": True, "tooltip": "Absolute path of the LoRA."}),
|
||||||
"blocks": ("SELECTEDDITBLOCKS",),
|
"blocks": ("SELECTEDDITBLOCKS",),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_TYPES = ("MODEL", "STRING", )
|
RETURN_TYPES = ("MODEL", "STRING", )
|
||||||
RETURN_NAMES = ("model", "rank", )
|
RETURN_NAMES = ("model", "rank", )
|
||||||
@ -2107,12 +2285,12 @@ class AudioConcatenate:
|
|||||||
"audio1": ("AUDIO",),
|
"audio1": ("AUDIO",),
|
||||||
"audio2": ("AUDIO",),
|
"audio2": ("AUDIO",),
|
||||||
"direction": (
|
"direction": (
|
||||||
[ 'right',
|
[ 'right',
|
||||||
'left',
|
'left',
|
||||||
],
|
],
|
||||||
{
|
{
|
||||||
"default": 'right'
|
"default": 'right'
|
||||||
}),
|
}),
|
||||||
}}
|
}}
|
||||||
|
|
||||||
RETURN_TYPES = ("AUDIO",)
|
RETURN_TYPES = ("AUDIO",)
|
||||||
@ -2293,8 +2471,8 @@ class VAELoaderKJ:
|
|||||||
"required": { "vae_name": (s.vae_list(), ),
|
"required": { "vae_name": (s.vae_list(), ),
|
||||||
"device": (["main_device", "cpu"],),
|
"device": (["main_device", "cpu"],),
|
||||||
"weight_dtype": (["bf16", "fp16", "fp32" ],),
|
"weight_dtype": (["bf16", "fp16", "fp32" ],),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_TYPES = ("VAE",)
|
RETURN_TYPES = ("VAE",)
|
||||||
FUNCTION = "load_vae"
|
FUNCTION = "load_vae"
|
||||||
@ -2355,14 +2533,14 @@ class ScheduledCFGGuidance:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
return {"required": {
|
return {"required": {
|
||||||
"model": ("MODEL",),
|
"model": ("MODEL",),
|
||||||
"positive": ("CONDITIONING", ),
|
"positive": ("CONDITIONING", ),
|
||||||
"negative": ("CONDITIONING", ),
|
"negative": ("CONDITIONING", ),
|
||||||
"cfg": ("FLOAT", {"default": 6.0, "min": 0.0, "max": 100.0, "step": 0.01}),
|
"cfg": ("FLOAT", {"default": 6.0, "min": 0.0, "max": 100.0, "step": 0.01}),
|
||||||
"start_percent": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step":0.01}),
|
"start_percent": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step":0.01}),
|
||||||
"end_percent": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step":0.01}),
|
"end_percent": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step":0.01}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
RETURN_TYPES = ("GUIDER",)
|
RETURN_TYPES = ("GUIDER",)
|
||||||
FUNCTION = "get_guider"
|
FUNCTION = "get_guider"
|
||||||
CATEGORY = "KJNodes/experimental"
|
CATEGORY = "KJNodes/experimental"
|
||||||
@ -2408,7 +2586,7 @@ class ApplyRifleXRoPE_WanVideo:
|
|||||||
[d - 4 * (d // 6), 2 * (d // 6), 2 * (d // 6)],
|
[d - 4 * (d // 6), 2 * (d // 6), 2 * (d // 6)],
|
||||||
num_frames,
|
num_frames,
|
||||||
k
|
k
|
||||||
)
|
)
|
||||||
|
|
||||||
model_clone.add_object_patch(f"diffusion_model.rope_embedder", rope_embedder)
|
model_clone.add_object_patch(f"diffusion_model.rope_embedder", rope_embedder)
|
||||||
|
|
||||||
@ -2443,7 +2621,7 @@ class ApplyRifleXRoPE_HunuyanVideo:
|
|||||||
model_class.params.axes_dim,
|
model_class.params.axes_dim,
|
||||||
num_frames,
|
num_frames,
|
||||||
k
|
k
|
||||||
)
|
)
|
||||||
|
|
||||||
model_clone.add_object_patch(f"diffusion_model.pe_embedder", pe_embedder)
|
model_clone.add_object_patch(f"diffusion_model.pe_embedder", pe_embedder)
|
||||||
|
|
||||||
@ -2497,16 +2675,16 @@ class TimerNodeKJ:
|
|||||||
@classmethod
|
@classmethod
|
||||||
|
|
||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
return {
|
return {
|
||||||
"required": {
|
"required": {
|
||||||
"any_input": (IO.ANY, ),
|
"any_input": (IO.ANY, ),
|
||||||
"mode": (["start", "stop"],),
|
"mode": (["start", "stop"],),
|
||||||
"name": ("STRING", {"default": "Timer"}),
|
"name": ("STRING", {"default": "Timer"}),
|
||||||
},
|
},
|
||||||
"optional": {
|
"optional": {
|
||||||
"timer": ("TIMER",),
|
"timer": ("TIMER",),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_TYPES = (IO.ANY, "TIMER", "INT", )
|
RETURN_TYPES = (IO.ANY, "TIMER", "INT", )
|
||||||
RETURN_NAMES = ("any_output", "timer", "time")
|
RETURN_NAMES = ("any_output", "timer", "time")
|
||||||
@ -2519,9 +2697,9 @@ class TimerNodeKJ:
|
|||||||
timer = Timer(name=name)
|
timer = Timer(name=name)
|
||||||
timer.start_time = time.time()
|
timer.start_time = time.time()
|
||||||
return {"ui": {
|
return {"ui": {
|
||||||
"text": [f"{timer.start_time}"]},
|
"text": [f"{timer.start_time}"]},
|
||||||
"result": (any_input, timer, 0)
|
"result": (any_input, timer, 0)
|
||||||
}
|
}
|
||||||
elif mode == "stop" and timer is not None:
|
elif mode == "stop" and timer is not None:
|
||||||
end_time = time.time()
|
end_time = time.time()
|
||||||
timer.elapsed = int((end_time - timer.start_time) * 1000)
|
timer.elapsed = int((end_time - timer.start_time) * 1000)
|
||||||
@ -2532,21 +2710,21 @@ class HunyuanVideoEncodeKeyframesToCond:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
return {"required": {
|
return {"required": {
|
||||||
"model": ("MODEL",),
|
"model": ("MODEL",),
|
||||||
"positive": ("CONDITIONING", ),
|
"positive": ("CONDITIONING", ),
|
||||||
"vae": ("VAE", ),
|
"vae": ("VAE", ),
|
||||||
"start_frame": ("IMAGE", ),
|
"start_frame": ("IMAGE", ),
|
||||||
"end_frame": ("IMAGE", ),
|
"end_frame": ("IMAGE", ),
|
||||||
"num_frames": ("INT", {"default": 33, "min": 2, "max": 4096, "step": 1}),
|
"num_frames": ("INT", {"default": 33, "min": 2, "max": 4096, "step": 1}),
|
||||||
"tile_size": ("INT", {"default": 512, "min": 64, "max": 4096, "step": 64}),
|
"tile_size": ("INT", {"default": 512, "min": 64, "max": 4096, "step": 64}),
|
||||||
"overlap": ("INT", {"default": 64, "min": 0, "max": 4096, "step": 32}),
|
"overlap": ("INT", {"default": 64, "min": 0, "max": 4096, "step": 32}),
|
||||||
"temporal_size": ("INT", {"default": 64, "min": 8, "max": 4096, "step": 4, "tooltip": "Only used for video VAEs: Amount of frames to encode at a time."}),
|
"temporal_size": ("INT", {"default": 64, "min": 8, "max": 4096, "step": 4, "tooltip": "Only used for video VAEs: Amount of frames to encode at a time."}),
|
||||||
"temporal_overlap": ("INT", {"default": 8, "min": 4, "max": 4096, "step": 4, "tooltip": "Only used for video VAEs: Amount of frames to overlap."}),
|
"temporal_overlap": ("INT", {"default": 8, "min": 4, "max": 4096, "step": 4, "tooltip": "Only used for video VAEs: Amount of frames to overlap."}),
|
||||||
},
|
},
|
||||||
"optional": {
|
"optional": {
|
||||||
"negative": ("CONDITIONING", ),
|
"negative": ("CONDITIONING", ),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_TYPES = ("MODEL", "CONDITIONING","CONDITIONING","LATENT")
|
RETURN_TYPES = ("MODEL", "CONDITIONING","CONDITIONING","LATENT")
|
||||||
RETURN_NAMES = ("model", "positive", "negative", "latent")
|
RETURN_NAMES = ("model", "positive", "negative", "latent")
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user