Files
2025-06-04 15:02:25 -04:00

145 lines
6.4 KiB
Python

import os
import folder_paths # type: ignore
import inspect
class DynamicLoRALoader:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"index": ("INT", {"default": 0, "min": 0, "max": 99, "step": 1}),
"LoRAnames": ("STRING", {"multiline": True, "default": "LoRAname1.safetensors\nLoRAname2.safetensors\nLoRAname3.safetensors"}),
"model": ("MODEL",),
"strength_model": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}),
"strength_clip": ("FLOAT", {"default": 1.0, "min": -10.0, "max": 10.0, "step": 0.01}),
},
"optional": {
"clip": ("CLIP",),
}
}
RETURN_TYPES = ("MODEL", "CLIP")
FUNCTION = "load_lora_by_index"
CATEGORY = "loaders"
def load_lora_by_index(self, index, LoRAnames, model, strength_model, strength_clip, clip=None):
# Split the LoRAnames into lines and remove empty lines
LoRAname_lines = [line.strip() for line in LoRAnames.split('\n') if line.strip()]
# Validate index
if len(LoRAname_lines) == 0:
print("No LoRAname provided. Returning model without changes.")
return (model, clip)
if index == -1:
return (model, clip)
if index < 0 or index >= len(LoRAname_lines):
print(f"LoRAname index {index} out of range. Using default index 0.")
index = 0
# Get the selected LoRAname
selected_LoRAname = LoRAname_lines[index]
# print(f"[DEBUG] LoRAname_lines: {LoRAname_lines}")
# print(f"[DEBUG] index: {index} (type: {type(index)})")
# print(f"[DEBUG] selected_LoRAname: {selected_LoRAname} (type: {type(selected_LoRAname)})")
# Find the LoRA file in any of the lora directories
lora_path = None
lora_dirs = folder_paths.get_folder_paths("loras")
# print(f"[DEBUG] lora_dirs: {lora_dirs}")
for lora_dir in lora_dirs:
# print(f"[DEBUG] Trying lora_dir: {lora_dir}, selected_LoRAname: {selected_LoRAname}")
potential_path = os.path.join(lora_dir, selected_LoRAname)
print(f"[DEBUG] potential_path: {potential_path}")
if os.path.isfile(potential_path):
lora_path = potential_path
break
# If we couldn't find the file
if lora_path is None:
print(f"LoRA file '{selected_LoRAname}' not found in any LoRA directories. Returning model without changes.")
return (model, clip)
print(f"Loading LoRA {selected_LoRAname} from {lora_path}")
print(f"Model strength: {strength_model}, Clip strength: {strength_clip}")
# Try to load the LoRA using ComfyUI's built-in LoRA loading functions
try:
# First try to import from comfy_extras
import importlib
# Try to find and use the built-in LoraLoader
try:
# Different ComfyUI versions store nodes in different places
nodes_lora = None
for module_name in ["comfy_extras.nodes_lora", "comfy.extra_model_paths", "nodes"]:
try:
nodes_lora = importlib.import_module(module_name)
if hasattr(nodes_lora, "LoraLoader"):
break
except ImportError:
continue
if nodes_lora and hasattr(nodes_lora, "LoraLoader"):
lora_loader = nodes_lora.LoraLoader()
# Dynamically call with the correct number of arguments based on signature
import inspect
sig = inspect.signature(lora_loader.load_lora)
param_names = list(sig.parameters.keys())
param_count = len(param_names)
# print(f"[DEBUG] lora_loader.load_lora param_names: {param_names}")
# The correct argument order is: model, clip, lora_name (filename only), strength_model, strength_clip
args = [model, clip, selected_LoRAname, strength_model, strength_clip]
# print(f"[DEBUG] lora_loader.load_lora param_count: {param_count}")
# print(f"[DEBUG] args (before trim): {args}")
# Remove trailing arguments if not required
while len(args) > param_count:
args.pop()
print(f"[DEBUG] args (after trim): {args}")
return lora_loader.load_lora(*args)
else:
print("Could not find LoraLoader implementation, falling back to manual loading")
except Exception as e:
print(f"Error using ComfyUI's LoraLoader: {str(e)}")
# If that fails, try direct loading method
import comfy.utils
import comfy.sd
# Load the LoRA file
lora_sd = comfy.utils.load_torch_file(lora_path)
# Different versions of ComfyUI have different methods for applying LoRAs
if hasattr(comfy.sd, "load_lora_for_models"):
print(f"[DEBUG] Using comfy.sd.load_lora_for_models")
return comfy.sd.load_lora_for_models(model, clip, lora_sd, strength_model, strength_clip)
elif hasattr(comfy.sd, "apply_lora"):
print(f"[DEBUG] Using comfy.sd.apply_lora")
model_out = model
clip_out = clip
if model is not None:
model_out = comfy.sd.apply_lora(model, lora_sd, strength_model)
if clip is not None:
clip_out = comfy.sd.apply_lora(clip, lora_sd, strength_clip)
return (model_out, clip_out)
else:
print("Could not find appropriate method to apply LoRA")
except Exception as e:
print(f"Error loading or applying LoRA: {str(e)}")
# If all methods fail, return original model
return (model, clip)
# Add the node to ComfyUI
NODE_CLASS_MAPPINGS = {
"DynamicLoRALoader": DynamicLoRALoader
}
NODE_DISPLAY_NAME_MAPPINGS = {
"DynamicLoRALoader": "LoRA Loader (by Name Index)"
}