Merge pull request #2 from Limbicnation/feature/lora-integration
Feature/lora integration
This commit is contained in:
@@ -88,3 +88,31 @@ comfy node publish --confirm
|
||||
1. Add entry to `config/templates.yaml` following existing format
|
||||
2. Add style key to `INPUT_TYPES()` style combo list in `prompt_generator_node.py`
|
||||
3. Optionally add to `DEFAULT_STYLES` dict for fallback when YAML unavailable
|
||||
|
||||
- **Current version**: `1.1.1` - Added dynamic LoRA model selection and prioritization. (2026-02-02)
|
||||
- **LoRA Training**: Trained QLoRA on Qwen3-4B-Instruct-2507 using the Limbicnation Video Diffusion Prompt dataset.
|
||||
- **Quantization**: Merged LoRA and converted to Q8_0 GGUF for Ollama.
|
||||
- **Integration**: `PromptGeneratorNode` now auto-discovers and prioritizes models containing `lora` or `limbicnation` keywords.
|
||||
|
||||
### Creating a LoRA-Enhanced Model
|
||||
|
||||
1. Fine-tune a LoRA on the [Limbicnation/Images-Diffusion-Prompt-Style](https://huggingface.co/datasets/Limbicnation/Images-Diffusion-Prompt-Style) dataset (750 prompts)
|
||||
|
||||
2. Export as `.safetensors` (non-quantized recommended)
|
||||
|
||||
3. Create the Ollama model:
|
||||
|
||||
```bash
|
||||
# Edit config/Modelfile.limbicnation with your adapter path
|
||||
ollama create qwen3-limbicnation -f config/Modelfile.limbicnation
|
||||
```
|
||||
|
||||
4. Restart ComfyUI - the new model will appear in the dropdown
|
||||
|
||||
### Modelfile Template
|
||||
|
||||
See `config/Modelfile.limbicnation` for a pre-configured template with:
|
||||
|
||||
- Limbicnation system prompt
|
||||
- Optimal temperature/top_p settings
|
||||
- ADAPTER placeholder for your LoRA
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# Limbicnation LoRA Modelfile Template
|
||||
#
|
||||
# This Modelfile creates an Ollama model with the Limbicnation image prompt style LoRA.
|
||||
#
|
||||
# Usage:
|
||||
# 1. Fine-tune your LoRA using the 750 prompts from Limbicnation/Images-Diffusion-Prompt-Style
|
||||
# 2. Export as .safetensors (non-quantized recommended)
|
||||
# 3. Update the ADAPTER path below
|
||||
# 4. Run: ollama create qwen3-limbicnation -f Modelfile.limbicnation
|
||||
# 5. Test: ollama run qwen3-limbicnation "Generate a cinematic forest prompt"
|
||||
|
||||
# Base model - use the same model you fine-tuned the LoRA on
|
||||
FROM qwen3:4b
|
||||
|
||||
# LoRA adapter path (update this to your fine-tuned adapter)
|
||||
# ADAPTER /path/to/limbicnation-lora.safetensors
|
||||
|
||||
# System prompt for image prompt generation
|
||||
SYSTEM """You are an expert AI Image Prompt Engineer specializing in the "Limbicnation" aesthetic.
|
||||
Your prompts emphasize: cinematic lighting, intricate textures, evocative atmosphere, dramatic compositions.
|
||||
|
||||
When generating image prompts:
|
||||
1. Use rich, sensory language
|
||||
2. Include quality tokens: photorealistic, 8k, detailed, masterpiece
|
||||
3. Specify lighting and atmosphere
|
||||
4. Add negative prompts when requested
|
||||
5. Format for Flux, Z Image, or Stable Diffusion models
|
||||
"""
|
||||
|
||||
# Optimal parameters for prompt generation
|
||||
PARAMETER temperature 0.7
|
||||
PARAMETER top_p 0.9
|
||||
PARAMETER num_ctx 4096
|
||||
@@ -191,14 +191,64 @@ Format the response as a single, detailed sci-fi prompt."""
|
||||
}
|
||||
}
|
||||
|
||||
# Class-level cache for available models
|
||||
_cached_models = None
|
||||
_cache_time = 0
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize the node and load style templates."""
|
||||
self.style_templates = self._load_templates()
|
||||
self.timeout = 120
|
||||
|
||||
@classmethod
|
||||
def _get_available_models(cls) -> list:
|
||||
"""
|
||||
Fetch available Ollama models with caching.
|
||||
Prioritizes LoRA-enhanced models (containing 'lora', 'limbicnation', 'fine').
|
||||
"""
|
||||
import time
|
||||
|
||||
# Cache for 60 seconds
|
||||
if cls._cached_models and (time.time() - cls._cache_time) < 60:
|
||||
return cls._cached_models
|
||||
|
||||
default_models = ["qwen3:8b", "qwen3:4b", "llama3.2:latest"]
|
||||
|
||||
if not OLLAMA_API_AVAILABLE:
|
||||
return default_models
|
||||
|
||||
try:
|
||||
result = ollama.list()
|
||||
models = [m['name'] for m in result.get('models', []) if 'name' in m]
|
||||
|
||||
if not models:
|
||||
return default_models
|
||||
|
||||
# Sort: LoRA/fine-tuned models first, then alphabetically
|
||||
lora_keywords = ['lora', 'limbicnation', 'fine', 'style', 'prompt']
|
||||
|
||||
def sort_key(name):
|
||||
name_lower = name.lower()
|
||||
is_lora = any(kw in name_lower for kw in lora_keywords)
|
||||
return (0 if is_lora else 1, name)
|
||||
|
||||
models = sorted(models, key=sort_key)
|
||||
|
||||
cls._cached_models = models
|
||||
cls._cache_time = time.time()
|
||||
|
||||
print(f"[PromptGenerator] Found {len(models)} Ollama models")
|
||||
return models
|
||||
|
||||
except Exception as e:
|
||||
print(f"[PromptGenerator] Could not fetch models: {e}")
|
||||
return default_models
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> Dict[str, Any]:
|
||||
"""Define input parameters for the node."""
|
||||
available_models = cls._get_available_models()
|
||||
|
||||
return {
|
||||
"required": {
|
||||
"description": ("STRING", {
|
||||
@@ -210,6 +260,10 @@ Format the response as a single, detailed sci-fi prompt."""
|
||||
"abstract", "cyberpunk", "sci-fi"], {
|
||||
"default": "cinematic"
|
||||
}),
|
||||
"model": (available_models, {
|
||||
"default": available_models[0] if available_models else "qwen3:8b",
|
||||
"tooltip": "Select Ollama model. LoRA-enhanced models appear first."
|
||||
}),
|
||||
},
|
||||
"optional": {
|
||||
"emphasis": ("STRING", {
|
||||
@@ -239,9 +293,6 @@ Format the response as a single, detailed sci-fi prompt."""
|
||||
"label_on": "Show Reasoning",
|
||||
"label_off": "Hide Reasoning"
|
||||
}),
|
||||
"model": ("STRING", {
|
||||
"default": "qwen3:8b"
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,6 +301,7 @@ Format the response as a single, detailed sci-fi prompt."""
|
||||
FUNCTION = "generate"
|
||||
CATEGORY = "text/generation"
|
||||
OUTPUT_NODE = False
|
||||
|
||||
|
||||
def _load_templates(self) -> Dict[str, Any]:
|
||||
"""Load style templates from YAML file or use defaults."""
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
[project]
|
||||
name = "comfyui-prompt-generator"
|
||||
description = "Generate Stable Diffusion prompts using Qwen3-8B via Ollama with 7 style presets"
|
||||
version = "1.0.5"
|
||||
description = "Generate Stable Diffusion prompts using Qwen/Ollama with LoRA support and 7 style presets"
|
||||
version = "1.1.2"
|
||||
license = {file = "LICENSE"}
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
|
||||
Reference in New Issue
Block a user