194 lines
8.1 KiB
Python
194 lines
8.1 KiB
Python
import folder_paths
|
|
import comfy.sd
|
|
import comfy.utils
|
|
import comfy.model_management
|
|
|
|
"""Prepack_Loras_and_MSSD3: load and apply up to 3 LoRA adapters to model, and apply SD3 model sampling."""
|
|
|
|
|
|
class PrepackLorasAndMSSD3:
|
|
def __init__(self):
|
|
self.loaded_lora = None
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(s):
|
|
lora_list = ["None"] + folder_paths.get_filename_list("loras")
|
|
return {
|
|
"required": {
|
|
"model": ("MODEL", {"tooltip": "The diffusion model to apply LoRA adapters and SD3 sampling to."}),
|
|
"lora_name_1": (lora_list, {
|
|
"tooltip": "Select the first LoRA file to apply (choose 'None' to skip)."
|
|
}),
|
|
"strength_model_1": ("FLOAT", {
|
|
"default": 1.0,
|
|
"min": -100.0,
|
|
"max": 100.0,
|
|
"step": 0.01,
|
|
"tooltip": "Strength for the diffusion model. Typical range [-2.0, 2.0]; 0 disables."
|
|
}),
|
|
},
|
|
"optional": {
|
|
"lora_name_2": (lora_list, {
|
|
"default": "None",
|
|
"tooltip": "Select the second LoRA file to apply (optional, choose 'None' to skip)."
|
|
}),
|
|
"strength_model_2": ("FLOAT", {
|
|
"default": 0.0,
|
|
"min": -100.0,
|
|
"max": 100.0,
|
|
"step": 0.01,
|
|
"tooltip": "Strength for the diffusion model. Typical range [-2.0, 2.0]; 0 disables."
|
|
}),
|
|
"lora_name_3": (lora_list, {
|
|
"default": "None",
|
|
"tooltip": "Select the third LoRA file to apply (optional, choose 'None' to skip)."
|
|
}),
|
|
"strength_model_3": ("FLOAT", {
|
|
"default": 0.0,
|
|
"min": -100.0,
|
|
"max": 100.0,
|
|
"step": 0.01,
|
|
"tooltip": "Strength for the diffusion model. Typical range [-2.0, 2.0]; 0 disables."
|
|
}),
|
|
"shift": ("FLOAT", {
|
|
"default": 3.0,
|
|
"min": 0.0,
|
|
"max": 100.0,
|
|
"step": 0.01,
|
|
"tooltip": "Shift parameter for SD3 model sampling."
|
|
}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = ("MODEL",)
|
|
RETURN_NAMES = ("model",)
|
|
OUTPUT_TOOLTIPS = (
|
|
"The diffusion model with up to 3 LoRAs applied and SD3 model sampling configured.",
|
|
)
|
|
FUNCTION = "load_loras_and_apply_mssd3"
|
|
|
|
CATEGORY = "💀Prepack"
|
|
DESCRIPTION = "Load and apply up to 3 LoRA adapters to the diffusion model and apply SD3 model sampling; integrated LoRA + ModelSamplingSD3 functionality."
|
|
|
|
def load_loras_and_apply_mssd3(self, model, lora_name_1, strength_model_1,
|
|
lora_name_2="None", strength_model_2=0.0,
|
|
lora_name_3="None", strength_model_3=0.0,
|
|
shift=3.0):
|
|
|
|
# First apply LoRAs (no CLIP processing)
|
|
loras_to_load = [(lora_name_1, float(strength_model_1))]
|
|
if lora_name_2 != "None":
|
|
loras_to_load.append((lora_name_2, float(strength_model_2)))
|
|
if lora_name_3 != "None":
|
|
loras_to_load.append((lora_name_3, float(strength_model_3)))
|
|
|
|
current_model = model
|
|
for lora_name, strength_model in loras_to_load:
|
|
# Skip when user selects "None" for a LoRA slot
|
|
if lora_name == "None":
|
|
continue
|
|
if strength_model == 0:
|
|
continue
|
|
|
|
try:
|
|
lora_path = folder_paths.get_full_path_or_raise("loras", lora_name)
|
|
lora = None
|
|
if self.loaded_lora is not None:
|
|
if self.loaded_lora[0] == lora_path:
|
|
lora = self.loaded_lora[1]
|
|
else:
|
|
self.loaded_lora = None
|
|
|
|
if lora is None:
|
|
lora = comfy.utils.load_torch_file(lora_path, safe_load=True)
|
|
self.loaded_lora = (lora_path, lora)
|
|
except Exception as e:
|
|
print(f"Warning: Failed to load LoRA file '{lora_name}': {str(e)}. Skipping this LoRA.")
|
|
continue
|
|
|
|
try:
|
|
# Apply LoRA only to model, not CLIP
|
|
model_lora, _ = comfy.sd.load_lora_for_models(
|
|
current_model, None, lora, strength_model, 0
|
|
)
|
|
current_model = model_lora
|
|
except Exception as e:
|
|
print(f"Warning: Failed to apply LoRA '{lora_name}': {str(e)}. Skipping this LoRA.")
|
|
continue
|
|
|
|
# Apply SD3 model sampling
|
|
current_model = self.apply_sd3_sampling(current_model, shift)
|
|
|
|
return (current_model,)
|
|
|
|
def apply_sd3_sampling(self, model, shift):
|
|
"""Apply SD3 model sampling configuration - safe detection of API availability."""
|
|
try:
|
|
# First check if SD3 sampling classes are available
|
|
sd3_sampling_class = None
|
|
|
|
# Try to find SD3 sampling class in various possible locations
|
|
try:
|
|
# Option 1: Direct import from ComfyUI's sampling module
|
|
import comfy.model_sampling
|
|
if hasattr(comfy.model_sampling, 'ModelSamplingSD3'):
|
|
sd3_sampling_class = comfy.model_sampling.ModelSamplingSD3
|
|
except (ImportError, AttributeError):
|
|
pass
|
|
|
|
# Option 2: Try alternative locations
|
|
if sd3_sampling_class is None:
|
|
try:
|
|
# Check if available in model_management or other modules
|
|
if hasattr(comfy.model_management, 'ModelSamplingSD3'):
|
|
sd3_sampling_class = comfy.model_management.ModelSamplingSD3
|
|
except AttributeError:
|
|
pass
|
|
|
|
# Option 3: Check in the model itself for existing sampling config
|
|
if sd3_sampling_class is None and hasattr(model.model, 'model_sampling'):
|
|
current_sampling = model.model.model_sampling
|
|
# If already has shift attribute, just modify it
|
|
if hasattr(current_sampling, 'shift'):
|
|
try:
|
|
m = model.clone()
|
|
m.model.model_sampling.shift = float(shift)
|
|
return m
|
|
except Exception:
|
|
pass
|
|
|
|
# If we found a proper SD3 sampling class, use it
|
|
if sd3_sampling_class is not None:
|
|
try:
|
|
m = model.clone()
|
|
# Create new SD3 sampling instance with shift parameter
|
|
sd3_sampling = sd3_sampling_class(shift=float(shift))
|
|
m.model.model_sampling = sd3_sampling
|
|
return m
|
|
except Exception as create_error:
|
|
print(f"Info: Could not create SD3 sampling instance: {create_error}")
|
|
|
|
# Fallback: No proper SD3 API found, but apply basic shift if possible
|
|
if hasattr(model.model, 'model_sampling'):
|
|
try:
|
|
m = model.clone()
|
|
# Try to set shift in any way possible
|
|
if not hasattr(m.model.model_sampling, 'shift'):
|
|
setattr(m.model.model_sampling, 'shift', float(shift))
|
|
else:
|
|
m.model.model_sampling.shift = float(shift)
|
|
return m
|
|
except Exception:
|
|
pass
|
|
|
|
# Ultimate fallback: return original model with info message
|
|
print(f"Info: SD3 sampling API not detected. Shift parameter ({shift}) ignored. Model returned unchanged.")
|
|
return model
|
|
|
|
except Exception as e:
|
|
# Fallback: return original model if any unexpected error occurs
|
|
print(f"Warning: Unexpected error in SD3 sampling configuration: {e}. Model returned unchanged.")
|
|
return model
|
|
|
|
|