diff --git a/README.md b/README.md index 0d97dd8..2e4f33d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# NF Review Selector +# NF Preview Selector -A floating dialog-based image review and selection system for ComfyUI. Inspired by cg-image-filter but designed as a simpler, more focused solution for image review workflows. +A floating dialog-based image review and selection system for ComfyUI. Inspired by cg-image-filter but designed as a simpler, more focused solution for image preview workflows. ## Features @@ -14,7 +14,7 @@ A floating dialog-based image review and selection system for ComfyUI. Inspired ## Usage -1. Add the "NF Review Selector" node to your workflow +1. Add the "NF Preview Selector" node to your workflow 2. Connect image input (and optionally latent input) 3. Choose a mode: - **review_and_select**: Opens floating dialog for manual selection @@ -35,9 +35,9 @@ When in review mode, a floating dialog will appear showing: ## Settings Access via ComfyUI Settings menu: +- **Dialog maximum width**: Determines the maximum width of the dialog in pixels. (Max 1800px) - **Remember window position**: Saves dialog position between uses -- **Use compact mode**: Smaller layout for limited screen space -- **Auto-select first image**: Automatically selects first image when dialog opens + ## Outputs @@ -47,9 +47,10 @@ Access via ComfyUI Settings menu: ## Installation -1. Place this folder in `ComfyUI/custom_nodes/` +1. Run git pull in the directory "ComfyUI/custom_nodes/". + ```git pull https://github.com/NyaFuP/ComfyUI_Preview_Selector.git``` 2. Restart ComfyUI -3. The "NF Review Selector" node will appear in the "image/review" category +3. The "NF Preview Selector" node will appear in the "image/review" category ## Technical Details @@ -59,13 +60,6 @@ Access via ComfyUI Settings menu: - Supports both image and latent workflows - Minimal dependencies (uses ComfyUI's built-in APIs) -## Comparison to Alternatives - -Unlike full-screen solutions, NF Review Selector: -- Doesn't take over the entire interface -- Allows interaction with other parts of ComfyUI while reviewing -- Provides a cleaner, more focused review experience -- Maintains workflow visibility ## License diff --git a/__init__.py b/__init__.py index 8ce889d..b0b4238 100644 --- a/__init__.py +++ b/__init__.py @@ -9,4 +9,4 @@ WEB_DIRECTORY = "./js" __all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS', 'WEB_DIRECTORY'] -print("NF Preview Selector: Loaded with floating dialog implementation") \ No newline at end of file +pass # NF Preview Selector loaded \ No newline at end of file diff --git a/js/nf_preview_selector.js b/js/nf_preview_selector.js index 27eb08f..47e0c82 100644 --- a/js/nf_preview_selector.js +++ b/js/nf_preview_selector.js @@ -7,25 +7,23 @@ import { app } from "../../scripts/app.js"; import { api } from "../../scripts/api.js"; import { nfPreviewDialog } from './preview_dialog.js'; -console.log("NF Preview Selector: Loading extension..."); +// NF Preview Selector loading app.registerExtension({ name: "nf.preview_selector", async setup() { - console.log("NF Preview Selector: Setting up extension"); - console.log("NF Preview Selector: API object:", api); - console.log("NF Preview Selector: API addEventListener available:", typeof api.addEventListener); + // Setting up extension // Register message handler using ComfyUI's system if (api.addEventListener) { // Register for our custom event type api.addEventListener("nf_preview_request", (event) => { - console.log("NF Preview Selector: Received review request via event", event.detail); + // Received review request nfPreviewDialog.show(event.detail); }); - console.log("NF Preview Selector: Event listener registered for nf_preview_request"); + // Event listener registered } // Event system is working correctly @@ -49,12 +47,12 @@ app.registerExtension({ // Auto-select first image setting removed - this is available in node UI - console.log("NF Preview Selector: Setup complete"); + // Setup complete }, async nodeCreated(node) { if (node.comfyClass === "NFPreviewSelector") { - console.log("NF Preview Selector: Node created", node.id); + // Node created // Set node title node.title = "NF Preview Selector"; @@ -68,7 +66,7 @@ app.registerExtension({ async beforeRegisterNodeDef(nodeType, nodeData, app) { if (nodeData.name === "NFPreviewSelector") { - console.log("NF Preview Selector: Registering node definition"); + // Registering node definition // Add any node definition modifications here const onNodeCreated = nodeType.prototype.onNodeCreated; @@ -84,4 +82,4 @@ app.registerExtension({ } }); -console.log("NF Preview Selector: Extension loaded successfully"); \ No newline at end of file +// Extension loaded successfully \ No newline at end of file diff --git a/js/preview_dialog.js b/js/preview_dialog.js index 429f04c..409a096 100644 --- a/js/preview_dialog.js +++ b/js/preview_dialog.js @@ -67,7 +67,7 @@ export class NFPreviewDialog { if (event.ctrlKey && event.key === 'Enter') { // Only handle if preview dialog is visible if (this.isVisible()) { - console.log('NF Preview Dialog: Queue Prompt keybinding detected - stopping dialog and allowing queue to proceed'); + // Queue Prompt keybinding detected // Stop the dialog processing immediately this.stopDialogForQueue(); @@ -85,7 +85,7 @@ export class NFPreviewDialog { // If queue is starting and dialog is visible, stop the dialog if (status && status.exec_info && status.exec_info.queue_remaining > 0) { if (this.isVisible()) { - console.log('NF Preview Dialog: Queue started programmatically - stopping dialog'); + // Queue started programmatically this.stopDialogForQueue(); } } @@ -96,7 +96,7 @@ export class NFPreviewDialog { // Stop countdown immediately this.stopCountdown(); - console.log('NF Preview Dialog: Stopping dialog processing for queue'); + // Stopping dialog processing for queue // Send cancellation response to backend (empty selection, cancelled=true) this.sendSelection([], true); @@ -110,14 +110,14 @@ export class NFPreviewDialog { } show(data) { - console.log("NF Preview Dialog: Showing review dialog", data); + // Showing review dialog // Apply latest max width setting this.applyMaxWidthSetting(); // If dialog is already open for this review, don't create another if (this.reviewId === data.review_id && this.window) { - console.log("NF Preview Dialog: Dialog already open for this review"); + // Dialog already open return; } @@ -284,12 +284,12 @@ export class NFPreviewDialog { // For landscape images, use slightly wider columns but still allow multiple columns const minColumnWidth = Math.max(200, Math.min(300, dialogWidth / 2)); // 200-300px, max 2 columns typically this.imageGrid.style.setProperty('--min-column-width', `${minColumnWidth}px`); - console.log('NF Preview Dialog: Using smart grid layout optimized for landscape images, min width:', minColumnWidth); + // Using landscape image layout } else { // For portrait/square images, use standard grid sizing const minColumnWidth = Math.max(120, Math.min(200, dialogWidth / 3)); // 120-200px, allow up to 3-4 columns this.imageGrid.style.setProperty('--min-column-width', `${minColumnWidth}px`); - console.log('NF Preview Dialog: Using smart grid layout optimized for portrait/square images, min width:', minColumnWidth); + // Using portrait/square image layout } } @@ -311,7 +311,7 @@ export class NFPreviewDialog { this.updateSelectionInfo(); this.updateConfirmButton(); - console.log("NF Preview Dialog: Selected indices:", Array.from(this.selectedIndices)); + // Selected indices updated } updateSelectionInfo() { @@ -335,7 +335,7 @@ export class NFPreviewDialog { this.updateCountdown(); if (this.remainingTime <= 0) { - console.log("NF Preview Dialog: Timeout reached"); + // Timeout reached this.timeoutSelection(); } }, 1000); @@ -358,7 +358,7 @@ export class NFPreviewDialog { this.stopCountdown(); const selection = Array.from(this.selectedIndices).sort((a, b) => a - b); - console.log("NF Preview Dialog: Confirming selection:", selection); + // Confirming selection this.sendSelection(selection, false); this.hide(); @@ -367,7 +367,7 @@ export class NFPreviewDialog { cancelSelection() { this.stopCountdown(); - console.log("NF Preview Dialog: Cancelling selection"); + // Cancelling selection this.sendSelection([], true); this.hide(); } @@ -377,7 +377,7 @@ export class NFPreviewDialog { // On timeout, select all images or none based on setting const selection = []; // Default to empty selection on timeout - console.log("NF Preview Dialog: Timeout - returning empty selection"); + // Timeout - returning empty selection this.sendSelection(selection, false); this.hide(); @@ -483,7 +483,7 @@ export class NFPreviewDialog { if (rememberPosition) { this.savePosition(x, y); } - console.log("NF Preview Dialog: Window moved to", x, y); + // Window moved } onWindowResize(width, height) { @@ -514,7 +514,7 @@ export class NFPreviewDialog { this.applyImageLayout(landscapeCount, portraitCount); } - console.log("NF Preview Dialog: Window resized to", width, height); + // Window resized } } diff --git a/nf_preview_selector.py b/nf_preview_selector.py index 812effc..dc05c4a 100644 --- a/nf_preview_selector.py +++ b/nf_preview_selector.py @@ -24,7 +24,7 @@ async def handle_review_response(request): selection = data.get('selection', []) cancelled = data.get('cancelled', False) - print(f"NF Preview Selector: Received response for review {review_id}: {selection}") + pass # Response received # Store response review_responses[review_id] = { @@ -34,7 +34,7 @@ async def handle_review_response(request): return web.json_response({'status': 'success'}) except Exception as e: - print(f"NF Preview Selector: Error handling response: {e}") + pass # Error handled return web.json_response({'status': 'error', 'message': str(e)}, status=500) # Register API endpoint @@ -76,7 +76,7 @@ class NFPreviewSelector(PreviewImage): def preview_images(self, images, mode, timeout, unique_id=None, latents=None, selection_indices="", prompt=None, extra_pnginfo=None): """Main function for image preview and selection""" - print(f"NF Preview Selector: Processing {len(images)} images with mode '{mode}'") + pass # Processing images # No flags needed anymore @@ -113,9 +113,9 @@ class NFPreviewSelector(PreviewImage): # Use ComfyUI's message dispatch system try: PromptServer.instance.send_sync("nf_preview_request", message_data) - print(f"NF Preview Selector: Sent review request via send_sync") + pass # Request sent except Exception as e: - print(f"NF Preview Selector: send_sync failed, trying direct WebSocket: {e}") + pass # Fallback to direct WebSocket # Fallback to direct WebSocket message = { "type": "nf_preview_request", @@ -127,20 +127,20 @@ class NFPreviewSelector(PreviewImage): try: await ws.send_str(json.dumps(message)) except Exception as e: - print(f"Failed to send message to client: {e}") + pass # Send failed if PromptServer.instance.loop: asyncio.run_coroutine_threadsafe(send_message(), PromptServer.instance.loop) - print(f"NF Preview Selector: Sent review request for {len(images)} images") + pass # Request sent # Wait for response from frontend result = self.wait_for_response(review_id, timeout) if result == "CANCELLED": - print(f"NF Preview Selector: Workflow cancelled by user") + pass # Cancelled raise InterruptProcessingException() elif result == "TIMEOUT": - print(f"NF Preview Selector: Workflow timed out") + pass # Timed out raise InterruptProcessingException() else: selected_indices = result @@ -152,7 +152,7 @@ class NFPreviewSelector(PreviewImage): # Process selection if not selected_indices: # For timeout or other cases, return empty tensors - print(f"NF Preview Selector: No selection made, returning empty tensors") + pass # No selection empty_image = torch.zeros((1, images.shape[1], images.shape[2], images.shape[3])) empty_latent = {"samples": torch.zeros((1, 4, 64, 64))} if latents is None else {"samples": torch.zeros((1, latents["samples"].shape[1], latents["samples"].shape[2], latents["samples"].shape[3]))} return (empty_image, empty_latent, "") @@ -170,7 +170,7 @@ class NFPreviewSelector(PreviewImage): indices_str = ",".join(str(i) for i in selected_indices) - print(f"NF Preview Selector: Selected {len(selected_indices)} images: [{indices_str}]") + pass # Selection made return { "result": (selected_images, selected_latents, indices_str), @@ -188,16 +188,16 @@ class NFPreviewSelector(PreviewImage): response = review_responses.pop(review_id) if response['cancelled']: - print(f"NF Preview Selector: Review {review_id} was cancelled") + pass # Review cancelled return "CANCELLED" else: selection = response['selection'] - print(f"NF Preview Selector: Review {review_id} completed with selection: {selection}") + pass # Review completed return selection time.sleep(0.1) # Poll every 100ms - print(f"NF Preview Selector: Review {review_id} timed out") + pass # Review timed out return "TIMEOUT" # Indicate timeout occurred # Node registration