+28
-43
@@ -3,40 +3,24 @@ PromptManager: A ComfyUI custom node that extends the standard text encoder
|
||||
with persistent prompt storage and advanced search capabilities using SQLite.
|
||||
"""
|
||||
|
||||
# Import logging system
|
||||
try:
|
||||
from .utils.logging_config import get_logger
|
||||
init_logger = get_logger('prompt_manager.init')
|
||||
init_logger.info("Starting to load PromptManager custom node...")
|
||||
except ImportError:
|
||||
# Fallback to print if logging isn't available yet
|
||||
init_logger = None
|
||||
print("[PromptManager] Starting to load PromptManager custom node...")
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
def log_message(message, level='info'):
|
||||
"""Helper to log messages with fallback to print."""
|
||||
if init_logger:
|
||||
getattr(init_logger, level)(message.replace("[PromptManager] ", ""))
|
||||
else:
|
||||
print(f"[PromptManager] {message}")
|
||||
def get_version():
|
||||
"""Parse version from pyproject.toml"""
|
||||
try:
|
||||
pyproject_path = Path(__file__).parent / "pyproject.toml"
|
||||
if pyproject_path.exists():
|
||||
content = pyproject_path.read_text()
|
||||
match = re.search(r'version\s*=\s*["\']([^"\']+)["\']', content)
|
||||
if match:
|
||||
return match.group(1)
|
||||
except Exception:
|
||||
pass
|
||||
return "unknown"
|
||||
|
||||
try:
|
||||
from .prompt_manager import PromptManager
|
||||
log_message("Successfully imported PromptManager class")
|
||||
except Exception as e:
|
||||
log_message(f"ERROR: Failed to import PromptManager class: {e}", 'error')
|
||||
import traceback
|
||||
log_message(f"Traceback: {traceback.format_exc()}", 'error')
|
||||
raise
|
||||
|
||||
try:
|
||||
from .prompt_manager_text import PromptManagerText
|
||||
log_message("Successfully imported PromptManagerText class")
|
||||
except Exception as e:
|
||||
log_message(f"ERROR: Failed to import PromptManagerText class: {e}", 'error')
|
||||
import traceback
|
||||
log_message(f"Traceback: {traceback.format_exc()}", 'error')
|
||||
raise
|
||||
from .prompt_manager import PromptManager
|
||||
from .prompt_manager_text import PromptManagerText
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"PromptManager": PromptManager,
|
||||
@@ -48,9 +32,6 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"PromptManagerText": "Prompt Manager Text",
|
||||
}
|
||||
|
||||
log_message(f"NODE_CLASS_MAPPINGS: {NODE_CLASS_MAPPINGS}")
|
||||
log_message(f"NODE_DISPLAY_NAME_MAPPINGS: {NODE_DISPLAY_NAME_MAPPINGS}")
|
||||
|
||||
# Define path to web directory for UI components
|
||||
WEB_DIRECTORY = "web"
|
||||
|
||||
@@ -69,15 +50,19 @@ try:
|
||||
api = PromptManagerAPI()
|
||||
api.add_routes(routes)
|
||||
|
||||
log_message("API routes registered successfully")
|
||||
log_message(f"Server instance: {config.server_instance}")
|
||||
log_message(f"Routes object: {routes}")
|
||||
|
||||
except Exception as e:
|
||||
log_message(f"Failed to register API routes: {e}", 'error')
|
||||
import traceback
|
||||
log_message(f"Traceback: {traceback.format_exc()}", 'error')
|
||||
# Log to internal logging system without console spam
|
||||
try:
|
||||
from .utils.logging_config import get_logger
|
||||
logger = get_logger('prompt_manager.init')
|
||||
logger.error(f"Failed to register API routes: {e}")
|
||||
except:
|
||||
pass
|
||||
|
||||
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS", "WEB_DIRECTORY"]
|
||||
|
||||
log_message("[SUCCESS] PromptManager custom node loaded successfully!")
|
||||
# Print startup message with loaded tools
|
||||
print(f"\033[94m[ComfyUI-PromptManager] Version:\033[0m {get_version()}")
|
||||
for node_key, display_name in NODE_DISPLAY_NAME_MAPPINGS.items():
|
||||
print(f"🫶 \033[94mLoaded:\033[0m {display_name}")
|
||||
print(f"\033[94mTotal: {len(NODE_CLASS_MAPPINGS)} tools loaded\033[0m")
|
||||
+6
-6
@@ -57,7 +57,7 @@ class PromptManager(ComfyNodeABC):
|
||||
|
||||
def __init__(self):
|
||||
self.logger = get_logger('prompt_manager.node')
|
||||
self.logger.info("Initializing PromptManager node")
|
||||
self.logger.debug("Initializing PromptManager node")
|
||||
|
||||
self.db = PromptDatabase()
|
||||
self.prompt_tracker = PromptTracker(self.db)
|
||||
@@ -65,7 +65,7 @@ class PromptManager(ComfyNodeABC):
|
||||
|
||||
# Start image monitoring automatically
|
||||
self._start_gallery_system()
|
||||
self.logger.info("PromptManager node initialization completed")
|
||||
self.logger.debug("PromptManager node initialization completed")
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> InputTypeDict:
|
||||
@@ -108,7 +108,7 @@ class PromptManager(ComfyNodeABC):
|
||||
"The final combined text string (with prepend/append applied) that was encoded."
|
||||
)
|
||||
FUNCTION = "encode"
|
||||
CATEGORY = "PromptManager/Text"
|
||||
CATEGORY = "ComfyAssets/Text"
|
||||
DESCRIPTION = (
|
||||
"Encodes a text prompt using a CLIP model into an embedding that can be used to guide "
|
||||
"the diffusion model towards generating specific images. Additionally saves all prompts "
|
||||
@@ -343,12 +343,12 @@ class PromptManager(ComfyNodeABC):
|
||||
def _start_gallery_system(self):
|
||||
"""Initialize and start the gallery monitoring system."""
|
||||
try:
|
||||
self.logger.info("Starting gallery system...")
|
||||
self.logger.debug("Starting gallery system...")
|
||||
|
||||
# Start image monitoring
|
||||
self.image_monitor.start_monitoring()
|
||||
|
||||
self.logger.info("Gallery system started successfully")
|
||||
self.logger.debug("Gallery system started successfully")
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to start gallery system: {e}")
|
||||
@@ -366,7 +366,7 @@ class PromptManager(ComfyNodeABC):
|
||||
try:
|
||||
if hasattr(self, 'image_monitor'):
|
||||
self.image_monitor.stop_monitoring()
|
||||
self.logger.info("Gallery system cleaned up")
|
||||
self.logger.debug("Gallery system cleaned up")
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error cleaning up gallery system: {e}")
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ class PromptManagerText(ComfyNodeABC):
|
||||
|
||||
def __init__(self):
|
||||
self.logger = get_logger('prompt_manager_text.node')
|
||||
self.logger.info("Initializing PromptManagerText node")
|
||||
self.logger.debug("Initializing PromptManagerText node")
|
||||
|
||||
self.db = PromptDatabase()
|
||||
self.prompt_tracker = PromptTracker(self.db)
|
||||
@@ -67,7 +67,7 @@ class PromptManagerText(ComfyNodeABC):
|
||||
|
||||
# Start image monitoring automatically
|
||||
self._start_gallery_system()
|
||||
self.logger.info("PromptManagerText node initialization completed")
|
||||
self.logger.debug("PromptManagerText node initialization completed")
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls) -> InputTypeDict:
|
||||
@@ -108,7 +108,7 @@ class PromptManagerText(ComfyNodeABC):
|
||||
"The final combined text string (with prepend/append applied) ready for use in other nodes.",
|
||||
)
|
||||
FUNCTION = "process_text"
|
||||
CATEGORY = "PromptManager/Text"
|
||||
CATEGORY = "ComfyAssets/Text"
|
||||
DESCRIPTION = (
|
||||
"Processes and manages text prompts with database storage and search capabilities. "
|
||||
"Outputs a plain STRING that can be used with any node that accepts text input. "
|
||||
@@ -318,12 +318,12 @@ class PromptManagerText(ComfyNodeABC):
|
||||
def _start_gallery_system(self):
|
||||
"""Initialize and start the gallery monitoring system."""
|
||||
try:
|
||||
self.logger.info("Starting gallery system...")
|
||||
self.logger.debug("Starting gallery system...")
|
||||
|
||||
# Start image monitoring
|
||||
self.image_monitor.start_monitoring()
|
||||
|
||||
self.logger.info("Gallery system started successfully")
|
||||
self.logger.debug("Gallery system started successfully")
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to start gallery system: {e}")
|
||||
@@ -341,7 +341,7 @@ class PromptManagerText(ComfyNodeABC):
|
||||
try:
|
||||
if hasattr(self, 'image_monitor'):
|
||||
self.image_monitor.stop_monitoring()
|
||||
self.logger.info("Gallery system cleaned up")
|
||||
self.logger.debug("Gallery system cleaned up")
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error cleaning up gallery system: {e}")
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
[project]
|
||||
name = "promptmanager"
|
||||
description = "A powerful ComfyUI custom node that extends the standard text encoder with persistent prompt storage, advanced search capabilities, and an automatic image gallery system using SQLite."
|
||||
version = "3.0.11"
|
||||
version = "3.0.12"
|
||||
license = {file = "LICENSE"}
|
||||
dependencies = ["# Core dependencies for PromptManager", "# Note: Most dependencies are already included with ComfyUI", "# Already included with Python standard library:", "# - sqlite3", "# - hashlib", "# - json", "# - datetime", "# - os", "# - typing", "# - threading", "# - uuid", "# Required for gallery functionality:", "watchdog>=2.1.0 # For file system monitoring", "Pillow>=8.0.0 # For image metadata extraction (usually included with ComfyUI)", "# Optional dependencies for enhanced search functionality:", "# fuzzywuzzy[speedup]>=0.18.0 # For fuzzy string matching (optional)", "# sqlalchemy>=1.4.0 # For advanced ORM features (optional)", "# Development dependencies (optional):", "# pytest>=6.0.0 # For running tests", "# black>=22.0.0 # For code formatting", "# flake8>=4.0.0 # For linting", "# mypy>=0.910 # For type checking"]
|
||||
|
||||
|
||||
+11
-11
@@ -36,7 +36,7 @@ class ImageGenerationHandler(FileSystemEventHandler):
|
||||
def on_created(self, event):
|
||||
"""Handle file creation events."""
|
||||
if not event.is_directory and self.is_image_file(event.src_path):
|
||||
self.logger.info(f"New image detected: {event.src_path}")
|
||||
self.logger.debug(f"New image detected: {event.src_path}")
|
||||
# Small delay to ensure file is fully written
|
||||
threading.Timer(
|
||||
self.processing_delay,
|
||||
@@ -51,7 +51,7 @@ class ImageGenerationHandler(FileSystemEventHandler):
|
||||
def process_new_image(self, image_path: str):
|
||||
"""Process a newly created image file."""
|
||||
try:
|
||||
self.logger.info(f"Processing image: {image_path}")
|
||||
self.logger.debug(f"Processing image: {image_path}")
|
||||
|
||||
if not os.path.exists(image_path):
|
||||
self.logger.warning(f"Image file no longer exists: {image_path}")
|
||||
@@ -62,11 +62,11 @@ class ImageGenerationHandler(FileSystemEventHandler):
|
||||
self.logger.debug(f"Current prompt context: {current_prompt['id'] if current_prompt else 'None'}")
|
||||
|
||||
if not current_prompt:
|
||||
self.logger.info(f"No active prompt context for image: {image_path}")
|
||||
self.logger.debug(f"No active prompt context for image: {image_path}")
|
||||
# Fallback: try to link to the most recent prompt in database
|
||||
current_prompt = self._get_fallback_prompt()
|
||||
if current_prompt:
|
||||
self.logger.info(f"Using fallback prompt: {current_prompt['id']}")
|
||||
self.logger.debug(f"Using fallback prompt: {current_prompt['id']}")
|
||||
else:
|
||||
self.logger.warning(f"No fallback prompt available, skipping image")
|
||||
return
|
||||
@@ -84,10 +84,10 @@ class ImageGenerationHandler(FileSystemEventHandler):
|
||||
metadata = None
|
||||
|
||||
if metadata:
|
||||
self.logger.info(f"Linking image with full metadata to prompt {current_prompt['id']}")
|
||||
self.logger.debug(f"Linking image with full metadata to prompt {current_prompt['id']}")
|
||||
self.link_image_to_prompt(image_path, current_prompt, metadata)
|
||||
else:
|
||||
self.logger.info(f"Linking image with basic info to prompt {current_prompt['id']}")
|
||||
self.logger.debug(f"Linking image with basic info to prompt {current_prompt['id']}")
|
||||
# Link with basic file info even without metadata
|
||||
basic_metadata = self.get_basic_file_info(image_path)
|
||||
self.link_image_to_prompt(image_path, current_prompt, {'file_info': basic_metadata})
|
||||
@@ -147,7 +147,7 @@ class ImageGenerationHandler(FileSystemEventHandler):
|
||||
metadata=metadata
|
||||
)
|
||||
fallback_note = " (fallback)" if prompt_context.get('fallback') else ""
|
||||
self.logger.info(f"Successfully linked image {image_id} to prompt {prompt_context['id']}{fallback_note}")
|
||||
self.logger.debug(f"Successfully linked image {image_id} to prompt {prompt_context['id']}{fallback_note}")
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to link image to prompt: {e}")
|
||||
|
||||
@@ -199,13 +199,13 @@ class ImageMonitor:
|
||||
if os.path.exists(output_dir):
|
||||
self.observer.schedule(self.handler, output_dir, recursive=True)
|
||||
self.monitored_directories.append(output_dir)
|
||||
self.logger.info(f"Monitoring directory: {output_dir}")
|
||||
self.logger.debug(f"Monitoring directory: {output_dir}")
|
||||
else:
|
||||
self.logger.warning(f"Directory does not exist: {output_dir}")
|
||||
|
||||
if self.monitored_directories:
|
||||
self.observer.start()
|
||||
self.logger.info(f"Image monitoring started for {len(self.monitored_directories)} directories")
|
||||
self.logger.debug(f"Image monitoring started for {len(self.monitored_directories)} directories")
|
||||
else:
|
||||
self.logger.warning("No valid directories to monitor")
|
||||
|
||||
@@ -217,7 +217,7 @@ class ImageMonitor:
|
||||
self.observer = None
|
||||
self.handler = None
|
||||
self.monitored_directories = []
|
||||
self.logger.info("Image monitoring stopped")
|
||||
self.logger.debug("Image monitoring stopped")
|
||||
|
||||
def detect_comfyui_output_dirs(self) -> list:
|
||||
"""Auto-detect ComfyUI output directories."""
|
||||
@@ -229,7 +229,7 @@ class ImageMonitor:
|
||||
output_dir = folder_paths.get_output_directory()
|
||||
if output_dir and os.path.exists(output_dir):
|
||||
potential_dirs.append(output_dir)
|
||||
self.logger.info(f"Detected ComfyUI output directory: {output_dir}")
|
||||
self.logger.debug(f"Detected ComfyUI output directory: {output_dir}")
|
||||
except ImportError:
|
||||
self.logger.debug("ComfyUI folder_paths not available, using fallback detection")
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ class PromptTracker:
|
||||
db_manager: Database manager instance
|
||||
"""
|
||||
self.logger = get_logger('prompt_manager.prompt_tracker')
|
||||
self.logger.info("Initializing PromptTracker")
|
||||
self.logger.debug("Initializing PromptTracker")
|
||||
|
||||
self.db_manager = db_manager
|
||||
self._local = threading.local()
|
||||
@@ -212,7 +212,7 @@ class PromptTracker:
|
||||
self.active_prompts.pop(exec_id, None)
|
||||
|
||||
if expired_ids:
|
||||
self.logger.info(f"Cleaned up {len(expired_ids)} expired prompts")
|
||||
self.logger.debug(f"Cleaned up {len(expired_ids)} expired prompts")
|
||||
|
||||
time.sleep(self.cleanup_interval)
|
||||
|
||||
@@ -244,7 +244,7 @@ class PromptTracker:
|
||||
# Clear thread-local storage as well
|
||||
self._local.current_prompt = None
|
||||
|
||||
self.logger.info(f"Cleared {cleared_count} active prompts")
|
||||
self.logger.debug(f"Cleared {cleared_count} active prompts")
|
||||
return cleared_count
|
||||
|
||||
def get_status(self) -> Dict[str, Any]:
|
||||
|
||||
Reference in New Issue
Block a user