From 3f600fdf108c3c5d0c359ac843d04e79f52d7180 Mon Sep 17 00:00:00 2001 From: limbicnation Date: Mon, 2 Feb 2026 03:54:04 +0100 Subject: [PATCH 1/4] feat: implement dynamic LoRA model selection v1.1.1 --- CLAUDE.md | 35 ++++++++++++++++++++ config/Modelfile.limbicnation | 33 +++++++++++++++++++ nodes/prompt_generator_node.py | 58 ++++++++++++++++++++++++++++++++-- pyproject.toml | 4 +-- 4 files changed, 125 insertions(+), 5 deletions(-) create mode 100644 config/Modelfile.limbicnation diff --git a/CLAUDE.md b/CLAUDE.md index 3d330fe..bf1db1d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -88,3 +88,38 @@ 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 + +## LoRA Integration + +**Current version**: `1.1.0` - Added dynamic LoRA model selection + +### Dynamic Model Selection + +The node now auto-discovers available Ollama models and prioritizes LoRA-enhanced models in the dropdown: + +- Models with keywords `lora`, `limbicnation`, `fine`, `style`, `prompt` appear first +- Model list is cached for 60 seconds for performance +- Graceful fallback to defaults if Ollama is unavailable + +### 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 diff --git a/config/Modelfile.limbicnation b/config/Modelfile.limbicnation new file mode 100644 index 0000000..f70bb3e --- /dev/null +++ b/config/Modelfile.limbicnation @@ -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 diff --git a/nodes/prompt_generator_node.py b/nodes/prompt_generator_node.py index 6608e5a..9f820fe 100644 --- a/nodes/prompt_generator_node.py +++ b/nodes/prompt_generator_node.py @@ -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.get('name', m.get('model', '')) for m in result.get('models', [])] + + 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.""" diff --git a/pyproject.toml b/pyproject.toml index 612d01c..dada7cf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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.1" license = {file = "LICENSE"} readme = "README.md" requires-python = ">=3.10" From 1455268c327aae9449ec2496bd6f59a08c75ee90 Mon Sep 17 00:00:00 2001 From: limbicnation Date: Mon, 2 Feb 2026 03:56:55 +0100 Subject: [PATCH 2/4] docs: update project memory with LoRA integration milestones --- CLAUDE.md | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index bf1db1d..564c2a6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -89,17 +89,10 @@ comfy node publish --confirm 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 -## LoRA Integration - -**Current version**: `1.1.0` - Added dynamic LoRA model selection - -### Dynamic Model Selection - -The node now auto-discovers available Ollama models and prioritizes LoRA-enhanced models in the dropdown: - -- Models with keywords `lora`, `limbicnation`, `fine`, `style`, `prompt` appear first -- Model list is cached for 60 seconds for performance -- Graceful fallback to defaults if Ollama is 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 From 7426ef860279591792cc148e6bb8d983ddb1d5d2 Mon Sep 17 00:00:00 2001 From: limbicnation Date: Mon, 2 Feb 2026 04:03:14 +0100 Subject: [PATCH 3/4] fix: use authoritative model name field only Addresses code review feedback to avoid ambiguous model identifiers. The 'model' field may contain only base names (e.g., 'qwen3') while 'name' contains the full identifier ('qwen3:8b'). Skipping models without proper 'name' field is safer than using potentially incorrect fallback data. --- nodes/prompt_generator_node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodes/prompt_generator_node.py b/nodes/prompt_generator_node.py index 9f820fe..3ff1a8e 100644 --- a/nodes/prompt_generator_node.py +++ b/nodes/prompt_generator_node.py @@ -219,7 +219,7 @@ Format the response as a single, detailed sci-fi prompt.""" try: result = ollama.list() - models = [m.get('name', m.get('model', '')) for m in result.get('models', [])] + models = [m['name'] for m in result.get('models', []) if 'name' in m] if not models: return default_models From eb884bd6649397513fa72b90dab9c7f8bcedec3c Mon Sep 17 00:00:00 2001 From: limbicnation Date: Mon, 2 Feb 2026 04:04:23 +0100 Subject: [PATCH 4/4] Update version to 1.1.2 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index dada7cf..f9e9060 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "comfyui-prompt-generator" description = "Generate Stable Diffusion prompts using Qwen/Ollama with LoRA support and 7 style presets" -version = "1.1.1" +version = "1.1.2" license = {file = "LICENSE"} readme = "README.md" requires-python = ">=3.10"