Files
ussoewwin-ComfyUI-QwenImage…/README.md
T

360 lines
21 KiB
Markdown

# ComfyUI-QwenImageLoraLoader
A ComfyUI custom node for loading and applying LoRA (Low-Rank Adaptation) to Nunchaku Qwen Image models.
**This project is based on the fork version of ComfyUI-nunchaku-qwen-lora-suport-standalone.**
## Source
This LoRA loader was extracted and modified from GavChap's fork:
- **Original Fork**: [GavChap/ComfyUI-nunchaku (qwen-lora-suport-standalone branch)](https://github.com/GavChap/ComfyUI-nunchaku/tree/qwen-lora-suport-standalone)
- **Extraction**: LoRA functionality was extracted from the full fork to create an independent custom node
- **Integration**: Modified to work with the official ComfyUI-nunchaku plugin
## Features
- **NunchakuQwenImageLoraLoader**: Load and apply single LoRA to Qwen Image models
- **NunchakuQwenImageLoraStack**: Apply multiple LoRAs with dynamic UI control
- **Dynamic VRAM Management**: Automatic CPU offloading based on available VRAM
- **LoRA Composition**: Efficient LoRA stacking and composition
- **ComfyUI Integration**: Seamless integration with ComfyUI workflows
## Installation
### Quick Installation (Recommended)
1. Clone this repository to your ComfyUI custom_nodes directory:
```bash
git clone https://github.com/ussoewwin/ComfyUI-QwenImageLoraLoader.git
```
2. Ensure you have the official ComfyUI-nunchaku plugin installed (which includes nunchaku as a dependency).
3. **Run the installation script:**
- Double-click `install_qwen_lora.bat` to automatically configure the integration
- This script will automatically modify the ComfyUI-nunchaku `__init__.py` file
- Restart ComfyUI
### Manual Installation
If you prefer manual installation, see [INSTALLATION.md](INSTALLATION.md) for detailed instructions.
## Integration with ComfyUI-nunchaku
**IMPORTANT**: This node requires modification of the official ComfyUI-nunchaku plugin to function properly.
### Required Modification
You must modify the `__init__.py` file in your ComfyUI-nunchaku plugin to import this LoRA loader:
```python
try:
# Import from the independent ComfyUI-QwenImageLoraLoader
import sys
import os
qwen_lora_path = os.path.join(os.path.dirname(__file__), "..", "ComfyUI-QwenImageLoraLoader")
if qwen_lora_path not in sys.path:
sys.path.insert(0, qwen_lora_path)
# Import directly from the file path
import importlib.util
spec = importlib.util.spec_from_file_location("qwenimage", os.path.join(qwen_lora_path, "nodes", "lora", "qwenimage.py"))
qwenimage_module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(qwenimage_module)
NunchakuQwenImageLoraLoader = qwenimage_module.NunchakuQwenImageLoraLoader
NunchakuQwenImageLoraStack = qwenimage_module.NunchakuQwenImageLoraStack
NODE_CLASS_MAPPINGS["NunchakuQwenImageLoraLoader"] = NunchakuQwenImageLoraLoader
NODE_CLASS_MAPPINGS["NunchakuQwenImageLoraStack"] = NunchakuQwenImageLoraStack
logger.info("Successfully imported Qwen Image LoRA loaders from ComfyUI-QwenImageLoraLoader")
except ImportError:
logger.exception("Nodes `NunchakuQwenImageLoraLoader` and `NunchakuQwenImageLoraStack` import failed:")
```
### Why This Modification is Required
- The independent LoRA loader exists as a separate custom node
- The official ComfyUI-nunchaku plugin needs to reference the independent LoRA loader
- Standard `from ... import ...` fails due to different package structures
- `importlib.util` allows direct module loading from file paths
### Automated Installation (Recommended)
**The batch file `install_qwen_lora.bat` automatically adds the above code to your ComfyUI-nunchaku `__init__.py` file:**
1. **What the batch file does:**
- Automatically detects your ComfyUI installation path
- Backs up the original `__init__.py` file (creates `__init__.py.backup`)
- Adds the exact import code shown above to the end of ComfyUI-nunchaku's `__init__.py`
- Performs error checking to ensure all required files exist
- Provides user feedback throughout the process
2. **Run the installation script:**
- Double-click `install_qwen_lora.bat` to automatically configure the integration
- No manual code editing required - the script handles everything
- Restart ComfyUI after installation
3. **Uninstall if needed:**
- Double-click `uninstall_qwen_lora.bat` to restore the original configuration
- This will restore the backup and remove the integration code
## Usage
### Available Nodes
- **NunchakuQwenImageLoraLoader**: Single LoRA loader
- **NunchakuQwenImageLoraStack**: Multi LoRA stacker with dynamic UI
### Basic Usage
1. Load your Nunchaku Qwen Image model using `Nunchaku Qwen Image DiT Loader`
2. Add either `NunchakuQwenImageLoraLoader` or `NunchakuQwenImageLoraStack` node
3. Select your LoRA file and set the strength
4. Connect to your workflow
### Dynamic UI Control
The `NunchakuQwenImageLoraStack` node automatically adjusts the number of visible LoRA slots based on the `lora_count` parameter (1-10).
## Features
- **Easy Installation**: Automated installation script included
- **Automatic Integration**: No manual code editing required
- **Backup & Restore**: Automatic backup of original files
- **Cross-Platform**: Works on Windows with batch files
- **Error Handling**: Comprehensive error checking and user feedback
- **Issue #1 Fixed**: Resolved [ComfyUI\custom_nodes not found error](https://github.com/ussoewwin/ComfyUI-QwenImageLoraLoader/issues/1) with improved path detection (thanks to @mcv1234's solution)
- **Issue #2 Fixed**: Fixed UTF-8 encoding error causing `SyntaxError: (unicode error)` by using dedicated Python script for proper UTF-8 encoding (thanks to @AHEKOT's bug report)
- **Issue #3 Fixed (v1.4.0)**: Resolved [Node break cached progress error](https://github.com/ussoewwin/ComfyUI-QwenImageLoraLoader/issues/3) by implementing proper IS_CHANGED method with hash-based change detection (thanks to @AHEKOT's bug report)
## Requirements
- ComfyUI
- ComfyUI-nunchaku plugin (with required modification)
- PyTorch
- Python 3.10+
## Compatibility
This node is designed to work with:
- ComfyUI-nunchaku plugin (modified)
- Nunchaku Qwen Image models
- Standard ComfyUI workflows
## Troubleshooting
### Error: "attempted relative import with no known parent package"
**Problem**: This error occurs when ComfyUI tries to load the LoRA loader nodes but fails due to import issues.
**Error Message**: `ValueError: attempted relative import with no known parent package`
**Root Cause**: The error was caused by using relative imports (`from ...wrappers`) in the LoRA loader code. Relative imports only work when the module is loaded as part of a package. However, ComfyUI-nunchaku loads the module directly using `importlib.util`, which bypasses package initialization. As a result, Python cannot resolve the relative import paths.
**Solution**: Fixed in v1.5.0 by changing relative imports to absolute imports:
- **Before**: `from ...wrappers.qwenimage import ComfyQwenImageWrapper`
- **After**: `from wrappers.qwenimage import ComfyQwenImageWrapper`
**How to Fix**:
1. Make sure you have the latest version of ComfyUI-QwenImageLoraLoader
2. Run `install_qwen_lora.bat` to ensure proper integration
3. Restart ComfyUI
**Technical Details**:
- The installation script adds `ComfyUI-QwenImageLoraLoader` to `sys.path`
- This allows absolute imports to work correctly
- The absolute import `from wrappers.qwenimage import` resolves to `ComfyUI-QwenImageLoraLoader/wrappers/qwenimage.py`
### Error: Installation Script Not Running
**Problem**: The batch file doesn't execute or shows errors.
**Solution**:
1. Right-click `install_qwen_lora.bat` and select "Run as Administrator"
2. Check that both `ComfyUI-nunchaku` and `ComfyUI-QwenImageLoraLoader` are in your `ComfyUI/custom_nodes` directory
3. Verify Python is installed and accessible from the command line
4. Check the console output for specific error messages
### Error: Nodes Not Appearing in ComfyUI
**Problem**: After installation, the LoRA loader nodes don't appear in ComfyUI.
**Solution**:
1. Restart ComfyUI completely (close all instances)
2. Check the ComfyUI console for error messages
3. Verify that the integration code was added to `ComfyUI-nunchaku/__init__.py` (search for "ComfyUI-QwenImageLoraLoader Integration")
4. If the integration code is missing, re-run `install_qwen_lora.bat`
5. Check that your ComfyUI-nunchaku version is compatible
### Error: "ModuleNotFoundError: No module named 'nunchaku'"
**Problem**: The nunchaku package is not installed.
**Solution**:
1. Install ComfyUI-nunchaku plugin from the official repository
2. Follow the nunchaku installation instructions to install the nunchaku wheel
3. Restart ComfyUI
## Known Limitations
### RES4LYF Sampler Compatibility Issue
- **Status**: Currently Not Supported
- **Issue**: Device mismatch errors occur when using RES4LYF sampler with LoRA ([Issue #7](https://github.com/ussoewwin/ComfyUI-QwenImageLoraLoader/issues/7), [Issue #8](https://github.com/ussoewwin/ComfyUI-QwenImageLoraLoader/issues/8))
- **Workaround**: Use other sampler types (e.g., res_samplers, standard samplers) with LoRA
- **Technical Note**: The device mismatch occurs in `ComfyUI-nunchaku\models\qwenimage.py` at `self.time_text_embed(timestep, hidden_states)` due to RES4LYF sampler's specific tensor device handling requirements. This LoRA loader cannot fix this issue.
- **Related Issues**: [Issue #7](https://github.com/ussoewwin/ComfyUI-QwenImageLoraLoader/issues/7), [Issue #8](https://github.com/ussoewwin/ComfyUI-QwenImageLoraLoader/issues/8)
## Changelog
### v1.5.3 (Latest)
- **Fixed Critical Bug**: Resolved `TypeError: This LoRA loader only works with Nunchaku Qwen Image models, but got ComfyQwenImageWrapper` error in different workflows
- **Problem**: LoRA loader failed when model was already wrapped with `ComfyQwenImageWrapper` in some workflows, even though the wrapper was correct
- **Root Cause**: Using type name comparison (`type(model_wrapper).__name__ == "ComfyQwenImageWrapper"`) failed in some execution contexts due to dynamic imports and different module loading paths. When `ComfyQwenImageWrapper` was loaded from different import paths, Python treated them as different classes even though they were functionally identical
- **Technical Solution**: Changed from type name comparison to attribute-based detection
- **Before**: `if type(model_wrapper).__name__ == "ComfyQwenImageWrapper"`
- **After**: `if hasattr(model_wrapper, 'model') and hasattr(model_wrapper, 'loras')`
- The `ComfyQwenImageWrapper` class always has `model` (transformer) and `loras` (LoRA list) attributes
- This detection method works regardless of how the class was imported or loaded
- **Technical Details**:
- Added comprehensive debug logging to help diagnose type detection issues
- Logs now show type name, module, attributes, and full type representation
- Enhanced error messages with detailed type information
- Applied fix to both `NunchakuQwenImageLoraLoader` and `NunchakuQwenImageLoraStack` classes
- **Benefits**:
- Works with all workflows regardless of model loading order
- No dependency on import mechanism or module path
- More robust and resilient to Python module system quirks
- Better debugging capabilities with detailed logging
- **Impact**: Completely resolves the TypeError that occurred when using LoRA nodes in certain workflow configurations
### v1.5.2
- **Fixed Critical Bug**: Resolved persistent `ModuleNotFoundError: No module named 'wrappers.qwenimage'` error
- **Reported by**: Multiple users experiencing intermittent import failures
- **Problem**: Despite v1.5.0 and v1.5.1 fixes, some users still experienced `ModuleNotFoundError` when executing LoRA nodes
- **Root Cause**: Module-level `sys.path` manipulation was insufficient in all execution contexts. The `from wrappers.qwenimage import ComfyQwenImageWrapper` statement at method execution time occasionally failed even though the module loaded successfully, due to timing issues, Python's module cache, and varying execution contexts in ComfyUI
- **Technical Solution**: Implemented robust dynamic import using `importlib.util` within method execution
- **Before**: Module-level `sys.path` setup + direct `from wrappers.qwenimage import` at method level
- **After**: Dynamic `importlib.util`-based import within `load_lora()` and `load_lora_stack()` methods
- **Technical Details**:
- Each method now dynamically calculates the parent directory path at execution time
- Uses `importlib.util.spec_from_file_location()` to create module spec from absolute file path
- Executes module with `spec.loader.exec_module()` and extracts `ComfyQwenImageWrapper` class
- Completely bypasses Python's normal import mechanism, making it independent of `sys.path` state
- Eliminates dependency on module loading order or execution context
- **Benefits**:
- 100% reliable import regardless of execution context
- No dependency on `sys.path` configuration
- Works in all ComfyUI execution scenarios
- No more intermittent import failures
- More resilient to future ComfyUI or Python updates
- **Impact**: Completely resolves the import reliability issue that affected multiple users
### v1.5.1
- **Fixed Critical Bug**: Additional fix for [Issue #6](https://github.com/ussoewwin/ComfyUI-QwenImageLoraLoader/issues/6) - persistent `ModuleNotFoundError`
- **Problem**: v1.5.0 fix was incomplete - path calculation error meant `sys.path` pointed to wrong directory
- **Root Cause**: Incorrect path calculation: `os.path.dirname(os.path.dirname(os.path.dirname(current_dir)))` went up 3 levels instead of 2
- 3 levels up → pointed to `custom_nodes/` instead of `ComfyUI-QwenImageLoraLoader/`
- This prevented `from wrappers.qwenimage` from resolving correctly
- **Technical Solution**: Corrected path calculation to go up exactly 2 levels from `nodes/lora/`
- **Before**: `os.path.dirname(os.path.dirname(os.path.dirname(current_dir)))` (3 levels)
- **After**: `os.path.dirname(os.path.dirname(current_dir))` (2 levels)
- **Result**: Correctly points to `ComfyUI-QwenImageLoraLoader/` root directory
- **Applied To**: Module-level `sys.path` initialization in `qwenimage.py`
- **Benefits**:
- Absolute imports now work correctly in all loading scenarios
- No more `ModuleNotFoundError` errors
- Module can be loaded regardless of import mechanism
- Completely resolves Issue #6
### v1.5.0
- **Fixed Critical Bug**: Resolved [Issue #6 - attempted relative import with no known parent package](https://github.com/ussoewwin/ComfyUI-QwenImageLoraLoader/issues/6)
- **Reported by**: @showevr (GitHub Issue #6)
- **Special Thanks**: This bug was discovered and reported by @showevr
- **Problem**: LoRA loader nodes failed to load with `ValueError: attempted relative import with no known parent package` error
- **Root Cause**: Using relative imports (`from ...wrappers.qwenimage import ComfyQwenImageWrapper`) in the LoRA loader code. Relative imports only work when the module is loaded as part of a package, but ComfyUI-nunchaku loads the module directly using `importlib.util`, which bypasses package initialization
- **Technical Solution**: Changed relative imports to absolute imports in `qwenimage.py`
- **Before**: `from ...wrappers.qwenimage import ComfyQwenImageWrapper`
- **After**: `from wrappers.qwenimage import ComfyQwenImageWrapper`
- **Technical Details**:
- The installation script adds `ComfyUI-QwenImageLoraLoader` to `sys.path`
- This allows absolute imports to work correctly
- The absolute import `from wrappers.qwenimage import` resolves to `ComfyUI-QwenImageLoraLoader/wrappers/qwenimage.py`
- Applied fix to both `NunchakuQwenImageLoraLoader` and `NunchakuQwenImageLoraStack` classes
- **Community Contribution**: This fix was made possible by @showevr's bug reporting
### v1.4.0
- **Fixed Critical Bug**: Resolved [Issue #3 - Node break cached progress](https://github.com/ussoewwin/ComfyUI-QwenImageLoraLoader/issues/3) reported by @AHEKOT
- **Reported by**: @AHEKOT (GitHub Issue #3)
- **Special Thanks**: This critical bug was discovered and reported by @AHEKOT, who identified the issue with cached progress being broken
- **Problem**: LoRA nodes were breaking ComfyUI's cached progress during image generation, causing the progress bar to reset and restart repeatedly
- **Root Cause**: The `IS_CHANGED` method was returning `float("NaN")` instead of a proper change detection hash
- `float("NaN")` causes ComfyUI to always treat the node as "changed"
- This invalidates the cache after every frame, forcing unnecessary re-execution
- Result: Progress bar jumps back and forth, cache is constantly invalidated, generation becomes unstable
- **Technical Solution**: Implemented proper hash-based change detection for both LoRA nodes
- **NunchakuQwenImageLoraLoader**: Creates SHA256 hash from `model`, `lora_name`, and `lora_strength`
- **NunchakuQwenImageLoraStack**: Creates SHA256 hash from `model`, `lora_count`, and all 10 LoRA slots (names and strengths)
- Returns hex digest as the cache key
- **Technical Details**:
- Uses Python's `hashlib.sha256()` to generate deterministic hashes
- Same inputs always produce same hash → cache is used correctly
- Different inputs produce different hashes → node re-executes as expected
- No more false positives causing cache invalidation
- **Benefits**:
- Stable cached progress during generation
- No more progress bar jumping back and forth
- Proper cache utilization for better performance
- Smooth generation experience
- VRAM usage optimized due to proper cache behavior
- **Community Contribution**: This fix was made possible by @AHEKOT's bug reporting and issue tracking
### v1.3.0
- **Fixed Critical Bug**: Resolved `SyntaxError: invalid character '' (U+FFFD)` error when running installation script
- **Problem**: PowerShell output was being written directly into Python files, causing syntax errors
- **Root Cause**: Using PowerShell commands with piping (`Get-Content | Add-Content`) caused PowerShell status messages and metadata to be included in the output, which were then written into `__init__.py`
- **Solution**: Replaced PowerShell-based approach with a dedicated Python script (`append_integration.py`)
- **Technical Details**:
- Created standalone Python script `append_integration.py` that handles UTF-8 file writing
- Batch file now calls the Python script instead of using inline PowerShell commands
- Python script uses proper UTF-8 encoding when writing to `__init__.py`
- Eliminates any possibility of output artifacts contaminating Python files
- **Benefits**:
- More reliable and maintainable solution
- No risk of shell output pollution
- Cleaner separation of concerns between batch file and Python code
- Better error handling and user feedback
### v1.2.0
- **Fixed [Issue #2](https://github.com/ussoewwin/ComfyUI-QwenImageLoraLoader/issues/2)**: Resolved UTF-8 encoding error that caused `SyntaxError: (unicode error) 'utf-8' codec can't decode byte 0x90 in position 0`
- **Reported by**: @AHEKOT (GitHub Issue #2)
- **Special Thanks**: This critical bug was discovered and reported by @AHEKOT, who provided detailed error traces and screenshots
- **Technical Fix**: Changed the batch file to use PowerShell for UTF-8 encoding when writing Python code to `__init__.py`
- **Root Cause**: Windows batch files write in Shift-JIS encoding by default, which causes Python to fail when reading files as UTF-8
- **Solution**: Temporary file creation + PowerShell UTF-8 encoding ensures proper file encoding
- **Technical Details**:
- Changed from direct append (`>>`) to temp file method
- Uses PowerShell `Get-Content` and `Add-Content` with `-Encoding UTF8` parameters
- Ensures all Python code is written with proper UTF-8 encoding
- **Impact**: Installation script now works correctly without encoding errors
- **Community Contribution**: This fix was made possible by @AHEKOT's thorough bug reporting and error documentation
### v1.1.0
- **Fixed [Issue #1](https://github.com/ussoewwin/ComfyUI-QwenImageLoraLoader/issues/1)**: Resolved "ComfyUI\custom_nodes not found" error reported by @mcv1234
- **Special Thanks**: This fix was implemented based on the excellent solution provided by @mcv1234 in the GitHub issue
- **Improved Path Detection**: Replaced unreliable wildcard search with relative path detection using script directory (solution by @mcv1234)
- **Enhanced Error Messages**: Added clear directory structure guidance and expected folder layout
- **Better User Experience**: More reliable installation process with comprehensive error checking
- **Technical Details**:
- Changed from `dir /s /b /ad "*ComfyUI\custom_nodes"` to relative path calculation (as suggested by @mcv1234)
- Uses `%~dp0` (script directory) to calculate ComfyUI root with `..\..` navigation
- Added validation for `custom_nodes` folder existence
- Improved error messages with expected directory structure display
- **Community Contribution**: This improvement was made possible by the community feedback and solution provided by @mcv1234
### v1.0.0
- Initial release with LoRA loading functionality
- Automated installation scripts
- Integration with ComfyUI-nunchaku
## License
This project is licensed under the MIT License.