mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-24 22:52:12 -03:00
feat: add LoraDemoNode and LoraRandomizerNode with documentation
- Import and register two new nodes: LoraDemoNode and LoraRandomizerNode - Update import exception handling for better readability with multi-line formatting - Add comprehensive documentation file `docs/custom-node-ui-output.md` for UI output usage in custom nodes - Ensure proper node registration in NODE_CLASS_MAPPINGS for ComfyUI integration - Maintain backward compatibility with existing node structure and import fallbacks
This commit is contained in:
95
py/nodes/lora_demo.py
Normal file
95
py/nodes/lora_demo.py
Normal file
@@ -0,0 +1,95 @@
|
||||
"""
|
||||
Lora Demo Node - Demonstrates LORAS custom widget type usage.
|
||||
|
||||
This node accepts LORAS widget input and outputs a summary string.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import random
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class LoraDemoNode:
|
||||
"""Demo node that uses LORAS custom widget type."""
|
||||
|
||||
NAME = "Lora Demo (LoraManager)"
|
||||
CATEGORY = "Lora Manager/demo"
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"loras": ("LORAS", {}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("STRING",)
|
||||
RETURN_NAMES = ("summary",)
|
||||
|
||||
FUNCTION = "process"
|
||||
OUTPUT_NODE = False
|
||||
|
||||
async def process(self, loras):
|
||||
"""
|
||||
Process LoRAs input and return summary + UI data for widget.
|
||||
|
||||
Args:
|
||||
loras: List of LoRA dictionaries with structure:
|
||||
[{'name': str, 'strength': float, 'clipStrength': float, 'active': bool, ...}]
|
||||
|
||||
Returns:
|
||||
Dictionary with 'result' (for workflow) and 'ui' (for frontend display)
|
||||
"""
|
||||
from ..services.service_registry import ServiceRegistry
|
||||
|
||||
# Get lora scanner to access available loras
|
||||
scanner = await ServiceRegistry.get_lora_scanner()
|
||||
|
||||
# Get available loras from cache
|
||||
available_loras = []
|
||||
try:
|
||||
cache_data = await scanner.get_cached_data(force_refresh=False)
|
||||
if cache_data and hasattr(cache_data, "raw_data"):
|
||||
available_loras = cache_data.raw_data
|
||||
except Exception as e:
|
||||
logger.warning(f"[LoraDemoNode] Failed to get lora cache: {e}")
|
||||
|
||||
# Randomly select 3-5 loras
|
||||
num_to_select = random.randint(3, 5)
|
||||
if len(available_loras) < num_to_select:
|
||||
num_to_select = len(available_loras)
|
||||
|
||||
selected_loras = (
|
||||
random.sample(available_loras, num_to_select) if num_to_select > 0 else []
|
||||
)
|
||||
|
||||
# Generate random loras data for widget
|
||||
widget_loras = []
|
||||
for lora in selected_loras:
|
||||
strength = round(random.uniform(0.1, 1.0), 2)
|
||||
widget_loras.append(
|
||||
{
|
||||
"name": lora.get("file_name", "Unknown"),
|
||||
"strength": strength,
|
||||
"clipStrength": strength,
|
||||
"active": True,
|
||||
"expanded": False,
|
||||
}
|
||||
)
|
||||
|
||||
# Create summary string
|
||||
active_names = [l["name"] for l in widget_loras]
|
||||
summary = f"Randomized {len(active_names)} LoRAs: {', '.join(active_names)}"
|
||||
|
||||
logger.info(f"[LoraDemoNode] {summary}")
|
||||
|
||||
# Return format: result for workflow + ui for frontend
|
||||
return {"result": (summary,), "ui": {"loras": widget_loras}}
|
||||
|
||||
|
||||
# Node class mappings for ComfyUI
|
||||
NODE_CLASS_MAPPINGS = {"LoraDemoNode": LoraDemoNode}
|
||||
|
||||
# Display name mappings
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {"LoraDemoNode": "LoRA Demo"}
|
||||
Reference in New Issue
Block a user