From d9adf51c555f379af97b0ed43f2858b62250fd16 Mon Sep 17 00:00:00 2001 From: shin132002 Date: Tue, 13 Jan 2026 21:43:53 +0900 Subject: [PATCH] Release v1.2.0 --- .gitignore | 32 +- CHANGELOG.md | 58 +- README.md | 1494 ++++++++++++----------- README_LBW.md | 382 ++++++ README_LBW_ja.md | 494 ++++++++ README_ja.md | 1788 +++++++++++++++------------- __init__.py | 17 +- filtered_random_lora_loader.py | 246 +++- filtered_random_lora_loader_lbw.py | 1292 ++++++++++++++++++++ images/lbw_final_single.webp | Bin 0 -> 247854 bytes pyproject.toml | 48 +- random_lora_loader.py | 251 +++- 12 files changed, 4468 insertions(+), 1634 deletions(-) create mode 100644 README_LBW.md create mode 100644 README_LBW_ja.md create mode 100644 filtered_random_lora_loader_lbw.py create mode 100644 images/lbw_final_single.webp diff --git a/.gitignore b/.gitignore index 8b8387a..3a6b15f 100644 --- a/.gitignore +++ b/.gitignore @@ -4,13 +4,41 @@ __pycache__/ *$py.class *.so .Python +*.egg-info/ +dist/ +build/ -# IDE +# IDEs .vscode/ .idea/ *.swp *.swo +*~ # OS .DS_Store -Thumbs.db \ No newline at end of file +Thumbs.db +desktop.ini + +# Personal folders +old/ +backup/ +test/ +tmp/ +temp/ +archive/ +_old/ +_backup/ +_test/ + +# Development files +DEVELOPMENT_SUMMARY.md +note_article.md +release_notes_*.md +*_backup.md +*_fixed.toml +__init___no_advanced.py + +# User data +*.log +*.cache diff --git a/CHANGELOG.md b/CHANGELOG.md index d76222b..c49d23c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,62 @@ All notable changes to this project will be documented in this file. +## [1.2.0] - 2026-01-13 + +### Added + +#### New Node: Filtered Random LoRA Loader (LBW) +- **LoRA Block Weight (LBW) support** for precise effect control +- **Automatic SD1.5/SDXL detection** - no manual model type selection needed +- **4 preset modes**: Style Focused, Character Focused, Structure/Composition Only, Balanced/Soft +- **Preset: Random mode** - randomly selects one of the 4 presets +- **Direct Input mode** - custom weight specification with auto-adjustment +- **Automatic weight adjustment** - handles mismatched element counts + - Too few elements: pads with 1.0 at the end + - Too many elements: truncates from the end +- U-Net block structure support: + - SDXL: 20 elements (BASE + IN:9 + MID:1 + OUT:9) + - SD1.5: 17 elements (BASE + IN:6 + MID:1 + OUT:9) +- LBW syntax output in `positive_text` for Wildcard Encode compatibility +- Includes all features from Filtered Random LoRA Loader + +#### Video Preview Support (All Nodes) +- Video file preview support (.mp4, .webm, .avi, .mov) +- Extracts first frame as static image +- Requires optional `opencv-python` dependency +- Graceful fallback to black screen with warning if opencv-python not installed +- Priority order: static images → animated images → video files + +### Changed + +#### Model Compatibility +- ⚠️ **Explicitly SD1.5/SDXL only** - other architectures (Flux, SD3, etc.) not supported +- LBW feature specifically designed for SD1.5/SDXL U-Net structure + +#### Dependencies +- Added optional dependency: `opencv-python` (for video preview only) +- Core functionality works without opencv-python + +### Technical Details + +#### LBW Implementation +- Direct tensor weight manipulation for precise block control +- Automatic LoRA type detection via output_blocks analysis +- Compatible with serial node chaining (different LBW per node) +- Zero weight (all 0) = complete LoRA disable + +#### Preview Image Processing +- Pillow-only support: .png, .jpg, .jpeg, .gif, .webp (always works) +- opencv-python support: .mp4, .webm, .avi, .mov (optional) +- First-frame extraction for animated/video formats +- Consistent 1240px preprocessing + +### Performance +- No performance impact when LBW not used (Normal mode) +- Metadata caching unchanged from v1.1.0 + +--- + ## [1.1.0] - 2026-01-04 ### Added @@ -63,7 +119,7 @@ All notable changes to this project will be documented in this file. --- -## [1.0.0] - 2025-12-XX +## [1.0.0] - 2025-12-30 ### Initial Release diff --git a/README.md b/README.md index 86e2495..d17d697 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,26 @@ **English | [日本語版 README](./README_ja.md)** -A ComfyUI custom node package for randomly selecting and applying LoRAs. Includes two nodes: +A ComfyUI custom node package for randomly selecting and applying LoRAs. Includes three nodes: 1. **Random LoRA Loader** - Select from 3 folders simultaneously -2. **Filtered Random LoRA Loader** - Single folder with keyword filtering (NEW v1.1.0) +2. **Filtered Random LoRA Loader** - Single folder with keyword filtering +3. **Filtered Random LoRA Loader (LBW)** - 🆕 LBW support with automatic SD1.5/SDXL detection (NEW v1.2.0) ![Random LoRA Loader Workflow Example](./images/RLL_final_single.webp) ![Filtered Random LoRA Loader Workflow Example](./images/filterd_final_single.webp) +![FilteredRandomLoRALoader(LBW) Workflow Example](./images/lbw_final_single.webp) + +--- + +## ⚠️ Important: Supported Models + +**These nodes are designed for SD1.5 and SDXL models ONLY.** + +- ✅ **Supported:** Stable Diffusion 1.5, Stable Diffusion XL (SDXL) +- ❌ **NOT Supported:** Flux, SD3, SDXL Turbo, Pony, or other architectures + +The LBW node's block weight feature specifically targets SD1.5/SDXL U-Net architecture. Other model types will not work correctly with LBW. --- @@ -23,7 +36,7 @@ Select LoRAs from up to 3 different folders. Ideal for folder-based organization - Fixed LoRA categories - Simple folder-based workflow -### Filtered Random LoRA Loader (NEW) +### Filtered Random LoRA Loader Select LoRAs from a single folder using keyword filtering. Ideal for dynamic selection and large collections. @@ -33,45 +46,101 @@ Select LoRAs from a single folder using keyword filtering. Ideal for dynamic sel - Metadata search capability - Recommended for chaining multiple instances +### Filtered Random LoRA Loader (LBW) 🆕 NEW v1.2.0 + +Advanced node with LoRA Block Weight (LBW) support for precise effect control. + +**Use case:** +- Separate control of style vs. structure +- Fine-tuned LoRA application +- Professional workflows requiring precision +- 4 preset modes + custom input + +**See [README_LBW.md](README_LBW.md) for detailed LBW documentation.** + --- -## Key Features (Both Nodes) +## Key Features + +### Common Features (All Nodes) -- **3-Group Support**: Select LoRAs from up to 3 different folders - **Multi-Source Metadata Reading**: Automatically retrieve trigger words and sample prompts with priority order: 1. `.metadata.json` format (ComfyUI Lora Manager) - Priority 1 2. `.info` format (Civitai Helper) - Priority 2 - 3. **Embedded metadata in LoRA file** - Priority 3 (NEW) -- **Strength Randomization**: Randomize strength with range specification (e.g., `0.4-0.8`) + 3. **Embedded metadata in LoRA file** - Priority 3 +- **Strength Randomization**: + - **Range specification with negative support**: `0.4-0.8`, `-0.8--0.3` (v1.2.0) + - **0.1 increments for ranges**: Easier to observe effect differences + - **Fixed values rounded to 2 decimals**: `0.847` → `0.85` - **Flexible Trigger Word Retrieval**: - `json_combined`: Combine all trigger word patterns (with deduplication) - `json_random`: Randomly select one pattern - `json_sample_prompt`: Randomly retrieve sample prompts - - **`metadata`**: Read directly from embedded metadata (NEW) + - `metadata`: Read directly from embedded metadata - **Sample Prompt Optimization**: Automatically remove LoRA syntax from samples and apply node-configured strength - **Dual Text Outputs**: Separate positive_text and negative_text outputs - **ComfyUI Standard Seed Control**: Supports fixed/randomize/increment/decrement - **Wildcard Encode Integration**: Works seamlessly with Wildcard Encode (Inspire) - **LoRA Syntax Auto-Removal**: Cleans up LoRA syntax in additional_prompt to prevent noise +- **Preview Image Support**: Display preview images/videos for selected LoRAs (v1.1.0) +- **Duplicate Filename Handling**: Exclude duplicate filenames across subfolders (v1.1.0) + +### Filtered Nodes (Filtered & LBW) + +- **Keyword Filtering**: Space-separated keywords with phrase support +- **AND/OR Modes**: Flexible filtering logic +- **Metadata Search**: Search in filenames or embedded metadata +- **Fast Caching**: Instant metadata access after first load + +### LBW Node Only 🆕 + +- **LoRA Block Weight Support**: Control which U-Net blocks are affected +- **Automatic SD1.5/SDXL Detection**: No manual model type selection needed +- **4 Preset Modes**: + - Style Focused - OUTPUT blocks only + - Character Focused - Balanced IN+MID+OUT + - Structure/Composition Only - INPUT+MID blocks only + - Balanced / Soft - Gentle application +- **Preset: Random Mode**: Randomly select one of the 4 presets +- **Direct Input Mode**: Custom weight specification +- **Automatic Weight Adjustment**: Handles mismatched element counts + +--- ## Installation +### ⚠️ Optional: Video Preview Support + +**For video file preview (.mp4, .webm, .avi, .mov), opencv-python is REQUIRED:** + +```bash +pip install opencv-python +``` + +**Without opencv-python:** +- ✅ Static images (.png, .jpg, .jpeg) work +- ✅ Animated images (.gif, .webp) work +- ❌ **Video files will show BLACK SCREEN** (with warning message in console) + +LoRA functionality works normally regardless of opencv-python installation. Only preview display is affected. + ### Requirements - ComfyUI (works with standard installation) -- **No additional libraries required** ✅ +- Python 3.9+ +- **Core dependencies included with ComfyUI** ✅ ### Steps ```bash cd ComfyUI/custom_nodes -git clone https://github.com/shin131002/RandomLoRALoader.git +git clone https://github.com/YOUR_USERNAME/RandomLoRALoader.git # Or manually create RandomLoRALoader folder and copy files ``` Restart ComfyUI. -**Note:** Uses only Python standard library and ComfyUI bundled libraries, so no `pip install` needed. +**Note:** Uses only Python standard library and ComfyUI bundled libraries for core functionality. opencv-python is optional for video preview only. ### Uninstallation @@ -88,9 +157,11 @@ rmdir /s RandomLoRALoader Or manually delete the RandomLoRALoader folder and restart ComfyUI. +--- + ## Usage -### Basic Usage +### Basic Usage (Random LoRA Loader) 1. **Add Node**: Search for "Random LoRA Loader" in the node browser 2. **Connect MODEL/CLIP**: Connect base model and CLIP to inputs @@ -119,7 +190,7 @@ This node works seamlessly with Wildcard Encode (Inspire) for dynamic prompt gen text: "__style__, {red|blue|green}, " ↓ ├─ populated_text ──→ [Random LoRA Loader] - │ additional_prompt + │ additional_prompt_positive └─ MODEL/CLIP ──────→ model/clip input [Random LoRA Loader] @@ -155,8 +226,8 @@ This node works seamlessly with Wildcard Encode (Inspire) for dynamic prompt gen ``` Group 1: style LoRAs - num_loras_1: 2 - - model_strength_1: "0.6-0.9" ← Random - - clip_strength_1: "0.6-0.9" ← Random + - model_strength_1: "0.6-0.9" ← Random (0.1 increments) + - clip_strength_1: "0.6-0.9" ← Random (0.1 increments) Group 2: character LoRAs - num_loras_2: 1 @@ -170,6 +241,8 @@ Group 3: Unused → Result: 2 style LoRAs (variable strength) + 1 character LoRA (fixed strength) = 3 LoRAs total ``` +--- + ## Settings ### Common Settings @@ -178,7 +251,8 @@ Group 3: Unused |---------|-------------|---------| | `token_normalization` | Token normalization method | `none` | | `weight_interpretation` | Prompt emphasis notation interpretation | `A1111` | -| `additional_prompt` | Additional prompt (combined with trigger words) | (empty) | +| `additional_prompt_positive` | Additional positive prompt (combined with trigger words) | (empty) | +| `additional_prompt_negative` | Additional negative prompt | (empty) | | `trigger_word_source` | Trigger word source | `json_combined` | | `seed` | Random selection seed | `0` | @@ -209,7 +283,7 @@ CLIP tokenization: [1girl, lora, anime, style, 0, 8, beautiful] **Correct usage:** ``` -additional_prompt: "1girl, beautiful" ← No LoRA syntax ✅ +additional_prompt_positive: "1girl, beautiful" ← No LoRA syntax ✅ LoRA application: Use folder specification feature ✅ ``` @@ -217,7 +291,7 @@ Or, when connecting from Wildcard Encode, LoRA syntax is automatically removed: ``` [Wildcard Encode] populated_text: "1girl, , beautiful" ↓ -[This Node] additional_prompt received → LoRA syntax auto-removed +[This Node] additional_prompt_positive received → LoRA syntax auto-removed ↓ Final prompt: "1girl, beautiful" ✅ ``` @@ -235,9 +309,11 @@ Each group can be configured individually: | `clip_strength_X` | CLIP application strength | `"1.0"` | | `num_loras_X` | Number of LoRAs to select | Group 1: `1`, Groups 2/3: `0` | +--- + ## Strength Specification (Important) -Strength fields accept **fixed values** or **random ranges**. +Strength fields accept **fixed values** or **random ranges**, including **negative values**. ### Fixed Value @@ -246,740 +322,828 @@ Input: "1.0" → Always applied at 1.0 Input: "0.55" -→ Always applied at 0.55 -``` +→ Rounded to 0.55 (2 decimals) -**Features:** -- Input value used as-is -- Up to 2 decimal places (e.g., `0.55`) +Input: "-0.5" +→ Negative LoRA at -0.5 ✅ (v1.2.0) +``` ### Random Range -``` -Input: "0.4-0.8" -→ Randomly selects from 0.4, 0.5, 0.6, 0.7, 0.8 (0.1 increments) - -Input: "0.5-1.0" -→ Randomly selects from 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 - -Input: "0.44-0.82" -→ Randomly selects from 0.4, 0.5, 0.6, 0.7, 0.8 - (Range automatically rounded to 1 decimal place) -``` - -**Features:** -- Specify range with hyphen (`-`) -- Values generated in 0.1 increments -- Range bounds with 2+ decimal places are rounded to 1 decimal place -- Different value selected each execution - -### Error Handling +**Format:** `min-max` ``` -Input: "abc" or invalid format -→ Error logged, processed with strength 1.0 +Input: "0.6-0.9" +→ Random from [0.6, 0.7, 0.8, 0.9] (0.1 increments) + +Input: "-0.8--0.3" +→ Random from [-0.8, -0.7, -0.6, -0.5, -0.4, -0.3] ✅ (v1.2.0) + +Input: "-0.5-0.5" +→ Random from [-0.5, -0.4, ..., 0.4, 0.5] ✅ ``` -**Error message example:** -``` -[RandomLoRALoader] ❌ Cannot parse strength 'abc', using 1.0 -[RandomLoRALoader] 💡 Usage: '1.0' or '0.4-0.8' -``` +**v1.2.0 Improvements:** +- ✅ **Negative range support**: `-0.8--0.3` now works correctly +- ✅ **0.1 increments for all ranges**: Easier to observe effect differences +- ✅ **Fixed values rounded to 2 decimals**: `0.847` → `0.85` -### Verifying Actual Strength +### Behavior -Actual strength used can be verified in `positive_text` output: - -``` -, anime style, vibrant, - ↑ ↑ - MODEL CLIP - strength strength -``` - -**Recommended:** Connect Show Text node to `positive_text` to verify actual strength. - -## MODEL Strength vs CLIP Strength - -### Basic Concept - -- **MODEL strength**: Affects image itself (art style, composition, colors) -- **CLIP strength**: Affects prompt understanding (trigger word effectiveness) - -### Recommended Settings - -**Beginners / General Use:** -``` -model_strength: "1.0" -clip_strength: "1.0" -``` -Using same value for both is the standard approach. - -**Advanced / Fine-tuning:** -``` -model_strength: "0.7" -clip_strength: "1.0" -``` -For cases like wanting subtle art style but strong trigger word effect. - -**Randomization for Experimentation:** -``` -model_strength: "0.6-0.9" -clip_strength: "0.6-0.9" -``` -For testing various strength combinations. - -## Trigger Word Retrieval Methods - -### json_combined (All Combined) - -Combines all trigger word patterns and removes duplicates. - -**Example:** -```json -"trainedWords": [ - "character, red hair, blue eyes, uniform", - "character, red hair, blue eyes, casual clothes" -] -``` -↓ -``` -Output: character, red hair, blue eyes, uniform, casual clothes -``` - -### json_random (Random Selection) - -Randomly selects one pattern from trigger words. - -**Example:** -```json -"trainedWords": [ - "character, red hair, blue eyes, uniform", - "character, red hair, blue eyes, casual clothes" -] -``` -↓ -``` -Output: character, red hair, blue eyes, casual clothes (random) -``` - -### json_sample_prompt (Sample Retrieval) - -Randomly retrieves one sample prompt from JSON. - -- Outputs both positive_text and negative_text -- Automatically removes `` syntax from samples -- Generates new LoRA syntax with node-configured strength - -**Example:** -```json -"images": [{ - "meta": { - "prompt": "1girl, , beautiful", - "negativePrompt": "bad quality, worst quality" - } -}] -``` -↓ -``` -positive_text: 1girl, beautiful (LoRA syntax removed) -negative_text: bad quality, worst quality -``` - -### metadata (Embedded Metadata Only - NEW) - -Reads trigger words **directly from LoRA file's embedded metadata**, ignoring external `.metadata.json` and `.info` files. - -**Supported metadata fields:** -- `ss_tag_frequency`: kohya_ss format tag frequency (extracts top 20 tags) -- `modelspec.trigger_word`: Trigger word -- `ss_output_name`: Model name - -**Use case:** -- When you want to use only the metadata embedded by the LoRA trainer -- When external JSON files contain incorrect information -- For LoRAs without external metadata files +**All Nodes:** +- Range: 0.1 increments list → random selection +- Fixed: Rounded to 2 decimals **Example:** ``` -LoRA file contains embedded metadata: - ss_tag_frequency: {"dataset1": {"alice": 150, "blonde": 120, ...}} - ↓ -Output: alice, blonde, blue_eyes, ... +model_strength_1: "0.6-0.9" +→ Each execution randomly selects from [0.6, 0.7, 0.8, 0.9] +→ Console: "[RandomLoRALoader] Selected strength: 0.7" ``` -**Note:** Other modes (`json_combined`, `json_random`, `json_sample_prompt`) use external files with priority, falling back to embedded metadata if external files are not found. - -## Outputs - -| Output | Type | Description | -|--------|------|-------------| -| `MODEL` | MODEL | Model with LoRA applied | -| `CLIP` | CLIP | CLIP with LoRA applied | -| `positive_text` | STRING | LoRA info and positive prompt | -| `negative_text` | STRING | Negative prompt (json_sample_prompt only) | -| `positive` | CONDITIONING | Positive conditioning | -| `negative` | CONDITIONING | Negative conditioning | - -### positive_text Output Example - -``` -1girl, beautiful, -, anime style, vibrant colors, -, alice, blonde hair, blue eyes, -``` - -## Required File Structure - -**Metadata files or embedded data** required for trigger word retrieval. - -### Priority Order - -The node reads metadata in the following priority order: - -1. **`.metadata.json`** (ComfyUI Lora Manager format) -2. **`.info`** (Civitai Helper format) -3. **Embedded metadata in LoRA file** (Always available if LoRA was trained with metadata) - -### 1. ComfyUI Lora Manager format (Recommended) - -``` -/path/to/lora/ -├── style_anime_v2.safetensors -├── style_anime_v2.metadata.json ← ComfyUI Lora Manager -├── character_alice.safetensors -└── character_alice.metadata.json -``` - -### 2. Civitai Helper format - -``` -/path/to/lora/ -├── style_anime_v2.safetensors -├── style_anime_v2.info ← Civitai Helper -├── character_alice.safetensors -└── character_alice.info -``` - -### 3. Embedded metadata (No external file needed) - -``` -/path/to/lora/ -├── style_anime_v2.safetensors ← Contains embedded metadata -└── character_alice.safetensors ← Contains embedded metadata -``` - -**Note:** -- If external files (`.metadata.json` or `.info`) exist, they take priority over embedded metadata (except when using `trigger_word_source: metadata`) -- When `trigger_word_source` is set to `metadata`, only embedded metadata is read, ignoring external files - -### Generating metadata files - -**ComfyUI Lora Manager (Recommended):** -- [ComfyUI Lora Manager](https://github.com/willmiao/ComfyUI-Lora-Manager) -- Generates `.metadata.json` files - -**Civitai Helper:** -- [Civitai Helper](https://github.com/butaixianran/Stable-Diffusion-Webui-Civitai-Helper) -- Generates `.info` files (also supported) - -**Embedded metadata:** -- Automatically created during LoRA training with kohya_ss or other trainers -- No additional tools required - -## Troubleshooting - -### Cannot retrieve trigger words - -**For external metadata files:** -- Check if metadata file exists (`.metadata.json` or `.info`) -- Verify JSON contains `civitai.trainedWords` or `civitai.images` -- Confirm filename matches `{LoRAfilename}.metadata.json` or `{LoRAfilename}.info` - -**For embedded metadata:** -- Set `trigger_word_source` to `metadata` to read directly from LoRA file -- Check if LoRA was trained with metadata (most modern LoRAs include this) -- Supported fields: `ss_tag_frequency`, `modelspec.trigger_word`, `ss_output_name` - - -### additional_prompt with LoRA syntax doesn't work - -**Symptom:** -``` -additional_prompt: ", 1girl" -→ anime_style not applied -``` - -**Cause:** -This node doesn't interpret `` syntax. LoRA syntax is automatically removed. - -**Solution:** -1. Use folder specification feature for LoRA application -2. When integrating with Wildcard Encode (Inspire), let it handle LoRA syntax - -### Unintended words in prompt - -**Symptom:** -``` -additional_prompt: "" -→ "anime", "style" words automatically added -``` - -**Cause:** -v1.0.0 and later automatically remove LoRA syntax, so this issue doesn't occur. -If using older version, LoRA syntax filename part was interpreted as tokens. - -**Solution:** -- Update node to latest version -- Don't write LoRA syntax in additional_prompt - -### LoRA not applied - -- Verify folder path is correct -- Check `num_loras` isn't 0 -- Check ComfyUI console for error logs - -### Strength not as intended - -- Check `positive_text` output with Show Text -- Displays actual strength like `` -- With random range specification, different value selected each time -- Check console for strength selection log: `[RandomLoRALoader] Selected 0.6 from range 0.4-0.8` - -### Strength input error - -**Symptom:** -``` -[RandomLoRALoader] ❌ Cannot parse strength 'abc', using 1.0 -``` - -**Solution:** -- Use correct format: `"1.0"` or `"0.4-0.8"` -- Range specification must use hyphen (`-`) -- Node won't crash with invalid input, operates with 1.0 - -### Default values not displayed - -- Completely restart ComfyUI -- Clear browser cache (Ctrl+Shift+R) -- Delete and re-add node - -### Console shows many "lora key not loaded" messages - -**Symptom:** -``` -lora key not loaded: lora_unet_input_blocks_4_1_proj_in.alpha -lora key not loaded: lora_unet_input_blocks_4_1_proj_in.lora_down.weight -... -``` - -**Cause and Solution:** - -These messages are compatibility warnings output by ComfyUI core and **don't affect functionality**. Displayed when some keys in LoRA file aren't compatible with current model, but compatible keys apply normally. - -v1.0.0 and later automatically suppress these warning messages. If still displayed in large quantities: - -1. Verify node file is latest version -2. Restart ComfyUI -3. If still appears and functionality is fine, safe to ignore - -## Tips & Tricks - -### Random LoRA Loader: Using as a LoRA Syntax Filter Only - -You can use this node as a simple LoRA syntax remover without applying any LoRAs. - -**Setup:** -- Set all `num_loras` to `0` (or leave all folder paths empty) -- Connect Wildcard Encode's `populated_text` to `additional_prompt` -- Connect `positive_text` output to next node - -**Use case:** -- Remove LoRA syntax from Wildcard Encode output -- Clean up prompts before passing to other nodes -- Use Wildcard Encode's LoRA processing while removing the syntax for compatibility - -**Example workflow:** -``` -[Wildcard Encode (Inspire)] - text: "__style__, {red|blue|green}, " - ↓ - populated_text: "anime style, blue, " - (LoRA already applied to MODEL by Wildcard Encode) - ↓ -[Random LoRA Loader] - num_loras: 0, 0, 0 ← No LoRA application - additional_prompt ← Connected from populated_text - ↓ - positive_text: "anime style, blue," ← LoRA syntax removed ✅ - ↓ -[Next Node] -``` - -**Benefits:** -- ✅ Removes `` syntax that can become noise tokens -- ✅ No need for separate text processing nodes -- ✅ Works with any text containing LoRA syntax - --- -## Filtered Random LoRA Loader (NEW v1.1.0) +## MODEL Strength vs CLIP Strength -![Filtered Random LoRA Loader x1 Workflow](./images/filterd_final_single.webp) +### MODEL Strength +- **Affects**: Image itself (art style, composition, colors, shapes) +- **Effect**: Visual characteristics of generated image +- **Example**: + - High value: Strong art style transfer + - Low value: Subtle style hints -### Overview +### CLIP Strength +- **Affects**: Prompt interpretation (concept understanding, language-image association) +- **Effect**: How strongly the model follows prompt instructions +- **Example**: + - High value: Strong semantic guidance from trigger words + - Low value: Weak semantic influence -A single-group LoRA loader with keyword filtering capabilities. Designed for chaining multiple instances together. +### Recommended Settings -**Key differences from Random LoRA Loader:** -- Single folder path (not 3) -- Keyword filtering with AND/OR modes -- Metadata search capability with caching -- Dual prompt inputs (positive and negative) -- Recommended for serial connection +**For most use cases:** +``` +model_strength: 0.8 +clip_strength: 0.8 +→ Balanced application +``` + +**For subtle style application:** +``` +model_strength: 0.4-0.6 +clip_strength: 0.8-1.0 +→ Light visual effect, strong semantic guidance +``` + +**For strong style override:** +``` +model_strength: 1.0-1.2 +clip_strength: 0.6-0.8 +→ Strong visual effect, moderate semantic guidance +``` + +--- + +## Trigger Word Retrieval Methods + +### json_combined (Default) + +Combines all trigger word patterns from JSON metadata. + +**Source:** +1. `activation text` field +2. `ss_tag_frequency` keys (first 3 highest frequency) +3. `modelspec.description` keywords +4. `ss_output_name` keywords + +**Example:** +```json +{ + "activation text": "anime style, detailed eyes", + "ss_tag_frequency": { + "1girl": 500, + "blue eyes": 300, + "long hair": 250 + } +} +``` +**Result:** `"anime style, detailed eyes, 1girl, blue eyes, long hair"` + +--- + +### json_random + +Randomly selects one trigger word pattern. + +**Example:** +``` +Candidates: +- "anime style, detailed eyes" +- "1girl, blue eyes, long hair" +- "anime, girl, portrait" + +Random selection: "1girl, blue eyes, long hair" +``` + +--- + +### json_sample_prompt + +Retrieves sample prompts from JSON metadata. + +**Source fields (priority order):** +1. `sample_prompts` +2. `civitai.images[0].meta.prompt` + +**Processing:** +- Automatically removes LoRA syntax (``) +- Replaces with node-configured strength +- Extracts negative prompt if available + +**Example:** +```json +{ + "sample_prompts": "1girl, , beautiful, detailed eyes" +} +``` +**Result:** `"1girl, beautiful, detailed eyes"` (LoRA syntax removed) + +--- + +### metadata + +Reads trigger words directly from embedded LoRA file metadata. + +**Source:** +- Safetensors metadata keys +- Similar to json_combined but reads from LoRA file directly + +**Use when:** +- No external JSON files available +- Want to use original training metadata + +--- + +## Outputs + +All nodes provide the following outputs: + +| Output | Type | Description | +|--------|------|-------------| +| `MODEL` | MODEL | Model with LoRAs applied | +| `CLIP` | CLIP | CLIP with LoRAs applied | +| `positive` | CONDITIONING | Positive conditioning (LoRA syntax removed) | +| `negative` | CONDITIONING | Negative conditioning | +| `positive_text` | STRING | Full positive prompt text with LoRA syntax | +| `negative_text` | STRING | Full negative prompt text | +| `preview` | IMAGE | Batch of preview images for selected LoRAs (v1.1.0) | + +### Text Output Format + +**positive_text example:** +``` +, , anime style, alice, blonde hair, 1girl, beautiful +``` + +**LBW node positive_text example:** +``` +, anime style, 1girl, beautiful +``` + +**positive (CONDITIONING) content:** +``` +anime style, alice, blonde hair, 1girl, beautiful +(LoRA syntax removed for clean prompt) +``` + +### Preview Images (v1.1.0) + +**Supported formats (priority order):** +1. Static images (.png, .jpg, .jpeg) - Always works +2. Animated images (.gif, .webp) - First frame, always works +3. Video files (.mp4, .webm, .avi, .mov) - First frame, requires opencv-python + +**File matching:** +- Files starting with the LoRA filename (case-insensitive) +- Example: `style_anime.safetensors` matches: + - `style_anime.png` ✅ + - `style_anime_preview.jpg` ✅ + - `STYLE_ANIME.PNG` ✅ + +--- + +## Filtered Random LoRA Loader + +**Single folder with keyword filtering.** + +![Filtered Random LoRA Loader Workflow](./images/filterd_final_single.webp) + +### Key Features + +- **Keyword Filtering**: Filter LoRAs by space-separated keywords +- **AND/OR Modes**: Flexible filtering logic +- **Phrase Matching**: Use quotes for exact phrases +- **Metadata Search**: Search in filenames or embedded metadata +- **Fast Caching**: Instant metadata access after first load +- **Serial Connection Ready**: Chain multiple instances for complex workflows ### Parameters -#### Common Settings -- `token_normalization` - Same as Random LoRA Loader -- `weight_interpretation` - Same as Random LoRA Loader +| Parameter | Description | Default | +|-----------|-------------|---------| +| `lora_folder_path` | LoRA folder path | (empty) | +| `keyword_filter` | Space-separated keywords or quoted phrases | (empty) | +| `filter_mode` | `AND` / `OR` | `AND` | +| `search_in_metadata` | Search in JSON/embedded metadata | `false` | +| `num_loras` | Number of LoRAs to select | `1` | +| `model_strength` | MODEL strength (fixed or range) | `"1.0"` | +| `clip_strength` | CLIP strength (fixed or range) | `"1.0"` | +| `include_subfolders` | Include subfolders | `true` | +| `unique_by_filename` | Exclude duplicate filenames | `true` | -#### Folder Settings -- `lora_folder_path` - Single folder path -- `include_subfolders` - Include subfolders (default: True) -- `unique_by_filename` - Exclude duplicate filenames across subfolders (default: True) +### Keyword Filter Syntax -#### Keyword Filter -- `keyword_filter` - Keywords (comma-separated, e.g., "style, anime") -- `filter_mode` - AND (all keywords) or OR (any keyword, default: AND) -- `search_in_metadata` - Search in metadata files (default: False - filename only) - -#### LoRA Settings -- `model_strength` - MODEL strength (e.g., "1.0" or "0.6-0.9") -- `clip_strength` - CLIP strength (e.g., "1.0" or "0.6-0.9") -- `num_loras` - Number of LoRAs to select (default: 1, range: 0-20) - -#### Trigger Word Settings -- `trigger_word_source` - Same as Random LoRA Loader - -#### Additional Prompts -- `additional_prompt_positive` - Additional positive prompt (input or direct entry) -- `additional_prompt_negative` - Additional negative prompt (input or direct entry) - -#### Seed -- `seed` - Random seed -- `control_after_generate` - Seed control mode - -### Keyword Filtering - -#### Filename Search (Default - Fast) - -Searches only in LoRA filename. - -**Example:** +**Basic keywords (AND mode):** ``` -Folder contents: - - style_anime_v1.safetensors - - style_realistic.safetensors - - character_alice.safetensors - -keyword_filter: "anime" -→ Matches: style_anime_v1.safetensors ✅ +keyword_filter: "anime girl" +→ Matches files containing BOTH "anime" AND "girl" ``` -#### Metadata Search (Optional - Slower) - -Searches in both filename and metadata fields: -- `model_name` -- `civitai.name` -- `civitai.trainedWords` -- `civitai.model.name` -- `civitai.model.tags` -- `tags` -- Embedded metadata - -**Performance Notes:** - -Initial loading time (SSD environment, with progress display): -- 100 files: Instant -- 1,000 files: ~2 seconds -- 5,000 files: ~10 seconds -- 10,000 files: ~20 seconds -- 20,000 files: ~40 seconds -- 50,000 files: ~100 seconds (1 min 40 sec) - -Memory usage: -- 10,000 files: ~150MB -- 20,000 files: ~300MB -- 50,000 files: ~750MB - -**Second time onward:** Instant (cached) - -**Recommendations:** -- Default filename search is always fast -- Enable metadata search only when needed -- For large collections (5,000+ files), initial loading will take time -- HDD environments take approximately 3x longer than SSD for initial loading - -**Example:** +**OR mode:** ``` -File: abc123.safetensors -Metadata: {"trainedWords": ["anime style", "vibrant colors"]} - -search_in_metadata: True -keyword_filter: "anime" -→ Matches ✅ +filter_mode: OR +keyword_filter: "anime realistic" +→ Matches files containing "anime" OR "realistic" ``` -#### AND vs OR Modes - -**AND Mode (default):** +**Phrase matching:** ``` -keyword_filter: "style, anime" -filter_mode: "AND" -→ Matches files containing BOTH "style" AND "anime" +keyword_filter: '"anime style" detailed' +→ Must contain exact phrase "anime style" AND word "detailed" ``` -**OR Mode:** +**Multiple phrases:** ``` -keyword_filter: "style, anime" -filter_mode: "OR" -→ Matches files containing EITHER "style" OR "anime" +keyword_filter: '"anime style" "detailed eyes" red' +→ Must contain "anime style" AND "detailed eyes" AND "red" ``` -### Handling Duplicate Filenames +### Metadata Search -If the same LoRA filename exists in multiple subfolders (e.g., originals and backups), the `unique_by_filename` option prevents selecting the same LoRA multiple times. - -**Example:** +**Filename search (default):** ``` -Folder structure: - /LoRA/ - ├── style/anime_v1.safetensors - └── backup/anime_v1.safetensors - -unique_by_filename: True (default) - → Only one anime_v1.safetensors will be selected - → First occurrence is kept (/LoRA/style/anime_v1.safetensors) - -unique_by_filename: False - → Both files can be selected - → May result in same LoRA applied twice with different strengths +search_in_metadata: false +→ Fast, searches only filenames ``` -**Log output when duplicates detected:** -``` -[FilteredRandomLoRALoader] Duplicate filename detected: anime_v1.safetensors - Keeping: /LoRA/style/anime_v1.safetensors - Skipping: /LoRA/backup/anime_v1.safetensors -``` - -**Recommendation:** Keep default `True` to avoid unintentional duplicate applications. - -### Metadata Search Performance - -**Filename search (Default):** -- `search_in_metadata: False` (default) -- Very fast even with 10,000+ LoRAs -- Processing time: <100ms - **Metadata search:** -- `search_in_metadata: True` -- Searches in both filename and LoRA metadata -- **First execution:** Builds cache - - 1,000 LoRAs: ~2 seconds - - 10,000 LoRAs: ~7-75 seconds (depends on metadata files) - - Progress displayed in console -- **Subsequent executions:** Very fast (<100ms) -- Cache persists until ComfyUI restart - -**Performance tip:** -- Use `include_subfolders: True` on first run to cache all LoRAs at once -- After cache is built, `include_subfolders: False` will still use cached metadata -- Cache is shared across all node instances - -### Usage Examples - -#### Basic Usage - ``` -[Filtered Random LoRA Loader] - lora_folder_path: /loras/all/ - keyword_filter: "anime" - num_loras: 1 - ↓ -Randomly selects 1 LoRA containing "anime" in filename +search_in_metadata: true +→ Slower, searches JSON/embedded metadata +→ Cached after first search (instant on 2nd+) ``` -#### Chaining Multiple Instances +**Performance:** +- Initial load (SSD): + - 1,000 files: ~2 seconds + - 5,000 files: ~10 seconds + - 10,000 files: ~20 seconds +- 2nd+ time: Instant (<100ms) +- Memory: ~150MB per 10,000 files + +### Use Cases + +#### Example 1: Character Selection + +``` +lora_folder_path: "/path/to/all_loras" +keyword_filter: "character girl" +filter_mode: AND +num_loras: 1 +``` + +**Result:** Select 1 character LoRA containing both "character" and "girl" + +--- + +#### Example 2: Multiple Instances (Recommended) ![Filtered Random LoRA Loader x2 Workflow](./images/filterd_final_double.webp) ``` -[Filtered Random LoRA Loader A] - folder: /loras/all/ - keyword_filter: "style, anime" - filter_mode: "AND" +[Load Checkpoint] + ↓ +[Filtered Random LoRA Loader #1] + keyword_filter: "style anime" num_loras: 1 ↓ -[Filtered Random LoRA Loader B] - folder: /loras/all/ +[Filtered Random LoRA Loader #2] keyword_filter: "character" num_loras: 1 - additional_prompt_positive ← A's positive_text - additional_prompt_negative ← A's negative_text ↓ -[Filtered Random LoRA Loader C] - folder: /loras/all/ - keyword_filter: "concept" - num_loras: 1 - additional_prompt_positive ← B's positive_text - additional_prompt_negative ← B's negative_text +[KSampler] ``` -#### With Wildcard Encode - -![Wildcard Encode + Filtered Random LoRA Loader Workflow](./images/filterd_final_wce.webp) - -``` -[Wildcard Encode] - populated_text: "1girl, beautiful" - negative_text: "bad quality" - ↓ -[Filtered Random LoRA Loader] - additional_prompt_positive ← populated_text - additional_prompt_negative ← negative_text - keyword_filter: "style" - ↓ -Combined output ✅ -``` - -### Best Practices - -1. **Use descriptive filenames:** `style_anime_v1.safetensors` -2. **Default mode (fast):** Keep `search_in_metadata: False` for daily use -3. **Enable metadata search when:** - - Filenames don't contain useful keywords - - Need to search in trigger words or tags -4. **First run optimization:** - - Use `include_subfolders: True` once to build complete cache - - Switch to `False` after for faster folder scanning -5. **Chaining:** - - Connect `positive_text` → next node's `additional_prompt_positive` - - Connect `negative_text` → next node's `additional_prompt_negative` - -### Troubleshooting - -**No LoRAs found matching filter:** -- Check if keyword exists in filenames -- Enable `search_in_metadata: True` to search in metadata -- Try OR mode instead of AND mode -- Verify folder path is correct - -**First execution is slow:** -- This is normal when `search_in_metadata: True` -- Cache is being built, subsequent executions will be fast -- Progress is shown in console - -**Cache not working:** -- Cache clears on ComfyUI restart -- Run once after startup to rebuild cache +**Benefits:** +- Different filtering per category +- Independent strength settings +- More flexibility --- -## Tips & Tricks (Original Node) +#### Example 3: Metadata Search -### Using as a LoRA Syntax Filter Only +``` +search_in_metadata: true +keyword_filter: "detailed eyes" +``` -You can use this node as a simple LoRA syntax remover without applying any LoRAs. +**Searches in:** +- Filenames +- JSON `activation text` +- JSON `ss_tag_frequency` +- JSON `modelspec.description` +- Embedded LoRA metadata -**Setup:** -- Set all `num_loras` to `0` (or leave all folder paths empty) -- Connect Wildcard Encode's `populated_text` to `additional_prompt` -- Connect `positive_text` output to next node +--- -**Use case:** -- Remove LoRA syntax from Wildcard Encode output -- Clean up prompts before passing to other nodes -- Use Wildcard Encode's LoRA processing while removing the syntax for compatibility +## Filtered Random LoRA Loader (LBW) 🆕 NEW v1.2.0 + +**Advanced node with LoRA Block Weight support.** + +![FilteredRandomLoRALoader(LBW) Workflow Example](./images/lbw_final_single.webp) + +### What is LBW? + +LoRA Block Weight allows you to control which parts of the U-Net are affected by the LoRA: + +``` +INPUT blocks → Structure, composition, layout + ↓ +MIDDLE block → Overall features + ↓ +OUTPUT blocks → Style, details, fine-tuning +``` + +### Key Features + +- **4 Preset Modes**: + - **Style Focused**: OUTPUT blocks only (style without changing structure) + - **Character Focused**: Balanced IN+MID+OUT (character features) + - **Structure/Composition Only**: INPUT+MID blocks (layout without style) + - **Balanced / Soft**: Gentle application (natural results) +- **Preset: Random**: Randomly select one of the 4 presets +- **Direct Input**: Custom weight specification +- **Automatic SD1.5/SDXL Detection**: No manual model type selection +- **Automatic Weight Adjustment**: Handles mismatched element counts + +### Parameters + +Same as Filtered Random LoRA Loader, plus: + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `weight_mode` | LBW preset or Direct Input | `Normal (All 1.0)` | +| `lbw_input` | Custom weights (for Direct Input) | (empty) | + +### Weight Modes + +#### Normal (All 1.0) +Standard LoRA application without block weighting. + +#### Style Focused +``` +SDXL: 1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1 +SD1.5: 1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1 +``` +- OUTPUT blocks only +- Style without changing structure +- Use for: Art style LoRAs, effect LoRAs + +#### Character Focused +``` +SDXL: 1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1 +SD1.5: 1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1 +``` +- Balanced IN+MID+OUT +- Character features preserved +- Use for: Character LoRAs, person LoRAs + +#### Structure/Composition Only +``` +SDXL: 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0 +SD1.5: 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0 +``` +- INPUT+MID blocks only +- Structure without changing style +- Use for: Pose LoRAs, composition LoRAs + +#### Balanced / Soft +``` +SDXL: 1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0 +SD1.5: 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,0,0 +``` +- Gentle application +- Natural results +- Use for: General LoRAs, multi-LoRA workflows + +#### Preset: Random +Randomly selects one of the 4 presets above each execution. + +#### Direct Input +``` +weight_mode: Direct Input +lbw_input: "1,0.5,0.5,0,0,0,0,0,0,0,1,0.8,0.8,0.8,0.8,0.8,0.5,0.5,0.5,0.5" +``` +- Custom weight specification +- SDXL: 20 elements, SD1.5: 17 elements +- Auto-adjusted if count doesn't match + +### Use Cases + +#### Example 1: Style Only + +``` +[Filtered Random LoRA Loader (LBW)] + keyword_filter: "anime watercolor" + weight_mode: Style Focused + ↓ +[KSampler] +``` + +**Result:** Applies anime watercolor style without changing composition + +--- + +#### Example 2: Structure then Style + +``` +[Load Checkpoint] + ↓ +[Filtered Random LoRA Loader (LBW)] + keyword_filter: "pose" + weight_mode: Structure/Composition Only + ↓ +[Filtered Random LoRA Loader (LBW)] + keyword_filter: "oil painting" + weight_mode: Style Focused + ↓ +[KSampler] +``` + +**Result:** Pose adjustment → Oil painting style applied + +--- + +#### Example 3: Custom Weights + +``` +weight_mode: Direct Input +lbw_input: "1,0.5,0.5,0.5,0,0,0,0,0,0,1,1,1,1,1,1,0.5,0.5,0.5,0.5" +``` + +**Result:** Custom block weight distribution + +--- + +### Advanced: Custom Presets + +You can edit presets directly in the source file: + +**File:** `filtered_random_lora_loader_lbw.py` (lines 29-41) + +See [README_LBW.md](README_LBW.md) for detailed customization guide. + +--- + +## Tips & Tricks + +### Serial Connection for Multiple Effects + +Connect nodes in series to apply different LoRA categories: + +``` +[Load Checkpoint] + ↓ +[Filtered Random LoRA Loader (LBW)] (Structure/Composition Only) + keyword_filter: "pose" + ↓ +[Filtered Random LoRA Loader (LBW)] (Style Focused) + keyword_filter: "watercolor" + ↓ +[KSampler] +``` + +**Benefits:** +- Different settings per category +- Cumulative LoRA effects +- More control over final result + +--- + +### Strength Randomization for Variety + +Use ranges instead of fixed values: + +``` +model_strength_1: "0.6-0.9" +clip_strength_1: "0.6-0.9" +``` + +**Effect:** +- Each generation uses different strength +- More variety in results +- Easier to find optimal strength + +--- + +### Keyword Filtering Best Practices + +**Use specific keywords:** +``` +✅ Good: "anime girl" +❌ Too broad: "anime" +``` + +**Combine with metadata search:** +``` +search_in_metadata: true +keyword_filter: "detailed eyes" +``` + +**Use phrases for precision:** +``` +keyword_filter: '"anime style" detailed' +→ Must contain exact phrase "anime style" AND word "detailed" +``` + +--- + +### Wildcard Encode + Random LoRA Loader + +**Ultimate dynamic workflow:** + +``` +[Wildcard Encode (Inspire)] + text: "__style__, __pose__, {red|blue|green}" + ↓ + populated_text ──→ [Random LoRA Loader] + additional_prompt_positive + ↓ +[KSampler] +``` + +**Result:** +- Wildcard expansion for prompts +- Random LoRA selection for variety +- Clean prompt without LoRA syntax +- Maximum flexibility + +--- + +### Preview Images for Organization + +Enable preview display to: +- See which LoRAs were selected +- Verify LoRA appearance before generation +- Organize LoRA collections visually + +**Recommended workflow:** +``` +[Random LoRA Loader] + preview ──→ [Preview Image] (for verification) + MODEL ──→ [KSampler] +``` + +--- + +## Troubleshooting + +### No LoRAs Found + +**Check:** +1. LoRA folder path is correct (absolute path) +2. `.safetensors` files exist in the folder +3. `include_subfolders` setting if LoRAs are in subfolders +4. Console for error messages + +**Example valid paths:** +``` +Windows: C:/ComfyUI/models/loras/style +Linux/Mac: /home/user/ComfyUI/models/loras/style +``` + +--- + +### No Trigger Words Found + +**Check:** +1. Metadata files (`.metadata.json` or `.info`) exist +2. JSON files contain required fields: + - `activation text` + - `ss_tag_frequency` + - `sample_prompts` + - `civitai.trainedWords` or `civitai.images` +3. Try different `trigger_word_source` settings + +**Verify JSON format:** +```json +{ + "activation text": "anime style, detailed", + "ss_tag_frequency": {...}, + "modelspec.description": "...", + "sample_prompts": "..." +} +``` + +--- + +### LoRA Not Applied + +**Check:** +1. `num_loras` is not 0 +2. Strength values are not all 0 +3. MODEL/CLIP outputs are connected properly +4. Console for LoRA application messages +5. For LBW node: weight_mode is not "Normal (All 1.0)" with all weights set to 0 + +--- + +### Preview Images Not Showing + +**Check:** +1. Preview files match LoRA filename +2. For video files: opencv-python is installed (`pip install opencv-python`) +3. Supported formats: .png, .jpg, .jpeg, .gif, .webp, .mp4, .webm, .avi, .mov +4. File permissions are correct + +**Without opencv-python:** +- Static images work ✅ +- Animated images work ✅ +- Video files show black screen ⚠️ + +--- + +### Strength Not Working with Negative Values (Fixed in v1.2.0) + +**Previous issue (v1.1.0):** +``` +Input: "-0.5" +Result: 1.0 ❌ (converted to default) +``` + +**Fixed in v1.2.0:** +``` +Input: "-0.5" +Result: -0.5 ✅ (negative LoRA applied correctly) + +Input: "-0.8--0.3" +Result: Random from [-0.8, -0.7, -0.6, -0.5, -0.4, -0.3] ✅ +``` + +--- + +### Wildcard Encode Issues + +**If wildcard text appears in output:** + +1. **Check connection**: Connect Wildcard Encode's `populated_text` to `additional_prompt_positive` +2. **Wrong output**: Don't connect `text` (input) to this node +3. **LoRA syntax appearing**: This node automatically removes it **Example workflow:** ``` [Wildcard Encode (Inspire)] - text: "__style__, {red|blue|green}, " - ↓ - populated_text: "anime style, blue, " - (LoRA already applied to MODEL by Wildcard Encode) - ↓ -[Random LoRA Loader] - num_loras: 0, 0, 0 ← No LoRA application - additional_prompt ← Connected from populated_text - ↓ - positive_text: "anime style, blue," ← LoRA syntax removed ✅ - ↓ -[Next Node] + populated_text ──→ [Random LoRA Loader] + (not "text") additional_prompt_positive ``` -**Benefits:** -- ✅ Removes `` syntax that can become noise tokens -- ✅ No need for separate text processing nodes -- ✅ Works with any text containing LoRA syntax +--- + +### Duplicate LoRAs Selected + +**Solution:** Enable `unique_by_filename` + +``` +unique_by_filename_1: true +``` + +This prevents selecting the same LoRA from different subfolders: +``` +/style/lora.safetensors +/backup/lora.safetensors +→ Only one selected ✅ +``` + +--- + +## Detailed Documentation + +- **[README_LBW.md](README_LBW.md)** - Complete LBW documentation (English) +- **[README_LBW_ja.md](README_LBW_ja.md)** - LBW詳細ガイド(日本語) +- **[README_ja.md](README_ja.md)** - 日本語メインドキュメント + +--- ## Disclaimer and Support Policy -### About This Node +### Disclaimer -This custom node was developed for personal use and is being shared publicly. +- This node is provided as-is with **no technical support** +- No warranty or guarantee of functionality +- No guaranteed compatibility with future ComfyUI updates +- Bug reports and feature requests may not be addressed +- Use at your own risk -### Support +### Support Status -- ❌ **No technical support provided** - - Usage questions - - Environment setup assistance - - Individual troubleshooting support +- ❌ No individual support via issues or email +- ❌ No guaranteed bug fixes or feature additions +- ✅ Code is open source - feel free to fork and modify +- ✅ Community discussions welcome (no promises of response) -- ❌ **No warranty** - - Operation in specific environments - - Compatibility with future ComfyUI updates - - Liability for data loss, etc. +### Reporting Issues -### Community Contributions +While support is not guaranteed, you can: +1. Check existing issues in the repository +2. Review this README and troubleshooting section +3. Open an issue (may or may not be addressed) +4. Fork and fix it yourself -The following are welcome but not guaranteed to be addressed: - -- ✅ Bug reports (Issues) -- ✅ Pull requests -- ✅ Feature suggestions - -### Terms of Use - -- Use entirely at your own risk -- Test thoroughly before production use -- Author assumes no liability for any issues +--- ## License MIT License -Copyright (c) 2025 - -This software is provided "as is" without any express or implied warranties. +--- ## Changelog -### v1.0.0 (2024-12-30) -- Initial public release -- 3-group support (select from different folders) -- Strength randomization (range specification: `0.4-0.8`) -- External JSON reading (Civitai Helper compatible) -- Auto-remove LoRA syntax in sample prompts -- **Auto-remove LoRA syntax in additional_prompt** (noise prevention) -- Separate positive_text/negative_text outputs -- Wildcard Encode (Inspire) integration -- Fully local operation (no API required) +### v1.2.0 (2026-01-13) + +#### Added +- ✅ **NEW NODE**: Filtered Random LoRA Loader (LBW) +- ✅ LoRA Block Weight (LBW) support with 4 presets +- ✅ Automatic SD1.5/SDXL detection for LBW +- ✅ Preset: Random mode for LBW +- ✅ Direct Input mode for custom LBW weights +- ✅ Automatic weight adjustment for LBW +- ✅ **Negative value support for strength**: `-0.5`, `-0.8--0.3` now work correctly +- ✅ **Video preview support**: .mp4, .webm, .avi, .mov (requires opencv-python) +- ✅ **Strength precision improvements**: + - Range specification: 0.1 increments for all nodes + - Fixed values: Rounded to 2 decimals + +#### Fixed +- ✅ **Critical bug**: Negative single values (`"-0.5"`) now work correctly (previously converted to 1.0) +- ✅ **Critical bug**: Negative ranges (`"-0.8--0.3"`) now work correctly (previously caused errors) +- ✅ Improved strength parsing with regex pattern matching + +#### Changed +- ✅ Unified strength behavior across all 3 nodes +- ✅ Renamed node: "Filtered Random LoRA Loader (Advanced)" → "Filtered Random LoRA Loader (LBW)" +- ✅ Enhanced documentation with model compatibility warnings + +### v1.1.0 (2026-01-04) + +#### Added +- ✅ **NEW NODE**: Filtered Random LoRA Loader +- ✅ Keyword filtering with AND/OR modes +- ✅ Metadata search with caching +- ✅ Preview image output (IMAGE type) +- ✅ Duplicate filename handling (`unique_by_filename`) +- ✅ Animated image support (.gif, .webp) + +#### Changed +- ✅ **Breaking**: Split `additional_prompt` into `additional_prompt_positive` and `additional_prompt_negative` +- ✅ Unified strength precision to 1 decimal place +- ✅ Improved LoRA syntax removal + +#### Fixed +- ✅ Fixed negative_text output in `json_sample_prompt` mode +- ✅ Fixed LoRA syntax appearing in metadata trigger words +- ✅ Fixed duplicate parameter in INPUT_TYPES + +### v1.0.0 (2025-12-30) + +#### Added +- ✅ Initial release +- ✅ Random LoRA Loader with 3-group support +- ✅ Multi-source metadata reading +- ✅ Strength randomization with range specification +- ✅ Trigger word extraction +- ✅ Wildcard Encode compatibility +- ✅ CONDITIONING output with cleaned prompts + +--- ## References - [ComfyUI](https://github.com/comfyanonymous/ComfyUI) -- [ComfyUI Lora Manager](https://github.com/willmiao/ComfyUI-Lora-Manager) - Generates `.metadata.json` (Recommended) -- [Civitai Helper](https://github.com/butaixianran/Stable-Diffusion-Webui-Civitai-Helper) - Generates `.info` (Also supported) +- [Wildcard Encode (Inspire)](https://github.com/ltdrdata/ComfyUI-Inspire-Pack) +- [LoRA Block Weight Theory](https://github.com/hako-mikan/sd-webui-lora-block-weight) + +--- + +**Enjoy flexible LoRA randomization with precise control! 🎲✨** diff --git a/README_LBW.md b/README_LBW.md new file mode 100644 index 0000000..52ea591 --- /dev/null +++ b/README_LBW.md @@ -0,0 +1,382 @@ +# Filtered Random LoRA Loader (LBW) + +**LoRA Block Weight (LBW) support with automatic SD1.5/SDXL detection** + +![FilteredRandomLoRALoader(LBW) Workflow Example](./images/lbw_final_single.webp) + +--- + +## Features + +### **Core Features (from Filtered Random LoRA Loader)** +- ✅ Random LoRA selection from a single folder +- ✅ Keyword filtering (AND/OR modes) +- ✅ Metadata search (filename or embedded metadata) +- ✅ Preview images (static/animated/video support) +- ✅ Trigger word extraction +- ✅ Duplicate removal by filename +- ✅ Direct serial connection support + +### **Advanced Features (LBW)** +- ✅ **LoRA Block Weight (LBW) support** +- ✅ **Automatic SD1.5/SDXL detection** +- ✅ **4 preset modes + custom input** +- ✅ **Automatic weight adjustment** + +--- + +## LoRA Block Weight (LBW) + +### **What is LBW?** + +LoRA Block Weight allows you to control which parts of the U-Net model are affected by the LoRA: + +- **INPUT blocks**: Structure, composition, layout +- **MIDDLE block**: Overall features +- **OUTPUT blocks**: Style, details, fine-tuning + +By adjusting weights for each block, you can precisely control the LoRA's effect. + +--- + +## Weight Modes + +### **1. Normal (All 1.0)** - Default +All blocks weighted at 1.0 (standard LoRA application, no LBW). + +--- + +### **2. Style Focused** +Emphasizes OUTPUT blocks only. + +**Best for:** +- Style LoRAs +- Art style transfer +- Visual aesthetic changes + +**SDXL:** `1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1` +**SD1.5:** `1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1` + +**Effect:** +- ✅ Strong style changes +- ❌ Minimal structure/character changes + +--- + +### **3. Character Focused** +Emphasizes INPUT (early) + MIDDLE + OUTPUT blocks. + +**Best for:** +- Character LoRAs +- Face/feature preservation +- Balanced application + +**SDXL:** `1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1` +**SD1.5:** `1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1` + +**Effect:** +- ✅ Strong character features +- ✅ Balanced overall effect + +--- + +### **4. Structure/Composition Only** +Emphasizes INPUT + MIDDLE blocks only. + +**Best for:** +- Pose LoRAs +- Composition LoRAs +- Layout/structure control + +**SDXL:** `1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0` +**SD1.5:** `1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0` + +**Effect:** +- ✅ Strong structure/pose changes +- ❌ Minimal style changes + +--- + +### **5. Balanced / Soft** +Soft application across selected blocks. + +**Best for:** +- Subtle effects +- Multi-LoRA workflows +- General-purpose LoRAs + +**SDXL:** `1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0` +**SD1.5:** `1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,0,0` + +**Effect:** +- ✅ Balanced, gentle application +- ✅ Good for stacking multiple LoRAs + +--- + +### **6. Preset: Random** +Randomly selects one of the 4 presets above. + +**Best for:** +- Experimentation +- Variation generation +- Random effects + +--- + +### **7. Direct Input** +Custom weight specification. + +**Format:** +- SDXL: 20 comma-separated values +- SD1.5: 17 comma-separated values + +**Example (SDXL):** +``` +1,0.5,0.5,0.3,0.3,0.3,0.3,0.3,0.3,0.3,0.7,0.7,0.7,1,1,1,1,1,1,1 +``` + +**Auto-adjustment:** +- If too few elements: pads with 1.0 at the end +- If too many elements: truncates from the end + +--- + +## Block Structure + +### **SDXL (20 elements)** +``` +BASE, IN00-IN08 (9), MID (1), OUT00-OUT08 (9) +``` + +### **SD1.5 (17 elements)** +``` +BASE, IN01,IN02,IN04,IN05,IN07,IN08 (6), MID (1), OUT03-OUT11 (9) +``` + +--- + +## Automatic Detection + +### **LoRA Type Detection** + +The node automatically detects whether a LoRA is SD1.5 or SDXL by analyzing the model structure: + +- **SD1.5**: `output_blocks_0` to `output_blocks_11` (12 blocks) +- **SDXL**: `output_blocks_0` to `output_blocks_8` (9 blocks) + +**You don't need to specify the model type manually!** ✅ + +--- + +### **Weight Adjustment** + +If the number of weights doesn't match the detected LoRA type: + +**Example 1: Too few weights** +``` +Input: 1,0,0 (3 elements) +Detected: SDXL (requires 20) +→ Auto-adjusted: 1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 +``` + +**Example 2: Too many weights** +``` +Input: 1,0,0,...,0,0,0 (25 elements) +Detected: SDXL (requires 20) +→ Auto-adjusted: 1,0,0,...,0,0,0 (first 20 only) +``` + +--- + +## Usage + +### **Basic Workflow** + +``` +[Filtered Random LoRA Loader (LBW)] + MODEL → [KSampler] + CLIP → [CLIP Text Encode] + positive_text → [Show Text] (optional, for debugging) +``` + +### **Parameters** + +#### **LoRA Settings** +- `lora_folder_path`: Path to LoRA folder +- `num_loras`: Number of LoRAs to apply (0-20) +- `model_strength`: LoRA strength for MODEL (e.g., "1.0" or "0.6-0.9") +- `clip_strength`: LoRA strength for CLIP (e.g., "1.0" or "0.6-0.9") + +#### **Keyword Filter** +- `keyword_filter`: Space-separated keywords (e.g., `style anime` or `"anime style" red`) +- `filter_mode`: AND / OR +- `search_in_metadata`: Search in JSON/embedded metadata (slower) + +#### **LBW Settings** (New!) +- `weight_mode`: Normal / 4 Presets / Random / Direct Input +- `lbw_input`: Custom weights (only for Direct Input mode) + +#### **Other** +- `trigger_word_source`: Trigger word extraction method +- `seed`: Random seed + +--- + +## Output Format + +### **LBW Syntax** + +When LBW is applied, the `positive_text` output includes LBW syntax: + +**Normal (All 1.0):** +``` + +``` + +**With LBW (Style Focused, SDXL):** +``` + +``` + +**Note:** The LBW is applied internally to the MODEL. The syntax in `positive_text` is for reference/re-use with other nodes. + +--- + +## Tips + +### **1. Preset Selection Guide** + +| LoRA Type | Recommended Preset | Why | +|-----------|-------------------|-----| +| Style/Art | Style Focused | OUTPUT blocks control style | +| Character | Character Focused | Balanced IN+MID+OUT for features | +| Pose/Composition | Structure/Composition Only | INPUT blocks control layout | +| General | Balanced / Soft | Gentle, stackable effect | + +--- + +### **2. Effect Visibility** + +The difference between presets is **more visible** with: +- ✅ Strong LoRAs (high model_strength) +- ✅ Single LoRA application (num_loras=1) +- ✅ Style or concept LoRAs + +The difference is **less visible** with: +- ⚠️ Weak LoRAs (low model_strength) +- ⚠️ Multiple LoRAs applied simultaneously +- ⚠️ LoRAs with evenly distributed training + +--- + +### **3. Zero Weight = No Effect** + +Setting all weights to 0 completely disables the LoRA effect: +``` +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +``` +This is equivalent to not applying the LoRA at all. + +--- + +### **4. Serial Connection** + +For applying different LBW settings to different LoRAs: +``` +[Filtered Random LoRA Loader (LBW)] (Style Focused) + ↓ +[Filtered Random LoRA Loader (LBW)] (Character Focused) + ↓ +[KSampler] +``` + +All LoRAs within a single node instance use the same LBW setting. + +--- + +## Requirements + +### **⚠️ Supported Models** +**This node is designed for SD1.5 and SDXL models ONLY.** + +- ✅ **Supported:** Stable Diffusion 1.5, Stable Diffusion XL (SDXL) +- ❌ **NOT Supported:** Flux, SD3, SDXL Turbo, Pony, or other architectures + +The LBW feature specifically targets SD1.5/SDXL U-Net architecture. Other model types will not work correctly. + +--- + +### **Dependencies** +- ComfyUI +- Pillow (included with ComfyUI) +- torch (included with ComfyUI) + +### **⚠️ Optional: Video Preview** +**For video preview support (.mp4, .webm, .avi, .mov), opencv-python is REQUIRED:** +```bash +pip install opencv-python +``` + +**Without opencv-python:** +- ✅ Static/animated images work +- ❌ Video files show black screen + +--- + +## Preview Images + +Supports the following formats (in priority order): + +1. **Static images** (.png, .jpg, .jpeg) +2. **Animated images** (.gif, .webp) - first frame +3. **Video files** (.mp4, .webm, .avi, .mov) - first frame (requires opencv-python) + +The node automatically searches for preview files matching the LoRA filename. + +--- + +## Disclaimer + +- No technical support provided +- No warranty or guarantee of functionality +- No guaranteed compatibility with future ComfyUI updates +- Bug reports and feature requests may not be addressed +- Use at your own risk + +--- + +## Changelog + +### v1.2.0 (2026-01-13) +- ✅ Added LoRA Block Weight (LBW) support +- ✅ Automatic SD1.5/SDXL detection +- ✅ 4 preset modes + custom input +- ✅ Automatic weight adjustment +- ✅ Video preview support (.mp4, .webm, etc.) + +### v1.1.0 (2026-01-04) +- ✅ Added Filtered Random LoRA Loader +- ✅ Keyword filtering with AND/OR modes +- ✅ Metadata search support +- ✅ Preview image display + +### v1.0.0 (2025-12-30) +- ✅ Initial release +- ✅ Random LoRA Loader (3 groups) + +--- + +## License + +MIT License + +--- + +## Author + +Your Name + +--- + +**Enjoy precise LoRA control with Block Weights!** 🎨✨ diff --git a/README_LBW_ja.md b/README_LBW_ja.md new file mode 100644 index 0000000..2f548cd --- /dev/null +++ b/README_LBW_ja.md @@ -0,0 +1,494 @@ +# Filtered Random LoRA Loader (LBW) - 詳細ガイド + +**LoRAブロックウェイト(LBW)対応版** + +![FilteredRandomLoRALoader(LBW)ワークフロー例](./images/lbw_final_single.webp) + +--- + +## 概要 + +Filtered Random LoRA Loader (LBW) は、LoRAブロックウェイト(LBW)機能を追加した高度なノードです。U-Netのどの部分にLoRAを適用するかを細かく制御できます。 + +--- + +## 主な機能 + +### **✅ LoRAブロックウェイト(LBW)対応** +- U-Netのブロックごとに個別の強度を設定 +- 画風、キャラクター、構図などを分離制御 + +### **✅ 自動SD1.5/SDXL検出** +- LoRAファイルを自動判定 +- ウェイト数を自動調整 + +### **✅ 4つのプリセットモード** +- Style Focused(画風特化) +- Character Focused(キャラ重視) +- Structure/Composition Only(構造・構図のみ) +- Balanced / Soft(バランス・穏やか) + +### **✅ カスタム入力** +- Direct Inputモードで任意のウェイトを指定 +- Preset: Randomモードでランダムプリセット選択 + +--- + +## LBWとは? + +### **LoRAブロックウェイトの仕組み** + +Stable DiffusionのU-Netは以下の3つの部分で構成されています: + +``` +INPUT blocks → 構造、構図、レイアウト + ↓ +MIDDLE block → 全体的な特徴 + ↓ +OUTPUT blocks → 画風、ディテール、細部調整 +``` + +LBWを使うと、**各ブロックに異なるLoRA強度を設定**できます。 + +--- + +## ブロック構造 + +### **SDXL(20要素)** + +| インデックス | ブロック | 役割 | +|------------|---------|------| +| 0 | BASE | 全体ベース | +| 1-9 | INPUT (IN00-08) | 構造・構図 | +| 10 | MIDDLE (M00) | 中間特徴 | +| 11-19 | OUTPUT (OUT00-08) | 画風・ディテール | + +**ウェイト例:** +``` +1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1 +BASE,IN00-08 (OFF),M00,OUT00-08 (ON) +→ OUTPUTブロックのみLoRA適用(画風特化) +``` + +--- + +### **SD1.5(17要素)** + +| インデックス | ブロック | 役割 | +|------------|---------|------| +| 0 | BASE | 全体ベース | +| 1-6 | INPUT (IN01,02,04,05,07,08) | 構造・構図 | +| 7 | MIDDLE (M00) | 中間特徴 | +| 8-16 | OUTPUT (OUT03-11) | 画風・ディテール | + +**ウェイト例:** +``` +1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1 +BASE,IN (OFF),M00,OUT (ON) +→ OUTPUTブロックのみLoRA適用(画風特化) +``` + +--- + +## プリセット詳細 + +### **1. Style Focused(画風特化)** + +**SDXL:** `1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1` +**SD1.5:** `1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1` + +**特徴:** +- OUTPUTブロックのみ有効 +- 構図を変えず画風のみ適用 +- 既存の構図を保ちたい場合に最適 + +**用途:** +- 画風LoRA(アニメ風、水彩風など) +- スタイルLoRA +- エフェクトLoRA + +--- + +### **2. Character Focused(キャラ重視)** + +**SDXL:** `1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1` +**SD1.5:** `1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1` + +**特徴:** +- INPUT前半 + MIDDLE + OUTPUT有効 +- キャラクターの特徴を保持 +- バランスの取れた適用 + +**用途:** +- キャラクターLoRA +- 人物LoRA +- コンセプトLoRA + +--- + +### **3. Structure/Composition Only(構造・構図のみ)** + +**SDXL:** `1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0` +**SD1.5:** `1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0` + +**特徴:** +- INPUT + MIDDLEブロックのみ有効 +- 画風を変えず構図のみ変更 +- ポーズや構図調整に最適 + +**用途:** +- ポーズLoRA +- 構図LoRA +- レイアウトLoRA + +--- + +### **4. Balanced / Soft(バランス・穏やか)** + +**SDXL:** `1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0` +**SD1.5:** `1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,0,0` + +**特徴:** +- 全体的に穏やかな適用 +- OUTPUT後半を弱めて過剰適用を防止 +- 自然な仕上がり + +**用途:** +- 汎用LoRA +- 微調整用 +- 複数LoRA併用時 + +--- + +## 使い方 + +### **基本的な使い方** + +1. **ノードを配置** + ``` + [Filtered Random LoRA Loader (LBW)] + ``` + +2. **フォルダとキーワードを設定** + ``` + lora_folder_path: "path/to/loras" + keyword_filter: "anime style" + num_loras: 1 + ``` + +3. **LBWモードを選択** + ``` + weight_mode: "Style Focused" + ``` + +4. **MODEL/CLIPを接続** + ``` + MODEL → [KSampler] + CLIP → [CLIP Text Encode] + ``` + +--- + +### **Direct Inputモード** + +カスタムウェイトを直接入力: + +``` +weight_mode: "Direct Input" +lbw_input: "1,0.5,0.5,0,0,0,0,0,0,0,1,1,1,1,1,1,0.5,0.5,0.5,0.5" +``` + +**ルール:** +- カンマ区切り +- SDXL: 20要素、SD1.5: 17要素 +- 要素数が合わない場合は自動調整 + +--- + +### **Preset: Randomモード** + +毎回異なるプリセットをランダム選択: + +``` +weight_mode: "Preset: Random" +→ 実行ごとに4つのプリセットから1つ選択 +``` + +--- + +## 使用例 + +### **例1: 画風のみ変更** + +``` +[Load Checkpoint] → [Filtered Random LoRA Loader (LBW)] + weight_mode: "Style Focused" + keyword_filter: "anime" + ↓ + [KSampler] +``` + +**結果:** 構図はそのまま、画風のみアニメ風に + +--- + +### **例2: 複数LoRAで段階適用** + +``` +[Load Checkpoint] + ↓ +[Filtered Random LoRA Loader (LBW)] (Structure/Composition Only) + keyword_filter: "pose" + ↓ +[Filtered Random LoRA Loader (LBW)] (Style Focused) + keyword_filter: "watercolor" + ↓ +[KSampler] +``` + +**結果:** ポーズ調整 → 水彩画風適用 + +--- + +### **例3: キャラ + 画風** + +``` +[Load Checkpoint] + ↓ +[Filtered Random LoRA Loader (LBW)] (Character Focused) + keyword_filter: "character_name" + ↓ +[Filtered Random LoRA Loader (LBW)] (Style Focused) + keyword_filter: "art_style" + ↓ +[KSampler] +``` + +**結果:** キャラ特徴保持 + 画風変更 + +--- + +## ヒント・Tips + +### **1. プリセット選択ガイド** + +| LoRAタイプ | 推奨プリセット | +|-----------|--------------| +| 画風・スタイル | Style Focused | +| キャラクター | Character Focused | +| ポーズ・構図 | Structure/Composition Only | +| 汎用・微調整 | Balanced / Soft | + +--- + +### **2. 直列接続のコツ** + +- **構造 → 画風の順**が基本 +- 各ノードで異なるLBW設定可能 +- 強度も個別に調整可能 + +--- + +### **3. ウェイト調整のコツ** + +- **0**: 完全無効 +- **0.5**: 弱め +- **1.0**: 標準 +- **1.5以上**: 強め(過剰に注意) + +--- + +### **4. トラブルシューティング** + +**効果が出ない場合:** +- すべて0になっていないか確認 +- LoRAが正しく読み込まれているか確認 +- コンソールでLBW適用メッセージを確認 + +**効果が強すぎる場合:** +- model_strengthを下げる +- Balanced / Softプリセットを試す +- ウェイトを0.5~0.8に調整 + +--- + +## 自動検出 + +### **SD1.5 / SDXL自動判定** + +ノードは自動的にLoRAタイプを検出: + +``` +SDXL検出 → 20要素ウェイト使用 +SD1.5検出 → 17要素ウェイト使用 +``` + +**ユーザーは何も設定不要** ✨ + +--- + +### **ウェイト数自動調整** + +入力したウェイト数が合わない場合、自動調整: + +``` +入力: 15要素(不足) +検出: SDXL(20要素必要) +→ 末尾に1.0を5個追加 + +入力: 25要素(過剰) +検出: SDXL(20要素必要) +→ 末尾から5個カット +``` + +--- + +## 要件 + +### **⚠️ 対応モデル** +**本ノードはSD1.5とSDXLモデル専用です。** + +- ✅ **対応:** Stable Diffusion 1.5、Stable Diffusion XL(SDXL) +- ❌ **非対応:** Flux、SD3、SDXL Turbo、Pony、その他のアーキテクチャ + +LBW機能は、SD1.5/SDXLのU-Netアーキテクチャ専用に設計されています。他のモデルタイプではLBWが正常に動作しません。 + +--- + +### **依存関係** +- ComfyUI +- Pillow(ComfyUIに含まれる) +- torch(ComfyUIに含まれる) + +### **⚠️ オプション: 動画プレビュー** +**動画ファイルプレビュー(.mp4, .webm, .avi, .mov)にはopencv-pythonが必須です:** +```bash +pip install opencv-python +``` + +**opencv-pythonなしの場合:** +- ✅ 静止画/アニメ画像は動作 +- ❌ 動画ファイルは黒画面 + +--- + +## プレビュー画像 + +以下の形式に対応(優先順位順): + +1. **静止画像**(.png, .jpg, .jpeg) - 常に動作 +2. **アニメ画像**(.gif, .webp) - 1フレーム目、常に動作 +3. **動画ファイル**(.mp4, .webm, .avi, .mov) - 1フレーム目、opencv-python必要 + +**ファイルマッチング:** +- LoRAファイル名で始まるファイル(大文字小文字無視) +- 例: `style_anime.safetensors` にマッチ: + - `style_anime.png` ✅ + - `style_anime_preview.jpg` ✅ + - `STYLE_ANIME.PNG` ✅ + +--- + +## 上級者向け: カスタムプリセット + +独自のプリセットを作成したり、既存のプリセットを変更したい場合は、ソースファイルを直接編集できます。 + +### **編集方法** + +**ファイル位置:** +``` +ComfyUI/custom_nodes/RandomLoRALoader/filtered_random_lora_loader_lbw.py +``` + +**編集箇所:** 29~41行目 + +### **例1: 独自プリセット追加** + +```python +SDXL_PRESETS = { + "Style Focused": "1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1", + "Character Focused": "1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1", + "Structure/Composition Only": "1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0", + "Balanced / Soft": "1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0", + # ↓ 独自プリセット + "My Custom Mix": "0.5,0.5,0.5,0.5,0,0,0,0,0,0,1,0.8,0.8,0.8,0.8,0.8,0.5,0.5,0.5,0.5" +} +``` + +### **例2: 既存プリセット調整** + +```python +SDXL_PRESETS = { + # Style Focusedをより強く + "Style Focused": "1,0,0,0,0,0,0,0,0,0,0,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2,1.2", + + # Character Focusedをマイルドに + "Character Focused": "0.8,0.8,0.8,0.8,0,0,0,0,0,0,0.8,0.8,0.8,0.8,0.8,0.8,0.8,0.8,0.8,0.8", + ... +} +``` + +### **例3: プリセット名変更** + +```python +SDXL_PRESETS = { + "画風特化": "1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1", + "キャラ重視": "1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1", + "構図のみ": "1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0", + ... +} +``` + +### **重要な注意事項** + +⚠️ **編集前に:** +- 元ファイルのバックアップを作成 +- Python構文(カンマ、引用符)に注意 + +⚠️ **ウェイト数:** +- SDXLプリセット: 必ず20要素 +- SD1.5プリセット: 必ず17要素 +- 要素数が合わない場合は自動調整されますが、正確に指定する方が良いです + +⚠️ **編集後:** +- ComfyUIを完全に再起動して変更を適用 +- コンソールで構文エラーを確認 + +💡 **ヒント:** ファイル編集が面倒な場合は、「Direct Input」モードを使ってください! + +--- + +## 更新履歴 + +### v1.2.0(2026-01-13) +- ✅ LoRAブロックウェイト(LBW)対応追加 +- ✅ SD1.5/SDXL自動検出 +- ✅ 4つのプリセットモード+カスタム入力 +- ✅ ウェイト数自動調整 +- ✅ 動画プレビュー対応(.mp4, .webm等) + +### v1.1.0(2026-01-04) +- ✅ Filtered Random LoRA Loader追加 +- ✅ キーワードフィルタリング(AND/ORモード) +- ✅ メタデータ検索対応 +- ✅ プレビュー画像表示 + +### v1.0.0(2025-12-30) +- ✅ 初回リリース +- ✅ Random LoRA Loader(3グループ) + +--- + +## ライセンス + +MIT License + +--- + +## 作者 + +Your Name + +--- + +**ブロックウェイトで精密なLoRA制御を楽しんでください!** 🎨✨ diff --git a/README_ja.md b/README_ja.md index 0b3e7ef..3746653 100644 --- a/README_ja.md +++ b/README_ja.md @@ -2,13 +2,26 @@ **[English README](./README.md) | 日本語版** -ComfyUIでLoRAをランダムに選択・適用するカスタムノードパッケージです。2つのノードを含みます: +ComfyUIでLoRAをランダムに選択・適用するカスタムノードパッケージです。3つのノードを含みます: 1. **Random LoRA Loader** - 3フォルダから同時選択 -2. **Filtered Random LoRA Loader** - 1フォルダ + キーワードフィルタ(新機能 v1.1.0) +2. **Filtered Random LoRA Loader** - 1フォルダ + キーワードフィルタ +3. **Filtered Random LoRA Loader (LBW)** - 🆕 LBW対応 + SD1.5/SDXL自動検出(v1.2.0新機能) -![RandomLoRAloderワークフロー例](./images/RLL_final_single.webp) -![FilteredRandomLoRAloderワークフロー例](./images/filterd_final_single.webp) +![RandomLoRALoaderワークフロー例](./images/RLL_final_single.webp) +![FilteredRandomLoRALoaderワークフロー例](./images/filterd_final_single.webp) +![FilteredRandomLoRALoader(LBW)ワークフロー例](./images/lbw_final_single.webp) + +--- + +## ⚠️ 重要: 対応モデル + +**本ノードはSD1.5とSDXLモデル専用です。** + +- ✅ **対応:** Stable Diffusion 1.5、Stable Diffusion XL(SDXL) +- ❌ **非対応:** Flux、SD3、SDXL Turbo、Pony、その他のアーキテクチャ + +LBWノードのブロックウェイト機能は、SD1.5/SDXLのU-Netアーキテクチャ専用に設計されています。他のモデルタイプではLBWが正常に動作しません。 --- @@ -23,7 +36,7 @@ ComfyUIでLoRAをランダムに選択・適用するカスタムノードパッ - 固定的なLoRAカテゴリ - シンプルなフォルダベースのワークフロー -### Filtered Random LoRA Loader(新機能) +### Filtered Random LoRA Loader 1つのフォルダからキーワードフィルタで選択。動的な選択と大規模コレクションに最適。 @@ -33,116 +46,190 @@ ComfyUIでLoRAをランダムに選択・適用するカスタムノードパッ - メタデータ検索機能 - 複数インスタンスの直列接続を推奨 +### Filtered Random LoRA Loader (LBW) 🆕 v1.2.0新機能 + +LoRAブロックウェイト(LBW)対応の高度なノード。精密な効果コントロールが可能。 + +**用途:** +- 画風と構造の分離制御 +- 精密なLoRA適用 +- プロフェッショナルワークフロー +- 4つのプリセットモード + カスタム入力 + +**詳細は [README_LBW_ja.md](README_LBW_ja.md) を参照してください。** + --- -## 主な機能(両ノード共通) +## 主な機能 + +### 共通機能(全ノード) -- **3グループ対応**: 最大3つの異なるフォルダからLoRAを選択可能 - **マルチソースメタデータ読み取り**: 優先順位に従ってトリガーワードと作例プロンプトを自動取得 1. `.metadata.json`形式(ComfyUI Lora Manager)- 優先度1 2. `.info`形式(Civitai Helper)- 優先度2 - 3. **LoRA本体ファイルの埋め込みメタデータ** - 優先度3(新機能) -- **強度ランダム化**: 範囲指定で強度をランダムに変化(例: `0.4-0.8`) + 3. **LoRA本体ファイルの埋め込みメタデータ** - 優先度3 +- **強度ランダム化**: + - **マイナス値対応の範囲指定**: `0.4-0.8`、`-0.8--0.3`(v1.2.0) + - **範囲指定は0.1刻み**: 効果の違いを確認しやすい + - **固定値は小数点2桁に丸め**: `0.847` → `0.85` - **柔軟なトリガーワード取得**: - `json_combined`: 全トリガーワードパターンを結合(重複除去) - `json_random`: ランダムに1パターン選択 - `json_sample_prompt`: 作例プロンプトをランダムに取得 - - **`metadata`**: 埋め込みメタデータから直接読み込み(新機能) -- **作例プロンプトの最適化**: 作例内のLoRA記述を自動削除し、ノード設定の強度を適用 -- **2つのテキスト出力**: positive_textとnegative_textを個別に出力 -- **ComfyUI標準のseed制御**: fixed/randomize/increment/decrementに対応 + - `metadata`: 埋め込みメタデータから直接読み込み +- **作例プロンプト最適化**: LoRA構文を自動除去し、ノード設定の強度を適用 +- **デュアルテキスト出力**: positive_textとnegative_textを分離出力 +- **ComfyUI標準シード制御**: 固定/ランダム/増分/減分に対応 +- **Wildcard Encode統合**: Wildcard Encode(Inspire)とシームレスに連携 +- **LoRA構文自動除去**: additional_prompt内のLoRA構文を自動削除 +- **プレビュー画像対応**: 選択されたLoRAのプレビュー画像/動画を表示(v1.1.0) +- **重複ファイル名処理**: サブフォルダ間の重複ファイル名を除外(v1.1.0) + +### Filteredノード(Filtered & LBW) + +- **キーワードフィルタリング**: スペース区切りキーワード、フレーズ対応 +- **AND/ORモード**: 柔軟なフィルタリングロジック +- **メタデータ検索**: ファイル名または埋め込みメタデータから検索 +- **高速キャッシング**: 初回読み込み後は即座にアクセス + +### LBWノード限定 🆕 + +- **LoRAブロックウェイト対応**: 影響を受けるU-Netブロックを制御 +- **SD1.5/SDXL自動検出**: 手動でモデルタイプを選択不要 +- **4つのプリセットモード**: + - Style Focused - OUTPUTブロックのみ + - Character Focused - バランスの取れたIN+MID+OUT + - Structure/Composition Only - INPUT+MIDブロックのみ + - Balanced / Soft - 穏やかな適用 +- **Preset: Randomモード**: 4つのプリセットからランダム選択 +- **Direct Inputモード**: カスタムウェイト指定 +- **ウェイト数自動調整**: 要素数の不一致を自動処理 + +--- ## インストール -### 必要な環境 +### ⚠️ オプション: 動画プレビュー対応 -- ComfyUI(動作確認済み環境があれば、そのまま使えます) -- **追加ライブラリのインストール: 不要** ✅ +**動画ファイルプレビュー(.mp4, .webm, .avi, .mov)にはopencv-pythonが必須です:** -### 手順 +```bash +pip install opencv-python +``` + +**opencv-pythonなしの場合:** +- ✅ 静止画(.png, .jpg, .jpeg)は動作 +- ✅ アニメ画像(.gif, .webp)は動作 +- ❌ **動画ファイルは黒画面表示**(コンソールに警告メッセージ) + +opencv-pythonの有無に関わらず、LoRA機能は正常に動作します。影響を受けるのはプレビュー表示のみです。 + +### 必要要件 + +- ComfyUI(標準インストールで動作) +- Python 3.9+ +- **コア依存関係はComfyUIに含まれる** ✅ + +### インストール手順 ```bash cd ComfyUI/custom_nodes -git clone https://github.com/your-repo/RandomLoRALoader.git -# または -# 手動でRandomLoRALoaderフォルダを作成し、ファイルをコピー +git clone https://github.com/YOUR_USERNAME/RandomLoRALoader.git +# または手動でRandomLoRALoaderフォルダを作成してファイルをコピー ``` -ComfyUIを再起動してください。 +ComfyUIを再起動。 -**注意:** Python標準ライブラリとComfyUI付属ライブラリのみ使用しているため、`pip install`などの追加インストールは一切不要です。 +**注意:** コア機能にはPython標準ライブラリとComfyUIバンドルライブラリのみを使用。opencv-pythonは動画プレビューのみのオプション。 + +### アンインストール + +```bash +# custom_nodesフォルダに移動 +cd ComfyUI/custom_nodes + +# RandomLoRALoaderフォルダを削除 +rm -rf RandomLoRALoader + +# Windowsの場合 +rmdir /s RandomLoRALoader +``` + +またはRandomLoRALoaderフォルダを手動で削除してComfyUIを再起動。 + +--- ## 使い方 -### 基本的な使用方法 +### 基本的な使い方(Random LoRA Loader) -1. **ノードを配置**: ノードブラウザから「Random LoRA Loader」を検索して配置 -2. **MODEL/CLIPを接続**: ベースモデルとCLIPを入力に接続 -3. **フォルダパスを設定**: - - グループ1: スタイル用LoRAフォルダのパス - - グループ2: キャラクター用LoRAフォルダのパス(オプション) - - グループ3: コンセプト用LoRAフォルダのパス(オプション) -4. **各グループの設定**: - - `num_loras`: 各グループから選択するLoRA個数 - - `model_strength` / `clip_strength`: 適用強度(固定値またはランダム範囲) -5. **出力を接続**: - - `MODEL` / `CLIP`: KSamplerなどに接続 +1. **ノード追加**: ノードブラウザで「Random LoRA Loader」を検索 +2. **MODEL/CLIP接続**: ベースモデルとCLIPを入力に接続 +3. **フォルダパス設定**: + - グループ1: スタイルLoRAフォルダパス + - グループ2: キャラクターLoRAフォルダパス(オプション) + - グループ3: コンセプトLoRAフォルダパス(オプション) +4. **各グループ設定**: + - `num_loras`: 各グループから選択するLoRA数 + - `model_strength` / `clip_strength`: 適用強度(固定値または範囲指定) +5. **出力接続**: + - `MODEL` / `CLIP`: KSamplerに接続 - `positive` / `negative`: Set ConditioningまたはKSamplerに接続 - - `positive_text` / `negative_text`: Show Textノードで確認(推奨) + - `positive_text` / `negative_text`: Show Textに接続して確認(推奨) -### Wildcard Encode (Inspire)との連携(推奨ワークフロー) +### Wildcard Encode連携(推奨) -このノードはWildcard Encode (Inspire)と組み合わせることで、wildcardによる動的プロンプト生成とランダムLoRA選択の両方を実現できます。 +このノードはWildcard Encode(Inspire)とシームレスに連携し、動的プロンプト生成とランダムLoRA選択を組み合わせます。 -![Wildcard Encode+RandomLoRALoderワークフロー](./images/RLL_final_wce.webp) +![Wildcard Encode + Random LoRA Loader ワークフロー](./images/RLL_final_wce.webp) -#### 推奨接続例 +#### 推奨接続方法 ``` [Wildcard Encode (Inspire)] text: "__style__, {red|blue|green}, " ↓ ├─ populated_text ──→ [Random LoRA Loader] - │ additional_prompt + │ additional_prompt_positive └─ MODEL/CLIP ──────→ model/clip入力 [Random LoRA Loader] - フォルダ1: character用LoRA - フォルダ2: concept用LoRA + フォルダ1: キャラクターLoRA + フォルダ2: コンセプトLoRA ↓ MODEL/CLIP/CONDITIONING → [KSampler] ``` -#### 動作の流れ +#### 動作の仕組み -1. **Wildcard Encodeの処理**: - - wildcard展開: `__style__` → "anime style" +1. **Wildcard Encode処理**: + - ワイルドカード展開: `__style__` → "anime style" - 選択肢展開: `{red|blue|green}` → "blue" - LoRA構文処理: `` → MODELに適用 - 結果: `populated_text` = "anime style, blue, " -2. **Random LoRA Loaderの処理**: - - `populated_text`から**LoRA構文を自動削除**: "anime style, blue" +2. **Random LoRA Loader処理**: + - **LoRA構文を自動除去**: `populated_text`から → "anime style, blue" - ランダムLoRA選択: character_alice, concept_magic - 最終プロンプト: "anime style, blue, alice, blonde hair, magic circle" - - MODEL/CLIP: base_effect + character_alice + concept_magic(全て適用済み) + - MODEL/CLIP: base_effect + character_alice + concept_magic(全て適用) #### メリット -- ✅ wildcard機能をWildcard Encodeに任せる(専門ツールの利用) -- ✅ ランダムLoRA選択をこのノードに任せる(シンプルな設定) -- ✅ プロンプト情報が完全に引き継がれる -- ✅ LoRA構文が自動クリーンアップされる(ノイズなし) +- ✅ ワイルドカード機能はWildcard Encodeに委任(専門ツール) +- ✅ ランダムLoRA選択はこのノードに委任(シンプル設定) +- ✅ プロンプト情報を完全に継承 +- ✅ LoRA構文を自動クリーンアップ(ノイズなし) -### 3グループの活用例 +### 3グループの例 ``` -グループ1: style用LoRAフォルダ +グループ1: スタイルLoRA - num_loras_1: 2 - - model_strength_1: "0.6-0.9" ← ランダム - - clip_strength_1: "0.6-0.9" ← ランダム + - model_strength_1: "0.6-0.9" ← ランダム(0.1刻み) + - clip_strength_1: "0.6-0.9" ← ランダム(0.1刻み) -グループ2: character用LoRAフォルダ +グループ2: キャラクターLoRA - num_loras_2: 1 - model_strength_2: "1.0" ← 固定 - clip_strength_2: "1.0" ← 固定 @@ -151,891 +238,912 @@ ComfyUIを再起動してください。 - lora_folder_path_3: (空) - num_loras_3: 0 -→ 結果: style 2個(可変強度)+ character 1個(固定強度)= 合計3個のLoRAが適用 +→ 結果: スタイルLoRA 2個(可変強度) + キャラクターLoRA 1個(固定強度) = 合計3個 ``` -## 設定項目 +--- + +## 設定 ### 共通設定 -| 項目 | 説明 | デフォルト | -|------|------|------------| -| `token_normalization` | トークン正規化方式 | `none` | -| `weight_interpretation` | プロンプト強調記法の解釈方式 | `A1111` | -| `additional_prompt` | 追加プロンプト(全LoRAのトリガーワードと結合) | (空) | -| `trigger_word_source` | トリガーワード取得元 | `json_combined` | -| `seed` | ランダム選択のシード値 | `0` | +| 設定項目 | 説明 | デフォルト | +|---------|------|-----------| +| `token_normalization` | トークン正規化方法 | `none` | +| `weight_interpretation` | プロンプト強調記法の解釈 | `A1111` | +| `additional_prompt_positive` | 追加ポジティブプロンプト(トリガーワードと結合) | (空) | +| `additional_prompt_negative` | 追加ネガティブプロンプト | (空) | +| `trigger_word_source` | トリガーワードソース | `json_combined` | +| `seed` | ランダム選択シード | `0` | -#### additional_promptに関する重要な注意事項 +#### additional_promptに関する重要な注意 -`additional_prompt`欄の動作仕様: - -**✅ 対応している:** +**対応:** - 通常のプロンプトテキスト -- 他ノードからのテキスト入力接続(例: Wildcard Encodeの`populated_text`) +- 他ノードからのテキスト入力(例: Wildcard Encodeの`populated_text`) -**❌ 対応していない(自動削除されます):** +**非対応(自動除去):** - `` 形式のLoRA構文 -- `{a|b|c}` 形式のwildcard構文 -- `__filename__` 形式のwildcard構文 +- `{a|b|c}` 形式のワイルドカード構文 +- `__filename__` 形式のワイルドカード構文 **理由:** -- このノードはフォルダ指定によるLoRA適用を行います -- wildcard機能は専用ノード(Wildcard Encode等)に任せる設計です -- LoRA構文を記述しても解釈されず、**ファイル名が意味のあるトークンとしてノイズになります** +- このノードはフォルダ指定でLoRAを適用 +- ワイルドカード機能は専用ノード(Wildcard Encodeなど)が処理すべき +- LoRA構文を書くと**ファイル名が意味のあるトークンとしてノイズになる** **例(問題のあるケース):** ``` 入力: "1girl, , beautiful" ↓ -CLIPのトークン化: [1girl, lora, anime, style, 0, 8, beautiful] - ^^^^^ ^^^^^ - 意図しない単語がプロンプトに追加される ❌ +CLIPトークン化: [1girl, lora, anime, style, 0, 8, beautiful] + ^^^^^ ^^^^^ + 意図しない単語がプロンプトに追加 ❌ ``` **正しい使い方:** ``` -additional_prompt: "1girl, beautiful" ← LoRA構文なし ✅ +additional_prompt_positive: "1girl, beautiful" ← LoRA構文なし ✅ LoRA適用: フォルダ指定機能を使用 ✅ ``` -または、Wildcard Encodeからの接続時は自動的にLoRA構文が削除されます: +または、Wildcard Encodeから接続する場合、LoRA構文は自動除去されます: ``` [Wildcard Encode] populated_text: "1girl, , beautiful" ↓ -[このノード] additional_prompt受信 → LoRA構文自動削除 +[このノード] additional_prompt_positive受信 → LoRA構文自動除去 ↓ 最終プロンプト: "1girl, beautiful" ✅ ``` -### グループ設定(1〜3) +### グループ設定(1-3) -各グループで以下の項目を個別に設定可能: +各グループを個別に設定可能: -| 項目 | 説明 | デフォルト | -|------|------|------------| +| 設定項目 | 説明 | デフォルト | +|---------|------|-----------| | `lora_folder_path_X` | LoRAフォルダの絶対パス | (空) | -| `include_subfolders_X` | サブフォルダを含めるか | `true` | +| `include_subfolders_X` | サブフォルダを含める | `true` | | `unique_by_filename_X` | 重複ファイル名を除外 | `true` | -| `model_strength_X` | MODELへの適用強度 | `"1.0"` | -| `clip_strength_X` | CLIPへの適用強度 | `"1.0"` | -| `num_loras_X` | 選択するLoRA個数 | グループ1: `1`, グループ2/3: `0` | - -## 強度の指定方法(重要) - -強度欄には**固定値**または**ランダム範囲**を指定できます。 - -### 固定値の場合 - -``` -入力: "1.0" -→ 常に 1.0 で適用 - -入力: "0.55" -→ 常に 0.55 で適用 - -入力: "0.8" -→ 常に 0.8 で適用 -``` - -**特徴:** -- 入力した数値がそのまま使用されます -- 小数第2位まで指定可能(例: `0.55`) - -### ランダム範囲の場合 - -``` -入力: "0.4-0.8" -→ 0.4, 0.5, 0.6, 0.7, 0.8 からランダムに選択(0.1刻み) - -入力: "0.5-1.0" -→ 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 からランダムに選択 - -入力: "0.44-0.82" -→ 0.4, 0.5, 0.6, 0.7, 0.8 からランダムに選択 - (範囲は自動的に小数第1位に丸められます) -``` - -**特徴:** -- ハイフン(`-`)で範囲を指定 -- 0.1刻みで値が生成されます -- 範囲の上限・下限が小数第2位以下の場合、小数第1位に丸められます -- 毎回実行するたびに異なる値が選ばれます - -### エラー処理 - -``` -入力: "abc" または不正な形式 -→ エラーログが出力され、強度 1.0 で処理されます -``` - -**エラーメッセージ例:** -``` -[RandomLoRALoader] ❌ 強度 'abc' を解析できません、1.0を使用 -[RandomLoRALoader] 💡 使用例: '1.0' または '0.4-0.8' -``` - -### 実際の強度確認 - -実際に使用された強度は `positive_text` 出力で確認できます: - -``` -, anime style, vibrant, - ↑ ↑ - MODEL強度 CLIP強度 -``` - -**推奨:** Show Textノードを `positive_text` に接続して、実際の強度を確認してください。 - -## トリガーワード取得方式 - -### json_combined(全結合) - -全トリガーワードパターンを結合し、重複を除去します。 - -**例:** -```json -"trainedWords": [ - "character, red hair, blue eyes, uniform", - "character, red hair, blue eyes, casual clothes" -] -``` -↓ -``` -出力: character, red hair, blue eyes, uniform, casual clothes -``` - -### json_random(ランダム選択) - -トリガーワードパターンからランダムに1つを選択します。 - -**例:** -```json -"trainedWords": [ - "character, red hair, blue eyes, uniform", - "character, red hair, blue eyes, casual clothes" -] -``` -↓ -``` -出力: character, red hair, blue eyes, casual clothes (ランダム) -``` - -### json_sample_prompt(作例取得) - -JSONの作例プロンプトからランダムに1つ取得します。 - -- positive_textとnegative_textの両方が出力されます -- 作例内の``記述は自動削除されます -- ノード設定の強度で新しいLoRA記述が生成されます - -**例:** -```json -"images": [{ - "meta": { - "prompt": "1girl, , beautiful", - "negativePrompt": "bad quality, worst quality" - } -}] -``` -↓ -``` -positive_text: 1girl, beautiful (LoRA記述削除済み) -negative_text: bad quality, worst quality -``` - -### metadata(埋め込みメタデータのみ - 新機能) - -外部の`.metadata.json`や`.info`ファイルを無視して、**LoRA本体ファイルの埋め込みメタデータから直接**トリガーワードを読み込みます。 - -**対応メタデータフィールド:** -- `ss_tag_frequency`: kohya_ss形式のタグ頻度(上位20個を抽出) -- `modelspec.trigger_word`: トリガーワード -- `ss_output_name`: モデル名 - -**使用例:** -- LoRA作成者が埋め込んだメタデータのみを使用したい場合 -- 外部JSONファイルに誤った情報が含まれている場合 -- 外部メタデータファイルがないLoRAを使用する場合 - -**例:** -``` -LoRAファイルに埋め込まれたメタデータ: - ss_tag_frequency: {"dataset1": {"alice": 150, "blonde": 120, ...}} - ↓ -出力: alice, blonde, blue_eyes, ... -``` - -**注意:** 他のモード(`json_combined`、`json_random`、`json_sample_prompt`)は外部ファイルを優先し、見つからない場合のみ埋め込みメタデータにフォールバックします。 - -## 出力 - -| 出力名 | 型 | 説明 | -|--------|-----|------| -| `MODEL` | MODEL | LoRA適用後のモデル | -| `CLIP` | CLIP | LoRA適用後のCLIP | -| `positive_text` | STRING | LoRA情報とpositiveプロンプト | -| `negative_text` | STRING | negativeプロンプト(json_sample_promptのみ) | -| `positive` | CONDITIONING | positiveコンディショニング | -| `negative` | CONDITIONING | negativeコンディショニング | - -### positive_text出力例 - -``` -1girl, beautiful, -, anime style, vibrant colors, -, alice, blonde hair, blue eyes, -``` - -## 必要なファイル構成 - -**トリガーワード取得のため、メタデータファイルまたは埋め込みデータが必要です。** - -### 優先順位 - -ノードは以下の優先順位でメタデータを読み込みます: - -1. **`.metadata.json`**(ComfyUI Lora Manager形式) -2. **`.info`**(Civitai Helper形式) -3. **LoRA本体ファイルの埋め込みメタデータ**(LoRAが学習時にメタデータを含んでいれば常に利用可能) - -### 1. ComfyUI Lora Manager形式(推奨) - -``` -/path/to/lora/ -├── style_anime_v2.safetensors -├── style_anime_v2.metadata.json ← ComfyUI Lora Manager -├── character_alice.safetensors -└── character_alice.metadata.json -``` - -### 2. Civitai Helper形式 - -``` -/path/to/lora/ -├── style_anime_v2.safetensors -├── style_anime_v2.info ← Civitai Helper -├── character_alice.safetensors -└── character_alice.info -``` - -### 3. 埋め込みメタデータ(外部ファイル不要) - -``` -/path/to/lora/ -├── style_anime_v2.safetensors ← 埋め込みメタデータを含む -└── character_alice.safetensors ← 埋め込みメタデータを含む -``` - -**注意:** -- 外部ファイル(`.metadata.json`または`.info`)が存在する場合、埋め込みメタデータより優先されます(`trigger_word_source: metadata`を使用する場合を除く) -- `trigger_word_source`を`metadata`に設定すると、外部ファイルを無視して埋め込みメタデータのみを読み込みます - -### メタデータファイルの生成方法 - -**ComfyUI Lora Manager(推奨):** -- [ComfyUI Lora Manager](https://github.com/willmiao/ComfyUI-Lora-Manager) -- `.metadata.json`ファイルを生成 - -**Civitai Helper:** -- [Civitai Helper](https://github.com/butaixianran/Stable-Diffusion-Webui-Civitai-Helper) -- `.info`ファイルを生成(こちらにも対応) - -**埋め込みメタデータ:** -- kohya_ssなどのLoRA学習ツールで自動的に作成されます -- 追加のツールは不要です - -## MODEL強度とCLIP強度について - -### 基本的な考え方 - -- **MODEL強度**: 画像そのものへの影響(画風、構図、色彩) -- **CLIP強度**: プロンプト理解への影響(トリガーワードの効き方) - -### 推奨設定 - -**初心者・一般的な使用:** -``` -model_strength: "1.0" -clip_strength: "1.0" -``` -両方同じ値にするのが基本です。 - -**上級者・微調整:** -``` -model_strength: "0.7" -clip_strength: "1.0" -``` -画風は控えめに、トリガーワードはしっかり効かせたい場合など。 - -**ランダム化で実験:** -``` -model_strength: "0.6-0.9" -clip_strength: "0.6-0.9" -``` -様々な強度の組み合わせを試したい場合。 - -## Token Normalization - -複数のプロンプトを結合する際のバランス調整: - -- **none**: トークン数が多いほど影響力大 -- **mean**: 平均値で正規化 -- **length**: 長さで正規化 -- **length+mean**: 両方を組み合わせ - -## Weight Interpretation - -プロンプト内の強調記法の解釈方式: - -- **comfy**: ComfyUI方式(絶対値、強調されすぎになりやすい) -- **A1111**: Automatic1111方式(正規化、バランス良い)← 推奨 -- **compel**: Compel方式 -- **comfy++**: ComfyUI拡張方式 -- **down_weight**: 減衰方式 - -## Seed制御 - -ComfyUIの標準`control_before_generate`機能に対応: - -- **fixed**: 固定seed(常に同じLoRAを選択、同じ強度) -- **randomize**: 毎回ランダム -- **increment**: 実行ごとに+1 -- **decrement**: 実行ごとに-1 - -## 技術的な詳細 - -### LoRA適用の仕組み - -1. 各グループからLoRAをランダム選択(全グループ共通seed) -2. 各LoRAに対して強度をパース(固定値またはランダム範囲から選択) -3. 選択されたLoRAを順次MODELとCLIPに適用 -4. トリガーワードを取得 -5. 全グループのトリガーワードを結合してCONDITIONINGを生成 - -### 強度ランダム化の仕組み - -```python -# 入力: "0.4-0.8" -# 処理: -1. 範囲を解析: min=0.4, max=0.8 -2. 0.1刻みのリスト生成: [0.4, 0.5, 0.6, 0.7, 0.8] -3. ランダムに1つ選択: 例えば 0.6 -4. MODEL/CLIPに適用 -``` - -**重要:** MODEL強度とCLIP強度は**独立してランダム選択**されます。 -- `model_strength: "0.4-0.8"`, `clip_strength: "0.4-0.8"` の場合 -- MODELが0.6、CLIPが0.7のように**異なる値**になる可能性があります - -### 重複選択について - -- 各グループ内では同じLoRAの重複選択なし -- 指定個数 > ファイル数の場合、全選択後に再選択で不足分を埋める - -### エラー処理 - -- フォルダパス空またはnum_loras=0: スキップ(エラーなし) -- 全グループ空: 空テキスト出力(エラーなし) -- JSONファイル未発見: 空文字列を返す(ログ出力) -- 強度パースエラー: 1.0で処理(ログ出力) - -## トラブルシューティング - -### additional_promptにLoRA構文を書いたのに効かない - -**症状:** -``` -additional_prompt: ", 1girl" -→ anime_styleが適用されない -``` - -**原因:** -このノードは``構文を解釈しません。LoRA構文は自動的に削除されます。 - -**対策:** -1. LoRA適用はフォルダ指定機能を使用してください -2. Wildcard Encode (Inspire)と連携する場合は、そちらでLoRA構文を処理してください - -### プロンプトに意図しない単語が含まれる - -**症状:** -``` -additional_prompt: "" -→ "anime", "style"という単語が勝手に追加される -``` - -**原因:** -v1.0.0以降では自動的にLoRA構文が削除されるため、この問題は発生しません。 -古いバージョンを使用している場合は、LoRA構文のファイル名部分がトークンとして解釈されていました。 - -**対策:** -- ノードを最新版に更新してください -- additional_promptにはLoRA構文を書かないでください - -### トリガーワードが取得できない - -**外部メタデータファイルの場合:** -- メタデータファイルが存在するか確認(`.metadata.json`または`.info`) -- JSONファイル内に`civitai.trainedWords`または`civitai.images`が存在するか確認 -- ファイル名が`{LoRAファイル名}.metadata.json`または`{LoRAファイル名}.info`と一致しているか確認 - -**埋め込みメタデータの場合:** -- `trigger_word_source`を`metadata`に設定してLoRAファイルから直接読み込む -- LoRAが学習時にメタデータを含んでいるか確認(最近のLoRAはほぼ含んでいます) -- 対応フィールド: `ss_tag_frequency`、`modelspec.trigger_word`、`ss_output_name` - -### LoRAが適用されない - -- フォルダパスが正しいか確認 -- `num_loras`が0になっていないか確認 -- ComfyUIのコンソールでエラーログを確認 - -### 強度が意図した値にならない - -- `positive_text`出力をShow Textで確認 -- ``のように実際の強度が表示されます -- ランダム範囲指定の場合、毎回異なる値になります -- コンソールで強度選択のログを確認: `[RandomLoRALoader] 強度範囲 0.4-0.8 から 0.6 を選択` - -### 強度入力でエラーが出る - -**症状:** -``` -[RandomLoRALoader] ❌ 強度 'abc' を解析できません、1.0を使用 -``` - -**対策:** -- 正しい形式で入力: `"1.0"` または `"0.4-0.8"` -- 範囲指定は必ずハイフン(`-`)で区切る -- 不正な入力でもノードはクラッシュせず、1.0で動作します - -### 初期値が表示されない - -- ComfyUIを完全に再起動 -- ブラウザのキャッシュをクリア(Ctrl+Shift+R) -- ノードを削除して新規配置 - -### コンソールに「lora key not loaded」メッセージが大量に出る - -**症状:** -``` -lora key not loaded: lora_unet_input_blocks_4_1_proj_in.alpha -lora key not loaded: lora_unet_input_blocks_4_1_proj_in.lora_down.weight -... -``` - -**原因と対策:** - -このメッセージはComfyUI本体が出力する互換性警告で、**機能には影響ありません**。LoRAファイルに含まれる一部のキーが現在のモデルと互換性がない場合に表示されますが、互換性のあるキーだけが正常に適用されます。 - -v1.0.0以降では、これらの警告メッセージを自動的に抑制するようになっています。もし大量に表示される場合は: - -1. ノードファイルが最新版か確認 -2. ComfyUIを再起動 -3. それでも表示される場合は、機能に問題がなければ無視して構いません - -## ライセンス - -MIT License - -## 更新履歴 - -### v1.0.0 (2024-12-30) -- 初回公開リリース -- 3グループ対応(異なるフォルダから選択可能) -- 強度ランダム化機能(範囲指定: `0.4-0.8`) -- 外部JSON読み取り(Civitai Helper対応) -- 作例プロンプト内のLoRA記述自動削除 -- **additional_prompt内のLoRA構文自動削除**(ノイズ防止) -- positive_text/negative_textの個別出力 -- Wildcard Encode (Inspire)との連携対応 -- 完全ローカル動作(API不要) - -## Tips & Tricks - -### Random LoRA Loader: LoRA構文フィルタとしての使用 - -LoRAを適用せず、単純にLoRA構文削除フィルタとしてこのノードを使用できます。 - -**設定:** -- 全グループの`num_loras`を`0`に設定(または全フォルダパスを空にする) -- Wildcard Encodeの`populated_text`を`additional_prompt`に接続 -- `positive_text`出力を次のノードに接続 - -**使用例:** -- Wildcard Encode出力からLoRA構文を削除 -- 他のノードに渡す前にプロンプトをクリーンアップ -- Wildcard EncodeのLoRA処理を使いつつ、互換性のために構文を削除 - -**ワークフロー例:** -``` -[Wildcard Encode (Inspire)] - text: "__style__, {red|blue|green}, " - ↓ - populated_text: "anime style, blue, " - (LoRAはWildcard EncodeによりMODELに適用済み) - ↓ -[Random LoRA Loader] - num_loras: 0, 0, 0 ← LoRA適用なし - additional_prompt ← populated_textから接続 - ↓ - positive_text: "anime style, blue," ← LoRA構文削除済み ✅ - ↓ -[次のノード] -``` - -**メリット:** -- ✅ ``構文がノイズトークンになるのを防止 -- ✅ 別途テキスト処理ノードが不要 -- ✅ LoRA構文を含むあらゆるテキストに対応 +| `model_strength_X` | MODEL適用強度 | `"1.0"` | +| `clip_strength_X` | CLIP適用強度 | `"1.0"` | +| `num_loras_X` | 選択するLoRA数 | グループ1: `1`、グループ2/3: `0` | --- -## Filtered Random LoRA Loader(新機能 v1.1.0) +## 強度指定(重要) -![FilteredRandomLoRALoder x1ワークフロー](./images/filterd_final_single.webp) +強度フィールドは**固定値**または**範囲指定**を受け付けます。**マイナス値にも対応**しています。 -### 概要 +### 固定値 -キーワードフィルタ機能を持つ単一グループLoRAローダー。複数インスタンスの直列接続を想定した設計。 +``` +入力: "1.0" +→ 常に1.0で適用 -**Random LoRA Loaderとの違い:** -- フォルダパスは1つ(3つではない) -- キーワードフィルタリング(AND/ORモード) -- メタデータ検索機能(キャッシュ付き) -- プロンプト入力が2つ(positive/negative) -- 直列接続を推奨 +入力: "0.55" +→ 0.55に丸められる(小数点2桁) + +入力: "-0.5" +→ マイナスLoRAとして-0.5で適用 ✅(v1.2.0) +``` + +### 範囲指定 + +**フォーマット:** `最小値-最大値` + +``` +入力: "0.6-0.9" +→ [0.6, 0.7, 0.8, 0.9] からランダム選択(0.1刻み) + +入力: "-0.8--0.3" +→ [-0.8, -0.7, -0.6, -0.5, -0.4, -0.3] からランダム選択 ✅(v1.2.0) + +入力: "-0.5-0.5" +→ [-0.5, -0.4, ..., 0.4, 0.5] からランダム選択 ✅ +``` + +**v1.2.0の改善:** +- ✅ **マイナス範囲対応**: `-0.8--0.3` が正しく動作 +- ✅ **全範囲で0.1刻み**: 効果の違いを確認しやすい +- ✅ **固定値は小数点2桁に丸め**: `0.847` → `0.85` + +### 動作 + +**全ノード:** +- 範囲: 0.1刻みリスト → ランダム選択 +- 固定: 小数点2桁に丸め + +**例:** +``` +model_strength_1: "0.6-0.9" +→ 各実行時に [0.6, 0.7, 0.8, 0.9] からランダム選択 +→ コンソール: "[RandomLoRALoader] Selected strength: 0.7" +``` + +--- + +## MODEL強度 vs CLIP強度 + +### MODEL強度 +- **影響範囲**: 画像そのもの(画風、構図、色、形) +- **効果**: 生成画像の視覚的特徴 +- **例**: + - 高い値: 強い画風転送 + - 低い値: 微妙な画風ヒント + +### CLIP強度 +- **影響範囲**: プロンプト解釈(概念理解、言語-画像関連付け) +- **効果**: モデルがプロンプト指示にどれだけ従うか +- **例**: + - 高い値: トリガーワードからの強いセマンティックガイダンス + - 低い値: 弱いセマンティック影響 + +### 推奨設定 + +**ほとんどのユースケース:** +``` +model_strength: 0.8 +clip_strength: 0.8 +→ バランスの取れた適用 +``` + +**微妙な画風適用:** +``` +model_strength: 0.4-0.6 +clip_strength: 0.8-1.0 +→ 軽い視覚効果、強いセマンティックガイダンス +``` + +**強い画風上書き:** +``` +model_strength: 1.0-1.2 +clip_strength: 0.6-0.8 +→ 強い視覚効果、中程度のセマンティックガイダンス +``` + +--- + +## トリガーワード取得方法 + +### json_combined(デフォルト) + +JSONメタデータから全トリガーワードパターンを結合。 + +**ソース:** +1. `activation text`フィールド +2. `ss_tag_frequency`キー(上位3つ) +3. `modelspec.description`キーワード +4. `ss_output_name`キーワード + +**例:** +```json +{ + "activation text": "anime style, detailed eyes", + "ss_tag_frequency": { + "1girl": 500, + "blue eyes": 300, + "long hair": 250 + } +} +``` +**結果:** `"anime style, detailed eyes, 1girl, blue eyes, long hair"` + +--- + +### json_random + +1つのトリガーワードパターンをランダムに選択。 + +**例:** +``` +候補: +- "anime style, detailed eyes" +- "1girl, blue eyes, long hair" +- "anime, girl, portrait" + +ランダム選択: "1girl, blue eyes, long hair" +``` + +--- + +### json_sample_prompt + +JSONメタデータから作例プロンプトを取得。 + +**ソースフィールド(優先順位順):** +1. `sample_prompts` +2. `civitai.images[0].meta.prompt` + +**処理:** +- LoRA構文(``)を自動除去 +- ノード設定の強度に置き換え +- ネガティブプロンプトも抽出(可能な場合) + +**例:** +```json +{ + "sample_prompts": "1girl, , beautiful, detailed eyes" +} +``` +**結果:** `"1girl, beautiful, detailed eyes"`(LoRA構文除去) + +--- + +### metadata + +埋め込みLoRAファイルメタデータから直接トリガーワードを読み込み。 + +**ソース:** +- Safetensorsメタデータキー +- json_combinedと同様だがLoRAファイルから直接読み込み + +**使用時:** +- 外部JSONファイルがない場合 +- オリジナルのトレーニングメタデータを使用したい場合 + +--- + +## 出力 + +全ノードは以下の出力を提供: + +| 出力 | タイプ | 説明 | +|------|------|------| +| `MODEL` | MODEL | LoRA適用済みモデル | +| `CLIP` | CLIP | LoRA適用済みCLIP | +| `positive` | CONDITIONING | ポジティブコンディショニング(LoRA構文除去) | +| `negative` | CONDITIONING | ネガティブコンディショニング | +| `positive_text` | STRING | LoRA構文付き完全ポジティブプロンプトテキスト | +| `negative_text` | STRING | 完全ネガティブプロンプトテキスト | +| `preview` | IMAGE | 選択されたLoRAのプレビュー画像バッチ(v1.1.0) | + +### テキスト出力形式 + +**positive_text例:** +``` +, , anime style, alice, blonde hair, 1girl, beautiful +``` + +**LBWノードのpositive_text例:** +``` +, anime style, 1girl, beautiful +``` + +**positive(CONDITIONING)内容:** +``` +anime style, alice, blonde hair, 1girl, beautiful +(クリーンなプロンプトのためLoRA構文除去) +``` + +### プレビュー画像(v1.1.0) + +**対応形式(優先順位順):** +1. 静止画(.png, .jpg, .jpeg) - 常に動作 +2. アニメ画像(.gif, .webp) - 1フレーム目、常に動作 +3. 動画ファイル(.mp4, .webm, .avi, .mov) - 1フレーム目、opencv-python必要 + +**ファイルマッチング:** +- LoRAファイル名で始まるファイル(大文字小文字無視) +- 例: `style_anime.safetensors` にマッチ: + - `style_anime.png` ✅ + - `style_anime_preview.jpg` ✅ + - `STYLE_ANIME.PNG` ✅ + +--- + +## Filtered Random LoRA Loader + +**キーワードフィルタリング付き単一フォルダ対応。** + +![Filtered Random LoRA Loader ワークフロー](./images/filterd_final_single.webp) + +### 主な機能 + +- **キーワードフィルタリング**: スペース区切りキーワードでLoRAを絞り込み +- **AND/ORモード**: 柔軟なフィルタリングロジック +- **フレーズマッチング**: 引用符で完全一致フレーズ +- **メタデータ検索**: ファイル名または埋め込みメタデータから検索 +- **高速キャッシング**: 初回検索後は即座にアクセス +- **直列接続対応**: 複雑なワークフロー向けに複数インスタンスを連結 ### パラメータ -#### 共通設定 -- `token_normalization` - Random LoRA Loaderと同じ -- `weight_interpretation` - Random LoRA Loaderと同じ +| パラメータ | 説明 | デフォルト | +|-----------|------|-----------| +| `lora_folder_path` | LoRAフォルダパス | (空) | +| `keyword_filter` | スペース区切りキーワードまたは引用符フレーズ | (空) | +| `filter_mode` | `AND` / `OR` | `AND` | +| `search_in_metadata` | JSON/埋め込みメタデータから検索 | `false` | +| `num_loras` | 選択するLoRA数 | `1` | +| `model_strength` | MODEL強度(固定または範囲) | `"1.0"` | +| `clip_strength` | CLIP強度(固定または範囲) | `"1.0"` | +| `include_subfolders` | サブフォルダを含める | `true` | +| `unique_by_filename` | 重複ファイル名を除外 | `true` | -#### フォルダ設定 -- `lora_folder_path` - フォルダパス(1つ) -- `include_subfolders` - サブフォルダを含む(デフォルト: True) -- `unique_by_filename` - サブフォルダ間の重複ファイル名を除外(デフォルト: True) +### キーワードフィルタ構文 -#### キーワードフィルタ -- `keyword_filter` - キーワード(カンマ区切り、例: "style, anime") -- `filter_mode` - AND(全キーワード)or OR(いずれか、デフォルト: AND) -- `search_in_metadata` - メタデータ内を検索(デフォルト: False - ファイル名のみ) - -#### LoRA設定 -- `model_strength` - MODEL強度(例: "1.0" or "0.6-0.9") -- `clip_strength` - CLIP強度(例: "1.0" or "0.6-0.9") -- `num_loras` - 選択するLoRA個数(デフォルト: 1、範囲: 0-20) - -#### トリガーワード設定 -- `trigger_word_source` - Random LoRA Loaderと同じ - -#### 追加プロンプト -- `additional_prompt_positive` - 追加ポジティブプロンプト(入力接続 or 直接記述) -- `additional_prompt_negative` - 追加ネガティブプロンプト(入力接続 or 直接記述) - -#### seed -- `seed` - ランダムシード -- `control_after_generate` - seed制御モード - -### キーワードフィルタリング - -#### ファイル名検索(デフォルト - 高速) - -LoRAファイル名のみを検索。 - -**例:** +**基本キーワード(ANDモード):** ``` -フォルダ内容: - - style_anime_v1.safetensors - - style_realistic.safetensors - - character_alice.safetensors - -keyword_filter: "anime" -→ マッチ: style_anime_v1.safetensors ✅ -``` - -#### メタデータ検索(オプション - 低速) - -ファイル名とメタデータの両方を検索: -- `model_name` -- `civitai.name` -- `civitai.trainedWords` -- `civitai.model.name` -- `civitai.model.tags` -- `tags` -- 埋め込みメタデータ - -**パフォーマンスについて:** - -初回読み込み時間(SSD環境、進捗表示あり): -- 100個: 瞬時 -- 1,000個: 約2秒 -- 5,000個: 約10秒 -- 10,000個: 約20秒 -- 20,000個: 約40秒 -- 50,000個: 約100秒(1分40秒) - -メモリ使用量: -- 10,000個: 約150MB -- 20,000個: 約300MB -- 50,000個: 約750MB - -**2回目以降:** 瞬時(キャッシュ利用) - -**推奨:** -- デフォルトのファイル名検索は常に高速 -- メタデータ検索は必要時のみ有効化 -- 大量のLoRA(5,000個以上)の場合、初回は時間がかかります -- HDD環境では初回読み込みがSSDの約3倍の時間がかかります - -**例:** -``` -ファイル: abc123.safetensors -メタデータ: {"trainedWords": ["anime style", "vibrant colors"]} - -search_in_metadata: True -keyword_filter: "anime" -→ マッチ ✅ -``` - -#### ANDモード vs ORモード - -**ANDモード(デフォルト):** -``` -keyword_filter: "style, anime" -filter_mode: "AND" -→ "style" AND "anime" の両方を含むファイルにマッチ +keyword_filter: "anime girl" +→ "anime"と"girl"の両方を含むファイルにマッチ ``` **ORモード:** ``` -keyword_filter: "style, anime" -filter_mode: "OR" -→ "style" OR "anime" のいずれかを含むファイルにマッチ +filter_mode: OR +keyword_filter: "anime realistic" +→ "anime"または"realistic"を含むファイルにマッチ ``` -### 重複ファイル名の処理 - -同じLoRAファイル名が複数のサブフォルダに存在する場合(例: オリジナルとバックアップ)、`unique_by_filename`オプションで同じLoRAが複数回選択されるのを防ぎます。 - -**例:** +**フレーズマッチング:** ``` -フォルダ構成: - /LoRA/ - ├── style/anime_v1.safetensors - └── backup/anime_v1.safetensors - -unique_by_filename: True(デフォルト) - → anime_v1.safetensorsは1つだけ選択される - → 最初に見つかったものを保持(/LoRA/style/anime_v1.safetensors) - -unique_by_filename: False - → 両方のファイルが選択される可能性あり - → 同じLoRAが異なる強度で2回適用される可能性 +keyword_filter: '"anime style" detailed' +→ 完全一致フレーズ"anime style"と単語"detailed"を含む必要 ``` -**重複検出時のログ出力:** +**複数フレーズ:** ``` -[FilteredRandomLoRALoader] Duplicate filename detected: anime_v1.safetensors - Keeping: /LoRA/style/anime_v1.safetensors - Skipping: /LoRA/backup/anime_v1.safetensors +keyword_filter: '"anime style" "detailed eyes" red' +→ "anime style"と"detailed eyes"と"red"を含む必要 ``` -**推奨:** 意図しない重複適用を避けるため、デフォルトの`True`を維持してください。 - -### メタデータ検索のパフォーマンス +### メタデータ検索 **ファイル名検索(デフォルト):** -- `search_in_metadata: False`(デフォルト) -- 10,000個以上のLoRAでも高速 -- 処理時間: <100ms +``` +search_in_metadata: false +→ 高速、ファイル名のみ検索 +``` **メタデータ検索:** -- `search_in_metadata: True` -- ファイル名とLoRAメタデータの両方を検索 -- **初回実行:** キャッシュ構築 - - 1,000個のLoRA: 約2秒 - - 10,000個のLoRA: 約7-75秒(メタデータファイルの有無による) - - コンソールに進捗表示 -- **2回目以降:** 超高速(<100ms) -- キャッシュはComfyUI再起動までl持続 +``` +search_in_metadata: true +→ 低速、JSON/埋め込みメタデータを検索 +→ 初回検索後はキャッシュ(2回目以降は即座) +``` -**パフォーマンスのヒント:** -- 初回に`include_subfolders: True`で実行すると全LoRAをキャッシュ構築 -- キャッシュ構築後は`include_subfolders: False`でもキャッシュ利用可能 -- キャッシュは全ノードインスタンスで共有 +**パフォーマンス:** +- 初回読み込み(SSD): + - 1,000ファイル: 約2秒 + - 5,000ファイル: 約10秒 + - 10,000ファイル: 約20秒 +- 2回目以降: 即座(<100ms) +- メモリ: 10,000ファイルあたり約150MB ### 使用例 -#### 基本的な使い方 +#### 例1: キャラクター選択 ``` -[Filtered Random LoRA Loader] - lora_folder_path: /loras/all/ - keyword_filter: "anime" - num_loras: 1 - ↓ -ファイル名に "anime" を含むLoRAから1個ランダム選択 +lora_folder_path: "/path/to/all_loras" +keyword_filter: "character girl" +filter_mode: AND +num_loras: 1 ``` -#### 複数インスタンスの直列接続 - -![FilteredRandomLoRALoder x2ワークフロー](./images/filterd_final_double.webp) - -``` -[Filtered Random LoRA Loader A] - folder: /loras/all/ - keyword_filter: "style, anime" - filter_mode: "AND" - num_loras: 1 - ↓ -[Filtered Random LoRA Loader B] - folder: /loras/all/ - keyword_filter: "character" - num_loras: 1 - additional_prompt_positive ← Aのpositive_text - additional_prompt_negative ← Aのnegative_text - ↓ -[Filtered Random LoRA Loader C] - folder: /loras/all/ - keyword_filter: "concept" - num_loras: 1 - additional_prompt_positive ← Bのpositive_text - additional_prompt_negative ← Bのnegative_text -``` - -#### Wildcard Encodeとの連携 - -![WildcardEncode + FilteredRandomLoRALoder ワークフロー](./images/filterd_final_wce.webp) - -``` -[Wildcard Encode] - populated_text: "1girl, beautiful" - negative_text: "bad quality" - ↓ -[Filtered Random LoRA Loader] - additional_prompt_positive ← populated_text - additional_prompt_negative ← negative_text - keyword_filter: "style" - ↓ -結合された出力 ✅ -``` - -### ベストプラクティス - -1. **説明的なファイル名を使用:** `style_anime_v1.safetensors` -2. **デフォルトモード(高速):** 通常は`search_in_metadata: False`のまま使用 -3. **メタデータ検索を有効化するタイミング:** - - ファイル名に有用なキーワードが含まれていない - - トリガーワードやタグで検索したい -4. **初回実行の最適化:** - - `include_subfolders: True`で1回実行して完全なキャッシュ構築 - - その後`False`に切り替えてフォルダスキャンを高速化 -5. **直列接続:** - - `positive_text` → 次のノードの`additional_prompt_positive`に接続 - - `negative_text` → 次のノードの`additional_prompt_negative`に接続 - -### トラブルシューティング - -**フィルタに一致するLoRAが見つからない:** -- キーワードがファイル名に含まれているか確認 -- `search_in_metadata: True`でメタデータ内も検索 -- ANDモードの代わりにORモードを試す -- フォルダパスが正しいか確認 - -**初回実行が遅い:** -- `search_in_metadata: True`の場合は正常 -- キャッシュ構築中、2回目以降は高速 -- コンソールに進捗表示 - -**キャッシュが機能しない:** -- ComfyUI再起動でキャッシュクリア -- 起動後1回実行してキャッシュ再構築 +**結果:** "character"と"girl"の両方を含むキャラクターLoRAを1つ選択 --- -## Tips & Tricks(オリジナルノード) +#### 例2: 複数インスタンス(推奨) -### LoRA構文フィルタとしての使用 +![Filtered Random LoRA Loader x2 ワークフロー](./images/filterd_final_double.webp) -LoRAを適用せず、単純にLoRA構文削除フィルタとしてこのノードを使用できます。 +``` +[Load Checkpoint] + ↓ +[Filtered Random LoRA Loader #1] + keyword_filter: "style anime" + num_loras: 1 + ↓ +[Filtered Random LoRA Loader #2] + keyword_filter: "character" + num_loras: 1 + ↓ +[KSampler] +``` -**設定:** -- 全グループの`num_loras`を`0`に設定(または全フォルダパスを空にする) -- Wildcard Encodeの`populated_text`を`additional_prompt`に接続 -- `positive_text`出力を次のノードに接続 +**メリット:** +- カテゴリごとに異なるフィルタリング +- 独立した強度設定 +- より柔軟性が高い -**使用例:** -- Wildcard Encode出力からLoRA構文を削除 -- 他のノードに渡す前にプロンプトをクリーンアップ -- Wildcard EncodeのLoRA処理を使いつつ、互換性のために構文を削除 +--- + +#### 例3: メタデータ検索 + +``` +search_in_metadata: true +keyword_filter: "detailed eyes" +``` + +**検索対象:** +- ファイル名 +- JSON `activation text` +- JSON `ss_tag_frequency` +- JSON `modelspec.description` +- 埋め込みLoRAメタデータ + +--- + +## Filtered Random LoRA Loader (LBW) 🆕 v1.2.0新機能 + +**LoRAブロックウェイト対応の高度なノード。** + +![FilteredRandomLoRALoader(LBW)ワークフロー例](./images/lbw_final_single.webp) + +### LBWとは? + +LoRAブロックウェイトにより、U-Netのどの部分がLoRAの影響を受けるかを制御できます: + +``` +INPUTブロック → 構造、構図、レイアウト + ↓ +MIDDLEブロック → 全体的な特徴 + ↓ +OUTPUTブロック → 画風、ディテール、微調整 +``` + +### 主な機能 + +- **4つのプリセットモード**: + - **Style Focused**: OUTPUTブロックのみ(構造を変えずに画風のみ) + - **Character Focused**: バランスの取れたIN+MID+OUT(キャラクター特徴) + - **Structure/Composition Only**: INPUT+MIDブロック(画風を変えずにレイアウトのみ) + - **Balanced / Soft**: 穏やかな適用(自然な結果) +- **Preset: Random**: 4つのプリセットから毎回ランダム選択 +- **Direct Input**: カスタムウェイト指定 +- **SD1.5/SDXL自動検出**: 手動でモデルタイプを選択不要 +- **ウェイト数自動調整**: 要素数の不一致を自動処理 + +### パラメータ + +Filtered Random LoRA Loaderと同じ、加えて: + +| パラメータ | 説明 | デフォルト | +|-----------|------|-----------| +| `weight_mode` | LBWプリセットまたはDirect Input | `Normal (All 1.0)` | +| `lbw_input` | カスタムウェイト(Direct Input用) | (空) | + +### ウェイトモード + +#### Normal (All 1.0) +ブロックウェイトなしの標準LoRA適用。 + +#### Style Focused +``` +SDXL: 1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1 +SD1.5: 1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1 +``` +- OUTPUTブロックのみ +- 構造を変えずに画風のみ +- 用途: 画風LoRA、エフェクトLoRA + +#### Character Focused +``` +SDXL: 1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1 +SD1.5: 1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1 +``` +- バランスの取れたIN+MID+OUT +- キャラクター特徴を保持 +- 用途: キャラクターLoRA、人物LoRA + +#### Structure/Composition Only +``` +SDXL: 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0 +SD1.5: 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0 +``` +- INPUT+MIDブロックのみ +- 画風を変えずに構造のみ +- 用途: ポーズLoRA、構図LoRA + +#### Balanced / Soft +``` +SDXL: 1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0 +SD1.5: 1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,0,0 +``` +- 穏やかな適用 +- 自然な結果 +- 用途: 汎用LoRA、マルチLoRAワークフロー + +#### Preset: Random +上記4つのプリセットから毎回ランダムに1つ選択。 + +#### Direct Input +``` +weight_mode: Direct Input +lbw_input: "1,0.5,0.5,0,0,0,0,0,0,0,1,0.8,0.8,0.8,0.8,0.8,0.5,0.5,0.5,0.5" +``` +- カスタムウェイト指定 +- SDXL: 20要素、SD1.5: 17要素 +- 要素数が合わない場合は自動調整 + +### 使用例 + +#### 例1: 画風のみ + +``` +[Filtered Random LoRA Loader (LBW)] + keyword_filter: "anime watercolor" + weight_mode: Style Focused + ↓ +[KSampler] +``` + +**結果:** 構図を変えずにアニメ水彩画風を適用 + +--- + +#### 例2: 構造 → 画風 + +``` +[Load Checkpoint] + ↓ +[Filtered Random LoRA Loader (LBW)] + keyword_filter: "pose" + weight_mode: Structure/Composition Only + ↓ +[Filtered Random LoRA Loader (LBW)] + keyword_filter: "oil painting" + weight_mode: Style Focused + ↓ +[KSampler] +``` + +**結果:** ポーズ調整 → 油絵風適用 + +--- + +#### 例3: カスタムウェイト + +``` +weight_mode: Direct Input +lbw_input: "1,0.5,0.5,0.5,0,0,0,0,0,0,1,1,1,1,1,1,0.5,0.5,0.5,0.5" +``` + +**結果:** カスタムブロックウェイト分布 + +--- + +### 上級者向け: カスタムプリセット + +ソースファイルで直接プリセットを編集できます: + +**ファイル:** `filtered_random_lora_loader_lbw.py`(29~41行目) + +詳細なカスタマイズガイドは [README_LBW_ja.md](README_LBW_ja.md) を参照してください。 + +--- + +## Tips & Tricks + +### 複数効果の直列接続 + +ノードを直列接続して異なるLoRAカテゴリを適用: + +``` +[Load Checkpoint] + ↓ +[Filtered Random LoRA Loader (LBW)] (Structure/Composition Only) + keyword_filter: "pose" + ↓ +[Filtered Random LoRA Loader (LBW)] (Style Focused) + keyword_filter: "watercolor" + ↓ +[KSampler] +``` + +**メリット:** +- カテゴリごとに異なる設定 +- 累積的なLoRA効果 +- 最終結果のより細かい制御 + +--- + +### バリエーションのための強度ランダム化 + +固定値の代わりに範囲を使用: + +``` +model_strength_1: "0.6-0.9" +clip_strength_1: "0.6-0.9" +``` + +**効果:** +- 各生成で異なる強度を使用 +- 結果にバリエーション +- 最適な強度を見つけやすい + +--- + +### キーワードフィルタリングのベストプラクティス + +**具体的なキーワードを使用:** +``` +✅ 良い: "anime girl" +❌ 広すぎる: "anime" +``` + +**メタデータ検索と組み合わせ:** +``` +search_in_metadata: true +keyword_filter: "detailed eyes" +``` + +**精密性のためフレーズを使用:** +``` +keyword_filter: '"anime style" detailed' +→ 完全一致フレーズ"anime style"と単語"detailed"を含む必要 +``` + +--- + +### Wildcard Encode + Random LoRA Loader + +**究極の動的ワークフロー:** + +``` +[Wildcard Encode (Inspire)] + text: "__style__, __pose__, {red|blue|green}" + ↓ + populated_text ──→ [Random LoRA Loader] + additional_prompt_positive + ↓ +[KSampler] +``` + +**結果:** +- プロンプトのワイルドカード展開 +- バリエーションのためのランダムLoRA選択 +- LoRA構文なしのクリーンなプロンプト +- 最大の柔軟性 + +--- + +### 整理のためのプレビュー画像 + +プレビュー表示を有効化して: +- どのLoRAが選択されたか確認 +- 生成前にLoRAの外観を検証 +- LoRAコレクションを視覚的に整理 + +**推奨ワークフロー:** +``` +[Random LoRA Loader] + preview ──→ [Preview Image](検証用) + MODEL ──→ [KSampler] +``` + +--- + +## トラブルシューティング + +### LoRAが見つからない + +**確認事項:** +1. LoRAフォルダパスが正しい(絶対パス) +2. フォルダに`.safetensors`ファイルが存在 +3. LoRAがサブフォルダにある場合は`include_subfolders`設定 +4. コンソールでエラーメッセージを確認 + +**有効なパスの例:** +``` +Windows: C:/ComfyUI/models/loras/style +Linux/Mac: /home/user/ComfyUI/models/loras/style +``` + +--- + +### トリガーワードが見つからない + +**確認事項:** +1. メタデータファイル(`.metadata.json`または`.info`)が存在 +2. JSONファイルに必要なフィールドが含まれている: + - `activation text` + - `ss_tag_frequency` + - `sample_prompts` + - `civitai.trainedWords`または`civitai.images` +3. 異なる`trigger_word_source`設定を試す + +**JSON形式を確認:** +```json +{ + "activation text": "anime style, detailed", + "ss_tag_frequency": {...}, + "modelspec.description": "...", + "sample_prompts": "..." +} +``` + +--- + +### LoRAが適用されない + +**確認事項:** +1. `num_loras`が0でない +2. 強度値が全て0でない +3. MODEL/CLIP出力が正しく接続されている +4. コンソールでLoRA適用メッセージを確認 +5. LBWノードの場合: weight_modeが"Normal (All 1.0)"で全ウェイトが0でない + +--- + +### プレビュー画像が表示されない + +**確認事項:** +1. プレビューファイルがLoRAファイル名とマッチ +2. 動画ファイルの場合: opencv-pythonがインストール済み(`pip install opencv-python`) +3. 対応形式: .png, .jpg, .jpeg, .gif, .webp, .mp4, .webm, .avi, .mov +4. ファイルパーミッションが正しい + +**opencv-pythonなし:** +- 静止画は動作 ✅ +- アニメ画像は動作 ✅ +- 動画ファイルは黒画面 ⚠️ + +--- + +### マイナス値で強度が動作しない(v1.2.0で修正) + +**以前の問題(v1.1.0):** +``` +入力: "-0.5" +結果: 1.0 ❌(デフォルトに変換) +``` + +**v1.2.0で修正:** +``` +入力: "-0.5" +結果: -0.5 ✅(マイナスLoRAが正しく適用) + +入力: "-0.8--0.3" +結果: [-0.8, -0.7, -0.6, -0.5, -0.4, -0.3] からランダム ✅ +``` + +--- + +### Wildcard Encodeの問題 + +**ワイルドカードテキストが出力に表示される場合:** + +1. **接続を確認**: Wildcard Encodeの`populated_text`を`additional_prompt_positive`に接続 +2. **間違った出力**: `text`(入力)をこのノードに接続しない +3. **LoRA構文が表示される**: このノードが自動的に除去 **ワークフロー例:** ``` [Wildcard Encode (Inspire)] - text: "__style__, {red|blue|green}, " - ↓ - populated_text: "anime style, blue, " - (LoRAはWildcard EncodeによりMODELに適用済み) - ↓ -[Random LoRA Loader] - num_loras: 0, 0, 0 ← LoRA適用なし - additional_prompt ← populated_textから接続 - ↓ - positive_text: "anime style, blue," ← LoRA構文削除済み ✅ - ↓ -[次のノード] + populated_text ──→ [Random LoRA Loader] + ("text"ではない) additional_prompt_positive ``` -**メリット:** -- ✅ ``構文がノイズトークンになるのを防止 -- ✅ 別途テキスト処理ノードが不要 -- ✅ LoRA構文を含むあらゆるテキストに対応 +--- -## 免責事項・サポートポリシー +### 重複LoRAが選択される -### 本ノードについて +**解決策:** `unique_by_filename`を有効化 -このカスタムノードは個人的な使用目的で開発したものを公開しています。 +``` +unique_by_filename_1: true +``` -### サポートについて +異なるサブフォルダから同じLoRAを選択するのを防ぎます: +``` +/style/lora.safetensors +/backup/lora.safetensors +→ 1つだけ選択 ✅ +``` -- ❌ **技術サポートは提供しません** - - 使い方の質問 - - 環境構築の支援 - - トラブルシューティングの個別対応 +--- -- ❌ **動作保証はありません** - - 特定環境での動作確認 - - 将来のComfyUI更新への対応保証 - - データ損失等の責任 +## 詳細ドキュメント -### コミュニティ貢献について +- **[README_LBW_ja.md](README_LBW_ja.md)** - LBW完全ガイド(日本語) +- **[README_LBW.md](README_LBW.md)** - LBW complete documentation (English) +- **[README.md](README.md)** - English main documentation -以下は歓迎しますが、対応は保証しません: +--- -- ✅ バグ報告(Issue) -- ✅ プルリクエスト -- ✅ 機能提案 +## 免責事項とサポートポリシー -### 使用条件 +### 免責事項 -- 使用は完全に自己責任です -- 本番環境での使用前に十分なテストを行ってください -- 問題が発生しても作者は一切の責任を負いません +- このノードは**技術サポートなし**で提供されます +- 機能の保証はありません +- 将来のComfyUIアップデートとの互換性は保証されません +- バグレポートや機能リクエストに対応しない場合があります +- 自己責任で使用してください + +### サポート状況 + +- ❌ issueやメールでの個別サポートなし +- ❌ バグ修正や機能追加の保証なし +- ✅ コードはオープンソース - 自由にフォーク・修正可能 +- ✅ コミュニティディスカッション歓迎(返答の約束なし) + +### 問題の報告 + +サポートは保証されませんが、以下が可能です: +1. リポジトリの既存issueを確認 +2. このREADMEとトラブルシューティングセクションを確認 +3. issueを開く(対応されない場合があります) +4. 自分でフォークして修正 + +--- ## ライセンス MIT License -Copyright (c) 2025 +--- -本ソフトウェアは「現状のまま」提供され、明示的または黙示的な保証を一切行いません。 +## 更新履歴 -## 参考リンク +### v1.2.0(2026-01-13) + +#### 追加 +- ✅ **新ノード**: Filtered Random LoRA Loader (LBW) +- ✅ 4つのプリセット付きLoRAブロックウェイト(LBW)対応 +- ✅ LBW用SD1.5/SDXL自動検出 +- ✅ LBW用Preset: Randomモード +- ✅ カスタムLBWウェイト用Direct Inputモード +- ✅ LBW用ウェイト数自動調整 +- ✅ **強度のマイナス値対応**: `-0.5`、`-0.8--0.3`が正しく動作 +- ✅ **動画プレビュー対応**: .mp4, .webm, .avi, .mov(opencv-python必要) +- ✅ **強度精度の改善**: + - 範囲指定: 全ノードで0.1刻み + - 固定値: 小数点2桁に丸め + +#### 修正 +- ✅ **重大バグ**: マイナス単一値(`"-0.5"`)が正しく動作(以前は1.0に変換) +- ✅ **重大バグ**: マイナス範囲(`"-0.8--0.3"`)が正しく動作(以前はエラー) +- ✅ 正規表現パターンマッチングで強度パースを改善 + +#### 変更 +- ✅ 全3ノードで強度動作を統一 +- ✅ ノード名変更: "Filtered Random LoRA Loader (Advanced)" → "Filtered Random LoRA Loader (LBW)" +- ✅ モデル互換性警告を強調したドキュメント強化 + +### v1.1.0(2026-01-04) + +#### 追加 +- ✅ **新ノード**: Filtered Random LoRA Loader +- ✅ AND/ORモード付きキーワードフィルタリング +- ✅ キャッシング付きメタデータ検索 +- ✅ プレビュー画像出力(IMAGEタイプ) +- ✅ 重複ファイル名処理(`unique_by_filename`) +- ✅ アニメ画像対応(.gif, .webp) + +#### 変更 +- ✅ **破壊的変更**: `additional_prompt`を`additional_prompt_positive`と`additional_prompt_negative`に分割 +- ✅ 強度精度を小数点1桁に統一 +- ✅ LoRA構文除去を改善 + +#### 修正 +- ✅ `json_sample_prompt`モードでnegative_text出力を修正 +- ✅ メタデータトリガーワードにLoRA構文が表示される問題を修正 +- ✅ INPUT_TYPESの重複パラメータを修正 + +### v1.0.0(2025-12-30) + +#### 追加 +- ✅ 初回リリース +- ✅ 3グループ対応のRandom LoRA Loader +- ✅ マルチソースメタデータ読み取り +- ✅ 範囲指定付き強度ランダム化 +- ✅ トリガーワード抽出 +- ✅ Wildcard Encode互換性 +- ✅ クリーンプロンプト付きCONDITIONING出力 + +--- + +## 参考文献 - [ComfyUI](https://github.com/comfyanonymous/ComfyUI) -- [ComfyUI Lora Manager](https://github.com/willmiao/ComfyUI-Lora-Manager) - `.metadata.json`を生成(推奨) -- [Civitai Helper](https://github.com/butaixianran/Stable-Diffusion-Webui-Civitai-Helper) - `.info`を生成(対応済み) +- [Wildcard Encode (Inspire)](https://github.com/ltdrdata/ComfyUI-Inspire-Pack) +- [LoRA Block Weight理論](https://github.com/hako-mikan/sd-webui-lora-block-weight) + +--- + +**精密な制御で柔軟なLoRAランダム化をお楽しみください!🎲✨** diff --git a/__init__.py b/__init__.py index 1e1a3e5..44563d1 100644 --- a/__init__.py +++ b/__init__.py @@ -6,14 +6,27 @@ RandomLoRALoader Custom Node for ComfyUI from .random_lora_loader import RandomLoRALoader from .filtered_random_lora_loader import FilteredRandomLoRALoader +# LBW版は任意(読み込めない場合はスキップ) +try: + from .filtered_random_lora_loader_lbw import FilteredRandomLoRALoaderLBW + HAS_LBW = True +except Exception as e: + print(f"[RandomLoRALoader] Failed to load LBW version: {e}") + HAS_LBW = False + NODE_CLASS_MAPPINGS = { "RandomLoRALoader": RandomLoRALoader, - "FilteredRandomLoRALoader": FilteredRandomLoRALoader + "FilteredRandomLoRALoader": FilteredRandomLoRALoader, } NODE_DISPLAY_NAME_MAPPINGS = { "RandomLoRALoader": "Random LoRA Loader", - "FilteredRandomLoRALoader": "Filtered Random LoRA Loader" + "FilteredRandomLoRALoader": "Filtered Random LoRA Loader", } +# LBW版が利用可能な場合のみ追加 +if HAS_LBW: + NODE_CLASS_MAPPINGS["FilteredRandomLoRALoaderLBW"] = FilteredRandomLoRALoaderLBW + NODE_DISPLAY_NAME_MAPPINGS["FilteredRandomLoRALoaderLBW"] = "Filtered Random LoRA Loader (LBW)" + __all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS'] diff --git a/filtered_random_lora_loader.py b/filtered_random_lora_loader.py index c715740..e85801d 100644 --- a/filtered_random_lora_loader.py +++ b/filtered_random_lora_loader.py @@ -27,6 +27,7 @@ class FilteredRandomLoRALoader: # クラス変数(全インスタンスで共有するメタデータキャッシュ) _metadata_cache = {} + _opencv_warning_shown = False # opencv警告表示フラグ @classmethod def INPUT_TYPES(cls): @@ -662,18 +663,20 @@ class FilteredRandomLoRALoader: プレビュー画像をTensorとして読み込み(部分一致、長辺1240px) 検索方法: - LoRAファイル名(拡張子除く)で始まる画像ファイルを検索 + LoRAファイル名(拡張子除く)で始まるファイルを検索 + 優先順位: + 1. 静止画像 (.png, .jpg, .jpeg, .webp) + 2. 動画ファイル (.gif, .webp, .mp4, .webm) の1フレーム目 + 例: style_anime_v1.safetensors → style_anime_v1.png - → style_anime_v1_preview.png - → style_anime_v1_001.jpg + → style_anime_v1_preview.jpg + → style_anime_v1.gif (1フレーム目) + → style_anime_v1.mp4 (1フレーム目、opencv-pythonが必要) → STYLE_ANIME_V1.PNG (大文字小文字無視) リサイズ: 長辺を1240pxに統一(アスペクト比保持) - 例: 1024x768 → 1240x930 - 512x512 → 1240x1240 - 800x1200 → 826x1240 Returns: torch.Tensor: (H, W, C) 形式、見つからない場合はNone @@ -690,70 +693,207 @@ class FilteredRandomLoRALoader: base_name = os.path.splitext(os.path.basename(lora_path))[0] folder = os.path.dirname(lora_path) - # 画像拡張子 - image_extensions = ('.png', '.jpg', '.jpeg', '.webp', '.gif') + # ファイル拡張子(優先順位順) + static_image_exts = ('.png', '.jpg', '.jpeg') + animated_image_exts = ('.gif', '.webp') # Pillowで対応可能 + video_exts = ('.mp4', '.webm', '.avi', '.mov') # opencv-python必要 try: # 同じフォルダ内のファイルを検索 - for file in os.listdir(folder): - # 部分一致(大文字小文字無視) + files = os.listdir(folder) + + # 部分一致するファイルを収集 + matched_files = [] + for file in files: if file.lower().startswith(base_name.lower()): - # 画像ファイルか確認 - if file.lower().endswith(image_extensions): - preview_path = os.path.join(folder, file) - try: - img = Image.open(preview_path).convert('RGB') - - # 長辺を1240pxにリサイズ(アスペクト比保持) - width, height = img.size - max_size = 1240 - - if max(width, height) > max_size: - # 長辺が1240pxを超える場合はリサイズ - if width > height: - new_width = max_size - new_height = int(height * (max_size / width)) - else: - new_height = max_size - new_width = int(width * (max_size / height)) - - img = img.resize((new_width, new_height), Image.Resampling.LANCZOS) - elif max(width, height) < max_size: - # 長辺が1240px未満の場合は拡大 - if width > height: - new_width = max_size - new_height = int(height * (max_size / width)) - else: - new_height = max_size - new_width = int(width * (max_size / height)) - - img = img.resize((new_width, new_height), Image.Resampling.LANCZOS) - - # numpy配列に変換 (H, W, C) - img_array = np.array(img).astype(np.float32) / 255.0 - # Tensor化 - return torch.from_numpy(img_array) - except Exception as e: - print(f"[FilteredRandomLoRALoader] Preview load error ({preview_path}): {e}") - continue + matched_files.append(file) + + if not matched_files: + return None + + # 優先順位でソート + def get_priority(filename): + lower = filename.lower() + if any(lower.endswith(ext) for ext in static_image_exts): + return 0 # 最優先 + elif any(lower.endswith(ext) for ext in animated_image_exts): + return 1 # 次優先 + elif any(lower.endswith(ext) for ext in video_exts): + return 2 # 最後 + else: + return 999 # その他 + + matched_files.sort(key=get_priority) + + # 各ファイルを試す + for file in matched_files: + preview_path = os.path.join(folder, file) + lower_file = file.lower() + + # 静止画像 + if any(lower_file.endswith(ext) for ext in static_image_exts): + img = self._load_static_image(preview_path) + if img is not None: + return img + + # アニメーション画像(GIF/WebP) + elif any(lower_file.endswith(ext) for ext in animated_image_exts): + img = self._load_animated_image_first_frame(preview_path) + if img is not None: + return img + + # 動画ファイル(opencv-python必要) + elif any(lower_file.endswith(ext) for ext in video_exts): + img = self._load_video_first_frame(preview_path) + if img is not None: + return img + except Exception as e: print(f"[FilteredRandomLoRALoader] Folder read error: {e}") return None + def _load_static_image(self, image_path): + """静止画像を読み込み""" + try: + from PIL import Image + import numpy as np + import torch + + img = Image.open(image_path).convert('RGB') + return self._resize_and_convert_image(img) + except Exception as e: + print(f"[FilteredRandomLoRALoader] Static image load error ({image_path}): {e}") + return None + + def _load_animated_image_first_frame(self, image_path): + """アニメーション画像(GIF/WebP)の1フレーム目を読み込み""" + try: + from PIL import Image + import numpy as np + import torch + + img = Image.open(image_path) + + # 1フレーム目に移動 + if hasattr(img, 'seek'): + img.seek(0) + + img = img.convert('RGB') + return self._resize_and_convert_image(img) + except Exception as e: + print(f"[FilteredRandomLoRALoader] Animated image load error ({image_path}): {e}") + return None + + def _load_video_first_frame(self, video_path): + """動画ファイルの1フレーム目を読み込み(opencv-python必要)""" + try: + import cv2 + from PIL import Image + import numpy as np + import torch + + # OpenCVで動画を開く + cap = cv2.VideoCapture(video_path) + + if not cap.isOpened(): + return None + + # 1フレーム目を読み込み + ret, frame = cap.read() + cap.release() + + if not ret: + return None + + # BGR → RGB 変換 + frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) + + # PIL Imageに変換 + img = Image.fromarray(frame_rgb) + + return self._resize_and_convert_image(img) + + except ImportError: + # opencv-pythonがインストールされていない(初回のみ警告) + if not FilteredRandomLoRALoader._opencv_warning_shown: + print("=" * 60) + print("[FilteredRandomLoRALoader] Video Preview Support") + print("=" * 60) + print(f"Video file detected: {os.path.basename(video_path)}") + print("opencv-python is not installed.") + print("") + print("To enable video preview support, install:") + print(" pip install opencv-python") + print("") + print("Static images (.png/.jpg) and animated images (.gif/.webp)") + print("will continue to work without opencv-python.") + print("=" * 60) + FilteredRandomLoRALoader._opencv_warning_shown = True + return None + except Exception as e: + print(f"[FilteredRandomLoRALoader] Video load error ({video_path}): {e}") + return None + + def _resize_and_convert_image(self, img): + """画像をリサイズしてTensorに変換""" + try: + from PIL import Image + import numpy as np + import torch + + # 長辺を1240pxにリサイズ(アスペクト比保持) + width, height = img.size + max_size = 1240 + + if max(width, height) > max_size: + # 長辺が1240pxを超える場合はリサイズ + if width > height: + new_width = max_size + new_height = int(height * (max_size / width)) + else: + new_height = max_size + new_width = int(width * (max_size / height)) + + img = img.resize((new_width, new_height), Image.Resampling.LANCZOS) + elif max(width, height) < max_size: + # 長辺が1240px未満の場合は拡大 + if width > height: + new_width = max_size + new_height = int(height * (max_size / width)) + else: + new_height = max_size + new_width = int(width * (max_size / height)) + + img = img.resize((new_width, new_height), Image.Resampling.LANCZOS) + + # numpy配列に変換 (H, W, C) + img_array = np.array(img).astype(np.float32) / 255.0 + # Tensor化 + return torch.from_numpy(img_array) + + except Exception as e: + print(f"[FilteredRandomLoRALoader] Image resize/convert error: {e}") + return None + def _get_random_strength(self, strength_str): - """強度をランダム取得(範囲指定対応)""" + """強度をランダム取得(範囲指定対応、マイナス値・マイナス範囲対応)""" + import re strength_str = strength_str.strip() - if '-' in strength_str: + # 範囲指定のパターンマッチ + range_pattern = r'^(-?\d+\.?\d*)\s*-\s*(-?\d+\.?\d*)$' + match = re.match(range_pattern, strength_str) + + if match: try: - parts = strength_str.split('-') - min_val = float(parts[0].strip()) - max_val = float(parts[1].strip()) + min_val = float(match.group(1)) + max_val = float(match.group(2)) return str(round(random.uniform(min_val, max_val), 1)) except: return "1.0" else: + # 単一値(マイナス含む) try: float(strength_str) return strength_str diff --git a/filtered_random_lora_loader_lbw.py b/filtered_random_lora_loader_lbw.py new file mode 100644 index 0000000..21e15ba --- /dev/null +++ b/filtered_random_lora_loader_lbw.py @@ -0,0 +1,1292 @@ +""" +Filtered Random LoRA Loader (Advanced) Node for ComfyUI +キーワードフィルタ + LoRA Block Weight 対応ランダムLoRA選択・適用ノード + +Author: Your Name +Version: 1.2.0 +License: MIT + +機能: +- 1つのフォルダから複数のLoRAをランダム選択 +- キーワードフィルタで絞り込み(AND/OR) +- メタデータ検索(ファイル名 or メタデータ内) +- LoRA Block Weight (LBW) 対応 +- SD1.5 / SDXL 対応 +- プリセット + カスタム設定 +- キャッシュ機能で高速化 +- 直列接続推奨 +""" + +import os +import random +import re +import json +import folder_paths +import comfy.sd + + +# LBW プリセット定義 +SDXL_PRESETS = { + "Style Focused": "1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1", + "Character Focused": "1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1", + "Structure/Composition Only": "1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0", + "Balanced / Soft": "1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0" +} + +SD15_PRESETS = { + "Style Focused": "1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1", + "Character Focused": "1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1", + "Structure/Composition Only": "1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0", + "Balanced / Soft": "1,1,1,1,0,0,0,1,1,1,1,1,0,0,0,0,0" +} + + +class FilteredRandomLoRALoaderLBW: + """キーワードフィルタ付きランダムLoRA選択・適用ノード(1グループ)""" + + # クラス変数(全インスタンスで共有するメタデータキャッシュ) + _metadata_cache = {} + _opencv_warning_shown = False # opencv警告表示フラグ + + @classmethod + def INPUT_TYPES(cls): + return { + "required": { + "model": ("MODEL",), + "clip": ("CLIP",), + + # 共通設定 + "token_normalization": ( + ["none", "mean", "length", "length+mean"], + {"default": "none"} + ), + "weight_interpretation": ( + ["comfy", "A1111", "compel", "comfy++", "down_weight"], + {"default": "comfy"} + ), + + # 追加プロンプト + "additional_prompt_positive": ("STRING", { + "default": "", + "multiline": True, + "placeholder": "Additional positive prompt" + }), + "additional_prompt_negative": ("STRING", { + "default": "", + "multiline": True, + "placeholder": "Additional negative prompt" + }), + + # フォルダ設定(1つのみ) + "lora_folder_path": ("STRING", { + "default": "", + "multiline": False, + "placeholder": "Path to LoRA folder" + }), + "include_subfolders": ("BOOLEAN", { + "default": True, + "label": "Include subfolders" + }), + "unique_by_filename": ("BOOLEAN", { + "default": True, + "label": "Unique by filename (exclude duplicates)" + }), + + # キーワードフィルタ設定 + "keyword_filter": ("STRING", { + "default": "", + "multiline": False, + "placeholder": "Keywords (space-separated, e.g., 'style anime' or \"anime style\" red)" + }), + "filter_mode": (["AND", "OR"], { + "default": "AND" + }), + "search_in_metadata": ("BOOLEAN", { + "default": False, + "label": "Search in metadata (slower)" + }), + + # LoRA設定 + "model_strength": ("STRING", { + "default": "1.0", + "multiline": False, + "placeholder": "e.g., 1.0 or 0.6-0.9" + }), + "clip_strength": ("STRING", { + "default": "1.0", + "multiline": False, + "placeholder": "e.g., 1.0 or 0.6-0.9" + }), + "num_loras": ("INT", { + "default": 1, + "min": 0, + "max": 20, + "step": 1 + }), + + # LoRA Block Weight (LBW) 設定 + "weight_mode": ([ + "Normal (All 1.0)", + "Style Focused", + "Character Focused", + "Structure/Composition Only", + "Balanced / Soft", + "Preset: Random", + "Direct Input" + ], { + "default": "Normal (All 1.0)" + }), + "lbw_input": ("STRING", { + "default": "", + "multiline": False, + "placeholder": "Comma-separated weights (SDXL: 20 elements, SD1.5: 17 elements)" + }), + + # トリガーワード設定 + "trigger_word_source": ( + ["json_combined", "json_random", "json_sample_prompt", "metadata"], + {"default": "json_combined"} + ), + + # seed + "seed": ("INT", { + "default": 0, + "min": 0, + "max": 0xffffffffffffffff + }), + } + } + + RETURN_TYPES = ("MODEL", "CLIP", "STRING", "STRING", "CONDITIONING", "CONDITIONING", "IMAGE") + RETURN_NAMES = ("MODEL", "CLIP", "positive_text", "negative_text", "positive", "negative", "preview") + FUNCTION = "load_loras" + CATEGORY = "loaders" + + def load_loras(self, model, clip, token_normalization, weight_interpretation, + additional_prompt_positive, additional_prompt_negative, + lora_folder_path, include_subfolders, unique_by_filename, + keyword_filter, filter_mode, search_in_metadata, + model_strength, clip_strength, num_loras, + weight_mode, lbw_input, + trigger_word_source, seed): + """メイン処理""" + + # seedの設定 + random.seed(seed) + + # LBW ウェイトの取得 + lbw_weights = self._get_lbw_weights(weight_mode, lbw_input) + + # 初期値 + final_positive = additional_prompt_positive.strip() + final_negative = additional_prompt_negative.strip() + + # num_loras が 0 の場合はスキップ + if num_loras == 0: + print("[FilteredRandomLoRALoaderLBW] num_loras=0, skipping LoRA application") + empty_preview = self._generate_preview_batch([]) + return self._generate_outputs(model, clip, final_positive, final_negative, + token_normalization, weight_interpretation, empty_preview) + + # フォルダパスが空の場合はスキップ + if not lora_folder_path.strip(): + print("[FilteredRandomLoRALoaderLBW] Warning: lora_folder_path is empty, skipping") + empty_preview = self._generate_preview_batch([]) + return self._generate_outputs(model, clip, final_positive, final_negative, + token_normalization, weight_interpretation, empty_preview) + + # LoRAファイル一覧を取得 + lora_files = self._find_lora_files(lora_folder_path, include_subfolders) + + if not lora_files: + print(f"[FilteredRandomLoRALoaderLBW] Warning: No LoRA files found in {lora_folder_path}") + empty_preview = self._generate_preview_batch([]) + return self._generate_outputs(model, clip, final_positive, final_negative, + token_normalization, weight_interpretation, empty_preview) + + # キーワードフィルタリング + filtered_files = self._filter_lora_files( + lora_files, keyword_filter, filter_mode, search_in_metadata + ) + + if not filtered_files: + print(f"[FilteredRandomLoRALoaderLBW] Warning: No LoRAs found matching filter '{keyword_filter}'") + empty_preview = self._generate_preview_batch([]) + return self._generate_outputs(model, clip, final_positive, final_negative, + token_normalization, weight_interpretation, empty_preview) + + # ファイル名でユニーク化(重複ファイル名を除外) + if unique_by_filename: + filtered_files = self._unique_by_filename(filtered_files) + if not filtered_files: + print(f"[FilteredRandomLoRALoaderLBW] Warning: No LoRAs after deduplication") + empty_preview = self._generate_preview_batch([]) + return self._generate_outputs(model, clip, final_positive, final_negative, + token_normalization, weight_interpretation, empty_preview) + + # ランダム選択(重複なし、不足時は重複で埋める) + available_count = len(filtered_files) + + if num_loras <= available_count: + # 十分な数がある場合は重複なしで選択 + selected_loras = random.sample(filtered_files, num_loras) + else: + # 不足する場合は全て選択後、再選択で埋める + selected_loras = filtered_files.copy() + remaining = num_loras - available_count + + print(f"[FilteredRandomLoRALoaderLBW] Warning: Requested {num_loras} LoRAs but only {available_count} available. Adding {remaining} duplicates.") + + # 不足分をランダムに追加(重複あり) + for _ in range(remaining): + selected_loras.append(random.choice(filtered_files)) + + # 最終的にシャッフル + random.shuffle(selected_loras) + + # LoRA適用 + lora_info_parts = [] + sample_negative_parts = [] # json_sample_prompt用のnegative収集 + preview_images = [] # プレビュー画像収集 + + for lora_path in selected_loras: + # 強度を取得 + model_str = self._get_random_strength(model_strength) + clip_str = self._get_random_strength(clip_strength) + + # LoRA適用(LBW対応) + model, clip = self._apply_lora(model, clip, lora_path, model_str, clip_str, lbw_weights) + + # LoRA情報を記録(LBW対応) + lora_name = os.path.splitext(os.path.basename(lora_path))[0] + if lbw_weights: + # LBW形式: + lora_notation = f"" + else: + # 通常形式: + lora_notation = f"" + + # トリガーワード取得 + if trigger_word_source == "json_sample_prompt": + # 作例プロンプト取得(positive/negative両方) + sample_positive, sample_negative = self._get_sample_prompt_from_json(lora_path) + trigger_words = sample_positive + if sample_negative: + sample_negative_parts.append(sample_negative) + else: + trigger_words = self._get_trigger_words(lora_path, trigger_word_source) + + # 結合 + if trigger_words: + lora_info_parts.append(f"{lora_notation}, {trigger_words}") + else: + lora_info_parts.append(lora_notation) + + # プレビュー画像を読み込み + preview = self._load_preview_image_as_tensor(lora_path) + if preview is not None: + preview_images.append(preview) + + # 最終プロンプト生成 + lora_info = ", ".join(lora_info_parts) + + # positive_text + parts_positive = [] + if final_positive: + parts_positive.append(final_positive) + parts_positive.append(lora_info) + final_positive = ", ".join(parts_positive) + + # negative_text + # 1. additional_prompt_negative + # 2. json_sample_promptからのnegative + if sample_negative_parts: + sample_negative_combined = ", ".join(sample_negative_parts) + if final_negative: + final_negative = f"{final_negative}, {sample_negative_combined}" + else: + final_negative = sample_negative_combined + + # プレビュー画像バッチ生成 + preview_batch = self._generate_preview_batch(preview_images) + + return self._generate_outputs(model, clip, final_positive, final_negative, + token_normalization, weight_interpretation, preview_batch) + + def _find_lora_files(self, folder_path, include_subfolders): + """フォルダ内のLoRAファイルを検索""" + if not os.path.exists(folder_path): + print(f"[FilteredRandomLoRALoaderLBW] Error: Folder not found: {folder_path}") + return [] + + lora_files = [] + extensions = ['.safetensors', '.pt', '.ckpt'] + + if include_subfolders: + for root, dirs, files in os.walk(folder_path): + for file in files: + if any(file.lower().endswith(ext) for ext in extensions): + lora_files.append(os.path.join(root, file)) + else: + for file in os.listdir(folder_path): + file_path = os.path.join(folder_path, file) + if os.path.isfile(file_path) and any(file.lower().endswith(ext) for ext in extensions): + lora_files.append(file_path) + + return lora_files + + def _parse_keywords(self, keyword_filter): + """ + キーワードをパース(スペース区切り、"..."でフレーズ対応) + + 例: + "anime style" → ["anime", "style"] + "anime style" red → ["anime style", "red"] + "anime style" "vibrant colors" → ["anime style", "vibrant colors"] + """ + if not keyword_filter.strip(): + return [] + + import re + + # ダブルクォート内のフレーズを抽出 + pattern = r'"([^"]+)"|(\S+)' + matches = re.findall(pattern, keyword_filter) + + # (quoted, unquoted) のタプルから値を取得 + keywords = [m[0] if m[0] else m[1] for m in matches] + + # 小文字化 + keywords = [kw.lower() for kw in keywords if kw] + + return keywords + + def _unique_by_filename(self, lora_files): + """ + ファイル名でユニーク化(重複ファイル名を除外) + + Args: + lora_files: LoRAファイルパスのリスト + + Returns: + list: ファイル名がユニークなファイルパスのリスト + + 例: + ["/path/style/anime.safetensors", "/path/backup/anime.safetensors"] + → ["/path/style/anime.safetensors"] # 最初に見つかったものを保持 + """ + seen_names = {} + unique_files = [] + + for file_path in lora_files: + filename = os.path.basename(file_path) + + if filename not in seen_names: + seen_names[filename] = file_path + unique_files.append(file_path) + else: + # 重複検出時はログ出力 + print(f"[FilteredRandomLoRALoaderLBW] Duplicate filename detected: {filename}") + print(f" Keeping: {seen_names[filename]}") + print(f" Skipping: {file_path}") + + return unique_files + + def _filter_lora_files(self, lora_files, keyword_filter, filter_mode="OR", search_in_metadata=False): + """キーワードでLoRAファイルをフィルタリング""" + if not keyword_filter.strip(): + return lora_files # フィルタなし = 全ファイル + + # キーワードをパース(スペース区切り、"..."でフレーズ対応) + keywords = self._parse_keywords(keyword_filter) + if not keywords: + return lora_files + + # メタデータ検索が無効な場合(デフォルト) + if not search_in_metadata: + # ファイル名のみ検索(超高速) + filtered = [] + for lora_path in lora_files: + filename = os.path.splitext(os.path.basename(lora_path))[0].lower() + if filter_mode == "AND": + if all(kw in filename for kw in keywords): + filtered.append(lora_path) + else: + if any(kw in filename for kw in keywords): + filtered.append(lora_path) + return filtered + + # メタデータ検索が有効な場合(初回は遅い) + total = len(lora_files) + filtered = [] + + print(f"[FilteredRandomLoRALoaderLBW] Building metadata cache for {total} files...") + + for i, lora_path in enumerate(lora_files): + # 進捗表示(100個ごと) + if i > 0 and i % 100 == 0: + print(f"[FilteredRandomLoRALoaderLBW] Progress: {i}/{total} ({int(i/total*100)}%)") + + filename = os.path.splitext(os.path.basename(lora_path))[0].lower() + search_target = filename + + # メタデータからキーワード取得(キャッシュ利用) + metadata_keywords = self._get_metadata_keywords(lora_path) + if metadata_keywords: + search_target = f"{filename} {metadata_keywords}" + + # フィルタリング + if filter_mode == "AND": + if all(kw in search_target for kw in keywords): + filtered.append(lora_path) + else: + if any(kw in search_target for kw in keywords): + filtered.append(lora_path) + + print(f"[FilteredRandomLoRALoaderLBW] Cache built. Filtered {len(filtered)}/{total} files.") + + return filtered + + def _get_metadata_keywords(self, lora_path): + """ + メタデータからキーワードを取得(キャッシュ付き) + + 検索対象: + 1. model_name(トップレベル) + 2. civitai.name + 3. civitai.trainedWords(全パターンを結合、重複除去) + 4. civitai.model.name + 5. civitai.model.tags + 6. tags(トップレベル) + 7. 埋め込みメタデータ(ss_tag_frequency等) + + Returns: + str: 検索用キーワード文字列(小文字、スペース区切り) + """ + # キャッシュ確認 + if lora_path in self._metadata_cache: + return self._metadata_cache[lora_path] + + # メタデータ読み込み + metadata = self._load_json_metadata(lora_path) + keywords_parts = [] + + if metadata: + # 1. トップレベルのmodel_name + model_name = metadata.get("model_name", "") + if model_name: + keywords_parts.append(model_name) + + # civitaiセクション + civitai = metadata.get("civitai", {}) + + # 2. civitai.name + civitai_name = civitai.get("name", "") + if civitai_name: + keywords_parts.append(civitai_name) + + # 3. civitai.trainedWords + trained_words = civitai.get("trainedWords", []) + if trained_words: + all_words = [] + for pattern in trained_words: + # カンマ区切りで分割 + words = [w.strip() for w in pattern.split(',')] + all_words.extend(words) + # 重複除去(順序維持) + unique_words = list(dict.fromkeys(all_words)) + keywords_parts.extend(unique_words) + + # civitai.modelセクション + model_info = civitai.get("model", {}) + + # 4. civitai.model.name + model_info_name = model_info.get("name", "") + if model_info_name: + keywords_parts.append(model_info_name) + + # 5. civitai.model.tags + model_tags = model_info.get("tags", []) + if model_tags: + keywords_parts.extend(model_tags) + + # 6. トップレベルのtags(通常は5と同じ内容だが念のため) + top_tags = metadata.get("tags", []) + if top_tags: + keywords_parts.extend(top_tags) + + # 重複除去(順序維持) + unique_keywords = list(dict.fromkeys(keywords_parts)) + + # 小文字化してスペース区切りで結合 + keywords = " ".join(unique_keywords).lower() + + # キャッシュに保存 + self._metadata_cache[lora_path] = keywords + + return keywords + + def _load_json_metadata(self, lora_path): + """ + メタデータファイルまたは埋め込みメタデータを読み込み + + 優先順位: + 1. .metadata.json(ComfyUI Lora Manager) + 2. .info(Civitai Helper) + 3. 埋め込みメタデータ + """ + base_path = os.path.splitext(lora_path)[0] + + # 1. .metadata.json + metadata_json_path = f"{base_path}.metadata.json" + if os.path.exists(metadata_json_path): + try: + with open(metadata_json_path, 'r', encoding='utf-8') as f: + return json.load(f) + except Exception as e: + print(f"[FilteredRandomLoRALoaderLBW] Warning: Failed to load {metadata_json_path}: {e}") + + # 2. .info + info_path = f"{base_path}.info" + if os.path.exists(info_path): + try: + with open(info_path, 'r', encoding='utf-8') as f: + return json.load(f) + except Exception as e: + print(f"[FilteredRandomLoRALoaderLBW] Warning: Failed to load {info_path}: {e}") + + # 3. 埋め込みメタデータ + embedded = self._load_embedded_metadata(lora_path) + if embedded: + return embedded + + return None + + def _load_embedded_metadata(self, lora_path): + """LoRAファイルから埋め込みメタデータを読み込み(Civitai形式に変換)""" + try: + from safetensors.torch import safe_open + + with safe_open(lora_path, framework="pt") as f: + metadata = f.metadata() + + if not metadata: + return None + + # Civitai形式に変換 + civitai_format = {"civitai": {}} + + # ss_tag_frequency からトリガーワード抽出 + if "ss_tag_frequency" in metadata: + try: + tag_freq_str = metadata.get("ss_tag_frequency", "{}") + tag_freq = json.loads(tag_freq_str) + + all_tags = [] + for dataset_name, tags_dict in tag_freq.items(): + sorted_tags = sorted(tags_dict.items(), key=lambda x: x[1], reverse=True) + top_tags = [tag for tag, freq in sorted_tags[:20]] + all_tags.extend(top_tags) + + if all_tags: + unique_tags = list(dict.fromkeys(all_tags)) + civitai_format["civitai"]["trainedWords"] = [", ".join(unique_tags)] + except: + pass + + # modelspec.trigger_word + if "modelspec.trigger_word" in metadata: + trigger_word = metadata.get("modelspec.trigger_word", "") + if trigger_word and "trainedWords" not in civitai_format["civitai"]: + civitai_format["civitai"]["trainedWords"] = [trigger_word] + + # ss_output_name + if "ss_output_name" in metadata: + model_name = metadata.get("ss_output_name", "") + if model_name: + civitai_format["model_name"] = model_name + + return civitai_format if civitai_format["civitai"] else None + + except Exception as e: + return None + + def _get_trigger_words(self, lora_path, trigger_word_source): + """トリガーワードを取得""" + if trigger_word_source == "metadata": + # 埋め込みメタデータのみ参照 + return self._get_trigger_words_from_embedded(lora_path) + elif trigger_word_source == "json_sample_prompt": + # 作例プロンプト取得 + sample_positive, sample_negative = self._get_sample_prompt_from_json(lora_path) + return sample_positive + elif trigger_word_source == "json_random": + # ランダム選択 + return self._get_trigger_words_random(lora_path) + else: # json_combined + # 全結合 + return self._get_trigger_words_combined(lora_path) + + def _get_trigger_words_combined(self, lora_path): + """全トリガーワードを結合""" + metadata = self._load_json_metadata(lora_path) + if not metadata: + return "" + + trained_words = metadata.get("civitai", {}).get("trainedWords", []) + if not trained_words: + return "" + + all_words = [] + for pattern in trained_words: + # LoRA構文を削除してから分割 + pattern = self._remove_lora_syntax(pattern) + words = [w.strip() for w in pattern.split(',')] + all_words.extend(words) + + unique_words = list(dict.fromkeys(all_words)) + return ", ".join(unique_words) + + def _get_trigger_words_random(self, lora_path): + """トリガーワードからランダムに1つ選択""" + metadata = self._load_json_metadata(lora_path) + if not metadata: + return "" + + trained_words = metadata.get("civitai", {}).get("trainedWords", []) + if not trained_words: + return "" + + # LoRA構文を削除 + selected = random.choice(trained_words) + return self._remove_lora_syntax(selected) + + def _get_sample_prompt_from_json(self, lora_path): + """作例プロンプトをランダムに取得""" + metadata = self._load_json_metadata(lora_path) + if not metadata: + return "", "" + + images = metadata.get("civitai", {}).get("images", []) + if not images: + return "", "" + + valid_images = [img for img in images if "meta" in img and img["meta"]] + if not valid_images: + return "", "" + + selected_image = random.choice(valid_images) + meta = selected_image["meta"] + + positive = meta.get("prompt", "") + negative = meta.get("negativePrompt", "") + + # LoRA構文削除(両方) + positive = self._remove_lora_syntax(positive) + negative = self._remove_lora_syntax(negative) + + return positive, negative + + def _get_trigger_words_from_embedded(self, lora_path): + """埋め込みメタデータから直接トリガーワード取得""" + embedded = self._load_embedded_metadata(lora_path) + if not embedded: + return "" + + trained_words = embedded.get("civitai", {}).get("trainedWords", []) + if not trained_words: + return "" + + return trained_words[0] if trained_words else "" + + def _remove_lora_syntax(self, text): + """プロンプトからLoRA構文を削除""" + pattern = r']+>' + return re.sub(pattern, '', text) + + def _load_preview_image_as_tensor(self, lora_path): + """ + プレビュー画像をTensorとして読み込み(部分一致、長辺1240px) + + 検索方法: + LoRAファイル名(拡張子除く)で始まるファイルを検索 + 優先順位: + 1. 静止画像 (.png, .jpg, .jpeg, .webp) + 2. 動画ファイル (.gif, .webp, .mp4, .webm) の1フレーム目 + + 例: style_anime_v1.safetensors + → style_anime_v1.png + → style_anime_v1_preview.jpg + → style_anime_v1.gif (1フレーム目) + → style_anime_v1.mp4 (1フレーム目、opencv-pythonが必要) + → STYLE_ANIME_V1.PNG (大文字小文字無視) + + リサイズ: + 長辺を1240pxに統一(アスペクト比保持) + + Returns: + torch.Tensor: (H, W, C) 形式、見つからない場合はNone + """ + try: + from PIL import Image + import numpy as np + import torch + except ImportError: + print("[FilteredRandomLoRALoaderLBW] PIL/torch not available for preview") + return None + + # LoRAファイル名(拡張子なし) + base_name = os.path.splitext(os.path.basename(lora_path))[0] + folder = os.path.dirname(lora_path) + + # ファイル拡張子(優先順位順) + static_image_exts = ('.png', '.jpg', '.jpeg') + animated_image_exts = ('.gif', '.webp') # Pillowで対応可能 + video_exts = ('.mp4', '.webm', '.avi', '.mov') # opencv-python必要 + + try: + # 同じフォルダ内のファイルを検索 + files = os.listdir(folder) + + # 部分一致するファイルを収集 + matched_files = [] + for file in files: + if file.lower().startswith(base_name.lower()): + matched_files.append(file) + + if not matched_files: + return None + + # 優先順位でソート + def get_priority(filename): + lower = filename.lower() + if any(lower.endswith(ext) for ext in static_image_exts): + return 0 # 最優先 + elif any(lower.endswith(ext) for ext in animated_image_exts): + return 1 # 次優先 + elif any(lower.endswith(ext) for ext in video_exts): + return 2 # 最後 + else: + return 999 # その他 + + matched_files.sort(key=get_priority) + + # 各ファイルを試す + for file in matched_files: + preview_path = os.path.join(folder, file) + lower_file = file.lower() + + # 静止画像 + if any(lower_file.endswith(ext) for ext in static_image_exts): + img = self._load_static_image(preview_path) + if img is not None: + return img + + # アニメーション画像(GIF/WebP) + elif any(lower_file.endswith(ext) for ext in animated_image_exts): + img = self._load_animated_image_first_frame(preview_path) + if img is not None: + return img + + # 動画ファイル(opencv-python必要) + elif any(lower_file.endswith(ext) for ext in video_exts): + img = self._load_video_first_frame(preview_path) + if img is not None: + return img + + except Exception as e: + print(f"[FilteredRandomLoRALoaderLBW] Folder read error: {e}") + + return None + + def _load_static_image(self, image_path): + """静止画像を読み込み""" + try: + from PIL import Image + import numpy as np + import torch + + img = Image.open(image_path).convert('RGB') + return self._resize_and_convert_image(img) + except Exception as e: + print(f"[FilteredRandomLoRALoaderLBW] Static image load error ({image_path}): {e}") + return None + + def _load_animated_image_first_frame(self, image_path): + """アニメーション画像(GIF/WebP)の1フレーム目を読み込み""" + try: + from PIL import Image + import numpy as np + import torch + + img = Image.open(image_path) + + # 1フレーム目に移動 + if hasattr(img, 'seek'): + img.seek(0) + + img = img.convert('RGB') + return self._resize_and_convert_image(img) + except Exception as e: + print(f"[FilteredRandomLoRALoaderLBW] Animated image load error ({image_path}): {e}") + return None + + def _load_video_first_frame(self, video_path): + """動画ファイルの1フレーム目を読み込み(opencv-python必要)""" + try: + import cv2 + from PIL import Image + import numpy as np + import torch + + # OpenCVで動画を開く + cap = cv2.VideoCapture(video_path) + + if not cap.isOpened(): + return None + + # 1フレーム目を読み込み + ret, frame = cap.read() + cap.release() + + if not ret: + return None + + # BGR → RGB 変換 + frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) + + # PIL Imageに変換 + img = Image.fromarray(frame_rgb) + + return self._resize_and_convert_image(img) + + except ImportError: + # opencv-pythonがインストールされていない(初回のみ警告) + if not FilteredRandomLoRALoader._opencv_warning_shown: + print("=" * 60) + print("[FilteredRandomLoRALoaderLBW] Video Preview Support") + print("=" * 60) + print(f"Video file detected: {os.path.basename(video_path)}") + print("opencv-python is not installed.") + print("") + print("To enable video preview support, install:") + print(" pip install opencv-python") + print("") + print("Static images (.png/.jpg) and animated images (.gif/.webp)") + print("will continue to work without opencv-python.") + print("=" * 60) + FilteredRandomLoRALoader._opencv_warning_shown = True + return None + except Exception as e: + print(f"[FilteredRandomLoRALoaderLBW] Video load error ({video_path}): {e}") + return None + + def _resize_and_convert_image(self, img): + """画像をリサイズしてTensorに変換""" + try: + from PIL import Image + import numpy as np + import torch + + # 長辺を1240pxにリサイズ(アスペクト比保持) + width, height = img.size + max_size = 1240 + + if max(width, height) > max_size: + # 長辺が1240pxを超える場合はリサイズ + if width > height: + new_width = max_size + new_height = int(height * (max_size / width)) + else: + new_height = max_size + new_width = int(width * (max_size / height)) + + img = img.resize((new_width, new_height), Image.Resampling.LANCZOS) + elif max(width, height) < max_size: + # 長辺が1240px未満の場合は拡大 + if width > height: + new_width = max_size + new_height = int(height * (max_size / width)) + else: + new_height = max_size + new_width = int(width * (max_size / height)) + + img = img.resize((new_width, new_height), Image.Resampling.LANCZOS) + + # numpy配列に変換 (H, W, C) + img_array = np.array(img).astype(np.float32) / 255.0 + # Tensor化 + return torch.from_numpy(img_array) + + except Exception as e: + print(f"[FilteredRandomLoRALoaderLBW] Image resize/convert error: {e}") + return None + + def _get_lbw_weights(self, weight_mode, lbw_input): + """ + LBW ウェイトを取得(型は自動検出されるため、ここではプリセットのみ処理) + + Returns: + str: カンマ区切りのウェイト文字列、または None (Normal mode) + """ + # Normal (All 1.0) の場合は None を返す(LBW構文なし) + if weight_mode == "Normal (All 1.0)": + return None + + # Preset: Random の場合 + if weight_mode == "Preset: Random": + presets = ["Style Focused", "Character Focused", + "Structure/Composition Only", "Balanced / Soft"] + weight_mode = random.choice(presets) + print(f"[FilteredRandomLoRALoaderLBW] Random preset selected: {weight_mode}") + + # Direct Input の場合 + if weight_mode == "Direct Input": + weights = lbw_input.strip() + + # 空欄の場合はNone(Normal All 1.0として扱う) + if not weights: + print(f"[FilteredRandomLoRALoaderLBW] Direct Input is empty, using Normal (All 1.0)") + return None + + # 数値チェックのみ(要素数チェックは _apply_lora で自動調整) + try: + weight_list = [w.strip() for w in weights.split(',')] + for w in weight_list: + float(w) + return weights + except ValueError: + print(f"[FilteredRandomLoRALoaderLBW] Error: Invalid number in LBW input") + print(f"[FilteredRandomLoRALoaderLBW] Using default (All 1.0)") + return None + + # プリセットの場合(SDXLプリセットを使用、_apply_loraで自動調整) + if weight_mode in SDXL_PRESETS: + return SDXL_PRESETS[weight_mode] + else: + print(f"[FilteredRandomLoRALoaderLBW] Unknown weight_mode: {weight_mode}") + return None + + def _get_random_strength(self, strength_str): + """強度をランダム取得(範囲指定は0.1刻み、固定値は小数点2桁)""" + import re + strength_str = strength_str.strip() + + # 範囲指定のパターンマッチ + range_pattern = r'^(-?\d+\.?\d*)\s*-\s*(-?\d+\.?\d*)$' + match = re.match(range_pattern, strength_str) + + if match: + try: + # 範囲の上限下限を1桁に丸める + min_val = round(float(match.group(1)), 1) + max_val = round(float(match.group(2)), 1) + + # 0.1刻みの値のリストを生成 + values = [] + current = min_val + while current <= max_val + 0.01: # 浮動小数点誤差対策 + values.append(round(current, 1)) + current += 0.1 + + if not values: + return "1.0" + + # ランダムに1つ選択 + selected = random.choice(values) + return str(selected) + except: + return "1.0" + else: + # 単一値(小数点2桁に丸める) + try: + value = float(strength_str) + return str(round(value, 2)) + except: + return "1.0" + + def _apply_lora(self, model, clip, lora_path, model_strength, clip_strength, lbw_weights=None): + """LoRAを適用(LBW対応)""" + try: + model_strength_f = float(model_strength) + clip_strength_f = float(clip_strength) + + lora = comfy.utils.load_torch_file(lora_path, safe_load=True) + + # LBWが指定されている場合 + if lbw_weights: + # LoRAファイルからSD1.5/SDXLを自動検出 + detected_type = self._detect_lora_type(lora) + + # ウェイトリストに変換 + weights_list = [float(w.strip()) for w in lbw_weights.split(',')] + + # 要素数チェック(検出された型に基づく) + expected_count = 20 if detected_type == "SDXL" else 17 + if len(weights_list) != expected_count: + print(f"[FilteredRandomLoRALoaderLBW] Warning: LoRA is {detected_type} but got {len(weights_list)} weights (expected {expected_count})") + print(f"[FilteredRandomLoRALoaderLBW] Adjusting weights to match LoRA type...") + + # ウェイトを調整 + if len(weights_list) < expected_count: + # 足りない場合は1.0で埋める + weights_list.extend([1.0] * (expected_count - len(weights_list))) + else: + # 多い場合は切り詰める + weights_list = weights_list[:expected_count] + + # LoRAのキーを解析してブロックウェイトを適用 + lora_with_weights = self._apply_block_weights(lora, weights_list, model_strength_f) + + # MODEL/CLIPに適用 + model_lora, clip_lora = comfy.sd.load_lora_for_models( + model, clip, lora_with_weights, 1.0, clip_strength_f + ) + else: + # 通常適用 + model_lora, clip_lora = comfy.sd.load_lora_for_models( + model, clip, lora, model_strength_f, clip_strength_f + ) + + return model_lora, clip_lora + except Exception as e: + print(f"[FilteredRandomLoRALoaderLBW] Warning: Failed to apply LoRA {lora_path}: {e}") + import traceback + traceback.print_exc() + return model, clip + + def _detect_lora_type(self, lora_dict): + """ + LoRAファイルからSD1.5/SDXLを自動検出 + + Args: + lora_dict: LoRAの辞書 + + Returns: + "SDXL" or "SD1.5" + """ + # input_blocksの最大番号を確認 + max_input_block = -1 + for key in lora_dict.keys(): + if "input_blocks" in key: + import re + match = re.search(r'input_blocks_(\d+)', key) + if match: + block_num = int(match.group(1)) + max_input_block = max(max_input_block, block_num) + + # SD1.5: input_blocks_0~8 (9個) + # SDXL: input_blocks_0~8 (9個) ← 同じ! + + # output_blocksの最大番号を確認 + max_output_block = -1 + for key in lora_dict.keys(): + if "output_blocks" in key: + import re + match = re.search(r'output_blocks_(\d+)', key) + if match: + block_num = int(match.group(1)) + max_output_block = max(max_output_block, block_num) + + # SD1.5: output_blocks_0~11 (12個) + # SDXL: output_blocks_0~8 (9個) + + if max_output_block >= 9: + # output_blocks が 9以上 → SD1.5 + return "SD1.5" + else: + # output_blocks が 8以下 → SDXL + return "SDXL" + + def _apply_block_weights(self, lora_dict, weights_list, base_strength): + """ + LoRAのテンソルにブロックウェイトを適用 + + Args: + lora_dict: LoRAの辞書 + weights_list: ウェイトのリスト(SD1.5: 17, SDXL: 20) + base_strength: ベース強度 + + Returns: + ウェイト適用済みのLoRA辞書 + """ + # ブロック名のマッピング(SD1.5/SDXL共通のパターン) + # キー名の例: + # "lora_unet_input_blocks_0_0.weight" → INブロック + # "lora_unet_middle_block_0.weight" → MIDブロック + # "lora_unet_output_blocks_0_0.weight" → OUTブロック + + weighted_lora = {} + + for key, value in lora_dict.items(): + weight_multiplier = base_strength + + # UNetのLoRAキーのみ処理 + if "lora_unet" in key: + block_index = self._get_block_index(key, len(weights_list)) + if block_index is not None and block_index < len(weights_list): + weight_multiplier = base_strength * weights_list[block_index] + + # ウェイトを適用 + weighted_lora[key] = value * weight_multiplier + + return weighted_lora + + def _get_block_index(self, key, num_weights): + """ + LoRAキー名からブロックインデックスを取得 + + Args: + key: LoRAのキー名 + num_weights: ウェイト数(17 or 20) + + Returns: + ブロックインデックス(0から始まる) + """ + # BASE(常に0番目) + if "time_embed" in key or "label_emb" in key: + return 0 + + # SD1.5の場合(17要素) + if num_weights == 17: + # INPUT blocks (IN01, IN02, IN04, IN05, IN07, IN08) + if "input_blocks" in key: + # input_blocks_X_... の X を抽出 + import re + match = re.search(r'input_blocks_(\d+)', key) + if match: + block_num = int(match.group(1)) + # SD1.5のINブロックマッピング + # IN01=1, IN02=2, IN04=3, IN05=4, IN07=5, IN08=6 + in_mapping = {1: 1, 2: 2, 4: 3, 5: 4, 7: 5, 8: 6} + if block_num in in_mapping: + return in_mapping[block_num] + + # MIDDLE block (M00 = index 7) + elif "middle_block" in key: + return 7 + + # OUTPUT blocks (OUT03-OUT11 = index 8-16) + elif "output_blocks" in key: + import re + match = re.search(r'output_blocks_(\d+)', key) + if match: + block_num = int(match.group(1)) + # OUT03-OUT11 → index 8-16 + if block_num >= 3 and block_num <= 11: + return 8 + (block_num - 3) + + # SDXLの場合(20要素) + elif num_weights == 20: + # INPUT blocks (IN00-IN08 = index 1-9) + if "input_blocks" in key: + import re + match = re.search(r'input_blocks_(\d+)', key) + if match: + block_num = int(match.group(1)) + if block_num <= 8: + return 1 + block_num + + # MIDDLE block (M00 = index 10) + elif "middle_block" in key: + return 10 + + # OUTPUT blocks (OUT00-OUT08 = index 11-19) + elif "output_blocks" in key: + import re + match = re.search(r'output_blocks_(\d+)', key) + if match: + block_num = int(match.group(1)) + if block_num <= 8: + return 11 + block_num + + # デフォルト: BASEとして扱う + return 0 + + + def _generate_preview_batch(self, preview_images): + """ + プレビュー画像のバッチを生成(1240pxに統一、パディング) + + Args: + preview_images: list of torch.Tensor (各々 H, W, C、長辺1240px) + + Returns: + torch.Tensor: (B, 1240, 1240, C) 形式 + """ + try: + import torch + import torch.nn.functional as F + except ImportError: + return None + + if not preview_images: + # プレビュー画像なし → 黒画像1枚(1240x1240) + black_image = torch.zeros((1, 1240, 1240, 3), dtype=torch.float32) + return black_image + + # 全て1240x1240にパディング + padded_images = [] + target_size = 1240 + + for img in preview_images: + h, w, c = img.shape + + # パディングが必要か確認 + if h == target_size and w == target_size: + padded_images.append(img) + else: + # パディング量を計算(中央配置) + pad_h = target_size - h + pad_w = target_size - w + pad_top = pad_h // 2 + pad_bottom = pad_h - pad_top + pad_left = pad_w // 2 + pad_right = pad_w - pad_left + + # (H, W, C) → (C, H, W) に変換してパディング + img_chw = img.permute(2, 0, 1) # (C, H, W) + + # F.pad: (left, right, top, bottom) + padded = F.pad(img_chw, (pad_left, pad_right, pad_top, pad_bottom), value=0) + + # (C, H, W) → (H, W, C) に戻す + padded = padded.permute(1, 2, 0) + padded_images.append(padded) + + # バッチ化 (B, 1240, 1240, C) + preview_batch = torch.stack(padded_images, dim=0) + return preview_batch + + def _generate_outputs(self, model, clip, final_positive, final_negative, + token_normalization, weight_interpretation, preview_batch): + """CONDITIONING生成と出力""" + try: + from nodes import CLIPTextEncode + + # LoRA構文を削除してクリーンなプロンプトにする + clean_positive = self._remove_lora_syntax(final_positive) if final_positive else "" + clean_negative = self._remove_lora_syntax(final_negative) if final_negative else "" + + # CONDITIONING生成 + positive_conditioning = CLIPTextEncode().encode( + clip=clip, + text=clean_positive + )[0] + + negative_conditioning = CLIPTextEncode().encode( + clip=clip, + text=clean_negative + )[0] + + return (model, clip, final_positive, final_negative, + positive_conditioning, negative_conditioning, preview_batch) + except Exception as e: + print(f"[FilteredRandomLoRALoaderLBW] Error generating outputs: {e}") + # エラー時は黒画像 + try: + import torch + black_image = torch.zeros((1, 1240, 1240, 3), dtype=torch.float32) + except: + black_image = None + return (model, clip, final_positive, final_negative, None, None, black_image) diff --git a/images/lbw_final_single.webp b/images/lbw_final_single.webp new file mode 100644 index 0000000000000000000000000000000000000000..16402916f72de1d6bb1db5816f0c856f37f36e06 GIT binary patch literal 247854 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 MD{Pa$y{6V)UB3mK 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

1< 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 AhyVZp literal 0 HcmV?d00001 diff --git a/pyproject.toml b/pyproject.toml index 9333580..a10ff08 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,19 +1,37 @@ [project] -name = "randomloraloader" -description = "Randomly select and apply LoRAs with keyword filtering, preview images, and multiple folder support for ComfyUI" -version = "1.1.0" -license = {file = "LICENSE"} - -classifiers = [ - "Operating System :: OS Independent", - "Environment :: GPU :: NVIDIA CUDA", - "Environment :: GPU :: AMD ROCm", +name = "comfyui-random-lora-loader" +version = "1.2.0" +description = "Randomly select and apply LoRAs with keyword filtering, LoRA Block Weight support, and preview images for ComfyUI" +readme = "README.md" +requires-python = ">=3.9" +license = {text = "MIT"} +authors = [ + {name = "Your Name", email = "your.email@example.com"} # 必要に応じて変更 ] -[project.urls] -Repository = "https://github.com/shin131002/RandomLoRALoader" +keywords = ["comfyui", "lora", "stable-diffusion", "ai", "image-generation", "block-weight", "lbw"] -[tool.comfy] -PublisherId = "" -DisplayName = "RandomLoRALoader" -Icon = "" \ No newline at end of file +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", +] + +[project.optional-dependencies] +video = ["opencv-python>=4.0.0"] + +[project.urls] +Homepage = "https://github.com/YOUR_USERNAME/RandomLoRALoader" +Repository = "https://github.com/YOUR_USERNAME/RandomLoRALoader" +Issues = "https://github.com/YOUR_USERNAME/RandomLoRALoader/issues" + +[build-system] +requires = ["setuptools>=61.0"] +build-backend = "setuptools.build_meta" + +[tool.setuptools] +packages = ["RandomLoRALoader"] diff --git a/random_lora_loader.py b/random_lora_loader.py index 615f417..731d893 100644 --- a/random_lora_loader.py +++ b/random_lora_loader.py @@ -77,6 +77,9 @@ except ImportError: class RandomLoRALoader: """ランダムLoRA選択・適用ノード(3グループ対応)""" + # クラス変数(opencv警告表示フラグ) + _opencv_warning_shown = False + @classmethod def INPUT_TYPES(cls): return { @@ -311,6 +314,7 @@ class RandomLoRALoader: - "0.55" → 0.55(そのまま) - "0.4-0.8" → 0.4, 0.5, 0.6, 0.7, 0.8からランダム(0.1刻み) - "0.44-0.82" → 0.4, 0.5, 0.6, 0.7, 0.8からランダム(範囲を1桁に丸める) + - "-0.8--0.3" → -0.8, -0.7, -0.6, ..., -0.3からランダム(マイナス範囲対応) Args: strength_str: 強度文字列 @@ -318,18 +322,19 @@ class RandomLoRALoader: Returns: float: 実際に使用する強度値 """ + import re strength_str = str(strength_str).strip() - # ハイフンがあればランダム範囲指定 - if '-' in strength_str: + # 範囲指定のパターンマッチ(マイナス値対応) + # 例: "0.6-0.9", "-0.8--0.3", "-0.5-0.5", "0.3--0.7" + range_pattern = r'^(-?\d+\.?\d*)\s*-\s*(-?\d+\.?\d*)$' + match = re.match(range_pattern, strength_str) + + if match: try: - parts = strength_str.split('-') - if len(parts) != 2: - raise ValueError("範囲指定は 'min-max' 形式で入力してください") - # 範囲の上限下限を1桁に丸める - min_val = round(float(parts[0].strip()), 1) - max_val = round(float(parts[1].strip()), 1) + min_val = round(float(match.group(1)), 1) + max_val = round(float(match.group(2)), 1) # バリデーション if min_val < -10.0 or max_val > 10.0: @@ -747,18 +752,20 @@ class RandomLoRALoader: プレビュー画像をTensorとして読み込み(部分一致、長辺1240px) 検索方法: - LoRAファイル名(拡張子除く)で始まる画像ファイルを検索 + LoRAファイル名(拡張子除く)で始まるファイルを検索 + 優先順位: + 1. 静止画像 (.png, .jpg, .jpeg, .webp) + 2. 動画ファイル (.gif, .webp, .mp4, .webm) の1フレーム目 + 例: style_anime_v1.safetensors → style_anime_v1.png - → style_anime_v1_preview.png - → style_anime_v1_001.jpg + → style_anime_v1_preview.jpg + → style_anime_v1.gif (1フレーム目) + → style_anime_v1.mp4 (1フレーム目、opencv-pythonが必要) → STYLE_ANIME_V1.PNG (大文字小文字無視) リサイズ: 長辺を1240pxに統一(アスペクト比保持) - 例: 1024x768 → 1240x930 - 512x512 → 1240x1240 - 800x1200 → 826x1240 Returns: torch.Tensor: (H, W, C) 形式、見つからない場合はNone @@ -774,57 +781,189 @@ class RandomLoRALoader: base_name = os.path.splitext(os.path.basename(lora_path))[0] folder = os.path.dirname(lora_path) - # 画像拡張子 - image_extensions = ('.png', '.jpg', '.jpeg', '.webp', '.gif') + # ファイル拡張子(優先順位順) + static_image_exts = ('.png', '.jpg', '.jpeg') + animated_image_exts = ('.gif', '.webp') # Pillowで対応可能 + video_exts = ('.mp4', '.webm', '.avi', '.mov') # opencv-python必要 try: # 同じフォルダ内のファイルを検索 - for file in os.listdir(folder): - # 部分一致(大文字小文字無視) + files = os.listdir(folder) + + # 部分一致するファイルを収集 + matched_files = [] + for file in files: if file.lower().startswith(base_name.lower()): - # 画像ファイルか確認 - if file.lower().endswith(image_extensions): - preview_path = os.path.join(folder, file) - try: - img = Image.open(preview_path).convert('RGB') - - # 長辺を1240pxにリサイズ(アスペクト比保持) - width, height = img.size - max_size = 1240 - - if max(width, height) > max_size: - # 長辺が1240pxを超える場合はリサイズ - if width > height: - new_width = max_size - new_height = int(height * (max_size / width)) - else: - new_height = max_size - new_width = int(width * (max_size / height)) - - img = img.resize((new_width, new_height), Image.Resampling.LANCZOS) - elif max(width, height) < max_size: - # 長辺が1240px未満の場合は拡大 - if width > height: - new_width = max_size - new_height = int(height * (max_size / width)) - else: - new_height = max_size - new_width = int(width * (max_size / height)) - - img = img.resize((new_width, new_height), Image.Resampling.LANCZOS) - - # numpy配列に変換 (H, W, C) - img_array = np.array(img).astype(np.float32) / 255.0 - # Tensor化 - return torch.from_numpy(img_array) - except Exception as e: - print(f"[RandomLoRALoader] Preview load error ({preview_path}): {e}") - continue + matched_files.append(file) + + if not matched_files: + return None + + # 優先順位でソート + def get_priority(filename): + lower = filename.lower() + if any(lower.endswith(ext) for ext in static_image_exts): + return 0 # 最優先 + elif any(lower.endswith(ext) for ext in animated_image_exts): + return 1 # 次優先 + elif any(lower.endswith(ext) for ext in video_exts): + return 2 # 最後 + else: + return 999 # その他 + + matched_files.sort(key=get_priority) + + # 各ファイルを試す + for file in matched_files: + preview_path = os.path.join(folder, file) + lower_file = file.lower() + + # 静止画像 + if any(lower_file.endswith(ext) for ext in static_image_exts): + img = self._load_static_image(preview_path) + if img is not None: + return img + + # アニメーション画像(GIF/WebP) + elif any(lower_file.endswith(ext) for ext in animated_image_exts): + img = self._load_animated_image_first_frame(preview_path) + if img is not None: + return img + + # 動画ファイル(opencv-python必要) + elif any(lower_file.endswith(ext) for ext in video_exts): + img = self._load_video_first_frame(preview_path) + if img is not None: + return img + except Exception as e: print(f"[RandomLoRALoader] Folder read error: {e}") return None + def _load_static_image(self, image_path): + """静止画像を読み込み""" + try: + from PIL import Image + import numpy as np + import torch + + img = Image.open(image_path).convert('RGB') + return self._resize_and_convert_image(img) + except Exception as e: + print(f"[RandomLoRALoader] Static image load error ({image_path}): {e}") + return None + + def _load_animated_image_first_frame(self, image_path): + """アニメーション画像(GIF/WebP)の1フレーム目を読み込み""" + try: + from PIL import Image + import numpy as np + import torch + + img = Image.open(image_path) + + # 1フレーム目に移動 + if hasattr(img, 'seek'): + img.seek(0) + + img = img.convert('RGB') + return self._resize_and_convert_image(img) + except Exception as e: + print(f"[RandomLoRALoader] Animated image load error ({image_path}): {e}") + return None + + def _load_video_first_frame(self, video_path): + """動画ファイルの1フレーム目を読み込み(opencv-python必要)""" + try: + import cv2 + from PIL import Image + import numpy as np + import torch + + # OpenCVで動画を開く + cap = cv2.VideoCapture(video_path) + + if not cap.isOpened(): + return None + + # 1フレーム目を読み込み + ret, frame = cap.read() + cap.release() + + if not ret: + return None + + # BGR → RGB 変換 + frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) + + # PIL Imageに変換 + img = Image.fromarray(frame_rgb) + + return self._resize_and_convert_image(img) + + except ImportError: + # opencv-pythonがインストールされていない(初回のみ警告) + if not RandomLoRALoader._opencv_warning_shown: + print("=" * 60) + print("[RandomLoRALoader] Video Preview Support") + print("=" * 60) + print(f"Video file detected: {os.path.basename(video_path)}") + print("opencv-python is not installed.") + print("") + print("To enable video preview support, install:") + print(" pip install opencv-python") + print("") + print("Static images (.png/.jpg) and animated images (.gif/.webp)") + print("will continue to work without opencv-python.") + print("=" * 60) + RandomLoRALoader._opencv_warning_shown = True + return None + except Exception as e: + print(f"[RandomLoRALoader] Video load error ({video_path}): {e}") + return None + + def _resize_and_convert_image(self, img): + """画像をリサイズしてTensorに変換""" + try: + from PIL import Image + import numpy as np + import torch + + # 長辺を1240pxにリサイズ(アスペクト比保持) + width, height = img.size + max_size = 1240 + + if max(width, height) > max_size: + # 長辺が1240pxを超える場合はリサイズ + if width > height: + new_width = max_size + new_height = int(height * (max_size / width)) + else: + new_height = max_size + new_width = int(width * (max_size / height)) + + img = img.resize((new_width, new_height), Image.Resampling.LANCZOS) + elif max(width, height) < max_size: + # 長辺が1240px未満の場合は拡大 + if width > height: + new_width = max_size + new_height = int(height * (max_size / width)) + else: + new_height = max_size + new_width = int(width * (max_size / height)) + + img = img.resize((new_width, new_height), Image.Resampling.LANCZOS) + + # numpy配列に変換 (H, W, C) + img_array = np.array(img).astype(np.float32) / 255.0 + # Tensor化 + return torch.from_numpy(img_array) + + except Exception as e: + print(f"[RandomLoRALoader] Image resize/convert error: {e}") + return None + def _generate_preview_batch(self, preview_images): """ プレビュー画像のバッチを生成(1240pxに統一、パディング)