mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-21 21:22:11 -03:00
Add name pattern filtering to LoRA Pool node allowing users to filter LoRAs by filename or model name using either plain text or regex patterns. Features: - Include patterns: only show LoRAs matching at least one pattern - Exclude patterns: exclude LoRAs matching any pattern - Regex toggle: switch between substring and regex matching - Case-insensitive matching for both modes - Invalid regex automatically falls back to substring matching - Filters apply to both file_name and model_name fields Backend: - Update LoraPoolLM._default_config() with namePatterns structure - Add name pattern filtering to _apply_pool_filters() and _apply_specific_filters() - Add API parameter parsing for name_pattern_include/exclude/use_regex - Update LoraPoolConfig type with namePatterns field Frontend: - Add NamePatternsSection.vue component with pattern input UI - Update useLoraPoolState to manage pattern state and API integration - Update LoraPoolSummaryView to display NamePatternsSection - Increase LORA_POOL_WIDGET_MIN_HEIGHT to accommodate new UI Tests: - Add 7 test cases covering text/regex include, exclude, combined filtering, model name fallback, and invalid regex handling Closes #839
89 lines
2.7 KiB
Python
89 lines
2.7 KiB
Python
"""
|
|
LoRA Pool Node - Defines filter configuration for LoRA selection.
|
|
|
|
This node provides a visual filter editor that generates a LORA_POOL_CONFIG
|
|
object for use by downstream nodes (like LoRA Randomizer).
|
|
"""
|
|
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class LoraPoolLM:
|
|
"""
|
|
A node that defines LoRA filter criteria through a Vue-based widget.
|
|
|
|
Outputs a LORA_POOL_CONFIG that can be consumed by:
|
|
- Frontend: LoRA Randomizer widget reads connected pool's widget value
|
|
- Backend: LoRA Randomizer receives config during workflow execution
|
|
"""
|
|
|
|
NAME = "Lora Pool (LoraManager)"
|
|
CATEGORY = "Lora Manager/randomizer"
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"pool_config": ("LORA_POOL_CONFIG", {}),
|
|
},
|
|
"hidden": {
|
|
# Hidden input to pass through unique node ID for frontend
|
|
"unique_id": "UNIQUE_ID",
|
|
},
|
|
}
|
|
|
|
RETURN_TYPES = ("POOL_CONFIG",)
|
|
RETURN_NAMES = ("POOL_CONFIG",)
|
|
|
|
FUNCTION = "process"
|
|
OUTPUT_NODE = False
|
|
|
|
def process(self, pool_config, unique_id=None):
|
|
"""
|
|
Pass through the pool configuration filters.
|
|
|
|
The config is generated entirely by the frontend widget.
|
|
This function validates and returns only the filters field.
|
|
|
|
Args:
|
|
pool_config: Dict containing filter criteria from widget
|
|
unique_id: Node's unique ID (hidden)
|
|
|
|
Returns:
|
|
Tuple containing the filters dict from pool_config
|
|
"""
|
|
# Validate required structure
|
|
if not isinstance(pool_config, dict):
|
|
logger.warning("Invalid pool_config type, using empty config")
|
|
pool_config = self._default_config()
|
|
|
|
# Ensure version field exists
|
|
if "version" not in pool_config:
|
|
pool_config["version"] = 1
|
|
|
|
# Extract filters field
|
|
filters = pool_config.get("filters", self._default_config()["filters"])
|
|
|
|
# Log for debugging
|
|
logger.debug(f"[LoraPoolLM] Processing filters: {filters}")
|
|
|
|
return (filters,)
|
|
|
|
@staticmethod
|
|
def _default_config():
|
|
"""Return default empty configuration."""
|
|
return {
|
|
"version": 1,
|
|
"filters": {
|
|
"baseModels": [],
|
|
"tags": {"include": [], "exclude": []},
|
|
"folders": {"include": [], "exclude": []},
|
|
"favoritesOnly": False,
|
|
"license": {"noCreditRequired": False, "allowSelling": False},
|
|
"namePatterns": {"include": [], "exclude": [], "useRegex": False},
|
|
},
|
|
"preview": {"matchCount": 0, "lastUpdated": 0},
|
|
}
|