From 6b6ba3c62c87315f195d44054dfa779c870e22b8 Mon Sep 17 00:00:00 2001 From: Vito Sansevero Date: Tue, 3 Jun 2025 17:03:18 -0700 Subject: [PATCH 1/6] feat(prompt_manager): add prepend and append text options --- prompt_manager.py | 56 ++++- web/admin.html | 76 ++++++- web/metadata.html | 558 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 677 insertions(+), 13 deletions(-) create mode 100644 web/metadata.html diff --git a/prompt_manager.py b/prompt_manager.py index 6fb19a1..f54848c 100644 --- a/prompt_manager.py +++ b/prompt_manager.py @@ -92,6 +92,12 @@ class PromptManager(ComfyNodeABC): "search_text": (IO.STRING, { "default": "", "tooltip": "Search for past prompts containing this text" + }), + "prepend_text": (IO.STRING, { + "tooltip": "Text to prepend to the main prompt (connected STRING nodes will be added before the main text)" + }), + "append_text": (IO.STRING, { + "tooltip": "Text to append to the main prompt (connected STRING nodes will be added after the main text)" }) } } @@ -114,7 +120,9 @@ class PromptManager(ComfyNodeABC): text: str, category: str = "", tags: str = "", - search_text: str = "" + search_text: str = "", + prepend_text: str = "", + append_text: str = "" ) -> Tuple[Any]: """ Encode the text prompt and save it to the database. @@ -125,6 +133,8 @@ class PromptManager(ComfyNodeABC): category: Optional category for organization tags: Comma-separated tags search_text: Text to search for in past prompts + prepend_text: Text to prepend to the main prompt + append_text: Text to append to the main prompt Returns: Tuple containing the conditioning for the diffusion model @@ -132,6 +142,20 @@ class PromptManager(ComfyNodeABC): Raises: RuntimeError: If clip input is invalid """ + # Combine prepend, main text, and append text + final_text = "" + if prepend_text and prepend_text.strip(): + final_text += prepend_text.strip() + " " + final_text += text + if append_text and append_text.strip(): + final_text += " " + append_text.strip() + + # Use the combined text for encoding + encoding_text = final_text + + # For database storage, save the original main text with metadata about prepend/append + storage_text = text + # Search functionality is now handled by the JavaScript UI # The search parameters are still available for backend processing if needed @@ -147,23 +171,33 @@ class PromptManager(ComfyNodeABC): # Save prompt to database and set execution context for gallery tracking prompt_id = None - if text and text.strip(): - self.logger.debug(f"Processing prompt text: {text[:100]}...") + if storage_text and storage_text.strip(): + self.logger.debug(f"Processing prompt text: {storage_text[:100]}...") + + # Add prepend/append info to tags if they exist + extended_tags = self._parse_tags(tags) or [] + if prepend_text and prepend_text.strip(): + extended_tags.append(f"prepend:{prepend_text.strip()[:50]}") + if append_text and append_text.strip(): + extended_tags.append(f"append:{append_text.strip()[:50]}") + try: prompt_id = self._save_prompt_to_database( - text=text.strip(), # Always strip whitespace + text=storage_text.strip(), # Always strip whitespace category=category.strip() if category else None, - tags=self._parse_tags(tags) + tags=extended_tags if extended_tags else None ) # Set current prompt for image tracking if prompt_id: execution_id = self.prompt_tracker.set_current_prompt( - prompt_text=text.strip(), + prompt_text=encoding_text.strip(), # Use final combined text for tracking additional_data={ 'category': category.strip() if category else None, - 'tags': self._parse_tags(tags), - 'prompt_id': prompt_id + 'tags': extended_tags, + 'prompt_id': prompt_id, + 'prepend_text': prepend_text.strip() if prepend_text else None, + 'append_text': append_text.strip() if append_text else None } ) self.logger.info(f"Set execution context: {execution_id} for prompt ID: {prompt_id}") @@ -173,9 +207,9 @@ class PromptManager(ComfyNodeABC): self.logger.warning(f"Failed to save prompt to database: {e}") # Already logged above, no need for additional print - # Perform standard CLIP text encoding - self.logger.debug("Performing CLIP text encoding") - tokens = clip.tokenize(text) + # Perform standard CLIP text encoding using the combined text + self.logger.debug(f"Performing CLIP text encoding on combined text: {encoding_text[:100]}...") + tokens = clip.tokenize(encoding_text) conditioning = clip.encode_from_tokens_scheduled(tokens) self.logger.debug("CLIP encoding completed successfully") diff --git a/web/admin.html b/web/admin.html index 7c22d44..744fef1 100644 --- a/web/admin.html +++ b/web/admin.html @@ -2843,7 +2843,9 @@ this.updateMetadataPanel(comfyData, imageSrc); } catch (error) { console.error('Error extracting metadata:', error); - this.showMetadataError(); + + // Try fallback: get prompt from database using current image + await this.tryFallbackMetadata(imageSrc); } } @@ -3129,12 +3131,82 @@ } async copyPrompt(type) { - if (!this.currentMetadata) return; + console.log('copyPrompt called with type:', type); + console.log('currentMetadata:', this.currentMetadata); + + if (!this.currentMetadata) { + console.error('No metadata available for copying'); + this.showNotification('❌ No metadata available for copying', 'error'); + return; + } const text = type === 'positive' ? this.currentMetadata.positivePrompt : this.currentMetadata.negativePrompt; + console.log('Copying text:', text?.substring(0, 100)); + + if (!text || text === 'No prompt found' || text === 'No negative prompt found') { + this.showNotification(`❌ No ${type} prompt available`, 'error'); + return; + } + await this.copyToClipboard(text); } + async tryFallbackMetadata(imageSrc) { + console.log('Trying fallback metadata extraction for:', imageSrc); + + try { + // Try to get prompt from current gallery image data + let fallbackPrompt = 'No prompt found'; + + if (this.currentGalleryImages && this.currentImageIndex !== null && this.currentGalleryImages[this.currentImageIndex]) { + const currentImage = this.currentGalleryImages[this.currentImageIndex]; + console.log('Current image data:', currentImage); + + // If we have prompt_id, try to get the prompt from our local prompts array + if (currentImage.prompt_id && this.prompts) { + const prompt = this.prompts.find(p => p.id === currentImage.prompt_id); + if (prompt) { + fallbackPrompt = prompt.text; + console.log('Found prompt from database:', fallbackPrompt.substring(0, 100)); + } + } + } + + // Set fallback metadata + this.currentMetadata = { + positivePrompt: fallbackPrompt, + negativePrompt: 'No negative prompt found', + checkpoint: 'Unknown', + steps: 'Unknown', + cfgScale: 'Unknown', + sampler: 'Unknown', + seed: 'Unknown', + workflow: null, + prompt: null + }; + + // Update metadata panel with fallback data + this.updateMetadataPanel({}, imageSrc); + + } catch (error) { + console.error('Fallback metadata extraction failed:', error); + this.showMetadataError(); + + // Set empty metadata as last resort + this.currentMetadata = { + positivePrompt: 'No prompt found', + negativePrompt: 'No negative prompt found', + checkpoint: 'Unknown', + steps: 'Unknown', + cfgScale: 'Unknown', + sampler: 'Unknown', + seed: 'Unknown', + workflow: null, + prompt: null + }; + } + } + async copyAllMetadata() { if (!this.currentMetadata) return; diff --git a/web/metadata.html b/web/metadata.html new file mode 100644 index 0000000..c8479b0 --- /dev/null +++ b/web/metadata.html @@ -0,0 +1,558 @@ + + + + + + Image Gallery - Generation Data + + + + + +
+ +
+ +
+ + + +

Drag & Drop PNG with ComfyUI Workflow

+

Or click to browse files

+
+ + + + + + + + +
+ Generated Image +
+ + +
+ + +
+ +
+
+ + + +

Generation data

+
+ +
+ + +
+ +
+ + + +

No Image Loaded

+

Upload a PNG with embedded ComfyUI workflow to view generation data

+
+
+
+
+ + \ No newline at end of file From 389d739303bf9d7454cdf8c51ae7b326bba38fd1 Mon Sep 17 00:00:00 2001 From: Vito Sansevero Date: Tue, 3 Jun 2025 17:03:29 -0700 Subject: [PATCH 2/6] refactor(admin): improve notification z-index handling --- web/admin.html | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/web/admin.html b/web/admin.html index 744fef1..69c76b8 100644 --- a/web/admin.html +++ b/web/admin.html @@ -1256,7 +1256,13 @@ showNotification(message, type = "info") { const notification = document.createElement("div"); - notification.className = `fixed top-4 right-4 px-6 py-4 rounded-lg shadow-lg z-50 transition-all duration-300 transform translate-x-full`; + + // Check if image viewer is open and use higher z-index + const imageViewerModal = document.getElementById('imageViewerModal'); + const isImageViewerOpen = imageViewerModal && !imageViewerModal.classList.contains('hidden'); + const zIndex = isImageViewerOpen ? 'z-[10000]' : 'z-50'; + + notification.className = `fixed top-4 right-4 px-6 py-4 rounded-lg shadow-lg ${zIndex} transition-all duration-300 transform translate-x-full`; const colors = { success: "bg-green-600 text-white", @@ -1273,7 +1279,11 @@ setTimeout(() => notification.classList.remove("translate-x-full"), 100); setTimeout(() => { notification.classList.add("translate-x-full"); - setTimeout(() => document.body.removeChild(notification), 300); + setTimeout(() => { + if (notification.parentNode) { + document.body.removeChild(notification); + } + }, 300); }, 3000); } @@ -3131,17 +3141,12 @@ } async copyPrompt(type) { - console.log('copyPrompt called with type:', type); - console.log('currentMetadata:', this.currentMetadata); - if (!this.currentMetadata) { - console.error('No metadata available for copying'); this.showNotification('❌ No metadata available for copying', 'error'); return; } const text = type === 'positive' ? this.currentMetadata.positivePrompt : this.currentMetadata.negativePrompt; - console.log('Copying text:', text?.substring(0, 100)); if (!text || text === 'No prompt found' || text === 'No negative prompt found') { this.showNotification(`❌ No ${type} prompt available`, 'error'); From e13d4f028487d07b7947d13574ac415d21fb7fbb Mon Sep 17 00:00:00 2001 From: Vito Sansevero Date: Tue, 3 Jun 2025 17:05:53 -0700 Subject: [PATCH 3/6] refactor(api): update html path in PromptManagerAPI --- py/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/api.py b/py/api.py index 63d6204..4b96101 100644 --- a/py/api.py +++ b/py/api.py @@ -131,7 +131,7 @@ class PromptManagerAPI: current_dir = os.path.dirname( os.path.dirname(os.path.abspath(__file__)) ) - html_path = os.path.join(current_dir, "gallery.html") + html_path = os.path.join(current_dir, "web", "metadata.html") if os.path.exists(html_path): with open(html_path, "r", encoding="utf-8") as f: From 704f5e0d4c9040091d55d86eb22005947b8064da Mon Sep 17 00:00:00 2001 From: Vito Sansevero Date: Tue, 3 Jun 2025 17:06:11 -0700 Subject: [PATCH 4/6] chore: remove gallery.html file --- gallery.html | 558 --------------------------------------------------- 1 file changed, 558 deletions(-) delete mode 100644 gallery.html diff --git a/gallery.html b/gallery.html deleted file mode 100644 index c8479b0..0000000 --- a/gallery.html +++ /dev/null @@ -1,558 +0,0 @@ - - - - - - Image Gallery - Generation Data - - - - - -
- -
- -
- - - -

Drag & Drop PNG with ComfyUI Workflow

-

Or click to browse files

-
- - - - - - - - -
- Generated Image -
- - -
- - -
- -
-
- - - -

Generation data

-
- -
- - -
- -
- - - -

No Image Loaded

-

Upload a PNG with embedded ComfyUI workflow to view generation data

-
-
-
-
- - \ No newline at end of file From 102390c95a9ae22c6965049dd72620cd630f9b64 Mon Sep 17 00:00:00 2001 From: Vito Sansevero Date: Tue, 3 Jun 2025 17:06:27 -0700 Subject: [PATCH 5/6] docs: Update metadata viewer path in README.md --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index ac55b13..22fd403 100644 --- a/README.md +++ b/README.md @@ -53,13 +53,13 @@ ComfyUI Prompt Manager functions as a drop-in replacement for ComfyUI's standard - **Generation Parameters**: Recover steps, CFG scale, sampler, seed, and model information - **Multi-Node Support**: Handles PromptManager, CLIPTextEncode, and other node types - **Copy & Export**: One-click copying of prompts and workflow JSON download -- **Standalone Viewer**: Dedicated metadata analysis tool at `/prompt_manager/gallery.html` +- **Standalone Viewer**: Dedicated metadata analysis tool at `/prompt_manager/metadata.html` - **Drag & Drop Interface**: Easy analysis by dropping PNG files directly into the viewer - **Error Handling**: Robust parsing with NaN value cleaning and malformed JSON recovery ### 📋 Standalone Metadata Viewer -- **Independent Tool**: Access at `http://localhost:8188/prompt_manager/gallery.html` +- **Independent Tool**: Access at `http://localhost:8188/prompt_manager/metadata.html` - **Real-time Analysis**: Instant PNG metadata extraction and display - **Comprehensive Display**: Shows all discoverable ComfyUI workflow information - **Export Capabilities**: Download workflow JSON files for reuse @@ -131,7 +131,7 @@ ComfyUI Prompt Manager functions as a drop-in replacement for ComfyUI's standard 5. **Access the web interface**: - **Admin Dashboard**: `http://localhost:8188/prompt_manager/admin` - Full management interface - - **Metadata Viewer**: `http://localhost:8188/prompt_manager/gallery.html` - Standalone PNG analysis tool + - **Metadata Viewer**: `http://localhost:8188/prompt_manager/metadata.html` - Standalone PNG analysis tool - **Simple Interface**: `http://localhost:8188/prompt_manager/` - Basic prompt browser ### Prerequisites @@ -182,7 +182,7 @@ The image gallery automatically captures and links generated images: Use the standalone metadata viewer to analyze any ComfyUI-generated PNG: -1. **Open the metadata viewer** at `http://localhost:8188/prompt_manager/gallery.html` +1. **Open the metadata viewer** at `http://localhost:8188/prompt_manager/metadata.html` 2. **Drag and drop** any PNG file with ComfyUI workflow data 3. **View extracted information**: - **Prompts**: Copy positive/negative prompts with one click @@ -334,7 +334,7 @@ CREATE TABLE generated_images ( - **`web/admin.html`** - Advanced admin dashboard with metadata panel - **`web/index.html`** - Simple web interface - **`web/prompt_manager.js`** - JavaScript functionality -- **`gallery.html`** - Standalone PNG metadata viewer +- **`web/metadata.html`** - Standalone PNG metadata viewer ### File Structure @@ -362,8 +362,8 @@ ComfyUI_PromptManager/ ├── web/ │ ├── admin.html # Advanced admin dashboard │ ├── index.html # Simple web interface +│ ├── metadata.html # Standalone metadata viewer │ └── prompt_manager.js # JavaScript functionality -├── gallery.html # Standalone metadata viewer ├── tests/ │ ├── __init__.py │ └── test_basic.py # Test suite @@ -554,7 +554,7 @@ MIT License - see LICENSE file for details. ### v3.0.0 (Metadata Analysis Release) - **🔬 PNG Metadata Analysis**: Advanced ComfyUI workflow extraction from PNG images -- **📋 Standalone Metadata Viewer**: Dedicated tool at `/gallery.html` for analyzing any ComfyUI image +- **📋 Standalone Metadata Viewer**: Dedicated tool at `/web/metadata.html` for analyzing any ComfyUI image - **🖼️ Integrated Metadata Panel**: Real-time workflow analysis in the image viewer - **📸 Bulk Image Scanning**: Mass import and analysis of existing ComfyUI output directories - **🛠️ System Management Suite**: Complete backup, restore, maintenance, and diagnostic tools From 4505e62261bbbba5b081808e928df17ec89a7264 Mon Sep 17 00:00:00 2001 From: Vito Sansevero Date: Tue, 3 Jun 2025 17:07:08 -0700 Subject: [PATCH 6/6] chore: bump version to 3.0.1 in pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 843fd5b..5770aea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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.0" +version = "3.0.1" 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"]