4 Commits
Author SHA1 Message Date
shin132002 37a2cfe7da v1.4.0: random loaders output clean positive_text, add lora_text
- positive_text no longer contains <lora:...> tags; it matches the encoded positive exactly

- New lora_text output (last slot) carries the previous positive_text content

- Filtered loader: collapse runs of commas left after removing tags
2026-09-25 06:33:12 +09:00
shin132002 3b0a271b39 Fixed an issue 2026-09-11 21:33:21 +09:00
shin132002 801b13a0d7 Update to v1.2.0 2026-01-13 22:20:07 +09:00
shin132002 83775df239 Add publisher-id to pyproject.toml 2026-01-13 22:07:54 +09:00
9 changed files with 839 additions and 298 deletions
+55
View File
@@ -2,6 +2,61 @@
All notable changes to this project will be documented in this file.
## [1.4.0] - 2026-09-24
### Changed
#### ⚠️ `positive_text` no longer contains LoRA syntax; new `lora_text` output
- `positive_text` is now the positive prompt **without** `<lora:...>` tags — exactly what is encoded into the `positive` CONDITIONING output — so it can be fed straight into a text encoder
- The previous content, tags included, now comes from a new **`lora_text`** output, added as the **last** slot
- All other outputs keep their positions and types, so existing workflow connections stay valid (ComfyUI connects outputs by position)
- Action for existing workflows:
- `positive_text` fed a text encoder: nothing to do
- `positive_text` was used to record the LoRA syntax (saved prompts, metadata): reconnect that link to `lora_text`
- Applies to all three nodes (Random LoRA Loader, Filtered Random LoRA Loader, Filtered Random LoRA Loader (LBW))
#### ⚠️ Filtered nodes: cleaner encoded prompt
- Filtered Random LoRA Loader / (LBW) removed `<lora:...>` tags before encoding but left the separators behind, so the positive conditioning was encoded from text like `masterpiece, , trig_a, , , trig_c`
- Runs of commas and leading/trailing commas are now tidied before encoding, matching the 3-folder node. This applies to the negative prompt too (e.g. a trailing `, ` is no longer encoded)
- Because the encoded text changes, **results with the same seed may differ from 1.3.0 and earlier**. Keep using an earlier version if identical results are required
### Fixed
- Random LoRA Loader: a run of three or more commas left after removing tags from the additional prompt was only partly collapsed
---
## [1.3.0] - 2026-09-11
### Fixed
#### Symlinked folders were skipped during scanning
- Folder scans now follow symbolic links, matching ComfyUI's own behaviour (`folder_paths.recursive_search` uses `followlinks=True`)
- Previously, a subfolder that was a symlink was skipped entirely, so LoRAs behind a link never appeared as candidates — even though they showed up fine in ComfyUI's native LoRA dropdown
- Affects all three nodes:
- **Random LoRA Loader**: `glob.glob("**/*.safetensors")` replaced with `os.walk(followlinks=True)` (glob's `**` does not descend into symlinked directories)
- **Filtered Random LoRA Loader** / **Filtered Random LoRA Loader (LBW)**: `os.walk()` now passes `followlinks=True`
- Symlink loops are detected via a `realpath` set and skipped, so a cyclic link cannot hang the scan
- A folder reachable through two different links is no longer scanned twice
#### Redundant error logging on non-safetensors LoRAs
- `_load_embedded_metadata` now returns early for `.pt` / `.ckpt` files instead of calling `safe_open`, which can only read `.safetensors`
- Previously every selected `.pt` / `.ckpt` produced a spurious "metadata read error" log line
- Trigger words for these formats still come from `.metadata.json` / `.info` sidecar files as before
### Changed
#### Seed reproducibility — candidate list is now sorted
- The candidate file list is sorted before random selection
- Previously the order came straight from the filesystem, so **the same seed could produce different selections on different machines**. Sorting makes a seed reproducible across environments
- ⚠️ Because the ordering changed, an existing workflow may select a different set of LoRAs after upgrading even with a fixed seed. If a result you were relying on changes, re-roll or re-pick the seed
#### Random LoRA Loader: extension support aligned with the Filtered nodes
- Now scans `.safetensors`, `.pt`, and `.ckpt` (previously `.safetensors` only)
- All three nodes now return an identical candidate list for the same folder
- Extension matching is case-insensitive, so `.SAFETENSORS` is picked up on Linux as well (glob was case-sensitive there)
---
## [1.2.0] - 2026-01-13
### Added
+33 -8
View File
@@ -78,7 +78,7 @@ Advanced node with LoRA Block Weight (LBW) support for precise effect control.
- `json_sample_prompt`: Randomly retrieve sample prompts
- `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
- **Text Outputs**: `positive_text` / `negative_text`, plus `lora_text` carrying the LoRA syntax (v1.4.0)
- **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
@@ -176,6 +176,7 @@ Or manually delete the RandomLoRALoader folder and restart ComfyUI.
- `MODEL` / `CLIP`: Connect to KSampler
- `positive` / `negative`: Connect to Set Conditioning or KSampler
- `positive_text` / `negative_text`: Connect to Show Text for verification (recommended)
- `lora_text`: Connect to Show Text or a prompt/metadata saving node to record which LoRAs were picked
### Wildcard Encode Integration (Recommended)
@@ -245,6 +246,20 @@ Group 3: Unused
## Settings
### Folder Scanning
All three nodes scan the folders you point them at the same way.
**Supported extensions:** `.safetensors`, `.pt`, `.ckpt` (case-insensitive).
> Note: `.pt` and `.ckpt` files have no readable embedded metadata, so trigger words for them come only from `.metadata.json` / `.info` sidecar files.
**Symbolic links are followed.** A subfolder that is a symlink is descended into, matching ComfyUI's own folder scan — so LoRAs that only exist behind a link are included as candidates, just as they appear in ComfyUI's native LoRA dropdown. Link loops are detected and skipped rather than hanging the scan, and a folder reachable through two different links is only scanned once.
**The candidate list is sorted before selection.** This makes a given `seed` reproduce the same selection on any machine. Prior to v1.3.0 the order came straight from the filesystem, so the same seed could pick different LoRAs on a different PC.
> ⚠️ Because the ordering changed, an existing workflow may select a different set of LoRAs after upgrading to v1.3.0, even with a fixed seed. If a result you were relying on changes, re-roll or re-pick the seed.
### Common Settings
| Setting | Description | Default |
@@ -303,7 +318,7 @@ Each group can be configured individually:
| Setting | Description | Default |
|---------|-------------|---------|
| `lora_folder_path_X` | LoRA folder absolute path | (empty) |
| `include_subfolders_X` | Include subfolders | `true` |
| `include_subfolders_X` | Include subfolders (symbolic links are followed) | `true` |
| `unique_by_filename_X` | Exclude duplicate filenames | `true` |
| `model_strength_X` | MODEL application strength | `"1.0"` |
| `clip_strength_X` | CLIP application strength | `"1.0"` |
@@ -494,23 +509,33 @@ All nodes provide the following outputs:
| `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 |
| `positive_text` | STRING | Positive prompt text **without** LoRA syntax — exactly what is encoded into `positive` (v1.4.0) |
| `negative_text` | STRING | Full negative prompt text |
| `preview` | IMAGE | Batch of preview images for selected LoRAs (v1.1.0) |
| `lora_text` | STRING | Positive prompt text **with** LoRA syntax (the former `positive_text` content, v1.4.0) |
> ⚠️ **Output changes in v1.4.0**
>
> `positive_text` no longer contains `<lora:...>` tags; the previous content now comes from the new `lora_text` output (last slot). All other outputs keep their positions and types, so existing connections stay valid.
>
> - `positive_text` fed a text encoder: no rewiring needed. The tags are no longer read as text
> - `positive_text` was used to record the LoRA syntax (saved prompts, metadata): reconnect that to `lora_text`
>
> The Filtered nodes also now tidy the stray `, ,` left behind after removing tags (and leading/trailing commas) before encoding, as the 3-folder node already did. Because the encoded text changes, **results with the same seed may differ from earlier versions**. If you need identical results to an earlier version, keep using that version.
### Text Output Format
**positive_text example:**
**lora_text example:**
```
<lora:style_anime:0.8:0.8>, <lora:character_alice:1.0:1.0>, anime style, alice, blonde hair, 1girl, beautiful
```
**LBW node positive_text example:**
**LBW node lora_text example:**
```
<lora:style_anime:0.8:0.8:lbw=1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1>, anime style, 1girl, beautiful
```
**positive (CONDITIONING) content:**
**positive_text / positive (CONDITIONING) content:**
```
anime style, alice, blonde hair, 1girl, beautiful
(LoRA syntax removed for clean prompt)
@@ -558,7 +583,7 @@ anime style, alice, blonde hair, 1girl, beautiful
| `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` |
| `include_subfolders` | Include subfolders (symbolic links are followed) | `true` |
| `unique_by_filename` | Exclude duplicate filenames | `true` |
### Keyword Filter Syntax
@@ -923,7 +948,7 @@ Enable preview display to:
**Check:**
1. LoRA folder path is correct (absolute path)
2. `.safetensors` files exist in the folder
2. `.safetensors`, `.pt` or `.ckpt` files exist in the folder
3. `include_subfolders` setting if LoRAs are in subfolders
4. Console for error messages
+272 -45
View File
@@ -6,9 +6,15 @@
---
## Overview
Filtered Random LoRA Loader (LBW) is the Filtered Random LoRA Loader with LoRA Block Weight (LBW) support added. It lets you control precisely which parts of the U-Net a LoRA is applied to.
---
## Features
### **Core Features (from Filtered Random LoRA Loader)**
### **Core Features (shared with Filtered Random LoRA Loader)**
- ✅ Random LoRA selection from a single folder
- ✅ Keyword filtering (AND/OR modes)
- ✅ Metadata search (filename or embedded metadata)
@@ -18,7 +24,7 @@
- ✅ Direct serial connection support
### **Advanced Features (LBW)**
- ✅ **LoRA Block Weight (LBW) support**
- ✅ **LoRA Block Weight (LBW) support**: set a separate strength for each U-Net block to control style, character, composition and so on independently
- ✅ **Automatic SD1.5/SDXL detection**
- ✅ **4 preset modes + custom input**
- ✅ **Automatic weight adjustment**
@@ -29,13 +35,17 @@
### **What is LBW?**
LoRA Block Weight allows you to control which parts of the U-Net model are affected by the LoRA:
LoRA Block Weight lets you control which parts of the U-Net the LoRA affects. The Stable Diffusion U-Net is made up of three parts:
- **INPUT blocks**: Structure, composition, layout
- **MIDDLE block**: Overall features
- **OUTPUT blocks**: Style, details, fine-tuning
```
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.
By adjusting the weight of each block, you can precisely control the LoRA's effect.
---
@@ -47,33 +57,33 @@ 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
Enables OUTPUT blocks only.
**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`
**Best for:**
- Style LoRAs (anime style, watercolor, etc.)
- Art style and effect LoRAs
- Changing the visual aesthetic
**Effect:**
- ✅ Strong style changes
- ❌ Minimal structure/character changes
- ❌ Minimal structure/character changes (ideal when you want to keep the existing composition)
---
### **3. Character Focused**
Emphasizes INPUT (early) + MIDDLE + OUTPUT blocks.
**Best for:**
- Character LoRAs
- Face/feature preservation
- Balanced application
Enables INPUT (early) + MIDDLE + OUTPUT blocks.
**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`
**Best for:**
- Character and person LoRAs
- Concept LoRAs
- Preserving faces/features
**Effect:**
- ✅ Strong character features
- ✅ Balanced overall effect
@@ -81,16 +91,15 @@ Emphasizes INPUT (early) + MIDDLE + OUTPUT blocks.
---
### **4. Structure/Composition Only**
Emphasizes INPUT + MIDDLE blocks only.
**Best for:**
- Pose LoRAs
- Composition LoRAs
- Layout/structure control
Enables INPUT + MIDDLE blocks 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`
**Best for:**
- Pose LoRAs
- Composition and layout LoRAs
**Effect:**
- ✅ Strong structure/pose changes
- ❌ Minimal style changes
@@ -98,24 +107,29 @@ Emphasizes INPUT + MIDDLE blocks only.
---
### **5. Balanced / Soft**
Soft application across selected blocks.
**Best for:**
- Subtle effects
- Multi-LoRA workflows
- General-purpose LoRAs
Soft application across selected blocks. The later OUTPUT blocks are turned down to avoid over-application.
**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`
**Best for:**
- Subtle effects and fine adjustment
- Multi-LoRA workflows
- General-purpose LoRAs
**Effect:**
- ✅ Balanced, gentle application
- ✅ Balanced, gentle application with a natural finish
- ✅ Good for stacking multiple LoRAs
---
### **6. Preset: Random**
Randomly selects one of the 4 presets above.
Randomly picks one of the 4 presets above on each run.
```
weight_mode: "Preset: Random"
→ One of the 4 presets is picked on each run
```
**Best for:**
- Experimentation
@@ -133,7 +147,8 @@ Custom weight specification.
**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
weight_mode: "Direct Input"
lbw_input: "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:**
@@ -149,11 +164,39 @@ Custom weight specification.
BASE, IN00-IN08 (9), MID (1), OUT00-OUT08 (9)
```
| Index | Block | Role |
|-------|-------|------|
| 0 | BASE | Overall base |
| 1-9 | INPUT (IN00-08) | Structure/composition |
| 10 | MIDDLE (M00) | Intermediate features |
| 11-19 | OUTPUT (OUT00-08) | Style/details |
**Weight example:**
```
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)
→ LoRA applied to OUTPUT blocks only (style focused)
```
### **SD1.5 (17 elements)**
```
BASE, IN01,IN02,IN04,IN05,IN07,IN08 (6), MID (1), OUT03-OUT11 (9)
```
| Index | Block | Role |
|-------|-------|------|
| 0 | BASE | Overall base |
| 1-6 | INPUT (IN01,02,04,05,07,08) | Structure/composition |
| 7 | MIDDLE (M00) | Intermediate features |
| 8-16 | OUTPUT (OUT03-11) | Style/details |
**Weight example:**
```
1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1
BASE,IN (OFF),M00,OUT (ON)
→ LoRA applied to OUTPUT blocks only (style focused)
```
---
## Automatic Detection
@@ -165,13 +208,18 @@ The node automatically detects whether a LoRA is SD1.5 or SDXL by analyzing the
- **SD1.5**: `output_blocks_0` to `output_blocks_11` (12 blocks)
- **SDXL**: `output_blocks_0` to `output_blocks_8` (9 blocks)
```
SDXL detected → 20-element weights are used
SD1.5 detected → 17-element weights are used
```
**You don't need to specify the model type manually!** ✅
---
### **Weight Adjustment**
If the number of weights doesn't match the detected LoRA type:
If the number of weights doesn't match the detected LoRA type, it is adjusted automatically:
**Example 1: Too few weights**
```
@@ -197,9 +245,34 @@ Detected: SDXL (requires 20)
[Filtered Random LoRA Loader (LBW)]
MODEL → [KSampler]
CLIP → [CLIP Text Encode]
positive_text → [Show Text] (optional, for debugging)
lora_text → [Show Text] (optional, for debugging)
```
**Steps:**
1. **Place the node**
```
[Filtered Random LoRA Loader (LBW)]
```
2. **Set the folder and keywords**
```
lora_folder_path: "path/to/loras"
keyword_filter: "anime style"
num_loras: 1
```
3. **Choose the LBW mode**
```
weight_mode: "Style Focused"
```
4. **Connect MODEL/CLIP**
```
MODEL → [KSampler]
CLIP → [CLIP Text Encode]
```
### **Parameters**
#### **LoRA Settings**
@@ -208,12 +281,14 @@ Detected: SDXL (requires 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")
> Folder scanning behaviour (supported extensions, symbolic links, sorted candidate order) is shared with the other nodes — see [Folder Scanning](README.md#folder-scanning) in the main README.
#### **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!)
#### **LBW Settings**
- `weight_mode`: Normal / 4 Presets / Random / Direct Input
- `lbw_input`: Custom weights (only for Direct Input mode)
@@ -227,7 +302,7 @@ Detected: SDXL (requires 20)
### **LBW Syntax**
When LBW is applied, the `positive_text` output includes LBW syntax:
When LBW is applied, the `lora_text` output (`positive_text` before v1.4.0) includes LBW syntax:
**Normal (All 1.0):**
```
@@ -239,7 +314,59 @@ When LBW is applied, the `positive_text` output includes LBW syntax:
<lora:style_anime:0.8:0.8:lbw=1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1>
```
**Note:** The LBW is applied internally to the MODEL. The syntax in `positive_text` is for reference/re-use with other nodes.
**Note:** The LBW is applied internally to the MODEL. The syntax in `lora_text` is for reference/re-use with other nodes.
---
## Examples
### **Example 1: Change the style only**
```
[Load Checkpoint] → [Filtered Random LoRA Loader (LBW)]
weight_mode: "Style Focused"
keyword_filter: "anime"
↓
[KSampler]
```
**Result:** The composition stays the same; only the style becomes anime-like
---
### **Example 2: Staged application with multiple LoRAs**
```
[Load Checkpoint]
↓
[Filtered Random LoRA Loader (LBW)] (Structure/Composition Only)
keyword_filter: "pose"
↓
[Filtered Random LoRA Loader (LBW)] (Style Focused)
keyword_filter: "watercolor"
↓
[KSampler]
```
**Result:** Pose adjustment → watercolor style applied
---
### **Example 3: Character + style**
```
[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]
```
**Result:** Character features preserved + style changed
---
@@ -250,9 +377,9 @@ When LBW is applied, the `positive_text` output includes LBW syntax:
| LoRA Type | Recommended Preset | Why |
|-----------|-------------------|-----|
| Style/Art | Style Focused | OUTPUT blocks control style |
| Character | Character Focused | Balanced IN+MID+OUT for features |
| Character | Character Focused | Balanced IN+MID+OUT preserves features |
| Pose/Composition | Structure/Composition Only | INPUT blocks control layout |
| General | Balanced / Soft | Gentle, stackable effect |
| General/fine adjustment | Balanced / Soft | Gentle, stackable effect |
---
@@ -266,7 +393,7 @@ The difference between presets is **more visible** with:
The difference is **less visible** with:
- ⚠️ Weak LoRAs (low model_strength)
- ⚠️ Multiple LoRAs applied simultaneously
- ⚠️ LoRAs with evenly distributed training
- ⚠️ LoRAs whose training effect is spread evenly across blocks
---
@@ -278,11 +405,17 @@ Setting all weights to 0 completely disables the LoRA effect:
```
This is equivalent to not applying the LoRA at all.
**Weight guide:**
- **0**: Completely off
- **0.5**: Weaker
- **1.0**: Standard
- **1.5 or more**: Stronger (watch for over-application)
---
### **4. Serial Connection**
For applying different LBW settings to different LoRAs:
For applying different LBW settings to different LoRAs, connect nodes in series:
```
[Filtered Random LoRA Loader (LBW)] (Style Focused)
↓
@@ -293,6 +426,24 @@ For applying different LBW settings to different LoRAs:
All LoRAs within a single node instance use the same LBW setting.
**Tips:**
- **Structure → style** is the basic order
- Strength can also be adjusted per node
---
### **5. Troubleshooting**
**If there is no effect:**
- Check that the weights aren't all 0
- Check that the LoRA is loaded correctly
- Check the console for the LBW application message
**If the effect is too strong:**
- Lower model_strength
- Try the Balanced / Soft preset
- Adjust the weights to 0.5–0.8
---
## Requirements
@@ -334,6 +485,82 @@ Supports the following formats (in priority order):
The node automatically searches for preview files matching the LoRA filename.
**File matching:**
- Files that start with the LoRA filename (case-insensitive)
- Example: matches for `style_anime.safetensors`:
- `style_anime.png` ✅
- `style_anime_preview.jpg` ✅
- `STYLE_ANIME.PNG` ✅
---
## Advanced: Custom Presets
To create your own presets or change the existing ones, you can edit the source file directly.
### **How to Edit**
**File location:**
```
ComfyUI/custom_nodes/RandomLoRALoader/filtered_random_lora_loader_lbw.py
```
**Lines to edit:** 29–41 (`SDXL_PRESETS` for SDXL, `SD15_PRESETS` for SD1.5)
### **Example 1: Add your own preset**
```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",
# ↓ Your own preset
"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"
}
```
### **Example 2: Adjust an existing preset**
```python
SDXL_PRESETS = {
# Make Style Focused stronger
"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",
# Make Character Focused milder
"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",
...
}
```
### **Example 3: Rename presets**
```python
SDXL_PRESETS = {
"Style Only": "1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1",
"Character First": "1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1",
"Composition Only": "1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0",
...
}
```
### **Important Notes**
⚠️ **Before editing:**
- Make a backup of the original file
- Watch the Python syntax (commas, quotes)
⚠️ **Number of weights:**
- SDXL presets: exactly 20 elements
- SD1.5 presets: exactly 17 elements
- Mismatched counts are auto-adjusted, but specifying them exactly is more reliable
⚠️ **After editing:**
- Fully restart ComfyUI to apply the changes
- Check the console for syntax errors
💡 **Tip:** If editing the file is a hassle, use the "Direct Input" mode!
---
## Disclaimer
@@ -375,7 +602,7 @@ MIT License
## Author
Your Name
konohana
---
+281 -166
View File
@@ -1,6 +1,6 @@
# Filtered Random LoRA Loader (LBW) - 詳細ガイド
# Filtered Random LoRA Loader (LBW)
**LoRAブロックウェイト(LBW)対応版**
**LoRAブロックウェイト(LBW)対応、SD1.5/SDXL自動検出付き**
![FilteredRandomLoRALoader(LBW)ワークフロー例](./images/lbw_final_single.webp)
@@ -8,53 +8,161 @@
## 概要
Filtered Random LoRA Loader (LBW) は、LoRAブロックウェイト(LBW)機能を追加した高度なノードです。U-Netのどの部分にLoRAを適用するかを細かく制御できます。
Filtered Random LoRA Loader (LBW) は、Filtered Random LoRA LoaderにLoRAブロックウェイト(LBW)機能を追加したノードです。U-Netのどの部分にLoRAを適用するかを細かく制御できます。
---
## 主な機能
### **✅ LoRAブロックウェイト(LBW)対応**
- U-Netのブロックごとに個別の強度を設定
- 画風、キャラクター、構図などを分離制御
### **基本機能(Filtered Random LoRA Loaderと共通)**
- ✅ 1つのフォルダからLoRAをランダム選択
- ✅ キーワードフィルタ(AND/ORモード)
- ✅ メタデータ検索(ファイル名または埋め込みメタデータ)
- ✅ プレビュー画像(静止画・アニメーション画像・動画に対応)
- ✅ トリガーワードの取得
- ✅ ファイル名による重複除外
- ✅ そのまま直列接続が可能
### **✅ 自動SD1.5/SDXL検出**
- LoRAファイルを自動判定
- ウェイト数を自動調整
### **✅ 4つのプリセットモード**
- Style Focused(画風特化)
- Character Focused(キャラ重視)
- Structure/Composition Only(構造・構図のみ)
- Balanced / Soft(バランス・穏やか)
### **✅ カスタム入力**
- Direct Inputモードで任意のウェイトを指定
- Preset: Randomモードでランダムプリセット選択
### **拡張機能(LBW)**
- ✅ **LoRAブロックウェイト(LBW)対応**:U-Netのブロックごとに個別の強度を設定し、画風・キャラクター・構図などを分離して制御
- ✅ **SD1.5/SDXLの自動検出**
- ✅ **4つのプリセットモード+カスタム入力**
- ✅ **ウェイト数の自動調整**
---
## LBWとは?
## LoRAブロックウェイト(LBW)
### **LoRAブロックウェイトの仕組み**
### **LBWとは?**
Stable DiffusionのU-Netは以下の3つの部分で構成されています:
LoRAブロックウェイトを使うと、U-Netのどの部分にLoRAを効かせるかを制御できます。Stable DiffusionのU-Netは次の3つの部分で構成されています。
```
INPUT blocks → 構造、構図、レイアウト
↓
MIDDLE block → 全体的な特徴
↓
OUTPUT blocks → 画風、ディテール、細部調整
OUTPUT blocks → 画風、ディテール、細部の調整
```
LBWを使うと、**各ブロックに異なるLoRA強度を設定**できます。
ブロックごとにウェイトを調整することで、LoRAの効き方を細かく制御できます。
---
## ウェイトモード
### **1. Normal (All 1.0)** - デフォルト
すべてのブロックのウェイトが1.0(LBWを使わない通常のLoRA適用)です。
---
### **2. Style Focused(画風特化)**
OUTPUTブロックのみを有効にします。
**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`
**向いているもの:**
- 画風LoRA(アニメ風、水彩風など)
- スタイルLoRA、エフェクトLoRA
- 見た目の雰囲気を変えたい場合
**効果:**
- ✅ 画風が強く変わる
- ❌ 構図やキャラクターはほとんど変わらない(既存の構図を保ちたい場合に最適)
---
### **3. Character Focused(キャラ重視)**
INPUT前半+MIDDLE+OUTPUTを有効にします。
**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`
**向いているもの:**
- キャラクターLoRA、人物LoRA
- コンセプトLoRA
- 顔や特徴を保ちたい場合
**効果:**
- ✅ キャラクターの特徴が強く出る
- ✅ 全体的にバランスの取れた効き方
---
### **4. Structure/Composition Only(構造・構図のみ)**
INPUT+MIDDLEブロックのみを有効にします。
**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`
**向いているもの:**
- ポーズLoRA
- 構図LoRA、レイアウトLoRA
**効果:**
- ✅ 構造やポーズが強く変わる
- ❌ 画風はほとんど変わらない
---
### **5. Balanced / Soft(バランス・穏やか)**
選んだブロックに穏やかに適用します。OUTPUT後半を弱めて過剰な効きを防ぎます。
**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
**効果:**
- ✅ バランスの取れた穏やかな効き方で、自然な仕上がり
- ✅ 複数のLoRAを重ねやすい
---
### **6. Preset: Random**
上記4つのプリセットから、実行ごとに1つをランダムに選びます。
```
weight_mode: "Preset: Random"
→ 実行ごとに4つのプリセットから1つ選択
```
**向いているもの:**
- 試行錯誤
- バリエーションの生成
- ランダムな効果
---
### **7. Direct Input**
ウェイトを直接指定します。
**形式:**
- SDXL: カンマ区切りで20個の値
- SD1.5: カンマ区切りで17個の値
**例(SDXL):**
```
weight_mode: "Direct Input"
lbw_input: "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"
```
**自動調整:**
- 要素数が足りない場合:末尾を1.0で埋める
- 要素数が多すぎる場合:末尾から切り詰める
---
## ブロック構造
### **SDXL(20要素)**
```
BASE, IN00-IN08 (9), MID (1), OUT00-OUT08 (9)
```
| インデックス | ブロック | 役割 |
|------------|---------|------|
@@ -70,9 +178,10 @@ BASE,IN00-08 (OFF),M00,OUT00-08 (ON)
→ OUTPUTブロックのみLoRA適用(画風特化)
```
---
### **SD1.5(17要素)**
```
BASE, IN01,IN02,IN04,IN05,IN07,IN08 (6), MID (1), OUT03-OUT11 (9)
```
| インデックス | ブロック | 役割 |
|------------|---------|------|
@@ -90,79 +199,56 @@ BASE,IN (OFF),M00,OUT (ON)
---
## プリセット詳細
## 自動検出
### **1. Style Focused(画風特化)**
### **LoRAタイプの検出**
**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`
ノードはモデル構造を解析して、LoRAがSD1.5用かSDXL用かを自動で判定します。
**特徴:**
- OUTPUTブロックのみ有効
- 構図を変えず画風のみ適用
- 既存の構図を保ちたい場合に最適
- **SD1.5**: `output_blocks_0`〜`output_blocks_11`(12ブロック)
- **SDXL**: `output_blocks_0`〜`output_blocks_8`(9ブロック)
**用途:**
- 画風LoRA(アニメ風、水彩風など)
- スタイルLoRA
- エフェクトLoRA
```
SDXL検出 → 20要素のウェイトを使用
SD1.5検出 → 17要素のウェイトを使用
```
**モデルの種類を手動で指定する必要はありません** ✅
---
### **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`
入力したウェイトの数が、検出したLoRAタイプと合わない場合は自動で調整します。
**特徴:**
- INPUT前半 + MIDDLE + OUTPUT有効
- キャラクターの特徴を保持
- バランスの取れた適用
**例1: 足りない場合**
```
入力: 1,0,0(3要素)
検出: SDXL(20要素必要)
→ 自動調整: 1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
```
**用途:**
- キャラクター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併用時
**例2: 多すぎる場合**
```
入力: 1,0,0,...,0,0,0(25要素)
検出: SDXL(20要素必要)
→ 自動調整: 1,0,0,...,0,0,0(先頭20要素のみ)
```
---
## 使い方
### **基本的な使い方**
### **基本的なワークフロー**
```
[Filtered Random LoRA Loader (LBW)]
MODEL → [KSampler]
CLIP → [CLIP Text Encode]
lora_text → [Show Text](任意、確認用)
```
**手順:**
1. **ノードを配置**
```
@@ -187,33 +273,49 @@ BASE,IN (OFF),M00,OUT (ON)
CLIP → [CLIP Text Encode]
```
---
### **パラメータ**
### **Direct Inputモード**
#### **LoRA設定**
- `lora_folder_path`: LoRAフォルダのパス
- `num_loras`: 適用するLoRAの数(0〜20)
- `model_strength`: MODELに対するLoRAの強度(例: "1.0" または "0.6-0.9")
- `clip_strength`: CLIPに対するLoRAの強度(例: "1.0" または "0.6-0.9")
カスタムウェイトを直接入力:
> フォルダスキャンの挙動(対象拡張子、シンボリックリンクの追跡、候補リストのソート)は他のノードと共通です。詳細は[README_ja.md の「フォルダスキャンについて」](README_ja.md#フォルダスキャンについて)を参照してください。
```
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"
```
#### **キーワードフィルタ**
- `keyword_filter`: スペース区切りのキーワード(例: `style anime` や `"anime style" red`)
- `filter_mode`: AND / OR
- `search_in_metadata`: JSONや埋め込みメタデータも検索対象にする(遅くなります)
**ルール:**
- カンマ区切り
- SDXL: 20要素、SD1.5: 17要素
- 要素数が合わない場合は自動調整
#### **LBW設定**
- `weight_mode`: Normal / 4つのプリセット / Random / Direct Input
- `lbw_input`: カスタムウェイト(Direct Inputモードのみ)
#### **その他**
- `trigger_word_source`: トリガーワードの取得方法
- `seed`: ランダムシード
---
### **Preset: Randomモード**
## 出力形式
毎回異なるプリセットをランダム選択:
### **LBW構文**
LBWを適用した場合、`lora_text`出力(v1.4.0より前は`positive_text`)にLBW構文が含まれます。
**Normal (All 1.0):**
```
weight_mode: "Preset: Random"
→ 実行ごとに4つのプリセットから1つ選択
<lora:style_anime:0.8:0.8>
```
**LBW適用時(Style Focused、SDXL):**
```
<lora:style_anime:0.8:0.8:lbw=1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1>
```
**注:** LBWはノード内部でMODELに適用済みです。`lora_text`の構文は、記録や他のノードでの再利用のためのものです。
---
## 使用例
@@ -272,74 +374,75 @@ weight_mode: "Preset: Random"
### **1. プリセット選択ガイド**
| LoRAタイプ | 推奨プリセット |
|-----------|--------------|
| 画風・スタイル | Style Focused |
| キャラクター | Character Focused |
| ポーズ・構図 | Structure/Composition Only |
| 汎用・微調整 | Balanced / Soft |
| LoRAタイプ | 推奨プリセット | 理由 |
|-----------|--------------|------|
| 画風・スタイル | Style Focused | OUTPUTブロックが画風を担うため |
| キャラクター | Character Focused | IN+MID+OUTのバランスで特徴を保つため |
| ポーズ・構図 | Structure/Composition Only | INPUTブロックがレイアウトを担うため |
| 汎用・微調整 | Balanced / Soft | 穏やかで重ねやすいため |
---
### **2. 直列接続のコツ**
### **2. 効果の見え方**
- **構造 → 画風の順**が基本
- 各ノードで異なるLBW設定可能
- 強度も個別に調整可能
プリセットごとの違いが**見えやすい**条件:
- ✅ 強めのLoRA(model_strengthが高い)
- ✅ 1つだけ適用(num_loras=1)
- ✅ 画風・コンセプト系のLoRA
違いが**見えにくい**条件:
- ⚠️ 弱めのLoRA(model_strengthが低い)
- ⚠️ 複数のLoRAを同時に適用
- ⚠️ 学習の効き方がブロック全体に均等に分散しているLoRA
---
### **3. ウェイト調整のコツ**
### **3. ウェイト0 = 効果なし**
すべてのウェイトを0にすると、LoRAの効果は完全に無効になります。
```
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
```
これはLoRAを適用しないのと同じです。
**ウェイト調整の目安:**
- **0**: 完全無効
- **0.5**: 弱め
- **1.0**: 標準
- **1.5以上**: 強め(過剰に注意)
- **1.5以上**: 強め(効きすぎに注意)
---
### **4. トラブルシューティング**
### **4. 直列接続**
LoRAごとに異なるLBW設定を使いたい場合は、ノードを直列に接続します。
```
[Filtered Random LoRA Loader (LBW)] (Style Focused)
↓
[Filtered Random LoRA Loader (LBW)] (Character Focused)
↓
[KSampler]
```
1つのノード内で選ばれたLoRAは、すべて同じLBW設定で適用されます。
**コツ:**
- **構造 → 画風の順**が基本
- 強度もノードごとに個別に調整可能
---
### **5. トラブルシューティング**
**効果が出ない場合:**
- すべて0になっていないか確認
- ウェイトがすべて0になっていないか確認
- LoRAが正しく読み込まれているか確認
- コンソールでLBW適用メッセージを確認
- コンソールで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個カット
```
- ウェイトを0.5〜0.8に調整
---
@@ -351,7 +454,7 @@ SD1.5検出 → 17要素ウェイト使用
- ✅ **対応:** Stable Diffusion 1.5、Stable Diffusion XL(SDXL)
- ❌ **非対応:** Flux、SD3、SDXL Turbo、Pony、その他のアーキテクチャ
LBW機能は、SD1.5/SDXLのU-Netアーキテクチャ専用に設計されています。他のモデルタイプではLBWが正常に動作しません。
LBW機能は、SD1.5/SDXLのU-Netアーキテクチャ専用に設計されています。他のモデルタイプでは正常に動作しません。
---
@@ -361,27 +464,29 @@ LBW機能は、SD1.5/SDXLのU-Netアーキテクチャ専用に設計されて
- torch(ComfyUIに含まれる)
### **⚠️ オプション: 動画プレビュー**
**動画ファイルプレビュー(.mp4, .webm, .avi, .mov)にはopencv-pythonが必須です:**
**動画ファイルのプレビュー(.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必要
1. **静止画像**(.png, .jpg, .jpeg)
2. **アニメーション画像**(.gif, .webp) - 1フレーム目
3. **動画ファイル**(.mp4, .webm, .avi, .mov) - 1フレーム目(opencv-pythonが必要)
LoRAのファイル名に一致するプレビューファイルを自動で探します。
**ファイルマッチング:**
- LoRAファイル名で始まるファイル(大文字小文字無視)
- LoRAファイル名で始まるファイル(大文字小文字は区別しない)
- 例: `style_anime.safetensors` にマッチ:
- `style_anime.png` ✅
- `style_anime_preview.jpg` ✅
@@ -400,7 +505,7 @@ pip install opencv-python
ComfyUI/custom_nodes/RandomLoRALoader/filtered_random_lora_loader_lbw.py
```
**編集箇所:** 29~41行目
**編集箇所:** 29〜41行目(SDXL用が`SDXL_PRESETS`、SD1.5用が`SD15_PRESETS`)
### **例1: 独自プリセット追加**
@@ -448,30 +553,40 @@ SDXL_PRESETS = {
⚠️ **ウェイト数:**
- SDXLプリセット: 必ず20要素
- SD1.5プリセット: 必ず17要素
- 要素数が合わない場合は自動調整されますが、正確に指定する方が良いです
- 要素数が合わない場合は自動調整されますが、正確に指定する方が確実です
⚠️ **編集後:**
- ComfyUIを完全に再起動して変更を適用
- コンソールで構文エラーを確認
- コンソールで構文エラーが出ていないか確認
💡 **ヒント:** ファイル編集が面倒な場合は、「Direct Input」モードを使ってください!
💡 **ヒント:** ファイル編集が面倒な場合は「Direct Input」モードを使ってください!
---
## 免責事項
- 技術サポートは提供しません
- 動作の保証はありません
- 今後のComfyUIのアップデートとの互換性は保証しません
- バグ報告や機能要望に対応できない場合があります
- 自己責任でご利用ください
---
## 更新履歴
### v1.2.0(2026-01-13)
- ✅ LoRAブロックウェイト(LBW)対応追加
- ✅ SD1.5/SDXL自動検出
- ✅ LoRAブロックウェイト(LBW)対応を追加
- ✅ SD1.5/SDXLの自動検出
- ✅ 4つのプリセットモード+カスタム入力
- ✅ ウェイト数自動調整
- ✅ ウェイト数の自動調整
- ✅ 動画プレビュー対応(.mp4, .webm等)
### v1.1.0(2026-01-04)
- ✅ Filtered Random LoRA Loader追加
- ✅ キーワードフィルタリング(AND/ORモード)
- ✅ メタデータ検索対応
- ✅ プレビュー画像表示
- ✅ Filtered Random LoRA Loaderを追加
- ✅ キーワードフィルタ(AND/ORモード)
- ✅ メタデータ検索に対応
- ✅ プレビュー画像の表示
### v1.0.0(2025-12-30)
- ✅ 初回リリース
@@ -487,7 +602,7 @@ MIT License
## 作者
Your Name
konohana
---
+33 -8
View File
@@ -78,7 +78,7 @@ LoRAブロックウェイト(LBW)対応の高度なノード。精密な効
- `json_sample_prompt`: 作例プロンプトをランダムに取得
- `metadata`: 埋め込みメタデータから直接読み込み
- **作例プロンプト最適化**: LoRA構文を自動除去し、ノード設定の強度を適用
- **デュアルテキスト出力**: positive_textとnegative_textを分離出力
- **テキスト出力**: `positive_text` / `negative_text`に加え、LoRA構文付きの`lora_text`(v1.4.0)
- **ComfyUI標準シード制御**: 固定/ランダム/増分/減分に対応
- **Wildcard Encode統合**: Wildcard Encode(Inspire)とシームレスに連携
- **LoRA構文自動除去**: additional_prompt内のLoRA構文を自動削除
@@ -176,6 +176,7 @@ rmdir /s RandomLoRALoader
- `MODEL` / `CLIP`: KSamplerに接続
- `positive` / `negative`: Set ConditioningまたはKSamplerに接続
- `positive_text` / `negative_text`: Show Textに接続して確認(推奨)
- `lora_text`: Show Textやプロンプト・メタデータ保存系のノードに接続して、選ばれたLoRAを記録
### Wildcard Encode連携(推奨)
@@ -245,6 +246,20 @@ rmdir /s RandomLoRALoader
## 設定
### フォルダスキャンについて
3つのノードとも、指定されたフォルダを同じ方法でスキャンします。
**対象拡張子:** `.safetensors` / `.pt` / `.ckpt`(大文字小文字は区別しません)
> 注: `.pt`と`.ckpt`は埋め込みメタデータを読み取れないため、トリガーワードは`.metadata.json`や`.info`のサイドカーファイルからのみ取得されます。
**シンボリックリンクを辿ります。** サブフォルダがシンボリックリンクの場合もその中まで検索します。ComfyUI本体のフォルダスキャンと同じ挙動なので、リンク先にしか存在しないLoRAも、ComfyUIネイティブのLoRAドロップダウンと同様に候補へ含まれます。リンクが循環している場合は検出してスキップするためスキャンが止まることはなく、同じフォルダに2本のリンクが張られていても二重に走査されません。
**候補リストは選択前にソートされます。** これにより、同じ`seed`ならどのマシンでも同じ選択結果が再現されます。v1.3.0より前は列挙順がファイルシステム任せだったため、PCが変わると同じシードでも違うLoRAが選ばれることがありました。
> ⚠️ 並び順が変わるため、v1.3.0へのアップグレード後は、シードを固定していても既存のワークフローで選ばれるLoRAが変わる可能性があります。依存していた結果が変わった場合はシードを振り直してください。
### 共通設定
| 設定項目 | 説明 | デフォルト |
@@ -303,7 +318,7 @@ LoRA適用: フォルダ指定機能を使用 ✅
| 設定項目 | 説明 | デフォルト |
|---------|------|-----------|
| `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"` |
@@ -494,23 +509,33 @@ JSONメタデータから作例プロンプトを取得。
| `CLIP` | CLIP | LoRA適用済みCLIP |
| `positive` | CONDITIONING | ポジティブコンディショニング(LoRA構文除去) |
| `negative` | CONDITIONING | ネガティブコンディショニング |
| `positive_text` | STRING | LoRA構文付き完全ポジティブプロンプトテキスト |
| `positive_text` | STRING | LoRA構文を**含まない**ポジティブプロンプトテキスト。`positive`にエンコードされる内容そのもの(v1.4.0) |
| `negative_text` | STRING | 完全ネガティブプロンプトテキスト |
| `preview` | IMAGE | 選択されたLoRAのプレビュー画像バッチ(v1.1.0) |
| `lora_text` | STRING | LoRA構文を**含む**ポジティブプロンプトテキスト(旧`positive_text`の内容、v1.4.0) |
> ⚠️ **v1.4.0での出力の変更**
>
> `positive_text`は`<lora:...>`を含まなくなりました。以前の内容は新しい出力`lora_text`(末尾)から出ます。他の出力は位置も型も変わっていないので、既存の接続はそのまま使えます。
>
> - `positive_text`をテキストエンコーダーに繋いでいた場合:つなぎ直しは不要です。`<lora:...>`が文字として読まれなくなります
> - `positive_text`をLoRA構文の記録(プロンプトの保存やメタデータ)に使っていた場合:`lora_text`につなぎ直してください
>
> あわせてFilteredノードでも、3フォルダ版と同様に、構文を除去した跡に残る`, ,`や前後のカンマを整理してからエンコードするようにしました。エンコードされる内容が変わるため、**同じシードでも以前のバージョンと生成結果が変わる場合があります**。以前と同じ結果が必要な場合は、以前のバージョンをお使いください。
### テキスト出力形式
**positive_text例:**
**lora_text例:**
```
<lora:style_anime:0.8:0.8>, <lora:character_alice:1.0:1.0>, anime style, alice, blonde hair, 1girl, beautiful
```
**LBWノードのpositive_text例:**
**LBWノードのlora_text例:**
```
<lora:style_anime:0.8:0.8:lbw=1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1>, anime style, 1girl, beautiful
```
**positive(CONDITIONING)内容:**
**positive_text / positive(CONDITIONING)内容:**
```
anime style, alice, blonde hair, 1girl, beautiful
(クリーンなプロンプトのためLoRA構文除去)
@@ -558,7 +583,7 @@ anime style, alice, blonde hair, 1girl, beautiful
| `num_loras` | 選択するLoRA数 | `1` |
| `model_strength` | MODEL強度(固定または範囲) | `"1.0"` |
| `clip_strength` | CLIP強度(固定または範囲) | `"1.0"` |
| `include_subfolders` | サブフォルダを含める | `true` |
| `include_subfolders` | サブフォルダを含める(シンボリックリンクも辿ります) | `true` |
| `unique_by_filename` | 重複ファイル名を除外 | `true` |
### キーワードフィルタ構文
@@ -923,7 +948,7 @@ keyword_filter: '"anime style" detailed'
**確認事項:**
1. LoRAフォルダパスが正しい(絶対パス)
2. フォルダに`.safetensors`ファイルが存在
2. フォルダに`.safetensors` / `.pt` / `.ckpt`ファイルが存在
3. LoRAがサブフォルダにある場合は`include_subfolders`設定
4. コンソールでエラーメッセージを確認
+47 -13
View File
@@ -120,8 +120,13 @@ class FilteredRandomLoRALoader:
}
}
RETURN_TYPES = ("MODEL", "CLIP", "STRING", "STRING", "CONDITIONING", "CONDITIONING", "IMAGE")
RETURN_NAMES = ("MODEL", "CLIP", "positive_text", "negative_text", "positive", "negative", "preview")
RETURN_TYPES = ("MODEL", "CLIP", "STRING", "STRING", "CONDITIONING", "CONDITIONING", "IMAGE", "STRING")
# 0〜6番はv1.4.0以前と位置・型とも同じ(保存済みワークフローは出力を番号で接続するため)。
# v1.4.0での変更:
# positive_text (2番) … <lora:...> を含まない。positive (CONDITIONING) にエンコード
# される文字列そのもの
# lora_text (7番) … 以前の positive_text の内容(<lora:...> 付き)。記録用
RETURN_NAMES = ("MODEL", "CLIP", "positive_text", "negative_text", "positive", "negative", "preview", "lora_text")
FUNCTION = "load_loras"
CATEGORY = "loaders"
@@ -277,7 +282,22 @@ class FilteredRandomLoRALoader:
extensions = ['.safetensors', '.pt', '.ckpt']
if include_subfolders:
for root, dirs, files in os.walk(folder_path):
# followlinks=True はComfyUI本体のフォルダスキャン
# (folder_paths.recursive_search) と同じ挙動。これがないと
# シンボリックリンクのサブフォルダが丸ごとスキップされ、
# ComfyUIネイティブのLoRAドロップダウンには出てくるのに
# ここでは候補に入らない、という食い違いが起きる。
#
# realpathの集合はリンクを辿る代償。リンクが循環している場合に
# スキャンが無限ループするのを防ぎ、同じフォルダに2本のリンクが
# 張られている場合の二重スキャンも抑止する。
seen_dirs = set()
for root, dirs, files in os.walk(folder_path, followlinks=True):
real_root = os.path.realpath(root)
if real_root in seen_dirs:
dirs[:] = []
continue
seen_dirs.add(real_root)
for file in files:
if any(file.lower().endswith(ext) for ext in extensions):
lora_files.append(os.path.join(root, file))
@@ -287,7 +307,10 @@ class FilteredRandomLoRALoader:
if os.path.isfile(file_path) and any(file.lower().endswith(ext) for ext in extensions):
lora_files.append(file_path)
return lora_files
# ソートして返す。以前は列挙順がファイルシステム任せだったため、
# 同じシードでもマシンが変われば選ばれるLoRAが違っていた。
# ソートすることでシード指定が環境をまたいで再現するようになる。
return sorted(lora_files)
def _parse_keywords(self, keyword_filter):
"""
@@ -518,6 +541,11 @@ class FilteredRandomLoRALoader:
def _load_embedded_metadata(self, lora_path):
"""LoRAファイルから埋め込みメタデータを読み込み(Civitai形式に変換)"""
# safe_open は .safetensors しか読めない。候補には .pt/.ckpt も
# 含まれるため、ここで弾いておかないと選択のたびに無駄な例外が出る
if not lora_path.lower().endswith(".safetensors"):
return None
try:
from safetensors.torch import safe_open
@@ -655,8 +683,13 @@ class FilteredRandomLoRALoader:
def _remove_lora_syntax(self, text):
"""プロンプトからLoRA構文を削除"""
pattern = r'<lora:[^>]+>'
return re.sub(pattern, '', text)
if not text:
return text
text = re.sub(r'<lora:[^>]+>', '', text)
# v1.4.0: 構文を消した跡に残る ", ," を詰める(以前はそのままエンコードしていた)。
# positive_text 出力として表に出るようになったため、3フォルダ版と同じ後処理に揃えた
text = re.sub(r',(\s*,)+', ',', text)
return text.strip().strip(',').strip()
def _load_preview_image_as_tensor(self, lora_path):
"""
@@ -974,13 +1007,13 @@ class FilteredRandomLoRALoader:
def _generate_outputs(self, model, clip, final_positive, final_negative,
token_normalization, weight_interpretation, preview_batch):
"""CONDITIONING生成と出力"""
# LoRA構文を削除してクリーンなプロンプトにする。clean_positive は positive_text
# 出力にもなるので、エラー時の戻り値でも使えるよう try の外で作る
clean_positive = self._remove_lora_syntax(final_positive) if final_positive else ""
clean_negative = self._remove_lora_syntax(final_negative) if final_negative else ""
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,
@@ -992,8 +1025,9 @@ class FilteredRandomLoRALoader:
text=clean_negative
)[0]
return (model, clip, final_positive, final_negative,
positive_conditioning, negative_conditioning, preview_batch)
# positive_text = エンコードした文字列そのもの / lora_text = <lora:...> 付き(旧 positive_text)
return (model, clip, clean_positive, final_negative,
positive_conditioning, negative_conditioning, preview_batch, final_positive)
except Exception as e:
print(f"[FilteredRandomLoRALoader] Error generating outputs: {e}")
# エラー時は黒画像
@@ -1002,7 +1036,7 @@ class FilteredRandomLoRALoader:
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)
return (model, clip, clean_positive, final_negative, None, None, black_image, final_positive)
NODE_CLASS_MAPPINGS = {
+47 -13
View File
@@ -157,8 +157,13 @@ class FilteredRandomLoRALoaderLBW:
}
}
RETURN_TYPES = ("MODEL", "CLIP", "STRING", "STRING", "CONDITIONING", "CONDITIONING", "IMAGE")
RETURN_NAMES = ("MODEL", "CLIP", "positive_text", "negative_text", "positive", "negative", "preview")
RETURN_TYPES = ("MODEL", "CLIP", "STRING", "STRING", "CONDITIONING", "CONDITIONING", "IMAGE", "STRING")
# 0〜6番はv1.4.0以前と位置・型とも同じ(保存済みワークフローは出力を番号で接続するため)。
# v1.4.0での変更:
# positive_text (2番) … <lora:...> を含まない。positive (CONDITIONING) にエンコード
# される文字列そのもの
# lora_text (7番) … 以前の positive_text の内容(<lora:...> 付き)。記録用
RETURN_NAMES = ("MODEL", "CLIP", "positive_text", "negative_text", "positive", "negative", "preview", "lora_text")
FUNCTION = "load_loras"
CATEGORY = "loaders"
@@ -323,7 +328,22 @@ class FilteredRandomLoRALoaderLBW:
extensions = ['.safetensors', '.pt', '.ckpt']
if include_subfolders:
for root, dirs, files in os.walk(folder_path):
# followlinks=True はComfyUI本体のフォルダスキャン
# (folder_paths.recursive_search) と同じ挙動。これがないと
# シンボリックリンクのサブフォルダが丸ごとスキップされ、
# ComfyUIネイティブのLoRAドロップダウンには出てくるのに
# ここでは候補に入らない、という食い違いが起きる。
#
# realpathの集合はリンクを辿る代償。リンクが循環している場合に
# スキャンが無限ループするのを防ぎ、同じフォルダに2本のリンクが
# 張られている場合の二重スキャンも抑止する。
seen_dirs = set()
for root, dirs, files in os.walk(folder_path, followlinks=True):
real_root = os.path.realpath(root)
if real_root in seen_dirs:
dirs[:] = []
continue
seen_dirs.add(real_root)
for file in files:
if any(file.lower().endswith(ext) for ext in extensions):
lora_files.append(os.path.join(root, file))
@@ -333,7 +353,10 @@ class FilteredRandomLoRALoaderLBW:
if os.path.isfile(file_path) and any(file.lower().endswith(ext) for ext in extensions):
lora_files.append(file_path)
return lora_files
# ソートして返す。以前は列挙順がファイルシステム任せだったため、
# 同じシードでもマシンが変われば選ばれるLoRAが違っていた。
# ソートすることでシード指定が環境をまたいで再現するようになる。
return sorted(lora_files)
def _parse_keywords(self, keyword_filter):
"""
@@ -564,6 +587,11 @@ class FilteredRandomLoRALoaderLBW:
def _load_embedded_metadata(self, lora_path):
"""LoRAファイルから埋め込みメタデータを読み込み(Civitai形式に変換)"""
# safe_open は .safetensors しか読めない。候補には .pt/.ckpt も
# 含まれるため、ここで弾いておかないと選択のたびに無駄な例外が出る
if not lora_path.lower().endswith(".safetensors"):
return None
try:
from safetensors.torch import safe_open
@@ -701,8 +729,13 @@ class FilteredRandomLoRALoaderLBW:
def _remove_lora_syntax(self, text):
"""プロンプトからLoRA構文を削除"""
pattern = r'<lora:[^>]+>'
return re.sub(pattern, '', text)
if not text:
return text
text = re.sub(r'<lora:[^>]+>', '', text)
# v1.4.0: 構文を消した跡に残る ", ," を詰める(以前はそのままエンコードしていた)。
# positive_text 出力として表に出るようになったため、3フォルダ版と同じ後処理に揃えた
text = re.sub(r',(\s*,)+', ',', text)
return text.strip().strip(',').strip()
def _load_preview_image_as_tensor(self, lora_path):
"""
@@ -1261,13 +1294,13 @@ class FilteredRandomLoRALoaderLBW:
def _generate_outputs(self, model, clip, final_positive, final_negative,
token_normalization, weight_interpretation, preview_batch):
"""CONDITIONING生成と出力"""
# LoRA構文を削除してクリーンなプロンプトにする。clean_positive は positive_text
# 出力にもなるので、エラー時の戻り値でも使えるよう try の外で作る
clean_positive = self._remove_lora_syntax(final_positive) if final_positive else ""
clean_negative = self._remove_lora_syntax(final_negative) if final_negative else ""
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,
@@ -1279,8 +1312,9 @@ class FilteredRandomLoRALoaderLBW:
text=clean_negative
)[0]
return (model, clip, final_positive, final_negative,
positive_conditioning, negative_conditioning, preview_batch)
# positive_text = エンコードした文字列そのもの / lora_text = <lora:...> 付き(旧 positive_text)
return (model, clip, clean_positive, final_negative,
positive_conditioning, negative_conditioning, preview_batch, final_positive)
except Exception as e:
print(f"[FilteredRandomLoRALoaderLBW] Error generating outputs: {e}")
# エラー時は黒画像
@@ -1289,4 +1323,4 @@ class FilteredRandomLoRALoaderLBW:
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)
return (model, clip, clean_positive, final_negative, None, None, black_image, final_positive)
+12 -30
View File
@@ -1,37 +1,19 @@
[project]
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"} # 必要に応じて変更
]
keywords = ["comfyui", "lora", "stable-diffusion", "ai", "image-generation", "block-weight", "lbw"]
name = "randomloraloader"
description = "Randomly select and apply LoRAs with keyword filtering, LoRA Block Weight support, preview images, and multiple folder support for ComfyUI"
version = "1.4.0"
license = {file = "LICENSE"}
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",
"Operating System :: OS Independent",
"Environment :: GPU :: NVIDIA CUDA",
"Environment :: GPU :: AMD ROCm",
]
[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"
Repository = "https://github.com/shin131002/RandomLoRALoader"
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
[tool.setuptools]
packages = ["RandomLoRALoader"]
[tool.comfy]
PublisherId = "konohana"
DisplayName = "RandomLoRALoader"
Icon = ""
+59 -15
View File
@@ -215,14 +215,19 @@ class RandomLoRALoader:
}
}
RETURN_TYPES = ("MODEL", "CLIP", "STRING", "STRING", "CONDITIONING", "CONDITIONING", "IMAGE")
RETURN_NAMES = ("MODEL", "CLIP", "positive_text", "negative_text", "positive", "negative", "preview")
RETURN_TYPES = ("MODEL", "CLIP", "STRING", "STRING", "CONDITIONING", "CONDITIONING", "IMAGE", "STRING")
# 0〜6番はv1.4.0以前と位置・型とも同じ(保存済みワークフローは出力を番号で接続するため)。
# v1.4.0での変更:
# positive_text (2番) … <lora:...> を含まない。positive (CONDITIONING) にエンコード
# される文字列そのもの
# lora_text (7番) … 以前の positive_text の内容(<lora:...> 付き)。記録用
RETURN_NAMES = ("MODEL", "CLIP", "positive_text", "negative_text", "positive", "negative", "preview", "lora_text")
FUNCTION = "load_random_loras"
CATEGORY = "loaders"
def _find_lora_files(self, folder_path, include_subfolders):
"""
指定フォルダ内のLoRAファイル(.safetensors)を検索
指定フォルダ内のLoRAファイル(.safetensors / .pt / .ckpt)を検索
Args:
folder_path: 検索対象フォルダの絶対パス
@@ -235,9 +240,41 @@ class RandomLoRALoader:
print(f"[RandomLoRALoader] フォルダが存在しません: {folder_path}")
return []
pattern = "**/*.safetensors" if include_subfolders else "*.safetensors"
lora_files = glob.glob(os.path.join(folder_path, pattern), recursive=include_subfolders)
lora_files = []
# Filtered版と対象拡張子を揃えている
extensions = ['.safetensors', '.pt', '.ckpt']
if include_subfolders:
# glob の "**" はシンボリックリンクのディレクトリを辿らないため
# os.walk(followlinks=True) に置き換えている。ComfyUI本体の
# フォルダスキャン (folder_paths.recursive_search) と挙動を揃える
# ためで、これがないとリンク先にしか存在しないLoRAが、
# ComfyUIネイティブのドロップダウンには出るのにここでは
# 候補に入らない、という食い違いが起きる。
#
# realpathの集合はリンクを辿る代償。リンクが循環している場合に
# スキャンが無限ループするのを防ぎ、同じフォルダに2本のリンクが
# 張られている場合の二重スキャンも抑止する。
seen_dirs = set()
for root, dirs, files in os.walk(folder_path, followlinks=True):
real_root = os.path.realpath(root)
if real_root in seen_dirs:
dirs[:] = []
continue
seen_dirs.add(real_root)
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)
# ソートして返す。以前は列挙順がファイルシステム任せだったため、
# 同じシードでもマシンが変われば選ばれるLoRAが違っていた。
# ソートすることでシード指定が環境をまたいで再現するようになる。
lora_files = sorted(lora_files)
print(f"[RandomLoRALoader] 検出されたLoRA数: {len(lora_files)}")
return lora_files
@@ -389,12 +426,12 @@ class RandomLoRALoader:
3. LoRA本体ファイルの埋め込みメタデータ
Args:
lora_path: LoRAファイルパス (.safetensors)
lora_path: LoRAファイルパス (.safetensors / .pt / .ckpt)
Returns:
dict: JSONデータ(読み込み失敗時はNone)
"""
# .safetensorsを除いたファイル名を取得
# 拡張子を除いたファイル名を取得
base_name = os.path.splitext(lora_path)[0]
# 優先順位1: .metadata.json (ComfyUI Lora Manager)
@@ -437,6 +474,11 @@ class RandomLoRALoader:
if not SAFETENSORS_AVAILABLE:
return None
# safe_open は .safetensors しか読めない。.pt/.ckpt も候補に含むように
# なったため、ここで弾いておかないと選択のたびにエラーログが出る
if not lora_path.lower().endswith(".safetensors"):
return None
if not os.path.exists(lora_path):
return None
@@ -740,7 +782,7 @@ class RandomLoRALoader:
text = re.sub(r'<lora:[^>]+>', '', text)
# 連続カンマを整理
text = re.sub(r',\s*,', ',', text)
text = re.sub(r',(\s*,)+', ',', text) # 3つ以上連続しても1回で詰める
# 行頭・行末の空白とカンマを削除
text = text.strip().strip(',').strip()
@@ -1086,7 +1128,7 @@ class RandomLoRALoader:
メイン処理:ランダムLoRA選択・適用(3グループ対応)
Returns:
tuple: (MODEL, CLIP, positive_text_output, negative_text_output, positive_conditioning, negative_conditioning)
tuple: (MODEL, CLIP, lora_text_output, negative_text_output, positive_conditioning, negative_conditioning)
"""
# seedをそのまま使用(ComfyUIのcontrol_before_generateで制御される)
print(f"[RandomLoRALoader] 使用seed: {seed}")
@@ -1186,18 +1228,18 @@ class RandomLoRALoader:
additional_with_comma += ','
if all_text_parts:
# LoRAがある場合: 追加プロンプト + LoRA情報
positive_text_output = additional_with_comma + "\n" + "\n".join(all_text_parts)
lora_text_output = additional_with_comma + "\n" + "\n".join(all_text_parts)
else:
# LoRAがない場合: 追加プロンプトのみ(末尾カンマなし)
positive_text_output = additional_prompt_positive.strip()
lora_text_output = additional_prompt_positive.strip()
else:
# 追加プロンプトなし
if all_text_parts:
# LoRAのみ
positive_text_output = "\n".join(all_text_parts)
lora_text_output = "\n".join(all_text_parts)
else:
# 何もない
positive_text_output = ""
lora_text_output = ""
# negativeテキスト出力
# 1. json_sample_promptからのnegative
@@ -1246,4 +1288,6 @@ class RandomLoRALoader:
# プレビュー画像バッチ生成
preview_batch = self._generate_preview_batch(preview_images)
return (model, clip, positive_text_output, negative_text_output, positive_conditioning, negative_conditioning, preview_batch)
# positive_text = positive にエンコードした文字列そのもの(<lora:...> なし)
return (model, clip, positive_text, negative_text_output, positive_conditioning,
negative_conditioning, preview_batch, lora_text_output)