feat: add AODH Image Saver (Metadata), Lora Selector, Checkpoint Selector, and various node improvements
This commit is contained in:
9
nodes/lora_selector/__init__.py
Normal file
9
nodes/lora_selector/__init__.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from .lora_selector import LoraSelector
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"LoraSelector": LoraSelector
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"LoraSelector": "Lora Selector"
|
||||
}
|
||||
121
nodes/lora_selector/lora_selector.py
Normal file
121
nodes/lora_selector/lora_selector.py
Normal file
@@ -0,0 +1,121 @@
|
||||
import os
|
||||
import random
|
||||
import folder_paths
|
||||
|
||||
class LoraSelector:
|
||||
def __init__(self):
|
||||
self.current_index = 0
|
||||
self.current_count = 0
|
||||
self.last_folder = None
|
||||
self.last_selection = None
|
||||
self.last_manual_index = 0
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
# Find 'Illustrious' folders in all lora paths
|
||||
lora_paths = folder_paths.get_folder_paths("loras")
|
||||
illustrious_folders = []
|
||||
|
||||
for path in lora_paths:
|
||||
illustrious_path = os.path.join(path, "Illustrious")
|
||||
if os.path.exists(illustrious_path) and os.path.isdir(illustrious_path):
|
||||
# List subdirectories
|
||||
try:
|
||||
subdirs = [d for d in os.listdir(illustrious_path) if os.path.isdir(os.path.join(illustrious_path, d))]
|
||||
illustrious_folders.extend(subdirs)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Remove duplicates and sort
|
||||
illustrious_folders = sorted(list(set(illustrious_folders)))
|
||||
|
||||
if not illustrious_folders:
|
||||
illustrious_folders = ["None"]
|
||||
|
||||
return {
|
||||
"required": {
|
||||
"folder": (illustrious_folders, ),
|
||||
"mode": (["Random", "Sequential", "Manual"], {"default": "Random"}),
|
||||
"repeat_count": ("INT", {"default": 1, "min": 1, "max": 100, "step": 1}),
|
||||
"manual_index": ("INT", {"default": 0, "min": 0, "max": 10000, "step": 1}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("STRING", "INT")
|
||||
RETURN_NAMES = ("lora_name", "total_loras")
|
||||
FUNCTION = "select_lora"
|
||||
CATEGORY = "AODH Pack"
|
||||
|
||||
def select_lora(self, folder, mode, repeat_count, manual_index):
|
||||
repeat_count = max(1, repeat_count)
|
||||
if folder == "None":
|
||||
return ("", 0)
|
||||
|
||||
# Find the full path for the selected folder
|
||||
lora_paths = folder_paths.get_folder_paths("loras")
|
||||
target_path = None
|
||||
|
||||
for path in lora_paths:
|
||||
check_path = os.path.join(path, "Illustrious", folder)
|
||||
if os.path.exists(check_path) and os.path.isdir(check_path):
|
||||
target_path = check_path
|
||||
break
|
||||
|
||||
if not target_path:
|
||||
return ("", 0)
|
||||
|
||||
# Find .safetensors files
|
||||
lora_files = [f for f in os.listdir(target_path) if f.endswith('.safetensors')]
|
||||
lora_files.sort() # Ensure consistent order
|
||||
|
||||
count = len(lora_files)
|
||||
if count == 0:
|
||||
return ("", 0)
|
||||
|
||||
selected_lora = ""
|
||||
|
||||
# Reset state if folder changes
|
||||
if self.last_folder != folder:
|
||||
self.current_index = 0
|
||||
self.current_count = 0
|
||||
self.last_selection = None
|
||||
self.last_folder = folder
|
||||
|
||||
# Reset state if manual_index changes (for Sequential mode)
|
||||
if self.last_manual_index != manual_index:
|
||||
self.current_index = 0
|
||||
self.current_count = 0
|
||||
self.last_manual_index = manual_index
|
||||
|
||||
if mode == "Random":
|
||||
if self.current_count >= repeat_count or self.last_selection is None:
|
||||
# Use a local Random instance to ensure randomness regardless of global seed
|
||||
rng = random.Random()
|
||||
self.last_selection = rng.choice(lora_files)
|
||||
self.current_count = 0
|
||||
|
||||
selected_lora = self.last_selection
|
||||
self.current_count += 1
|
||||
|
||||
elif mode == "Sequential":
|
||||
if self.current_count >= repeat_count:
|
||||
self.current_index += 1
|
||||
self.current_count = 0
|
||||
|
||||
selected_lora = lora_files[(self.current_index + manual_index) % count]
|
||||
self.current_count += 1
|
||||
|
||||
elif mode == "Manual":
|
||||
selected_lora = lora_files[manual_index % count]
|
||||
|
||||
# Construct the relative path for ComfyUI Lora loader
|
||||
# Use forward slashes for consistency
|
||||
full_lora_name = f"Illustrious/{folder}/{selected_lora}"
|
||||
|
||||
return (full_lora_name, count)
|
||||
|
||||
@classmethod
|
||||
def IS_CHANGED(s, folder, mode, repeat_count, manual_index):
|
||||
if mode == "Random" or mode == "Sequential":
|
||||
return float("nan")
|
||||
return f"{folder}_{manual_index}"
|
||||
Reference in New Issue
Block a user