diff --git a/README.md b/README.md index bba0eec..1262f2d 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,8 @@ Calculate upscaled dimensions from image or latent inputs with precision. - Ensure ComfyUI tensor compatibility - Optimize batch processing workflows +![Resolution Calculator Example](examples/workflows/resolution_calculator_example.png) + #### 📏 Width Height Selector Advanced preset-based dimension selection with visual swap button. @@ -60,6 +62,8 @@ Advanced seed tracking with interactive history management and UI. - Maintain reproducibility across sessions - Compare results from different seeds efficiently +![Seed History functionality is shown in various workflow examples] + #### ⚙️ Sampler Combo Unified sampling configuration interface combining sampler, scheduler, steps, and CFG. @@ -92,6 +96,8 @@ Advanced empty latent creation with preset support and batch processing capabili - Optimize memory usage with batch size planning - Quick preset-based latent generation for different aspect ratios +![Empty Latent Batch Example](examples/workflows/empty_latent_batch_example.png) + #### 💾 Kiko Save Image Enhanced image saving with format selection, quality control, and floating popup viewer. @@ -104,6 +110,8 @@ Enhanced image saving with format selection, quality control, and floating popup - **Smart UI**: Auto-hide/show, minimize/maximize, roll-up functionality - **Popup Toggle**: Enable/disable popup viewer per save operation +![Kiko Save Image Example](examples/workflows/kiko_save_image_example.png) + #### 📋 Display Text Advanced text display node with intelligent formatting and enhanced user interaction. @@ -122,6 +130,8 @@ Advanced text display node with intelligent formatting and enhanced user interac - View long text content with proper wrapping - Debug prompt generation workflows +![Display Text Example](examples/workflows/display_text_example.png) + #### 🤖 Gemini Prompt Engineer AI-powered image analysis using Google's Gemini to generate optimized prompts for various models. @@ -144,6 +154,44 @@ AI-powered image analysis using Google's Gemini to generate optimized prompts fo - Analyze and replicate lighting/mood from existing artwork - Access latest Gemini models including 2.0 and 2.5 versions +![Gemini Prompt Example](examples/workflows/gemini_prompt_example.png) + +#### 🔍 Display Any +Universal debugging node that displays any type of input value or tensor information. + +- **Universal Input Acceptance**: Works with any data type (tensors, strings, numbers, lists, dicts) +- **Two Display Modes**: Raw value showing string representation, or tensor shape extraction +- **Nested Structure Support**: Finds tensors within complex nested data structures +- **Debugging Focus**: Essential tool for understanding data flow and tensor dimensions +- **Clean Output**: Formatted display directly in ComfyUI interface + +**Use Cases:** +- Debug tensor dimensions at any point in workflow +- Inspect latent space data structures +- View metadata and configuration objects +- Track shape changes through processing nodes +- Understand complex data types in ComfyUI + +![Display Any Example](examples/workflows/display_any_example.png) + +#### 🖼️ Image to Multiple Of +Adjusts image dimensions to be multiples of a specified value for model compatibility. + +- **Dimension Adjustment**: Ensures image dimensions are multiples of specified value (e.g., 64, 128) +- **Two Processing Methods**: Center crop for minimal loss, or rescale to fit +- **Model Compatibility**: Essential for models requiring specific dimension constraints +- **Flexible Multiple Values**: Support from 1 to 256 with 16-step increments +- **Preserves Quality**: Smart processing maintains image quality + +**Use Cases:** +- Prepare images for VAE encoding (multiple of 8 requirement) +- Ensure compatibility with specific model architectures +- Standardize dimensions across image batches +- Fix dimension errors in complex workflows +- Optimize for tiled processing requirements + +![Image to Multiple Of Example](examples/workflows/image_to_multiple_of_example.png) + ### 💾 Kiko Save Image Features **Use Cases:** @@ -294,6 +342,29 @@ Load Image → Gemini Prompt → Display Text → Text Generation Model **API:** Requires Gemini API key (free tier available) **Refresh:** Click button to fetch latest available models +### Display Any Example +``` +Any Node → Display Any → Debug Output +🔍 tensor ↘ mode: shape ↘ "[[1, 3, 512, 512]]" +``` + +**Input:** Any data type (image, latent, config, etc.) +**Mode:** "raw value" or "tensor shape" +**Output:** Formatted display of value or tensor dimensions +**Use Case:** Debug workflows, inspect data structures + +### Image to Multiple Of Example +``` +Load Image → Image to Multiple Of → VAE Encode → KSampler +🖼️ 513×769 ↘ multiple: 64 ↘ 512×768 → latent + method: crop +``` + +**Input:** Image with arbitrary dimensions +**Multiple Of:** 64 (common for VAE compatibility) +**Method:** "center crop" or "rescale" +**Output:** Adjusted image with compatible dimensions + ### Common Workflows
@@ -338,6 +409,8 @@ Load Image → Gemini Prompt → Display Text → Text Generation Model | **Kiko Save Image** | Enhanced image saving with popup viewer and multi-format support | ✅ Complete | [Docs](examples/documentation/kiko_save_image.md) | | **Display Text** | Advanced text display with smart prompt detection and split view | ✅ Complete | [Docs](examples/documentation/display_text.md) | | **Gemini Prompt Engineer** | AI-powered image analysis with dynamic model refresh | ✅ Complete | [Docs](examples/documentation/gemini_prompt.md) | +| **Display Any** | Universal debugging tool for any data type or tensor shapes | ✅ Complete | [Docs](examples/documentation/display_any.md) | +| **Image to Multiple Of** | Adjust image dimensions to multiples for model compatibility | ✅ Complete | [Docs](examples/documentation/image_to_multiple_of.md) | | **Batch Image Processor** | Process multiple images with consistent settings | 🚧 Planned | Coming Soon | | **Advanced Prompt Utilities** | Enhanced prompt manipulation and generation | 🚧 Planned | Coming Soon | @@ -631,7 +704,7 @@ MIT License - see [LICENSE](LICENSE) file for details. ## 📈 Stats -- **Nodes**: 8 (Resolution Calculator, Width Height Selector, Seed History, Sampler Combo, Empty Latent Batch, Kiko Save Image, Display Text, Gemini Prompt Engineer) +- **Nodes**: 10 (Resolution Calculator, Width Height Selector, Seed History, Sampler Combo, Empty Latent Batch, Kiko Save Image, Display Text, Gemini Prompt Engineer, Display Any, Image to Multiple Of) - **Format Support**: 3 (PNG, JPEG, WebP with advanced controls) - **Presets**: 26 curated resolution presets - **Interactive Features**: 6 (Width/Height Swap Button, Seed History UI, Empty Latent Batch Swap Button, Kiko Save Image Popup Viewer, Display Text Split View, Gemini Model Refresh) diff --git a/examples/documentation/display_text.md b/examples/documentation/display_text.md new file mode 100644 index 0000000..fa3e7c5 --- /dev/null +++ b/examples/documentation/display_text.md @@ -0,0 +1,147 @@ +# Display Text + +The Display Text node provides advanced text display capabilities with smart formatting, interactive features, and responsive design for ComfyUI workflows. + +## Features + +- **Smart Prompt Detection**: Automatically detects and formats SDXL-style positive/negative prompt pairs +- **Text Wrapping**: Proper word wrapping that reflows when node is resized +- **Scrollable Content**: Mouse wheel scrolling for long texts with visual indicators +- **Copy Functionality**: Always-visible copy button with visual feedback +- **Split View Mode**: Side-by-side display for prompt pairs +- **Responsive Design**: Content adapts to node resizing + +## Inputs + +- **text** (STRING): The text to display + - Can be a single text block + - Can contain "Positive prompt:" and "Negative prompt:" sections for automatic split view + +## Outputs + +- **text** (STRING): Pass-through of the input text + +## Display Modes + +### Single Text Mode + +When the input is regular text without prompt markers, it displays as a single scrollable text area with: +- Word wrapping at word boundaries +- Vertical scrolling for long content +- Single copy button for the entire text + +### Split View Mode + +Automatically activated when text contains both "Positive prompt:" and "Negative prompt:" sections: +- Side-by-side display with 50/50 split +- Independent scrolling for each section +- Separate copy buttons for each prompt +- Labels are stripped when copying (clean prompts) + +## Usage Examples + +### 1. Display Generated Prompts + +``` +Gemini Prompt → Display Text → Copy to workflow +``` +The node automatically detects SDXL format and shows positive/negative prompts side-by-side. + +### 2. Debug Text Processing + +``` +Text Processing → Display Text → Further Processing +``` +View intermediate text processing results with proper formatting. + +### 3. Show Long Descriptions + +``` +Load Text → Display Text → Review +``` +Display long text content with scrolling and word wrapping. + +## Interactive Features + +### Copy Button +- Always visible in the top-right corner +- Shows "✓ Copied!" feedback on click +- In split view: separate buttons for each section +- Strips prompt labels for clean copying + +### Scrolling +- Mouse wheel scrolling when hovering over text +- Visual indicators appear when content is scrollable +- Smooth scrolling with proper boundaries +- Independent scrolling in split view mode + +### Resizing +- Text reflows when node width changes +- Maintains readability at different sizes +- Split view maintains 50/50 proportions +- Minimum height ensures usability + +## Smart Prompt Detection + +The node intelligently detects prompt formats: + +1. **SDXL Format**: + - Looks for "Positive prompt:" and "Negative prompt:" markers + - Case-insensitive detection + - Handles various formatting styles + +2. **Label Stripping**: + - When copying from split view, labels are removed + - "Positive prompt: beautiful sunset" → "beautiful sunset" + - Clean prompts ready for direct use + +## Styling + +- **Font**: Monospace for consistent alignment +- **Colors**: + - Text: Light gray (#ddd) on dark background + - Background: Semi-transparent dark (#1a1a1a) + - Borders: Subtle gray (#333) +- **Spacing**: Comfortable padding and line height +- **Visual Feedback**: Hover effects on interactive elements + +## Use Cases + +### Prompt Engineering Workflows +- Display AI-generated prompts with proper formatting +- Compare positive and negative prompts side-by-side +- Copy refined prompts without manual cleanup + +### Text Processing Pipelines +- Debug text transformations at each step +- View formatted outputs from text nodes +- Monitor prompt construction workflows + +### Documentation and Notes +- Display workflow instructions +- Show generation parameters +- Present formatted metadata + +## Technical Details + +- **Text Processing**: Preserves original text while adding display formatting +- **Responsive Design**: CSS-based layout adapts to node dimensions +- **Event Handling**: Proper event propagation for ComfyUI compatibility +- **Memory Efficient**: Only renders visible text portions + +## Tips + +1. **For Long Prompts**: The scrolling feature handles texts of any length efficiently +2. **Quick Copy**: Use the copy buttons to quickly grab prompts for other nodes +3. **Resizing**: Drag node edges to find optimal display width for your content +4. **Split View**: Works best with SDXL-format prompts but handles any dual-section text + +## Integration Example + +``` +[Gemini Prompt Engineer] → [Display Text] → [Copy Button Click] + ↓ ↓ ↓ + SDXL Format Split View Display Clean Prompts +``` + +This creates a seamless workflow from prompt generation to usage, with the Display Text node providing the visual interface for review and interaction. \ No newline at end of file diff --git a/examples/documentation/gemini_prompt.md b/examples/documentation/gemini_prompt.md index 32beb56..60655c4 100644 --- a/examples/documentation/gemini_prompt.md +++ b/examples/documentation/gemini_prompt.md @@ -8,6 +8,9 @@ The Gemini Prompt Engineer node uses Google's Gemini AI to analyze images and ge - **Custom Prompts**: Override templates with your own system prompts - **Visual Feedback**: UI shows processing status and error states - **Flexible API Key Management**: Multiple ways to provide API credentials +- **Dynamic Model Selection**: Fetch and use latest Gemini models with refresh button +- **Model Caching**: Persistent storage of available models for offline access +- **Help Integration**: Built-in setup guide accessible via help button ## Setup @@ -49,6 +52,10 @@ Choose one of these methods: - `sdxl`: Positive/negative prompt pairs with weight emphasis - `danbooru`: Anime-style booru tags with underscores - `video`: Motion and temporal descriptions for video generation +- **model** (DROPDOWN): Gemini model selection + - Dynamically populated list of available models + - Includes latest models like gemini-2.0-flash-exp + - Click refresh button to update model list - **api_key** (STRING, optional): Gemini API key if not set elsewhere - **custom_prompt** (STRING, optional): Override template with custom system prompt @@ -72,15 +79,27 @@ majestic mountain landscape at golden hour, oil painting style, dramatic lightin ``` ### SDXL Format -Generates positive and negative prompt pairs: -- Detailed positive prompts with weight emphasis +Generates positive and negative prompt pairs with enhanced structure: +- Layered positive prompts: main subject → style → composition → technical - Comprehensive negative prompts to avoid common issues - Uses parentheses for emphasis: `(detailed eyes:1.2)` +- Includes quality boosters and technical specifications Example output: ``` -Positive: beautiful woman, (detailed eyes:1.2), flowing red dress, golden hour lighting, professional photography, 85mm lens, shallow depth of field, bokeh, high resolution, masterpiece -Negative: low quality, blurry, distorted features, bad anatomy, poorly drawn, amateur, oversaturated, jpeg artifacts +Positive prompt: +beautiful woman with flowing red hair, elegant pose, (detailed eyes:1.2), serene expression +oil painting style, renaissance art influence, classical portraiture +golden hour lighting, warm color palette, soft shadows, dramatic chiaroscuro +centered composition, rule of thirds, shallow depth of field, bokeh background +masterpiece, best quality, highly detailed, 8k uhd, professional artwork + +Negative prompt: +low quality, worst quality, blurry, out of focus, pixelated, low resolution +bad anatomy, deformed features, extra limbs, missing limbs, disconnected limbs +poorly drawn face, poorly drawn hands, amateur drawing, bad proportions +oversaturated, overexposed, underexposed, bad lighting, harsh shadows +jpeg artifacts, watermark, signature, text, cropped, duplicate ``` ### Danbooru Format @@ -130,12 +149,40 @@ The node provides clear error messages for common issues: Errors are displayed in the prompt output for easy debugging. +## Model Selection + +### Dynamic Model List +- Click the refresh button (🔄) next to the model dropdown to fetch latest models +- Models are fetched from Google's API and include all available versions +- Common models include: + - `gemini-2.0-flash-exp`: Latest experimental flash model + - `gemini-1.5-pro`: Advanced model with larger context + - `gemini-1.5-flash`: Fast and efficient for most tasks + +### Model Caching +- Available models are cached locally for offline access +- Cache persists across ComfyUI sessions +- Refresh button updates the cache with latest models + +## UI Features + +### Help Button +- Click the help button (?) for quick setup instructions +- Shows API key setup methods +- Links to Google AI Studio for key generation + +### Status Indicators +- Processing spinner during API calls +- Error messages displayed in red +- Success feedback when prompt is generated + ## Tips 1. **API Usage**: Gemini has generous free tier limits, but be mindful of rate limits 2. **Image Quality**: Higher resolution images provide better analysis results 3. **Prompt Refinement**: You can chain multiple Gemini nodes with different custom prompts 4. **Caching**: Results are not cached, so identical images will make new API calls +5. **Model Selection**: Use flash models for faster responses, pro models for complex analysis ## Example Workflow diff --git a/examples/documentation/kiko_save_image.md b/examples/documentation/kiko_save_image.md new file mode 100644 index 0000000..22372ee --- /dev/null +++ b/examples/documentation/kiko_save_image.md @@ -0,0 +1,213 @@ +# Kiko Save Image + +Enhanced image saving node with multiple format support, quality controls, and an interactive floating popup viewer for ComfyUI. + +## Features + +- **Multiple Format Support**: Save as PNG, JPEG, or WebP with format-specific optimizations +- **Advanced Quality Controls**: Fine-tune compression settings per format +- **Floating Popup Viewer**: Interactive window showing saved images immediately +- **Batch Operations**: Multi-select images for bulk actions +- **File Size Display**: Real-time feedback on compression effectiveness +- **Smart UI**: Auto-hide, draggable, resizable popup window + +## Inputs + +- **images** (IMAGE): Batch of images to save +- **filename_prefix** (STRING): Prefix for saved filenames + - Default: "KikoSave" + - Supports subfolder paths (e.g., "outputs/renders/final") +- **format** (DROPDOWN): Output format selection + - `PNG`: Lossless compression, best quality + - `JPEG`: Lossy compression, smaller files + - `WEBP`: Modern format, best compression ratio +- **quality** (INT): JPEG/WebP quality level + - Range: 1-100 (default: 90) + - Higher values = better quality, larger files +- **png_compress_level** (INT): PNG compression level + - Range: 0-9 (default: 4) + - Higher values = smaller files, slower saving +- **webp_lossless** (BOOLEAN): Use lossless WebP compression + - Default: False (lossy) + - True: Lossless compression like PNG +- **popup** (BOOLEAN): Enable popup viewer window + - Default: True + - Toggle per save operation + +## Outputs + +- **UI**: Enhanced preview data with interactive popup viewer + +## Popup Viewer Features + +### Window Controls +- **Drag Handle**: Click and drag the header to move window +- **Minimize Button**: Collapse to title bar only +- **Maximize Button**: Expand to larger viewing size +- **Roll-up Button**: Show/hide content area +- **Close Button**: Hide the popup (can reopen with toggle) + +### Image Grid +- **Thumbnails**: Click any image to open full-size in new tab +- **File Info**: Shows filename and size for each image +- **Quality Indicators**: + - PNG: Compression level (0-9) + - JPEG/WebP: Quality percentage +- **Batch Selection**: Checkboxes for multi-select operations + +### Bulk Actions +- **Open All Selected**: Opens selected images in new tabs +- **Download All Selected**: Downloads selected images as a batch +- **Individual Downloads**: Download button per image + +### Smart Behavior +- **Auto-positioning**: Appears in convenient screen location +- **Persistence**: Stays open across multiple saves +- **Auto-hide**: Can be minimized when not needed +- **Responsive**: Adapts to different image counts + +## Format Details + +### PNG Format +- **Pros**: Lossless quality, transparency support, wide compatibility +- **Cons**: Larger file sizes +- **Best for**: Final outputs, images with transparency, archival +- **Compression**: 0 (none) to 9 (maximum) + - Level 4 (default) balances size and speed + - Level 9 for maximum compression (slow) + +### JPEG Format +- **Pros**: Smaller files, fast loading, universal support +- **Cons**: Lossy compression, no transparency +- **Best for**: Web images, previews, photos +- **Quality**: 1-100% + - 90% (default) excellent quality with good compression + - 95%+ for near-lossless quality + - 70-85% for web optimization + +### WebP Format +- **Pros**: Best compression ratios, supports transparency, modern +- **Cons**: Limited software support +- **Best for**: Web deployment, storage optimization +- **Modes**: + - Lossy (default): Excellent compression with quality control + - Lossless: PNG-like quality with better compression + +## Usage Examples + +### High-Quality Archive +``` +Format: PNG +Compression: 0-2 +Use Case: Final renders for portfolio or client delivery +``` + +### Web Optimization +``` +Format: JPEG or WebP +Quality: 80-85 +Use Case: Website images, social media posts +``` + +### Balanced Storage +``` +Format: WebP +Quality: 90 +Lossless: False +Use Case: Large batches with storage constraints +``` + +### Transparency Preservation +``` +Format: PNG or WebP (lossless) +Use Case: Logos, UI elements, cutout images +``` + +## Workflow Integration + +### Basic Save +``` +Generate → Kiko Save Image + format: PNG + popup: enabled +``` + +### Format Comparison +``` +Generate → Kiko Save Image (PNG) → Compare file sizes + ↘ Kiko Save Image (JPEG) ↗ + ↘ Kiko Save Image (WebP) ↗ +``` + +### Batch Processing +``` +Batch Generate → Kiko Save Image → Popup Viewer + ↓ ↓ + 4 images Select best results +``` + +## Tips and Best Practices + +1. **Format Selection**: + - Use PNG for maximum quality and transparency + - Use JPEG for photographs without transparency + - Use WebP for modern web deployment + +2. **Quality Settings**: + - Start with defaults (90 for JPEG/WebP, 4 for PNG) + - Adjust based on file size requirements + - Preview results in popup before finalizing + +3. **Popup Management**: + - Drag to second monitor for larger workspace + - Use roll-up to save screen space + - Disable popup for automated workflows + +4. **Batch Operations**: + - Use checkboxes to select multiple images + - Open all in tabs for side-by-side comparison + - Download all for quick collection + +5. **File Organization**: + - Use subfolders in filename_prefix + - Include descriptive prefixes + - Let ComfyUI handle timestamp suffixes + +## Advantages Over Standard Save Image + +- **Immediate Preview**: No need to navigate file system +- **Format Flexibility**: Choose optimal format per use case +- **Quality Control**: Fine-tune compression settings +- **Batch Management**: Handle multiple images efficiently +- **Modern UI**: Floating interface doesn't interrupt workflow +- **File Size Awareness**: See compression effectiveness immediately +- **Quick Access**: One-click opening and downloading + +## Technical Details + +- **Image Processing**: Uses Pillow for format conversion +- **Metadata**: Preserves ComfyUI metadata in saved files +- **File Naming**: Automatic timestamp and counter suffixes +- **Memory Efficiency**: Processes images individually +- **Thread Safety**: Proper handling of concurrent saves + +## Troubleshooting + +**Popup not appearing**: +- Check that popup input is enabled +- Look for minimized window +- Try toggling the popup button in node + +**WebP not working**: +- Ensure Pillow has WebP support +- Update Pillow: `pip install --upgrade pillow` + +**Large file sizes**: +- Increase compression (PNG) or reduce quality (JPEG/WebP) +- Consider switching formats +- Check image dimensions + +**Can't see all images**: +- Scroll within the popup grid +- Maximize the popup window +- Images are shown newest first \ No newline at end of file diff --git a/examples/workflows/display_any_example.json b/examples/workflows/display_any_example.json new file mode 100644 index 0000000..f1c4a8f --- /dev/null +++ b/examples/workflows/display_any_example.json @@ -0,0 +1,379 @@ +{ + "id": "display-any-example", + "revision": 0, + "last_node_id": 11, + "last_link_id": 9, + "nodes": [ + { + "id": 1, + "type": "DisplayAny", + "pos": [ + 400, + 270 + ], + "size": [ + 210, + 60 + ], + "flags": {}, + "order": 3, + "mode": 0, + "inputs": [ + { + "name": "input", + "type": "*", + "link": 1 + } + ], + "outputs": [ + { + "name": "display_text", + "type": "STRING", + "links": [ + 8 + ] + } + ], + "properties": { + "cnr_id": "kikotools", + "ver": "271cd020c1b2f78e7ee40c1f08e70191fed00012", + "Node name for S&R": "DisplayAny" + }, + "widgets_values": [ + "tensor shape" + ] + }, + { + "id": 2, + "type": "LoadImage", + "pos": [ + 50, + 270 + ], + "size": [ + 315, + 314 + ], + "flags": {}, + "order": 2, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 1, + 5 + ] + }, + { + "name": "MASK", + "type": "MASK", + "links": null + } + ], + "properties": { + "cnr_id": "comfy-core", + "ver": "0.3.47", + "Node name for S&R": "LoadImage" + }, + "widgets_values": [ + "example.png", + "image" + ] + }, + { + "id": 4, + "type": "DisplayAny", + "pos": [ + 400, + 520 + ], + "size": [ + 210, + 70 + ], + "flags": {}, + "order": 6, + "mode": 0, + "inputs": [ + { + "name": "input", + "type": "*", + "link": 7 + } + ], + "outputs": [ + { + "name": "display_text", + "type": "STRING", + "links": [ + 9 + ] + } + ], + "properties": { + "cnr_id": "kikotools", + "ver": "271cd020c1b2f78e7ee40c1f08e70191fed00012", + "Node name for S&R": "DisplayAny" + }, + "widgets_values": [ + "raw value" + ] + }, + { + "id": 7, + "type": "VAELoader", + "pos": [ + -250, + 410 + ], + "size": [ + 270, + 58 + ], + "flags": {}, + "order": 0, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "VAE", + "type": "VAE", + "links": [ + 6 + ] + } + ], + "properties": { + "cnr_id": "comfy-core", + "ver": "0.3.47", + "Node name for S&R": "VAELoader" + }, + "widgets_values": [ + "ae.safetensors" + ] + }, + { + "id": 8, + "type": "VAEEncode", + "pos": [ + 430, + 390 + ], + "size": [ + 140, + 46 + ], + "flags": {}, + "order": 4, + "mode": 0, + "inputs": [ + { + "name": "pixels", + "type": "IMAGE", + "link": 5 + }, + { + "name": "vae", + "type": "VAE", + "link": 6 + } + ], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 7 + ] + } + ], + "properties": { + "cnr_id": "comfy-core", + "ver": "0.3.47", + "Node name for S&R": "VAEEncode" + }, + "widgets_values": [] + }, + { + "id": 9, + "type": "DisplayText", + "pos": [ + 640, + 270 + ], + "size": [ + 450, + 278 + ], + "flags": {}, + "order": 5, + "mode": 0, + "inputs": [ + { + "name": "text", + "type": "STRING", + "link": 8 + } + ], + "outputs": [ + { + "name": "text", + "type": "STRING", + "links": null + } + ], + "properties": { + "cnr_id": "kikotools", + "ver": "271cd020c1b2f78e7ee40c1f08e70191fed00012", + "Node name for S&R": "DisplayText" + }, + "widgets_values": [ + null + ] + }, + { + "id": 10, + "type": "DisplayText", + "pos": [ + 640, + 610 + ], + "size": [ + 590, + 278 + ], + "flags": {}, + "order": 7, + "mode": 0, + "inputs": [ + { + "name": "text", + "type": "STRING", + "link": 9 + } + ], + "outputs": [ + { + "name": "text", + "type": "STRING", + "links": null + } + ], + "properties": { + "cnr_id": "kikotools", + "ver": "271cd020c1b2f78e7ee40c1f08e70191fed00012", + "Node name for S&R": "DisplayText" + }, + "widgets_values": [ + null + ] + }, + { + "id": 11, + "type": "MarkdownNote", + "pos": [ + -320, + 530 + ], + "size": [ + 350, + 270 + ], + "flags": {}, + "order": 1, + "mode": 0, + "inputs": [], + "outputs": [], + "properties": {}, + "widgets_values": [ + "Display Any Example\n\nUniversal debugging tool:\n- Accepts ANY input type\n- Two modes: raw value or tensor shape\n- Finds tensors in nested structures\n\nUse cases:\n- Debug tensor dimensions\n- Inspect latent data\n- View config objects\n- Track data flow\n\nConnect anything to see its contents!" + ], + "color": "#432", + "bgcolor": "#653" + } + ], + "links": [ + [ + 1, + 2, + 0, + 1, + 0, + "IMAGE" + ], + [ + 5, + 2, + 0, + 8, + 0, + "IMAGE" + ], + [ + 6, + 7, + 0, + 8, + 1, + "VAE" + ], + [ + 7, + 8, + 0, + 4, + 0, + "*" + ], + [ + 8, + 1, + 0, + 9, + 0, + "STRING" + ], + [ + 9, + 4, + 0, + 10, + 0, + "STRING" + ] + ], + "groups": [ + { + "id": 1, + "title": "Display Any", + "bounding": [ + -400, + 130, + 1740, + 850 + ], + "color": "#ffffff", + "font_size": 24, + "flags": {} + } + ], + "config": {}, + "extra": { + "ds": { + "scale": 0.6115909044841477, + "offset": [ + 689.1392030323894, + -27.435530779258137 + ] + }, + "frontendVersion": "1.23.4", + "VHS_latentpreview": true, + "VHS_latentpreviewrate": 0, + "VHS_MetadataImage": true, + "VHS_KeepIntermediate": true + }, + "version": 0.4 +} \ No newline at end of file diff --git a/examples/workflows/display_any_example.png b/examples/workflows/display_any_example.png new file mode 100644 index 0000000..80291db Binary files /dev/null and b/examples/workflows/display_any_example.png differ diff --git a/examples/workflows/display_text_example.json b/examples/workflows/display_text_example.json new file mode 100644 index 0000000..01823e5 --- /dev/null +++ b/examples/workflows/display_text_example.json @@ -0,0 +1,144 @@ +{ + "id": "display-text-example", + "revision": 0, + "last_node_id": 6, + "last_link_id": 2, + "nodes": [ + { + "id": 1, + "type": "DisplayText", + "pos": [ + -160, + 70 + ], + "size": [ + 500, + 400 + ], + "flags": {}, + "order": 2, + "mode": 0, + "inputs": [ + { + "name": "text", + "type": "STRING", + "link": 2 + } + ], + "outputs": [ + { + "name": "text", + "type": "STRING", + "links": null + } + ], + "properties": { + "cnr_id": "kikotools", + "ver": "271cd020c1b2f78e7ee40c1f08e70191fed00012", + "Node name for S&R": "DisplayText" + }, + "widgets_values": [ + null + ] + }, + { + "id": 4, + "type": "easy positive", + "pos": [ + -620, + 70 + ], + "size": [ + 400, + 200 + ], + "flags": {}, + "order": 0, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "positive", + "type": "STRING", + "links": [ + 2 + ] + } + ], + "properties": { + "cnr_id": "comfyui-easy-use", + "ver": "1.3.1", + "Node name for S&R": "easy positive" + }, + "widgets_values": [ + "Positive prompt:\nbeautiful landscape, mountains in background, sunset lighting, golden hour, professional photography, high resolution, detailed textures, vibrant colors, masterpiece\n\nNegative prompt:\nlow quality, blurry, pixelated, bad composition, oversaturated, underexposed, amateur" + ], + "color": "#232", + "bgcolor": "#353" + }, + { + "id": 6, + "type": "MarkdownNote", + "pos": [ + -620, + 330 + ], + "size": [ + 360, + 250 + ], + "flags": {}, + "order": 1, + "mode": 0, + "inputs": [], + "outputs": [], + "properties": {}, + "widgets_values": [ + "Display Text Example\n\nSmart text display with:\n- Auto-detection of SDXL prompt format\n- Split view for positive/negative prompts\n- Text wrapping and scrolling\n- Copy buttons (strips labels)\n- Responsive resizing\n\nTry editing the text to see:\n1. Single text mode (no prompt markers)\n2. Split view mode (with Positive/Negative prompts)\n\nPerfect for displaying Gemini-generated prompts!" + ], + "color": "#432", + "bgcolor": "#653" + } + ], + "links": [ + [ + 2, + 4, + 0, + 1, + 0, + "STRING" + ] + ], + "groups": [ + { + "id": 1, + "title": "Display Text", + "bounding": [ + -750, + -60, + 1240, + 700 + ], + "color": "#ffffff", + "font_size": 24, + "flags": {} + } + ], + "config": {}, + "extra": { + "ds": { + "scale": 0.90909090909091, + "offset": [ + 720, + 30 + ] + }, + "frontendVersion": "1.23.4", + "VHS_latentpreview": true, + "VHS_latentpreviewrate": 0, + "VHS_MetadataImage": true, + "VHS_KeepIntermediate": true + }, + "version": 0.4 +} \ No newline at end of file diff --git a/examples/workflows/display_text_example.png b/examples/workflows/display_text_example.png new file mode 100644 index 0000000..740e408 Binary files /dev/null and b/examples/workflows/display_text_example.png differ diff --git a/examples/workflows/empty_latent_batch_example.json b/examples/workflows/empty_latent_batch_example.json new file mode 100644 index 0000000..d476bb3 --- /dev/null +++ b/examples/workflows/empty_latent_batch_example.json @@ -0,0 +1,301 @@ +{ + "id": "empty-latent-batch-example", + "revision": 0, + "last_node_id": 9, + "last_link_id": 8, + "nodes": [ + { + "id": 1, + "type": "EmptyLatentBatch", + "pos": [ + 350, + 350 + ], + "size": [ + 370, + 210 + ], + "flags": {}, + "order": 0, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "latent", + "type": "LATENT", + "slot_index": 0, + "links": [] + }, + { + "name": "width", + "type": "INT", + "slot_index": 1, + "links": [ + 4 + ] + }, + { + "name": "height", + "type": "INT", + "slot_index": 2, + "links": [ + 5 + ] + } + ], + "properties": { + "cnr_id": "kikotools", + "ver": "271cd020c1b2f78e7ee40c1f08e70191fed00012", + "Node name for S&R": "EmptyLatentBatch" + }, + "widgets_values": [ + "896×1152 - 7:9 (1.0MP) - SDXL", + 896, + 1152, + 4 + ] + }, + { + "id": 2, + "type": "Note", + "pos": [ + -50, + 320 + ], + "size": [ + 350, + 250 + ], + "flags": {}, + "order": 1, + "mode": 0, + "inputs": [], + "outputs": [], + "properties": { + "text": "Empty Latent Batch Example\n\nThis node creates empty latent tensors with:\n- 26 preset resolutions for SDXL/FLUX/Ultra-wide\n- Batch size support (1-64)\n- Interactive swap button\n- Memory usage estimation\n\nConnect to:\n- KSampler for image generation\n- Other latent processing nodes\n\nOutputs sanitized dimensions divisible by 8." + }, + "widgets_values": [ + "Empty Latent Batch Example\n\nThis node creates empty latent tensors with:\n- 26 preset resolutions for SDXL/FLUX/Ultra-wide\n- Batch size support (1-64)\n- Interactive swap button\n- Memory usage estimation\n\nConnect to:\n- KSampler for image generation\n- Other latent processing nodes\n\nOutputs sanitized dimensions divisible by 8." + ], + "color": "#432", + "bgcolor": "#653" + }, + { + "id": 5, + "type": "DisplayAny", + "pos": [ + 760, + 280 + ], + "size": [ + 210, + 60 + ], + "flags": {}, + "order": 2, + "mode": 0, + "inputs": [ + { + "name": "input", + "type": "*", + "link": 4 + } + ], + "outputs": [ + { + "name": "display_text", + "type": "STRING", + "links": [ + 7 + ] + } + ], + "properties": { + "cnr_id": "kikotools", + "ver": "271cd020c1b2f78e7ee40c1f08e70191fed00012", + "Node name for S&R": "DisplayAny" + }, + "widgets_values": [ + "raw value" + ] + }, + { + "id": 6, + "type": "DisplayAny", + "pos": [ + 770, + 500 + ], + "size": [ + 210, + 60 + ], + "flags": {}, + "order": 3, + "mode": 0, + "inputs": [ + { + "name": "input", + "type": "*", + "link": 5 + } + ], + "outputs": [ + { + "name": "display_text", + "type": "STRING", + "links": [ + 8 + ] + } + ], + "properties": { + "cnr_id": "kikotools", + "ver": "271cd020c1b2f78e7ee40c1f08e70191fed00012", + "Node name for S&R": "DisplayAny" + }, + "widgets_values": [ + "raw value" + ] + }, + { + "id": 8, + "type": "DisplayText", + "pos": [ + 1000, + 280 + ], + "size": [ + 210, + 138 + ], + "flags": {}, + "order": 4, + "mode": 0, + "inputs": [ + { + "name": "text", + "type": "STRING", + "link": 7 + } + ], + "outputs": [ + { + "name": "text", + "type": "STRING", + "links": null + } + ], + "properties": { + "cnr_id": "kikotools", + "ver": "271cd020c1b2f78e7ee40c1f08e70191fed00012", + "Node name for S&R": "DisplayText" + }, + "widgets_values": [ + null + ] + }, + { + "id": 9, + "type": "DisplayText", + "pos": [ + 1010, + 500 + ], + "size": [ + 210, + 138 + ], + "flags": {}, + "order": 5, + "mode": 0, + "inputs": [ + { + "name": "text", + "type": "STRING", + "link": 8 + } + ], + "outputs": [ + { + "name": "text", + "type": "STRING", + "links": null + } + ], + "properties": { + "cnr_id": "kikotools", + "ver": "271cd020c1b2f78e7ee40c1f08e70191fed00012", + "Node name for S&R": "DisplayText" + }, + "widgets_values": [ + null + ] + } + ], + "links": [ + [ + 4, + 1, + 1, + 5, + 0, + "*" + ], + [ + 5, + 1, + 2, + 6, + 0, + "*" + ], + [ + 7, + 5, + 0, + 8, + 0, + "STRING" + ], + [ + 8, + 6, + 0, + 9, + 0, + "STRING" + ] + ], + "groups": [ + { + "id": 1, + "title": "Empty Latent", + "bounding": [ + -110, + 120, + 1440, + 620 + ], + "color": "#ffffff", + "font_size": 24, + "flags": {} + } + ], + "config": {}, + "extra": { + "ds": { + "scale": 0.8264462809917358, + "offset": [ + 156.41790912499965, + -2.272547312500285 + ] + }, + "frontendVersion": "1.23.4", + "VHS_latentpreview": true, + "VHS_latentpreviewrate": 0, + "VHS_MetadataImage": true, + "VHS_KeepIntermediate": true + }, + "version": 0.4 +} \ No newline at end of file diff --git a/examples/workflows/empty_latent_batch_example.png b/examples/workflows/empty_latent_batch_example.png new file mode 100644 index 0000000..1903982 Binary files /dev/null and b/examples/workflows/empty_latent_batch_example.png differ diff --git a/examples/workflows/gemini_prompt_example.json b/examples/workflows/gemini_prompt_example.json new file mode 100644 index 0000000..afc3e21 --- /dev/null +++ b/examples/workflows/gemini_prompt_example.json @@ -0,0 +1,207 @@ +{ + "id": "gemini-prompt-example", + "revision": 0, + "last_node_id": 6, + "last_link_id": 4, + "nodes": [ + { + "id": 2, + "type": "LoadImage", + "pos": [ + 300, + 30 + ], + "size": [ + 315, + 314 + ], + "flags": {}, + "order": 1, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 3 + ] + }, + { + "name": "MASK", + "type": "MASK", + "links": null + } + ], + "properties": { + "cnr_id": "comfy-core", + "ver": "0.3.47", + "Node name for S&R": "LoadImage" + }, + "widgets_values": [ + "example.png", + "image" + ] + }, + { + "id": 3, + "type": "DisplayText", + "pos": [ + 1070, + 30 + ], + "size": [ + 500, + 400 + ], + "flags": {}, + "order": 3, + "mode": 0, + "inputs": [ + { + "name": "text", + "type": "STRING", + "link": 4 + } + ], + "outputs": [ + { + "name": "text", + "type": "STRING", + "links": null + } + ], + "properties": { + "cnr_id": "kikotools", + "ver": "271cd020c1b2f78e7ee40c1f08e70191fed00012", + "Node name for S&R": "DisplayText" + }, + "widgets_values": [ + null + ] + }, + { + "id": 5, + "type": "GeminiPrompt", + "pos": [ + 640, + 30 + ], + "size": [ + 400, + 276 + ], + "flags": {}, + "order": 2, + "mode": 0, + "inputs": [ + { + "name": "image", + "type": "IMAGE", + "link": 3 + } + ], + "outputs": [ + { + "name": "prompt", + "type": "STRING", + "links": [ + 4 + ] + }, + { + "name": "negative_prompt", + "type": "STRING", + "links": null + } + ], + "properties": { + "cnr_id": "kikotools", + "ver": "271cd020c1b2f78e7ee40c1f08e70191fed00012", + "Node name for S&R": "GeminiPrompt" + }, + "widgets_values": [ + "sdxl", + "gemini-2.0-flash", + "1234-1234-1234-1234", + "", + true, + null, + null, + null + ] + }, + { + "id": 6, + "type": "MarkdownNote", + "pos": [ + 300, + 410 + ], + "size": [ + 400, + 240 + ], + "flags": {}, + "order": 0, + "mode": 0, + "inputs": [], + "outputs": [], + "properties": {}, + "widgets_values": [ + "Gemini Prompt Engineer Example\n\nAI-powered image analysis:\n- Analyzes image content and style\n- Generates optimized prompts for FLUX/SDXL/Danbooru/Video\n- Dynamic model selection with refresh button\n- Custom system prompt override\n\nSetup:\n1. Get free API key from Google AI Studio\n2. Set GEMINI_API_KEY env var or use config file\n3. Click refresh button to get latest models\n\nDisplayText automatically shows split view for SDXL prompts!" + ], + "color": "#432", + "bgcolor": "#653" + } + ], + "links": [ + [ + 3, + 2, + 0, + 5, + 0, + "IMAGE" + ], + [ + 4, + 5, + 0, + 3, + 0, + "STRING" + ] + ], + "groups": [ + { + "id": 1, + "title": "Gemini Prompt Engineer", + "bounding": [ + 210, + -110, + 1460, + 850 + ], + "color": "#ffffff", + "font_size": 24, + "flags": {} + } + ], + "config": {}, + "extra": { + "ds": { + "scale": 0.7513148009015777, + "offset": [ + 97.5582232217803, + 133.12148846503663 + ] + }, + "frontendVersion": "1.23.4", + "VHS_latentpreview": true, + "VHS_latentpreviewrate": 0, + "VHS_MetadataImage": true, + "VHS_KeepIntermediate": true + }, + "version": 0.4 +} \ No newline at end of file diff --git a/examples/workflows/gemini_prompt_example.png b/examples/workflows/gemini_prompt_example.png new file mode 100644 index 0000000..ed83b4b Binary files /dev/null and b/examples/workflows/gemini_prompt_example.png differ diff --git a/examples/workflows/image_to_multiple_of_example.json b/examples/workflows/image_to_multiple_of_example.json index f21dc57..7b14a84 100644 --- a/examples/workflows/image_to_multiple_of_example.json +++ b/examples/workflows/image_to_multiple_of_example.json @@ -1,123 +1,552 @@ { - "last_node_id": 4, - "last_link_id": 3, + "id": "3cd0ac86-8d11-41e5-9d8b-6621bc810ee6", + "revision": 0, + "last_node_id": 21, + "last_link_id": 21, "nodes": [ { "id": 1, "type": "LoadImage", - "pos": [100, 200], - "size": [315, 314], + "pos": [ + -80, + 850 + ], + "size": [ + 315, + 314.0000305175781 + ], "flags": {}, - "order": 0, + "order": 1, "mode": 0, + "inputs": [], "outputs": [ { + "label": "IMAGE", "name": "IMAGE", "type": "IMAGE", - "links": [1], - "shape": 3, - "label": "IMAGE" + "links": [ + 13 + ] }, { "name": "MASK", "type": "MASK", - "links": null, - "shape": 3 + "links": null } ], "properties": { + "cnr_id": "comfy-core", + "ver": "0.3.47", "Node name for S&R": "LoadImage" }, - "widgets_values": ["example.png", "image"] + "widgets_values": [ + "example.png", + "image" + ] }, { - "id": 2, - "type": "ImageToMultipleOf", - "pos": [500, 200], - "size": [315, 106], + "id": 8, + "type": "GetNode", + "pos": [ + 540, + 840 + ], + "size": [ + 210, + 34 + ], + "flags": { + "collapsed": true + }, + "order": 0, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "UPSCALE_MODEL", + "type": "UPSCALE_MODEL", + "links": [] + } + ], + "title": "Get_upscale_skin_model", + "properties": { + "widget_ue_connectable": {} + }, + "widgets_values": [ + "upscale_skin_model" + ] + }, + { + "id": 9, + "type": "ImageUpscaleWithModel", + "pos": [ + 530, + 810 + ], + "size": [ + 221.98202514648438, + 60 + ], "flags": {}, - "order": 1, + "order": 5, + "mode": 0, + "inputs": [ + { + "name": "upscale_model", + "type": "UPSCALE_MODEL", + "link": 16 + }, + { + "name": "image", + "type": "IMAGE", + "link": 5 + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 10, + 21 + ] + } + ], + "properties": { + "cnr_id": "comfy-core", + "ver": "0.3.28", + "Node name for S&R": "ImageUpscaleWithModel", + "widget_ue_connectable": {} + }, + "widgets_values": [] + }, + { + "id": 10, + "type": "ImageToMultipleOf", + "pos": [ + 1000, + 810 + ], + "size": [ + 230, + 82 + ], + "flags": {}, + "order": 9, "mode": 0, "inputs": [ { "name": "image", "type": "IMAGE", - "link": 1 + "link": 6 } ], "outputs": [ { "name": "image", "type": "IMAGE", - "links": [2, 3], - "shape": 3, - "label": "image" + "links": [ + 18 + ] } ], "properties": { - "Node name for S&R": "ImageToMultipleOf" + "cnr_id": "comfyui-glifnodes", + "ver": "1.0.0", + "Node name for S&R": "ImageToMultipleOf", + "widget_ue_connectable": {} }, - "widgets_values": [64, "center crop"] + "widgets_values": [ + 65, + "center crop" + ] }, { - "id": 3, - "type": "PreviewImage", - "pos": [900, 100], - "size": [210, 246], + "id": 13, + "type": "ImageScaleBy", + "pos": [ + 760, + 810 + ], + "size": [ + 220, + 82 + ], + "flags": {}, + "order": 7, + "mode": 0, + "inputs": [ + { + "name": "image", + "type": "IMAGE", + "link": 10 + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 6, + 19 + ] + } + ], + "properties": { + "cnr_id": "comfy-core", + "ver": "0.3.28", + "Node name for S&R": "ImageScaleBy", + "widget_ue_connectable": {} + }, + "widgets_values": [ + "lanczos", + 0.5000000000000001 + ] + }, + { + "id": 14, + "type": "ImageUpscaleWithModel", + "pos": [ + 280, + 830 + ], + "size": [ + 221.98202514648438, + 60 + ], + "flags": {}, + "order": 4, + "mode": 0, + "inputs": [ + { + "name": "upscale_model", + "type": "UPSCALE_MODEL", + "link": 15 + }, + { + "name": "image", + "type": "IMAGE", + "link": 13 + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 5, + 20 + ] + } + ], + "properties": { + "cnr_id": "comfy-core", + "ver": "0.3.28", + "Node name for S&R": "ImageUpscaleWithModel", + "widget_ue_connectable": {} + }, + "widgets_values": [] + }, + { + "id": 15, + "type": "UpscaleModelLoader", + "pos": [ + -90, + 720 + ], + "size": [ + 320, + 60 + ], "flags": {}, "order": 2, "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "UPSCALE_MODEL", + "type": "UPSCALE_MODEL", + "links": [ + 15 + ] + } + ], + "properties": { + "cnr_id": "comfy-core", + "ver": "0.3.28", + "Node name for S&R": "UpscaleModelLoader", + "widget_ue_connectable": {} + }, + "widgets_values": [ + "4x-ClearRealityV1.pth" + ], + "color": "#232", + "bgcolor": "#353" + }, + { + "id": 16, + "type": "UpscaleModelLoader", + "pos": [ + 140, + 610 + ], + "size": [ + 320, + 60 + ], + "flags": {}, + "order": 3, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "UPSCALE_MODEL", + "type": "UPSCALE_MODEL", + "links": [ + 16 + ] + } + ], + "properties": { + "cnr_id": "comfy-core", + "ver": "0.3.28", + "Node name for S&R": "UpscaleModelLoader", + "widget_ue_connectable": {} + }, + "widgets_values": [ + "1xSkinContrast-High-SuperUltraCompact.pth" + ], + "color": "#232", + "bgcolor": "#353" + }, + { + "id": 18, + "type": "PreviewImage", + "pos": [ + 1260, + 810 + ], + "size": [ + 270, + 280 + ], + "flags": {}, + "order": 11, + "mode": 0, "inputs": [ { "name": "images", "type": "IMAGE", - "link": 2 + "link": 18 } ], + "outputs": [], "properties": { + "cnr_id": "comfy-core", + "ver": "0.3.47", "Node name for S&R": "PreviewImage" - } + }, + "widgets_values": [] }, { - "id": 4, - "type": "VAEEncode", - "pos": [900, 400], - "size": [210, 46], + "id": 19, + "type": "PreviewImage", + "pos": [ + 1010, + 940 + ], + "size": [ + 210, + 258 + ], "flags": {}, - "order": 3, + "order": 10, "mode": 0, "inputs": [ { - "name": "pixels", + "name": "images", "type": "IMAGE", - "link": 3 - }, - { - "name": "vae", - "type": "VAE", - "link": null - } - ], - "outputs": [ - { - "name": "LATENT", - "type": "LATENT", - "links": null, - "shape": 3 + "link": 19 } ], + "outputs": [], "properties": { - "Node name for S&R": "VAEEncode" - } + "cnr_id": "comfy-core", + "ver": "0.3.47", + "Node name for S&R": "PreviewImage" + }, + "widgets_values": [] + }, + { + "id": 20, + "type": "PreviewImage", + "pos": [ + 520, + 940 + ], + "size": [ + 210, + 258 + ], + "flags": {}, + "order": 6, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 20 + } + ], + "outputs": [], + "properties": { + "cnr_id": "comfy-core", + "ver": "0.3.47", + "Node name for S&R": "PreviewImage" + }, + "widgets_values": [] + }, + { + "id": 21, + "type": "PreviewImage", + "pos": [ + 750, + 940 + ], + "size": [ + 210, + 258 + ], + "flags": {}, + "order": 8, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 21 + } + ], + "outputs": [], + "properties": { + "cnr_id": "comfy-core", + "ver": "0.3.47", + "Node name for S&R": "PreviewImage" + }, + "widgets_values": [] } ], "links": [ - [1, 1, 0, 2, 0, "IMAGE"], - [2, 2, 0, 3, 0, "IMAGE"], - [3, 2, 0, 4, 0, "IMAGE"] + [ + 5, + 14, + 0, + 9, + 1, + "IMAGE" + ], + [ + 6, + 13, + 0, + 10, + 0, + "IMAGE" + ], + [ + 10, + 9, + 0, + 13, + 0, + "IMAGE" + ], + [ + 13, + 1, + 0, + 14, + 1, + "IMAGE" + ], + [ + 15, + 15, + 0, + 14, + 0, + "UPSCALE_MODEL" + ], + [ + 16, + 16, + 0, + 9, + 0, + "UPSCALE_MODEL" + ], + [ + 18, + 10, + 0, + 18, + 0, + "IMAGE" + ], + [ + 19, + 13, + 0, + 19, + 0, + "IMAGE" + ], + [ + 20, + 14, + 0, + 20, + 0, + "IMAGE" + ], + [ + 21, + 9, + 0, + 21, + 0, + "IMAGE" + ] + ], + "groups": [ + { + "id": 1, + "title": "Image to Multiple of", + "bounding": [ + -180, + 420, + 1800, + 830 + ], + "color": "#ffffff", + "font_size": 24, + "flags": {} + } ], - "groups": [], "config": {}, - "extra": {}, + "extra": { + "ds": { + "scale": 0.6655312045216585, + "offset": [ + 292.51725658775155, + -375.0766486499791 + ] + }, + "frontendVersion": "1.23.4", + "VHS_latentpreview": true, + "VHS_latentpreviewrate": 0, + "VHS_MetadataImage": true, + "VHS_KeepIntermediate": true + }, "version": 0.4 } \ No newline at end of file diff --git a/examples/workflows/image_to_multiple_of_example.png b/examples/workflows/image_to_multiple_of_example.png new file mode 100644 index 0000000..2202caf Binary files /dev/null and b/examples/workflows/image_to_multiple_of_example.png differ diff --git a/examples/workflows/kiko_save_image_example.json b/examples/workflows/kiko_save_image_example.json new file mode 100644 index 0000000..db7d335 --- /dev/null +++ b/examples/workflows/kiko_save_image_example.json @@ -0,0 +1,147 @@ +{ + "id": "kiko-save-image-example", + "revision": 0, + "last_node_id": 4, + "last_link_id": 1, + "nodes": [ + { + "id": 1, + "type": "KikoSaveImage", + "pos": [ + 390, + 80 + ], + "size": [ + 400, + 390 + ], + "flags": {}, + "order": 2, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 1 + } + ], + "outputs": [], + "properties": { + "cnr_id": "kikotools", + "ver": "271cd020c1b2f78e7ee40c1f08e70191fed00012", + "Node name for S&R": "KikoSaveImage" + }, + "widgets_values": [ + "KikoSave", + "PNG", + 90, + 4, + false, + true + ] + }, + { + "id": 2, + "type": "LoadImage", + "pos": [ + -10, + 80 + ], + "size": [ + 315, + 314 + ], + "flags": {}, + "order": 1, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 1 + ] + }, + { + "name": "MASK", + "type": "MASK", + "links": null + } + ], + "properties": { + "cnr_id": "comfy-core", + "ver": "0.3.47", + "Node name for S&R": "LoadImage" + }, + "widgets_values": [ + "example.png", + "image" + ] + }, + { + "id": 4, + "type": "MarkdownNote", + "pos": [ + -10, + 460 + ], + "size": [ + 370, + 270 + ], + "flags": {}, + "order": 0, + "mode": 0, + "inputs": [], + "outputs": [], + "properties": {}, + "widgets_values": [ + "Kiko Save Image Example\n\nEnhanced image saving with:\n- Format selection: PNG, JPEG, WebP\n- Quality controls per format\n- Floating popup viewer (draggable)\n- Batch operations support\n- File size display\n\nPopup Features:\n- Click images to open in new tab\n- Download individual or selected images\n- Minimize/maximize/roll-up controls\n- Persistent across saves\n\nTry different formats to compare file sizes!" + ], + "color": "#432", + "bgcolor": "#653" + } + ], + "links": [ + [ + 1, + 2, + 0, + 1, + 0, + "IMAGE" + ] + ], + "groups": [ + { + "id": 1, + "title": "Kiko save Image", + "bounding": [ + -110, + -60, + 1020, + 870 + ], + "color": "#ffffff", + "font_size": 24, + "flags": {} + } + ], + "config": {}, + "extra": { + "ds": { + "scale": 0.7513148009015777, + "offset": [ + 648.1018911400128, + 110.02838653698085 + ] + }, + "frontendVersion": "1.23.4", + "VHS_latentpreview": true, + "VHS_latentpreviewrate": 0, + "VHS_MetadataImage": true, + "VHS_KeepIntermediate": true + }, + "version": 0.4 +} \ No newline at end of file diff --git a/examples/workflows/kiko_save_image_example.png b/examples/workflows/kiko_save_image_example.png new file mode 100644 index 0000000..ada2e1a Binary files /dev/null and b/examples/workflows/kiko_save_image_example.png differ diff --git a/examples/workflows/resolution_calculator_example.json b/examples/workflows/resolution_calculator_example.json index d0ff947..08e50fa 100644 --- a/examples/workflows/resolution_calculator_example.json +++ b/examples/workflows/resolution_calculator_example.json @@ -1,15 +1,15 @@ { "id": "41469b2d-d616-479d-879a-95cdc6074a37", "revision": 0, - "last_node_id": 6, - "last_link_id": 5, + "last_node_id": 11, + "last_link_id": 9, "nodes": [ { "id": 1, "type": "ResolutionCalculator", "pos": [ - 60, - 430 + -30, + 210 ], "size": [ 315, @@ -38,8 +38,7 @@ "type": "INT", "slot_index": 0, "links": [ - 1, - 3 + 6 ] }, { @@ -47,15 +46,15 @@ "type": "INT", "slot_index": 1, "links": [ - 2, - 4 + 7 ] } ], "properties": { - "aux_id": "ComfyAssets/ComfyUI-KikoTools", + "cnr_id": "kikotools", "ver": "965ad60c74d7f25b1acce890d9c06518e46e6d0b", "Node name for S&R": "ResolutionCalculator", + "aux_id": "ComfyAssets/ComfyUI-KikoTools", "widget_ue_connectable": {} }, "widgets_values": [ @@ -66,8 +65,8 @@ "id": 6, "type": "LoadImage", "pos": [ - -250, - 430 + -340, + 210 ], "size": [ 274.080078125, @@ -94,8 +93,8 @@ "properties": { "cnr_id": "comfy-core", "ver": "0.3.40", - "widget_ue_connectable": {}, - "Node name for S&R": "LoadImage" + "Node name for S&R": "LoadImage", + "widget_ue_connectable": {} }, "widgets_values": [ "image-2025-06-13-105737.jpg", @@ -103,80 +102,14 @@ ] }, { - "id": 4, - "type": "Display Int (rgthree)", + "id": 7, + "type": "MarkdownNote", "pos": [ - 420, - 360 + -350, + 610 ], "size": [ - 210, - 88 - ], - "flags": {}, - "order": 3, - "mode": 0, - "inputs": [ - { - "dir": 3, - "name": "input", - "type": "INT", - "link": 3 - } - ], - "outputs": [], - "properties": { - "cnr_id": "rgthree-comfy", - "ver": "1.0.2506081210", - "Node name for S&R": "Display Int (rgthree)", - "widget_ue_connectable": {} - }, - "widgets_values": [ - "" - ] - }, - { - "id": 5, - "type": "Display Int (rgthree)", - "pos": [ - 430, - 530 - ], - "size": [ - 210, - 88 - ], - "flags": {}, - "order": 4, - "mode": 0, - "inputs": [ - { - "dir": 3, - "name": "input", - "type": "INT", - "link": 4 - } - ], - "outputs": [], - "properties": { - "cnr_id": "rgthree-comfy", - "ver": "1.0.2506081210", - "widget_ue_connectable": {}, - "Node name for S&R": "Display Int (rgthree)" - }, - "widgets_values": [ - "" - ] - }, - { - "id": 2, - "type": "Note", - "pos": [ - -150, - 170 - ], - "size": [ - 400, + 410, 200 ], "flags": {}, @@ -184,50 +117,167 @@ "mode": 0, "inputs": [], "outputs": [], - "properties": { - "text": "Resolution Calculator Example\n\nThis node calculates upscaled dimensions from:\n- IMAGE tensors (connect from image loaders)\n- LATENT tensors (connect from VAE encode/generation)\n\nUse cases:\n- Calculate target dimensions for upscalers\n- Plan memory usage for large generations\n- Ensure dimensions are divisible by 8\n\nScale factors optimized for SDXL and FLUX models.", - "widget_ue_connectable": {} - }, + "properties": {}, "widgets_values": [ "Resolution Calculator Example\n\nThis node calculates upscaled dimensions from:\n- IMAGE tensors (connect from image loaders)\n- LATENT tensors (connect from VAE encode/generation)\n\nUse cases:\n- Calculate target dimensions for upscalers\n- Plan memory usage for large generations\n- Ensure dimensions are divisible by 8\n\nScale factors optimized for SDXL and FLUX models." ], "color": "#432", "bgcolor": "#653" + }, + { + "id": 8, + "type": "DisplayAny", + "pos": [ + 330, + 160 + ], + "size": [ + 270, + 58 + ], + "flags": {}, + "order": 3, + "mode": 0, + "inputs": [ + { + "name": "input", + "type": "*", + "link": 6 + } + ], + "outputs": [ + { + "name": "display_text", + "type": "STRING", + "links": [ + 8 + ] + } + ], + "properties": { + "cnr_id": "kikotools", + "ver": "271cd020c1b2f78e7ee40c1f08e70191fed00012", + "Node name for S&R": "DisplayAny" + }, + "widgets_values": [ + "raw value" + ] + }, + { + "id": 9, + "type": "DisplayAny", + "pos": [ + 330, + 310 + ], + "size": [ + 270, + 58 + ], + "flags": {}, + "order": 4, + "mode": 0, + "inputs": [ + { + "name": "input", + "type": "*", + "link": 7 + } + ], + "outputs": [ + { + "name": "display_text", + "type": "STRING", + "links": [ + 9 + ] + } + ], + "properties": { + "cnr_id": "kikotools", + "ver": "271cd020c1b2f78e7ee40c1f08e70191fed00012", + "Node name for S&R": "DisplayAny" + }, + "widgets_values": [ + "raw value" + ] + }, + { + "id": 10, + "type": "DisplayText", + "pos": [ + 670, + 160 + ], + "size": [ + 210, + 138 + ], + "flags": {}, + "order": 5, + "mode": 0, + "inputs": [ + { + "name": "text", + "type": "STRING", + "link": 8 + } + ], + "outputs": [ + { + "name": "text", + "type": "STRING", + "links": null + } + ], + "properties": { + "cnr_id": "kikotools", + "ver": "271cd020c1b2f78e7ee40c1f08e70191fed00012", + "Node name for S&R": "DisplayText" + }, + "widgets_values": [ + null + ] + }, + { + "id": 11, + "type": "DisplayText", + "pos": [ + 660, + 400 + ], + "size": [ + 210, + 138 + ], + "flags": {}, + "order": 6, + "mode": 0, + "inputs": [ + { + "name": "text", + "type": "STRING", + "link": 9 + } + ], + "outputs": [ + { + "name": "text", + "type": "STRING", + "links": null + } + ], + "properties": { + "cnr_id": "kikotools", + "ver": "271cd020c1b2f78e7ee40c1f08e70191fed00012", + "Node name for S&R": "DisplayText" + }, + "widgets_values": [ + null + ] } ], "links": [ - [ - 1, - 1, - 0, - 3, - 0, - "INT" - ], - [ - 2, - 1, - 1, - 3, - 1, - "INT" - ], - [ - 3, - 1, - 0, - 4, - 0, - "INT" - ], - [ - 4, - 1, - 1, - 5, - 0, - "INT" - ], [ 5, 6, @@ -235,25 +285,71 @@ 1, 0, "IMAGE" + ], + [ + 6, + 1, + 0, + 8, + 0, + "*" + ], + [ + 7, + 1, + 1, + 9, + 0, + "*" + ], + [ + 8, + 8, + 0, + 10, + 0, + "STRING" + ], + [ + 9, + 9, + 0, + 11, + 0, + "STRING" ] ], - "groups": [], + "groups": [ + { + "id": 1, + "title": "Resolution Calculator", + "bounding": [ + -480, + 20, + 1480, + 880 + ], + "color": "#ffffff", + "font_size": 24, + "flags": {} + } + ], "config": {}, "extra": { "ue_links": [], "ds": { - "scale": 0.7972024500000015, + "scale": 0.45000000000000145, "offset": [ - 709.6391289161842, - -90.0127389290854 + 1248.1498802376432, + 256.0155843113725 ] }, "links_added_by_ue": [], - "frontendVersion": "1.21.7", + "frontendVersion": "1.23.4", "VHS_latentpreview": true, "VHS_latentpreviewrate": 0, "VHS_MetadataImage": true, "VHS_KeepIntermediate": true }, "version": 0.4 -} +} \ No newline at end of file diff --git a/examples/workflows/resolution_calculator_example.png b/examples/workflows/resolution_calculator_example.png new file mode 100644 index 0000000..c47e320 Binary files /dev/null and b/examples/workflows/resolution_calculator_example.png differ diff --git a/kikotools/tools/display_text/__init__.py b/kikotools/tools/display_text/__init__.py index c8af0da..0fe932e 100644 --- a/kikotools/tools/display_text/__init__.py +++ b/kikotools/tools/display_text/__init__.py @@ -2,4 +2,4 @@ from .node import DisplayTextNode, NODE_DISPLAY_NAME -__all__ = ["DisplayTextNode", "NODE_DISPLAY_NAME"] \ No newline at end of file +__all__ = ["DisplayTextNode", "NODE_DISPLAY_NAME"] diff --git a/kikotools/tools/display_text/node.py b/kikotools/tools/display_text/node.py index e4c0ec9..491b669 100644 --- a/kikotools/tools/display_text/node.py +++ b/kikotools/tools/display_text/node.py @@ -5,7 +5,7 @@ from ...base import ComfyAssetsBaseNode class DisplayTextNode(ComfyAssetsBaseNode): """Displays text in the ComfyUI interface with copy-to-clipboard functionality.""" - + @classmethod def INPUT_TYPES(cls): """Define input types for the node.""" @@ -14,13 +14,13 @@ class DisplayTextNode(ComfyAssetsBaseNode): "text": ("STRING", {"forceInput": True}), }, } - + RETURN_TYPES = ("STRING",) RETURN_NAMES = ("text",) OUTPUT_NODE = True FUNCTION = "display_text" CATEGORY = "ComfyAssets" - + DESCRIPTION = """ Displays text in the UI with a copy-to-clipboard feature. @@ -29,13 +29,13 @@ Features: - Copy button appears on hover - Passes text through for chaining """ - + def display_text(self, text): """Display the text and pass it through. - + Args: text: Input text to display - + Returns: Tuple containing the text """ @@ -45,4 +45,4 @@ Features: # Node display name -NODE_DISPLAY_NAME = "Display Text" \ No newline at end of file +NODE_DISPLAY_NAME = "Display Text" diff --git a/kikotools/tools/gemini_prompt/.gemini_models_cache.json b/kikotools/tools/gemini_prompt/.gemini_models_cache.json index bad519e..14ef142 100644 --- a/kikotools/tools/gemini_prompt/.gemini_models_cache.json +++ b/kikotools/tools/gemini_prompt/.gemini_models_cache.json @@ -85,5 +85,5 @@ "gemma-3n-e2b-it": "Gemma 3n E2B", "gemini-2.5-flash-lite": "Gemini 2.5 Flash-Lite" }, - "timestamp": 1754078815.7280848 + "timestamp": 1754142231.0568295 } \ No newline at end of file diff --git a/kikotools/tools/gemini_prompt/node.py b/kikotools/tools/gemini_prompt/node.py index 2dbebeb..de90b8a 100644 --- a/kikotools/tools/gemini_prompt/node.py +++ b/kikotools/tools/gemini_prompt/node.py @@ -41,7 +41,10 @@ class GeminiPromptNode(ComfyAssetsBaseNode): "placeholder": "Optional: Enter custom system prompt instead of using templates", }, ), - "refresh_models": ("BOOLEAN", {"default": False, "label_on": "Refresh", "label_off": "Skip"}), + "refresh_models": ( + "BOOLEAN", + {"default": False, "label_on": "Refresh", "label_off": "Skip"}, + ), }, } @@ -63,7 +66,15 @@ Requires Gemini API key (set GEMINI_API_KEY env var or provide in node). Install: pip install google-generativeai """ - def generate_prompt(self, image, prompt_type, model, api_key="", custom_prompt="", refresh_models=False): + def generate_prompt( + self, + image, + prompt_type, + model, + api_key="", + custom_prompt="", + refresh_models=False, + ): """Generate prompt from image using Gemini. Args: @@ -81,12 +92,15 @@ Install: pip install google-generativeai if refresh_models and api_key: try: from .models import clear_cache + # Clear cache to force refresh on next node creation clear_cache() - print("Model cache cleared. Please recreate the node to see updated models.") + print( + "Model cache cleared. Please recreate the node to see updated models." + ) except Exception as e: print(f"Failed to clear model cache: {e}") - + # Validate prompt type if not validate_prompt_type(prompt_type): raise ValueError(f"Invalid prompt type: {prompt_type}") @@ -132,9 +146,13 @@ Install: pip install google-generativeai for line in lines: if line.lower().startswith("positive:"): - positive_prompt = line.replace("Positive:", "").replace("positive:", "").strip() + positive_prompt = ( + line.replace("Positive:", "").replace("positive:", "").strip() + ) elif line.lower().startswith("negative:"): - negative_prompt = line.replace("Negative:", "").replace("negative:", "").strip() + negative_prompt = ( + line.replace("Negative:", "").replace("negative:", "").strip() + ) # If format not found, assume entire response is positive prompt if not positive_prompt: @@ -148,4 +166,4 @@ Install: pip install google-generativeai # Node display name -NODE_DISPLAY_NAME = "Gemini Prompt Engineer" \ No newline at end of file +NODE_DISPLAY_NAME = "Gemini Prompt Engineer" diff --git a/kikotools/tools/gemini_prompt/prompts.py b/kikotools/tools/gemini_prompt/prompts.py index 99a2ec4..ebc8d37 100644 --- a/kikotools/tools/gemini_prompt/prompts.py +++ b/kikotools/tools/gemini_prompt/prompts.py @@ -125,4 +125,4 @@ DEFAULT_GEMINI_MODELS = [ "gemini-2.0-flash", "gemini-1.5-flash", "gemini-1.5-pro", -] \ No newline at end of file +]