19 Commits
Author SHA1 Message Date
kmlbdh d8d0378eff fix missing lib: folder_paths 2025-08-07 15:47:38 +03:00
kmlbdh a269cc7c10 returned the old llama-cpp-python with auto install 2025-08-07 15:29:50 +03:00
kmlbdh d30adb0991 fix seeds problem "documentation" 2025-08-07 14:37:29 +03:00
kmlbdh a6e26965dc new fix: seeds problem with transformers 2025-08-07 14:31:16 +03:00
kmlbdh c1fda57913 fix: seeds problem with ctransformers 2025-08-07 14:23:30 +03:00
kmlbdh 2e86d327b0 unwanted file 2025-08-07 14:12:06 +03:00
kmlbdh 5e35b2899d fix: issue with seeds and transformers 2025-08-07 14:10:14 +03:00
kmlbdh 3e6c897e8a change llama-cpp-python to ctransformers and install it by the node itself 2025-08-07 13:58:03 +03:00
kmlbdh 543e86c153 Merge branch 'main' of https://github.com/kmlbdh/ComfyUI_LocalLLMNodes 2025-08-06 22:20:05 +03:00
kmlbdh 5ab3ed1d75 add arabic product description node 2025-08-06 22:09:33 +03:00
Obada Shawabke 53a487f8ee Update README.md 2025-08-03 11:32:27 +03:00
kmlbdh e595e8e8b1 fix name issue with pyproject toml 2025-08-03 11:27:18 +03:00
kmlbdh 704c059b3f fix: add valid repository URL for registry 2025-08-03 11:00:40 +03:00
kmlbdh dcba492d07 add .gitignore 2025-08-03 10:44:02 +03:00
kmlbdh da3be65a5a change the pyproject.toml 2025-08-03 10:43:16 +03:00
kmlbdh f32a1cb55e remove sheep icons 2025-08-03 10:29:42 +03:00
kmlbdh d9e2846ecd fix username and email 2025-08-03 09:33:08 +03:00
kmlbdh 3ffae39bb3 add pyproject.toml for ComfyUI registry 2025-08-03 09:30:59 +03:00
kmlbdh aba688dbd6 fix text of presets 2025-08-03 09:29:36 +03:00
7 changed files with 277 additions and 19 deletions
+4
View File
@@ -0,0 +1,4 @@
__pycache__/__init__.cpython-310.pyc
__pycache__/local_gguf_llm_connector.cpython-310.pyc
__pycache__/local_llm_connector.cpython-310.pyc
__pycache__/local_prompt_generator.cpython-310.pyc
+2 -2
View File
@@ -1,6 +1,6 @@
# ComfyUI_LocalLLMNodes
A custom node pack for [ComfyUI](https://github.com/comfyanonymous/ComfyUI) to run Large Language Models (LLMs) locally for prompt generation and text tasks within ComfyUI workflows.
A custom node pack for [ComfyUI](https://github.com/comfyanonymous/ComfyUI) to run Large Language Models (LLMs) locally for flux kontext dev prompt generation within ComfyUI workflows.
**Purpose:**
This pack is designed to simplify the creation of detailed, high-quality prompts for advanced image generation models like **Flux Kontext Dev**. It achieves this by using a **locally running LLM** (Large Language Model) to process:
@@ -128,4 +128,4 @@ Running large LLMs alongside large image models can strain resources.
## Acknowledgements
This node pack builds upon concepts from the excellent [ComfyUI-MieNodes](https://github.com/MieMieeeee/ComfyUI-MieNodes) extension.
This node pack builds upon concepts from the excellent [ComfyUI-MieNodes](https://github.com/MieMieeeee/ComfyUI-MieNodes) extension.
+9 -5
View File
@@ -55,6 +55,8 @@ if GGUF_DEPS_AVAILABLE:
else:
print("[ComfyUI_LocalLLMNodes] GGUF LLM Connector node will NOT be available due to missing dependency (llama-cpp-python).")
from .arabic_product_node import ArabicProductDescriptionGenerator
# --- Define Mappings ---
# Populate the dictionaries based on which nodes were successfully imported.
@@ -65,12 +67,14 @@ if LOCAL_LLM_NODES_AVAILABLE:
"LocalKontextPromptGenerator": LocalKontextPromptGenerator,
"AddUserLocalKontextPreset": AddUserLocalKontextPreset,
"RemoveUserLocalKontextPreset": RemoveUserLocalKontextPreset,
"ArabicProductDescriptionGenerator": ArabicProductDescriptionGenerator,
})
NODE_DISPLAY_NAME_MAPPINGS.update({
"SetLocalLLMServiceConnector": "Set Local LLM Service Connector 🐑 (HuggingFace)",
"LocalKontextPromptGenerator": "Local Kontext Prompt Generator 🐑",
"AddUserLocalKontextPreset": "Add User Local Kontext Preset 🐑",
"RemoveUserLocalKontextPreset": "Remove User Local Kontext Preset 🐑",
"SetLocalLLMServiceConnector": "Set Local LLM Service Connector (HuggingFace)",
"LocalKontextPromptGenerator": "Local Kontext Prompt Generator",
"AddUserLocalKontextPreset": "Add User Local Kontext Preset",
"RemoveUserLocalKontextPreset": "Remove User Local Kontext Preset",
"ArabicProductDescriptionGenerator": "Arabic Product Description Generator"
})
# Add GGUF based nodes if available
@@ -79,7 +83,7 @@ if LOCAL_GGUF_NODES_AVAILABLE:
"SetLocalGGUFLLMServiceConnector": SetLocalGGUFLLMServiceConnector,
})
NODE_DISPLAY_NAME_MAPPINGS.update({
"SetLocalGGUFLLMServiceConnector": "Set Local GGUF LLM Service Connector 🐑",
"SetLocalGGUFLLMServiceConnector": "Set Local GGUF LLM Service Connector",
})
# --- Define what ComfyUI sees ---
+183
View File
@@ -0,0 +1,183 @@
# arabic_product_node.py
import hashlib
import os
import json
# --- Simple logging utility ---
def log(message):
print(f"[ArabicProductDesc] {message}")
# --- Paths and Preset Setup (Same as original) ---
script_directory = os.path.dirname(os.path.abspath(__file__))
USER_PRESETS_FILE = os.path.join(script_directory, "user_kontext_presets.json")
# --- Built-in Presets for Arabic Product Descriptions ---
ARABIC_PRODUCT_PRESETS = {
"عام - وصفي": {
"system": (
"أنت خبير تسويق إلكتروني. اكتب وصفًا احترافيًا باللغة العربية للمنتج بناءً على الوصف المرئي أو المعلومات المقدمة. "
"يجب أن يتضمن الوصف: اسم المنتج (إن عُرف)، المكونات أو المواصفات، الفوائد الرئيسية، طريقة الاستخدام، الفئة المستهدفة، وأي ملاحظات أمان. "
"استخدم لغة تسويقية جذابة، واضحة، وسلسة. لا تستخدم تنسيق Markdown أو عناوين فرعية. لا تضيف تعليقات خارجية."
)
},
"عناية بالبشرة": {
"system": (
"أنت أخصائي عناية بالبشرة. اكتب وصفًا عربيًا احترافيًا لكريم أو سيروم بناءً على الوصف المرئي أو التقني. "
"ركّز على المكونات الفعالة (مثل SPF، حمض الهيالورونيك)، الفوائد (ترطيب، حماية، تفتيح)، ومدى ملاءمته لأنواع البشرة. "
"اذكر طريقة الاستخدام (قبل النوم، بعد التنظيف، إلخ)، وكم مرة يُستخدم. استخدم لغة جذابة لكن علمية."
)
},
"طعام ومشروبات": {
"system": (
"أنت كاتب محتوى غذائي. اكتب وصفًا شهيًا وملهمًا بالعربية لمنتج غذائي أو شراب. "
"صف الطعم، القوام، المكونات الطبيعية، القيمة الغذائية، ومتى يُفضل تناوله (صباحًا، بعد التمرين). "
"استخدم لغة حسية ومشوقة. لا تبالغ. لا تستخدم تنسيق."
)
},
"إلكترونيات": {
"system": (
"أنت خبير تقني. اكتب وصفًا عربيًا واضحًا لجهاز إلكتروني (مثل سماعة، شاحن، ساعة ذكية). "
"اذكر المواصفات الأساسية (البطارية، التوصيل، الجودة)، الفوائد (راحة، دقة، كفاءة)، والجمهور المستهدف. "
"اجعله سهل الفهم للمستخدم العادي مع لمسة احترافية."
)
}
}
def load_user_presets():
"""Load user-defined presets from JSON file."""
if os.path.exists(USER_PRESETS_FILE):
try:
with open(USER_PRESETS_FILE, "r", encoding="utf-8") as f:
return json.load(f)
except (json.JSONDecodeError, IOError) as e:
log(f"Error loading user presets: {e}")
return {}
return {}
def get_all_product_presets():
"""Get combined built-in and user-defined presets."""
all_presets = ARABIC_PRODUCT_PRESETS.copy()
user_presets = load_user_presets()
all_presets.update(user_presets)
return all_presets
# --- Category for UI ---
PRODUCT_DESC_CATEGORY = "Local LLM Nodes/Product Description (Arabic)"
class ArabicProductDescriptionGenerator:
"""
Generates a detailed Arabic product description using:
- Optional image description
- User instruction in Arabic
- Selected preset (system prompt)
- Local LLM via LLMServiceConnector
"""
@classmethod
def INPUT_TYPES(cls):
all_presets = get_all_product_presets()
default_preset = next(iter(all_presets.keys()), "") if all_presets else ""
return {
"required": {
"llm_service_connector": ("LLMServiceConnector",),
"user_instruction_ar": ("STRING", {
"default": "اكتب وصفًا تفصيليًا لهذا المنتج",
"multiline": True,
"tooltip": "التعليمات من المستخدم بالعربية، مثلاً: اكتب وصفًا تسويقيًا"
}),
"preset": (list(all_presets.keys()), {
"default": default_preset,
"tooltip": "اختر نمط الوصف (عام، عناية بالبشرة، إلخ)"
}),
"seed": ("INT", {
"default": 0,
"min": 0,
"max": 0xffffffffffffffff,
"control_after_generate": True
})
},
"optional": {
"image_description": ("STRING", {
"default": "",
"multiline": True,
"tooltip": "وصف الصورة أو التفاصيل التقنية عن المنتج (اختياري)"
})
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("arabic_product_description",)
FUNCTION = "generate_description"
CATEGORY = PRODUCT_DESC_CATEGORY
def generate_description(self, llm_service_connector, user_instruction_ar, preset, seed=None, image_description=None):
# Load preset
all_presets = get_all_product_presets()
preset_data = all_presets.get(preset)
if not preset_data:
raise ValueError(f"النمط غير معروف: {preset}")
# Safe string conversion
def safe_str(s):
return str(s) if s is not None else ""
img_desc = safe_str(image_description).strip()
user_inst = safe_str(user_instruction_ar).strip()
# Build user content
user_content_parts = []
if img_desc:
user_content_parts.append(f"وصف المنتج أو الصورة: {img_desc}")
if user_inst:
user_content_parts.append(f"التعليمات: {user_inst}")
else:
user_content_parts.append("التعليمات: اكتب وصفًا تفصيليًا للمنتج.")
user_content = " ".join(user_content_parts).strip()
if not user_content:
user_content = "وصف المنتج: منتج على خلفية بيضاء. التعليمات: اكتب وصفًا تسويقيًا بالعربية."
# Build messages
messages = [
{"role": "system", "content": preset_data["system"]},
{"role": "user", "content": user_content}
]
# Call LLM
try:
response = llm_service_connector.invoke(messages, seed=seed)
return (response.strip(),)
except Exception as e:
error_msg = f"[خطأ] تعذر إنشاء الوصف: {str(e)}"
log(error_msg)
return (error_msg,)
def is_changed(self, llm_service_connector, user_instruction_ar, preset, seed, image_description=None):
"""Ensure node re-runs only when inputs change."""
try:
hasher = hashlib.md5()
hasher.update(str(user_instruction_ar).encode('utf-8'))
hasher.update(preset.encode('utf-8'))
hasher.update(str(seed).encode('utf-8'))
hasher.update(str(image_description).encode('utf-8'))
# Add preset system prompt
all_presets = get_all_product_presets()
preset_data = all_presets.get(preset)
if preset_data and "system" in preset_data:
hasher.update(preset_data["system"].encode('utf-8'))
# Add connector state
try:
connector_state = llm_service_connector.get_state()
except AttributeError:
connector_state = str(llm_service_connector)
hasher.update(connector_state.encode('utf-8'))
return hasher.hexdigest()
except Exception as e:
log(f"is_changed error: {e}")
return float("nan")
+50 -8
View File
@@ -1,19 +1,61 @@
# ComfyUI/custom_nodes/ComfyUI_LocalLLMNodes/local_gguf_llm_connector.py
import os
import subprocess
import sys
import platform
import folder_paths
# --- Library for GGUF local LLM inference ---
try:
import llama_cpp
# import llama_cpp.llama_tokenizer # Optional, remove if not used
LLAMA_CPP_AVAILABLE = True
except ImportError:
# --- Simple logging utility for this package (reuse existing one) ---
# Import here to avoid potential issues if log isn't defined yet if imported at top in case of circular import risks,
# though usually safe. Ensure local_llm_connector.py defines 'log' early.
from .local_llm_connector import log
log("[LocalGGUFLLMConnector] Warning: llama-cpp-python library not found.")
LLAMA_CPP_AVAILABLE = False
llama_cpp = None
def check_nvidia_gpu():
try:
result = subprocess.run(['nvidia-smi'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
return result.returncode == 0
except (FileNotFoundError, OSError):
return False
def check_apple_metal():
return platform.system() == "Darwin" and "arm" in platform.machine().lower()
log("[LocalGGUFLLMConnector] llama-cpp-python not found. Attempting auto-install...")
# Detect hardware
cmake_args = []
if check_nvidia_gpu():
log("NVIDIA GPU detected: Enabling CUDA acceleration.")
cmake_args.append("-DLLAMA_CUBLAS=on")
elif check_apple_metal():
log("Apple Silicon (M1/M2/M3) detected: Enabling Metal acceleration.")
cmake_args.append("-DLLAMA_METAL=on")
else:
log("💻 No compatible GPU found: Installing CPU-only version.")
# Build pip install command
cmd = [sys.executable, "-m", "pip", "install", "llama-cpp-python"]
if cmake_args:
cmd += [f"--config-settings=cmake_args={';'.join(cmake_args)}"]
cmd += ["--force-reinstall", "--no-cache-dir"]
try:
log(f"📦 Running: {' '.join(cmd)}")
subprocess.check_call(cmd)
log("llama-cpp-python installed successfully!")
# Force reload after install
import importlib
import llama_cpp
importlib.reload(llama_cpp)
LLAMA_CPP_AVAILABLE = True
except subprocess.CalledProcessError as e:
log(f"Installation failed: {e}")
LLAMA_CPP_AVAILABLE = False
except Exception as e:
log(f"Unexpected error during install: {e}")
LLAMA_CPP_AVAILABLE = False
# Reuse the logging function from local_llm_connector
from .local_llm_connector import log # Ensure this is the final import for log
+4 -4
View File
@@ -16,7 +16,7 @@ USER_PRESETS_FILE = os.path.join(script_directory, "user_kontext_presets.json")
# --- Replicate Built-in Presets (from MieNodes' prompt_generator.py) ---
KONTEXT_PRESETS = {
"Kid Clothes -> Flux Prompt": {
"Kid Clothes": {
"system": (
"You are an expert prompt generator for Flux Kontext. Your task is to place clothing described by the user onto a baby or child with Arab facial features, while preserving all material, color, and style details from the original clothing description. "
"Input: "
@@ -36,7 +36,7 @@ KONTEXT_PRESETS = {
"A photorealistic Arab baby with round cheeks and light tan skin, lying on a soft white fleece blanket, wearing a pale blue cotton romper with stitched white cloud patterns and integrated footies, captured in soft natural lighting with shallow DOF, cozy nursery ambiance, 8K resolution, cinematic baby fashion catalog style."
)
},
"Women’s Clothes -> Flux Prompt": {
"Women’s Clothes": {
"system": (
"You are an expert visual prompt composer for Flux Kontext. Your job is to place the clothing described by the user onto a realistic Muslim woman model in her 20s with Arab features, while preserving all original garment details. "
"Input: "
@@ -56,7 +56,7 @@ KONTEXT_PRESETS = {
"A young Arab Muslim woman in her 20s with soft olive skin and delicate features, wearing a beige linen abaya with subtle gold-stitched cuffs and a loosely tied waist sash, standing in a minimalist white studio under soft diffused lighting, side-facing pose with natural folds in the fabric, fashion editorial style with cinematic shallow DOF."
)
},
"Beauty Product Use -> Flux Prompt": {
"Beauty Product Use": {
"system": (
"You are a creative image prompt generator for Flux Kontext focused on health, skincare, and beauty products. Your job is to place the described product in an artistic or commercial setting — either used by a model (Arab man or woman), or placed within a creative, beauty-inspired scene — while preserving all visual and material details of the product. "
"Input: "
@@ -75,7 +75,7 @@ KONTEXT_PRESETS = {
"An elegant Arab woman with natural tan skin and voluminous dark hair, holding an amber glass dropper bottle with a gold label and black cap, delicately applying serum to her cheek in front of a glowing vanity mirror, soft candle-lit ambiance, subtle shadows, cinematic close-up, bokeh background, luxury skincare ad style."
)
},
"Beauty Product Display -> Flux Prompt": {
"Beauty Product Display": {
"system": (
"You are an expert in luxury beauty product visuals for Flux Kontext. Place the described product in a stunning, creative, brand-inspired environment (without any models), using beauty aesthetics and visual storytelling. "
"Input: "
+25
View File
@@ -0,0 +1,25 @@
[project]
name = "LocalLLMnodes"
description = "Run local LLMs in ComfyUI and generate Flux Kontext.dev prompts from simple English descriptions"
readme = "README.md"
version = "0.1.0"
license = { text = "MIT" }
dependencies = ["# Core dependencies for Hugging Face transformers based nodes (e.g., Hermes-2-Pro-Llama-3-8B)", "transformers>=4.38.0 # Or a specific version you know works", "torch>=2.0.0 # Or a specific version you know works", "# Optional, for quantization with transformers (e.g., 4-bit)", "# bitsandbytes # Uncomment if you use BitsAndBytesConfig in local_llm_connector.py", "# accelerate # Often needed with transformers, especially for device_map", "# Core dependency for GGUF based nodes (e.g., Mistral-7B-Instruct-Q8.gguf)", "llama-cpp-python>=0.1.0 # Or a specific version", "# Optional: For downloading models from Hugging Face Hub", "huggingface_hub", "# Optional: If your package uses any specific utility libraries", "# (Although deepdiff, pillow, etc. might be pulled in by ComfyUI or other nodes)", "# deepdiff", "# pillow", "# Notes for Users:", "# For llama-cpp-python with GPU support (CUDA), installation is more complex.", "# Example for CUDA 11.8 (check llama-cpp-python docs for your version):", "# CMAKE_ARGS=\"-DLLAMA_CUBLAS=on\" pip install llama-cpp-python", "# Example for CUDA 12.1:", "# CMAKE_ARGS=\"-DLLAMA_CUDA=on\" pip install llama-cpp-python"]
authors = [
{ name = "Obada Shawabke", email = "obdkml@gmail.com" }
]
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
]
[project.urls]
Repository = "https://github.com/kmlbdh/ComfyUI_LocalLLMNodes"
Homepage = "https://github.com/kmlbdh/ComfyUI_LocalLLMNodes"
[tool.comfy]
PublisherId = "kmlbdh"
DisplayName = "ComfyUI_LocalLLMNodes"
Icon = "🤖"
includes = []