Skip to content

Conversation

bryzle
Copy link
Contributor

@bryzle bryzle commented Aug 9, 2025

Description

Brief description of what this PR does.

Changes Made

  • Added LabeledGridExporter class in grid_exporter.py
  • Implemented image discovery and metadata extraction from logs
  • Added grid creation with parameter labels burned into each cell
  • Created comprehensive test suite with snapshot testing (11 tests)
  • Fixed Unicode encoding issues for Windows compatibility
  • Added CLI interface for command-line usage
  • Integrated Grid Export UI in Extras tab of frontend

Evidence Required ✅

UI Screenshot

<!image

Generated Image

  [SCAN] Scanning directory: C:\Users\brand\Documents\DreamLayer\Dream_Layer_Resources\output     
  [SCAN] Scanning directory:
  C:\Users\brand\Documents\DreamLayer\dream_layer_backend\served_images
  [INFO] Found 4 recent images
  [LIST] Selected images:
     1. labeled_grid_1754667667.png
     2. DreamLayer_00008_.png
     3. DreamLayer_00007_.png
     4. DreamLayer_00006_.png
  [GRID] Creating labeled grid...
  [GRID] Creating 2x2 grid for 4 images
  [OK] Loaded: labeled_grid_1754667667.png (1626x2031)
  [OK] Loaded: DreamLayer_00008_.png (512x512)
  [OK] Loaded: DreamLayer_00007_.png (512x512)
  [OK] Loaded: DreamLayer_00006_.png (512x512)
  [SIZE] Grid canvas size: 3312x4392
  [SIZE] Cell size: 1656x2196
  [OK] Grid assembly completed
  [OK] Grid exported successfully:
     [FILE] File: pr_demo_grid.png
     [SIZE] Size: 4,951,397 bytes
     [DIM] Dimensions: 3312x4392

Tests (Optional)

  platform win32 -- Python 3.12.4, pytest-8.3.5, pluggy-1.5.0
  collected 11 items

  test_grid_exporter.py::TestLabeledGridExporter::test_initialization PASSED [  9%]
  test_grid_exporter.py::TestLabeledGridExporter::test_get_recent_images PASSED [ 18%]
  test_grid_exporter.py::TestLabeledGridExporter::test_metadata_extraction PASSED [ 27%]
  test_grid_exporter.py::TestLabeledGridExporter::test_create_labeled_grid_basic PASSED [
  36%]
  test_grid_exporter.py::TestLabeledGridExporter::test_grid_auto_sizing PASSED [ 45%]
  test_grid_exporter.py::TestLabeledGridExporter::test_export_grid PASSED [ 54%]
  test_grid_exporter.py::TestLabeledGridExporter::test_create_grid_from_recent PASSED [ 63%]      
  test_grid_exporter.py::TestLabeledGridExporter::test_snapshot_grid_output PASSED [ 72%]
  test_grid_exporter.py::TestLabeledGridExporter::test_stable_ordering PASSED [ 81%]
  test_grid_exporter.py::TestLabeledGridExporter::test_error_handling PASSED [ 90%]
  test_grid_exporter.py::test_cli_interface PASSED [100%]

  ============================= 11 passed in 0.84s ==============================

Checklist

  • UI screenshot provided
  • Generated image provided
  • Logs provided
  • Tests added (optional)
  • Code follows project style
  • Self-review completed

Summary by Sourcery

Introduce a new LabeledGridExporter module and test suite to generate annotated image grids from recent DreamLayer outputs, complete with metadata labels, CLI support, and frontend integration.

New Features:

  • Add LabeledGridExporter class for assembling labeled image grids from recent outputs
  • Provide a command-line interface for on-demand grid generation
  • Integrate the grid exporter UI in the frontend Extras tab

Bug Fixes:

  • Resolve Unicode encoding and font loading issues on Windows

Enhancements:

  • Implement image discovery and metadata extraction from logs
  • Auto-calculate grid layouts and burn generation parameters into each cell
  • Ensure stable ordering of images in generated grids

Tests:

  • Add comprehensive test suite with snapshot testing covering grid creation, metadata extraction, error handling, and CLI usage

Summary by CodeRabbit

  • New Features

    • Create labeled image grids from recent outputs with parameter overlays and PNG export; CLI for testing.
    • Backend API endpoint to generate grids and a route to serve generated images.
    • Frontend "Grid Export" subtab with controls, preview, and export flow; static UI mockup included.
  • Tests

    • Comprehensive test suite covering discovery, metadata, grid generation, export, ordering, error cases, and CLI.
  • Chores

    • Added backend settings.json and a local .claude permissions file; added comfy-easy-grids subproject reference.

Copy link
Contributor

sourcery-ai bot commented Aug 9, 2025

Reviewer's Guide

This PR adds a new LabeledGridExporter module that discovers recent DreamLayer images, extracts or mocks generation metadata, assembles them into parameter-labeled grids, and exports optimized PNGs. It also provides a CLI interface, integrates the feature into the frontend Extras tab with font assets for cross-platform Unicode support, and delivers a comprehensive 11-test pytest suite including snapshot testing.

Sequence diagram for CLI grid export process

sequenceDiagram
    actor User
    participant CLI
    participant LabeledGridExporter
    participant FileSystem
    User->>CLI: Run grid_exporter.py with arguments
    CLI->>LabeledGridExporter: __init__()
    CLI->>LabeledGridExporter: create_grid_from_recent(count, grid_size, filename)
    LabeledGridExporter->>FileSystem: get_recent_images(count)
    LabeledGridExporter->>FileSystem: extract_metadata_from_logs()
    LabeledGridExporter->>LabeledGridExporter: create_labeled_grid(images, grid_size)
    LabeledGridExporter->>FileSystem: export_grid(images, filename, grid_size)
    CLI->>User: Output success message with grid path
Loading

Class diagram for the new LabeledGridExporter module

classDiagram
    class LabeledGridExporter {
        +__init__(output_dir: Optional[str])
        +get_recent_images(count: int) List[Dict]
        +extract_metadata_from_logs(image_filename: str, image_timestamp: float) Dict[str, str]
        +create_labeled_grid(images: List[Dict], grid_size: Optional[Tuple[int, int]]) Image
        +export_grid(images: List[Dict], filename: Optional[str], grid_size: Optional[Tuple[int, int]]) str
        +create_grid_from_recent(count: int, grid_size: Optional[Tuple[int, int]], filename: Optional[str]) str
        -_setup_font() ImageFont
        -output_dir: str
        -served_images_dir: str
        -logs_dir: str
        -font: ImageFont
    }
    LabeledGridExporter --> ImageFont : uses
    LabeledGridExporter --> Image : creates
    LabeledGridExporter --> Dict : returns
    LabeledGridExporter --> List : returns
Loading

File-Level Changes

Change Details Files
LabeledGridExporter class implementation
  • Initialized output, served_images, and logs directories with proper defaults
  • Implemented get_recent_images to scan and sort PNG files by timestamp
  • Created extract_metadata_from_logs to derive sampler, steps, cfg, preset, and seed values
  • Designed create_labeled_grid to auto-calculate grid layout, load and convert images, compute canvas/cell sizes, paste images, and burn parameter labels
  • Added export_grid and create_grid_from_recent methods for saving grids and a one-call workflow
dream_layer_backend/grid_exporter.py
CLI interface and cross-platform compatibility
  • Added main() entrypoint with argparse options (--count, --cols, --rows, --output) for command-line usage
  • Implemented font fallback logic across Windows, Linux, macOS, and PIL default
  • Ensured Unicode-safe path handling and optimized PNG saving for Windows compatibility
dream_layer_backend/grid_exporter.py
UI assets and Extras tab integration
  • Introduced comfy-easy-grids folder housing Roboto font assets as a fallback
  • Updated settings.json to register the grid exporter UI in the frontend Extras tab
comfy-easy-grids
dream_layer_backend/settings.json
Comprehensive pytest test suite
  • Created test_grid_exporter.py with 11 tests covering initialization, discovery, metadata extraction, grid creation (basic and auto-sizing), export, convenience method, snapshot analysis, stable ordering, error handling, and CLI
  • Employed tiny 64×64 image fixtures for snapshot validation and color complexity checks
dream_layer_backend/test_grid_exporter.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

coderabbitai bot commented Aug 9, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds a labeled image grid export feature: backend exporter module, JSON settings, API endpoints, frontend UI for creating/previewing grids, a pytest suite, a CLI entry, and supporting files including a UI mockup and local permissions config.

Changes

Cohort / File(s) Change Summary
Submodule Reference Update
comfy-easy-grids
Added/updated subproject commit reference 376a8adf2a86fec214816c26789849c866f25466.
Grid exporter implementation
dream_layer_backend/grid_exporter.py
New module providing MetadataExtractor, GridLayoutManager, GridRenderer, and LabeledGridExporter classes; image discovery, mock/log metadata extraction, grid layout/calculation, label rendering, PNG export, CLI entrypoint, and logging/error handling.
Backend configuration
dream_layer_backend/settings.json
New static JSON configuration for backend directories, model paths, filename format, and metadata saving flag.
Tests
dream_layer_backend/test_grid_exporter.py
New pytest suite covering initialization, recent-image discovery, metadata extraction, grid creation/export, snapshot checks, ordering stability, error cases, and a minimal CLI invocation. Includes temp dirs and generated test images.
API endpoints & serving
dream_layer_backend/extras.py
Added /api/extras/grid-export POST endpoint to create grids and return image info, and /images/<filename> route to serve generated images; imports LabeledGridExporter; error handling for invalid requests and failures.
Frontend integration
dream_layer_frontend/src/components/tabs/ExtrasTab.tsx, dream_layer_frontend/src/features/Extras/ExtrasPage.tsx
Added "Grid Export" subtab/page UI, state for grid settings/results/errors, handlers to POST to backend, preview rendering, and controls for count, grid size, labels, filenames, and filename input.
UI mockup
ui_mockup_grid_export.html
New static Tailwind-based mockup illustrating Grid Export controls and preview layout (no scripting).
Local permissions
.claude/settings.local.json
New local permissions JSON allowing specific shell and Python commands (including test script execution).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Frontend
    participant BackendAPI
    participant LabeledGridExporter
    participant FileSystem

    User->>Frontend: Open Grid Export UI, set options, submit
    Frontend->>BackendAPI: POST /api/extras/grid-export (params)
    BackendAPI->>LabeledGridExporter: create_grid_from_recent(params)
    LabeledGridExporter->>FileSystem: scan recent images (served/output dirs)
    LabeledGridExporter->>LabeledGridExporter: extract metadata (logs or mock)
    LabeledGridExporter->>FileSystem: load images, assemble canvas, render labels
    LabeledGridExporter->>FileSystem: save PNG to served dir
    LabeledGridExporter-->>BackendAPI: return file path, size, dimensions
    BackendAPI-->>Frontend: JSON with image URL and metadata
    Frontend-->>User: display preview and info
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • darcy3000

Poem

🐇 Soft hops through folders, pixels in a row,
I stitch each label where the gentle captions go.
From backend burrow to the frontend's light,
I craft the grid by day and test it through the night.
Click, preview, save — the rabbit's ribboned show. 🎨🐰


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 51ae1f0 and f799e78.

📒 Files selected for processing (2)
  • dream_layer_backend/grid_exporter.py (1 hunks)
  • dream_layer_backend/test_grid_exporter.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • dream_layer_backend/test_grid_exporter.py
  • dream_layer_backend/grid_exporter.py
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @bryzle - I've reviewed your changes - here's some feedback:

  • Replace the numerous print statements with Python’s logging module to allow configurable verbosity and better integration with your existing logs.
  • The extract_metadata_from_logs method currently returns mock metadata—consider implementing actual log-file parsing or clearly separating the stub logic to avoid confusion in production.
  • The LabeledGridExporter class is handling many responsibilities; think about refactoring into smaller components (e.g., metadata extraction, grid layout, rendering) to improve maintainability.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Replace the numerous print statements with Python’s logging module to allow configurable verbosity and better integration with your existing logs.
- The extract_metadata_from_logs method currently returns mock metadata—consider implementing actual log-file parsing or clearly separating the stub logic to avoid confusion in production.
- The LabeledGridExporter class is handling many responsibilities; think about refactoring into smaller components (e.g., metadata extraction, grid layout, rendering) to improve maintainability.

## Individual Comments

### Comment 1
<location> `dream_layer_backend/grid_exporter.py:353` </location>
<code_context>
+        output_path = os.path.join(self.output_dir, filename)
+        
+        # Save with metadata
+        grid_image.save(output_path, format='PNG', optimize=True)
+        
+        file_size = os.path.getsize(output_path)
+        print(f"✅ Grid exported successfully:")
+        print(f"   📄 File: {output_path}")
</code_context>

<issue_to_address>
PNG metadata is mentioned but not actually set.

To embed metadata as described, use the 'pnginfo' parameter in the save method.
</issue_to_address>

### Comment 2
<location> `dream_layer_backend/test_grid_exporter.py:101` </location>
<code_context>
+        metadata2 = self.exporter.extract_metadata_from_logs("test_image_002.png", 1234567891.0)
+        assert metadata != metadata2  # Should be different due to index variation
+    
+    def test_create_labeled_grid_basic(self):
+        """Test basic grid creation functionality"""
+        images = self.exporter.get_recent_images(count=4)
+        grid_image = self.exporter.create_labeled_grid(images, grid_size=(2, 2))
+        
+        assert isinstance(grid_image, Image.Image)
+        assert grid_image.mode == 'RGB'
+        assert grid_image.width > 0
+        assert grid_image.height > 0
+        
+        # Grid should be larger than individual images due to labels and padding
+        assert grid_image.width > 64 * 2  # Larger than 2 images side by side
+        assert grid_image.height > 64 * 2  # Larger than 2 images stacked
+    
+    def test_grid_auto_sizing(self):
</code_context>

<issue_to_address>
Test does not verify that labels are actually rendered in the grid.

Add an assertion to check that the expected label text or color regions appear in the grid image to ensure labels are rendered correctly.

Suggested implementation:

```python
    def test_create_labeled_grid_basic(self):
        """Test basic grid creation functionality"""
        import pytesseract

        images = self.exporter.get_recent_images(count=4)
        grid_image = self.exporter.create_labeled_grid(images, grid_size=(2, 2))

        assert isinstance(grid_image, Image.Image)
        assert grid_image.mode == 'RGB'
        assert grid_image.width > 0
        assert grid_image.height > 0

        # Grid should be larger than individual images due to labels and padding
        assert grid_image.width > 64 * 2  # Larger than 2 images side by side
        assert grid_image.height > 64 * 2  # Larger than 2 images stacked

        # Check that expected label text appears in the grid image
        # Assuming labels are based on image filenames
        expected_labels = [img.filename if hasattr(img, "filename") else f"Image {i+1}" for i, img in enumerate(images)]
        ocr_text = pytesseract.image_to_string(grid_image)
        for label in expected_labels:
            assert label in ocr_text, f"Label '{label}' not found in grid image OCR output"

```

- If your images do not have a `filename` attribute, adjust the `expected_labels` list to match how labels are generated in `create_labeled_grid`.
- Ensure `pytesseract` is installed and available in your test environment.
- If you use a different method for rendering labels (e.g., colored rectangles), you may want to check pixel colors instead of using OCR.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +353 to +355
grid_image.save(output_path, format='PNG', optimize=True)

file_size = os.path.getsize(output_path)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: PNG metadata is mentioned but not actually set.

To embed metadata as described, use the 'pnginfo' parameter in the save method.

Comment on lines +101 to +110
def test_create_labeled_grid_basic(self):
"""Test basic grid creation functionality"""
images = self.exporter.get_recent_images(count=4)
grid_image = self.exporter.create_labeled_grid(images, grid_size=(2, 2))

assert isinstance(grid_image, Image.Image)
assert grid_image.mode == 'RGB'
assert grid_image.width > 0
assert grid_image.height > 0

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Test does not verify that labels are actually rendered in the grid.

Add an assertion to check that the expected label text or color regions appear in the grid image to ensure labels are rendered correctly.

Suggested implementation:

    def test_create_labeled_grid_basic(self):
        """Test basic grid creation functionality"""
        import pytesseract

        images = self.exporter.get_recent_images(count=4)
        grid_image = self.exporter.create_labeled_grid(images, grid_size=(2, 2))

        assert isinstance(grid_image, Image.Image)
        assert grid_image.mode == 'RGB'
        assert grid_image.width > 0
        assert grid_image.height > 0

        # Grid should be larger than individual images due to labels and padding
        assert grid_image.width > 64 * 2  # Larger than 2 images side by side
        assert grid_image.height > 64 * 2  # Larger than 2 images stacked

        # Check that expected label text appears in the grid image
        # Assuming labels are based on image filenames
        expected_labels = [img.filename if hasattr(img, "filename") else f"Image {i+1}" for i, img in enumerate(images)]
        ocr_text = pytesseract.image_to_string(grid_image)
        for label in expected_labels:
            assert label in ocr_text, f"Label '{label}' not found in grid image OCR output"
  • If your images do not have a filename attribute, adjust the expected_labels list to match how labels are generated in create_labeled_grid.
  • Ensure pytesseract is installed and available in your test environment.
  • If you use a different method for rendering labels (e.g., colored rectangles), you may want to check pixel colors instead of using OCR.

Comment on lines +86 to +87
for i in range(len(images) - 1):
assert images[i]['mtime'] >= images[i+1]['mtime']
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Avoid loops in tests. (no-loop-in-tests)

ExplanationAvoid complex code, like loops, in test functions.

Google's software engineering guidelines says:
"Clear tests are trivially correct upon inspection"
To reach that avoid complex code in tests:

  • loops
  • conditionals

Some ways to fix this:

  • Use parametrized tests to get rid of the loop.
  • Move the complex logic into helpers.
  • Move the complex part into pytest fixtures.

Complexity is most often introduced in the form of logic. Logic is defined via the imperative parts of programming languages such as operators, loops, and conditionals. When a piece of code contains logic, you need to do a bit of mental computation to determine its result instead of just reading it off of the screen. It doesn't take much logic to make a test more difficult to reason about.

Software Engineering at Google / Don't Put Logic in Tests

Comment on lines 102 to 105
try:
return ImageFont.load_default()
except:
return ImageFont.load_default()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Use except Exception: rather than bare except: (do-not-use-bare-except)


# Extract index from filename (e.g., DreamLayer_00001_.png -> 1)
match = re.search(r'(\d+)', image_filename)
index = int(match.group(1)) if match else 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Replace m.group(x) with m[x] for re.Match objects (use-getitem-for-re-match-groups)

'seed': seeds[index % len(seeds)]
}

def create_labeled_grid(self,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Low code quality found in LabeledGridExporter.create_labeled_grid - 25% (low-code-quality)


ExplanationThe quality score for this function is below the quality threshold of 25%.
This score is a combination of the method length, cognitive complexity and working memory.

How can you solve this?

It might be worth refactoring this function to make it shorter and more readable.

  • Reduce the function length by extracting pieces of functionality out into
    their own functions. This is the most important thing you can do - ideally a
    function should be less than 10 lines.
  • Reduce nesting, perhaps by introducing guard clauses to return early.
  • Ensure that variables are tightly scoped, so that code using related concepts
    sits together within the function rather than being scattered.

if not filename.lower().endswith('.png'):
filename += '.png'

print(f"🎨 Creating labeled grid...")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Replace f-string with no interpolated values with string [×2] (remove-redundant-fstring)

if not recent_images:
raise ValueError("No recent images found to create grid")

print(f"📋 Selected images:")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Replace f-string with no interpolated values with string (remove-redundant-fstring)



def main():
"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): We've found these issues:

file_size = os.path.getsize(output_path)
assert 5000 < file_size < 100000 # Reasonable PNG size for small grid

print(f"✅ Snapshot test passed!")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Replace f-string with no interpolated values with string (remove-redundant-fstring)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (8)
dream_layer_backend/settings.json (1)

9-9: Confirm metadata writing honors UTF-8 and Windows-safe behavior.

With "saveMetadata": true, ensure the writer uses UTF-8, disables ASCII-escaping, and normalizes newlines so Unicode remains intact on Windows.

Checklist:

  • Use encoding="utf-8" and ensure_ascii=False when serializing JSON metadata.
  • Normalize path separators when embedding paths in metadata.
  • If EXIF/IPTC writing is involved, validate code paths on Windows with non-ASCII content. I can help add a small utility to centralize safe metadata writes.
comfy-easy-grids (1)

1-1: Optional: prefer a tagged release or document the bump

If a stable tag exists for this commit, consider pinning to the tag for clarity. Otherwise, add a brief note in CHANGELOG/Release notes indicating the submodule bump and any expected impact.

dream_layer_backend/test_grid_exporter.py (3)

12-12: Remove unused import Path

pathlib.Path is imported but not used.

-from pathlib import Path

186-186: Remove unnecessary f-string without placeholders

Avoid f-strings with no interpolations.

-        print(f"✅ Snapshot test passed!")
+        print("✅ Snapshot test passed!")

161-191: Optional: Avoid using the closed PIL image outside the context manager

While width/height are accessible, it’s cleaner to compute and print inside the context or cache values before closing.

Example:

with Image.open(output_path) as grid_img:
    w, h = grid_img.width, grid_img.height
    grid_array = np.array(grid_img)
# ...
print(f"   📐 Dimensions: {w}x{h}")
dream_layer_backend/grid_exporter.py (3)

15-15: Remove unused imports

json and Path are not used.

-import json
@@
-from pathlib import Path

Also applies to: 17-17


343-343: Remove unnecessary f-strings without placeholders

These prints don’t interpolate values; drop the f prefix to appease linters.

-        print(f"🎨 Creating labeled grid...")
+        print("🎨 Creating labeled grid...")
@@
-        print(f"✅ Grid exported successfully:")
+        print("✅ Grid exported successfully:")
@@
-        print(f"📋 Selected images:")
+        print("📋 Selected images:")

Also applies to: 356-356, 393-393


410-446: Optional: Replace prints with logging for better control and Windows encoding safety

Emojis can cause UnicodeEncodeError on some Windows consoles. Using logging with a safe formatter or stripping non-ASCII for stream handlers can improve UX.

Example:

import logging
logger = logging.getLogger(__name__)
# then: logger.info("Grid exported successfully")
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1911cd3 and 126e6f5.

📒 Files selected for processing (4)
  • comfy-easy-grids (1 hunks)
  • dream_layer_backend/grid_exporter.py (1 hunks)
  • dream_layer_backend/settings.json (1 hunks)
  • dream_layer_backend/test_grid_exporter.py (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: rachanavarsha
PR: DreamLayer-AI/DreamLayer#80
File: report_bundler/bundler.py:7-7
Timestamp: 2025-08-06T18:59:31.412Z
Learning: In report_bundler/bundler.py, the REQUIRED_COLUMNS set intentionally contains only essential fields (image_path, sampler, steps, cfg, preset, seed) needed for bundling logic. Additional columns like width, height, grid_label, and notes are treated as optional metadata.
🧬 Code Graph Analysis (1)
dream_layer_backend/test_grid_exporter.py (1)
dream_layer_backend/grid_exporter.py (7)
  • LabeledGridExporter (23-398)
  • get_recent_images (107-158)
  • extract_metadata_from_logs (160-194)
  • create_labeled_grid (196-315)
  • export_grid (317-361)
  • create_grid_from_recent (363-398)
  • main (401-446)
🪛 Ruff (0.12.2)
dream_layer_backend/test_grid_exporter.py

12-12: pathlib.Path imported but unused

Remove unused import: pathlib.Path

(F401)


186-186: f-string without any placeholders

Remove extraneous f prefix

(F541)


215-215: Local variable grid is assigned to but never used

Remove assignment to unused variable grid

(F841)

dream_layer_backend/grid_exporter.py

15-15: json imported but unused

Remove unused import: json

(F401)


17-17: pathlib.Path imported but unused

Remove unused import: pathlib.Path

(F401)


104-104: Do not use bare except

(E722)


343-343: f-string without any placeholders

Remove extraneous f prefix

(F541)


356-356: f-string without any placeholders

Remove extraneous f prefix

(F541)


393-393: f-string without any placeholders

Remove extraneous f prefix

(F541)

🔇 Additional comments (2)
dream_layer_backend/settings.json (1)

1-10: Centralizing backend paths in a single config is a good move.

This improves testability and simplifies CLI/UI integration. No blockers from a config-structure standpoint.

comfy-easy-grids (1)

1-1: Ignore submodule verification – no submodule defined

There is no .gitmodules file in the repository and comfy-easy-grids/ is a normal source directory, not a git submodule. You can disregard the SHA‐validation and CI submodule initialization steps.

Likely an incorrect or invalid review comment.

Comment on lines 2 to 7
"outputDirectory": "/path/to/outputs",
"modelsDirectory": "/path/to/parent/of/models",
"controlNetModelsPath": "/path/to/models/ControlNet",
"upscalerModelsPath": "/path/to/models/ESRGAN",
"vaeModelsPath": "/path/to/models/VAE",
"loraEmbeddingsPath": "/path/to/models/Lora",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Make paths portable and safe-by-default (avoid absolute placeholders).

Use relative, project-root-based defaults and allow env/home expansion to work cross-platform and in CI. Absolute placeholders like “/path/to/…” often break on Windows and in sandboxed environments.

Suggested diff:

-  "outputDirectory": "/path/to/outputs",
-  "modelsDirectory": "/path/to/parent/of/models",
-  "controlNetModelsPath": "/path/to/models/ControlNet",
-  "upscalerModelsPath": "/path/to/models/ESRGAN",
-  "vaeModelsPath": "/path/to/models/VAE",
-  "loraEmbeddingsPath": "/path/to/models/Lora",
+  "outputDirectory": "./outputs",
+  "modelsDirectory": "./models",
+  "controlNetModelsPath": "./models/ControlNet",
+  "upscalerModelsPath": "./models/ESRGAN",
+  "vaeModelsPath": "./models/VAE",
+  "loraEmbeddingsPath": "./models/Lora",

Additionally:

  • Support expansion at load time: expanduser (~), expandvars ($VAR/%VAR%), and Path.resolve().
  • Consider allowing overrides via environment variables or CLI flags (e.g., DREAMLAYER_OUTPUT_DIR). I can draft the loader helper if helpful.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"outputDirectory": "/path/to/outputs",
"modelsDirectory": "/path/to/parent/of/models",
"controlNetModelsPath": "/path/to/models/ControlNet",
"upscalerModelsPath": "/path/to/models/ESRGAN",
"vaeModelsPath": "/path/to/models/VAE",
"loraEmbeddingsPath": "/path/to/models/Lora",
"outputDirectory": "./outputs",
"modelsDirectory": "./models",
"controlNetModelsPath": "./models/ControlNet",
"upscalerModelsPath": "./models/ESRGAN",
"vaeModelsPath": "./models/VAE",
"loraEmbeddingsPath": "./models/Lora",
🤖 Prompt for AI Agents
In dream_layer_backend/settings.json lines 2 to 7, replace the absolute
placeholder paths with relative paths based on the project root to ensure
portability across platforms. Implement path expansion at load time to handle
user home (~) and environment variables ($VAR or %VAR%) and resolve paths
properly. Additionally, modify the configuration loader to allow overriding
these paths via environment variables or CLI flags for flexibility in different
environments like CI or sandboxed systems.

"upscalerModelsPath": "/path/to/models/ESRGAN",
"vaeModelsPath": "/path/to/models/VAE",
"loraEmbeddingsPath": "/path/to/models/Lora",
"filenameFormat": "paste the path if it is outside project root",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

filenameFormat contains an instruction, not a usable format; clarify intent and set a valid default.

Current value looks like guidance text rather than a real format string, which can cause runtime issues if the code expects a pattern.

Action options (pick the one that matches actual usage in grid_exporter.py):

  • If this is a filename pattern: set a sane default like a timestamp-based name.
-  "filenameFormat": "paste the path if it is outside project root",
+  "filenameFormat": "grid_{timestamp}.png",
  • If the intent was a directory path (e.g., a “served images” dir), then rename the key and provide a valid path instead:
-  "filenameFormat": "paste the path if it is outside project root",
+  "servedImagesDirectory": "./outputs/served",

To verify actual usage in the repo, run:


🏁 Script executed:

#!/bin/bash
# Inspect where/ how filenameFormat (or a served images dir) is referenced.
rg -n --hidden -S "filenameFormat|servedImagesDirectory|served.*images|file(name)?_?format" -A 3

Length of output: 13448


Replace placeholder with a concrete filename pattern

The filenameFormat setting isn’t a directory path but a filename template for saved images. Right now it’s just guidance text, which will break any code that tries to format filenames at runtime. Please update it to a valid pattern and keep front- and back-end defaults in sync:

• In dream_layer_backend/settings.json (around line 8):

-  "filenameFormat": "paste the path if it is outside project root",
+  "filenameFormat": "[model_name]_[seed]_[prompt_words]",

• In dream_layer_frontend/src/features/Configurations/useSettingsStore.ts (around line 70):

-  filenameFormat: 'paste the path if it is outside project root',
+  filenameFormat: '[model_name]_[seed]_[prompt_words]',

If you’d rather use a timestamp-based default, you could substitute "[model_name]_[seed]_[prompt_words]" with something like "grid_{timestamp}.png". Just ensure it’s a real template string, not instructional text.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"filenameFormat": "paste the path if it is outside project root",
"filenameFormat": "[model_name]_[seed]_[prompt_words]",
Suggested change
"filenameFormat": "paste the path if it is outside project root",
filenameFormat: '[model_name]_[seed]_[prompt_words]',
🤖 Prompt for AI Agents
In dream_layer_backend/settings.json at line 8, replace the placeholder text in
the "filenameFormat" setting with a valid filename template string instead of
instructional text. Use a concrete pattern like "grid_{timestamp}.png" or
"[model_name]_[seed]_[prompt_words].png" to ensure the filename formatting code
works correctly at runtime. Also verify that this pattern matches the default
used in dream_layer_frontend/src/features/Configurations/useSettingsStore.ts
around line 70 to keep front- and back-end defaults consistent.

Comment on lines 213 to 217
# Test with invalid grid size
images = self.exporter.get_recent_images(count=4)
grid = self.exporter.create_labeled_grid(images, grid_size=(0, 1))
# Should handle gracefully and auto-calculate

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Invalid grid_size test relies on unimplemented fallback; add assertion and align implementation

create_labeled_grid currently does not auto-calc when grid_size has zeros; this can lead to creating a 0-width image. Either assert that a ValueError is raised or, preferably, make the exporter treat invalid grid_size as None and auto-calc. Also fixes the F841 lint by using the returned value.

Apply this diff to the test:

-        # Test with invalid grid size
-        images = self.exporter.get_recent_images(count=4)
-        grid = self.exporter.create_labeled_grid(images, grid_size=(0, 1))
-        # Should handle gracefully and auto-calculate
+        # Test with invalid grid size -> should be handled gracefully by auto-calculation
+        images = self.exporter.get_recent_images(count=4)
+        grid = self.exporter.create_labeled_grid(images, grid_size=(0, 1))
+        assert isinstance(grid, Image.Image)

And update the implementation as suggested in grid_exporter.py (see separate comment) to auto-calc on invalid (cols < 1 or rows < 1).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Test with invalid grid size
images = self.exporter.get_recent_images(count=4)
grid = self.exporter.create_labeled_grid(images, grid_size=(0, 1))
# Should handle gracefully and auto-calculate
# Test with invalid grid size -> should be handled gracefully by auto-calculation
images = self.exporter.get_recent_images(count=4)
grid = self.exporter.create_labeled_grid(images, grid_size=(0, 1))
assert isinstance(grid, Image.Image)
🧰 Tools
🪛 Ruff (0.12.2)

215-215: Local variable grid is assigned to but never used

Remove assignment to unused variable grid

(F841)

🤖 Prompt for AI Agents
In dream_layer_backend/test_grid_exporter.py around lines 213 to 217, the test
for invalid grid_size currently calls create_labeled_grid with a zero dimension
but does not assert the expected behavior or use the returned value, causing a
lint warning. Update the test to either assert that a ValueError is raised when
grid_size contains zeros or modify the test to check that the exporter treats
invalid grid_size as None and auto-calculates the grid size. Also, ensure the
returned grid is used to avoid the F841 lint error. Additionally, update the
create_labeled_grid implementation in grid_exporter.py to auto-calc grid size
when cols or rows are less than 1.

bryzle added 2 commits August 9, 2025 11:32
- Added state management for grid export settings including count, grid size, and filename.
- Integrated API call to create grid and handle responses, including success and error states.
- Enhanced UI components in ExtrasTab and ExtrasPage for grid export settings and preview.
- Introduced logging for test cases in test_grid_exporter.py to replace print statements with logger.
- Created a mockup HTML for grid export UI to visualize the feature.
- Updated permissions in settings.local.json for backend operations.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (4)
dream_layer_backend/grid_exporter.py (3)

585-593: Invalid grid_size (0 or negative) still not handled

If a caller supplies (0, 1) or similar, cols or rows become zero and later maths will produce a zero-width canvas. Refactor to fall back to auto-calc when either dimension ≤ 0 (see previous review).


595-611: Image files opened without context manager

Images remain open, causing Windows file-lock issues and resource leaks. Use with Image.open(...) as im: and .copy() to detach.


404-415: Bare except hides real errors in font loading

Replace with except Exception: (or log & continue) and drop the second try/except – ImageFont.load_default() never raises.

-        try:
-            return ImageFont.load_default()
-        except:
-            return ImageFont.load_default()
+        return ImageFont.load_default()
dream_layer_backend/test_grid_exporter.py (1)

220-222: Unused variable grid

The variable is assigned but not used, tripping Ruff F841. Either assert on it or drop the assignment.

🧹 Nitpick comments (6)
dream_layer_backend/extras.py (1)

344-350: Remove redundant f-strings

Lines 344–349 contain f" strings without placeholders – drop the f prefix to silence Ruff F541 and avoid the runtime cost of interpolating nothing.
Same applies to the similar log block around Line 374.

dream_layer_backend/grid_exporter.py (1)

13-19: Remove unused imports

json and pathlib.Path are imported but never used – triggers Ruff F401.

-import json
-from pathlib import Path
+# json and Path not used – delete to keep the import list clean
dream_layer_backend/test_grid_exporter.py (1)

13-14: Drop unused import

Path is never referenced – remove to satisfy Ruff F401.

dream_layer_frontend/src/components/tabs/ExtrasTab.tsx (2)

29-32: Debug console.log left in production code

Remove or wrap with a debug flag to avoid noisy consoles and potential PII leakage.


50-56: Store numeric fields as numbers, not strings

count and gridSize default to string values and are repeatedly coerced with parseInt. Keep them numeric to simplify state handling and avoid accidental NaNs.

-  const [gridSettings, setGridSettings] = useState({
-    count: '4',
+  const [gridSettings, setGridSettings] = useState({
+    count: 4,
dream_layer_frontend/src/features/Extras/ExtrasPage.tsx (1)

538-550: Button handler branches are getting complex

Consider extracting the “Grid” vs “Upscale” action into two small callbacks and wiring the correct one via a variable (const onPrimaryAction = activeSubTab==='grid' ? handleCreateGrid : handleGenerate). Keeps JSX tidy.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 126e6f5 and ad2bdc6.

📒 Files selected for processing (7)
  • .claude/settings.local.json (1 hunks)
  • dream_layer_backend/extras.py (2 hunks)
  • dream_layer_backend/grid_exporter.py (1 hunks)
  • dream_layer_backend/test_grid_exporter.py (1 hunks)
  • dream_layer_frontend/src/components/tabs/ExtrasTab.tsx (4 hunks)
  • dream_layer_frontend/src/features/Extras/ExtrasPage.tsx (5 hunks)
  • ui_mockup_grid_export.html (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • .claude/settings.local.json
  • ui_mockup_grid_export.html
🧰 Additional context used
🪛 Ruff (0.12.2)
dream_layer_backend/extras.py

341-341: Do not use bare except

(E722)


344-344: f-string without any placeholders

Remove extraneous f prefix

(F541)


374-374: f-string without any placeholders

Remove extraneous f prefix

(F541)

dream_layer_backend/grid_exporter.py

15-15: json imported but unused

Remove unused import: json

(F401)


18-18: pathlib.Path imported but unused

Remove unused import: pathlib.Path

(F401)


414-414: Do not use bare except

(E722)

dream_layer_backend/test_grid_exporter.py

13-13: pathlib.Path imported but unused

Remove unused import: pathlib.Path

(F401)


191-191: f-string without any placeholders

Remove extraneous f prefix

(F541)


220-220: Local variable grid is assigned to but never used

Remove assignment to unused variable grid

(F841)

🔇 Additional comments (1)
dream_layer_backend/extras.py (1)

351-360: Unused request flags

show_labels and show_filenames are parsed but never forwarded to LabeledGridExporter, so the endpoint ignores the caller’s choices. Pass them through (or drop them from the request contract).

Would you like a patch that plumbs these flags into create_grid_from_recent and toggles label rendering?

Comment on lines +338 to +343
try:
cols, rows = grid_size_str.split('x')
grid_size = (int(cols), int(rows))
except:
grid_size = None

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Replace bare except with a specific exception

Catching all exceptions swallows programming errors and makes debugging harder. Catch ValueError (and optionally TypeError) that int() / split() may raise instead.

-    try:
-        cols, rows = grid_size_str.split('x')
-        grid_size = (int(cols), int(rows))
-    except:
-        grid_size = None
+    try:
+        cols, rows = grid_size_str.split('x')
+        grid_size = (int(cols), int(rows))
+    except (ValueError, TypeError):
+        grid_size = None
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try:
cols, rows = grid_size_str.split('x')
grid_size = (int(cols), int(rows))
except:
grid_size = None
try:
cols, rows = grid_size_str.split('x')
grid_size = (int(cols), int(rows))
except (ValueError, TypeError):
grid_size = None
🧰 Tools
🪛 Ruff (0.12.2)

341-341: Do not use bare except

(E722)

🤖 Prompt for AI Agents
In dream_layer_backend/extras.py around lines 338 to 343, replace the bare
except clause with a specific exception handler. Catch ValueError and optionally
TypeError exceptions that can be raised by the split or int conversion
operations. This will prevent swallowing unrelated exceptions and improve
debugging by only handling expected conversion errors.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (1)
dream_layer_backend/grid_exporter.py (1)

708-708: PNG metadata still not embedded
The save call lacks a pnginfo object, so no metadata is written despite earlier feedback.

🧹 Nitpick comments (3)
dream_layer_backend/grid_exporter.py (3)

81-83: Modernise re.Match access

Since Python 3.11 re.Match implements __getitem__; match[1] is shorter and marginally faster than match.group(1).


289-295: Avoid magic cell_padding constant inside renderer

GridRenderer.render_cell() hard-codes cell_padding = 15, drifting from GridLayoutManager.cell_padding. Pass the padding via arguments or read from the layout manager to keep one source of truth.


402-410: Default font size may clash with 22 px line spacing

ImageFont.load_default() returns a ~10 px bitmap font, yet later you assume 22 px per label line. Consider scaling the fallback font or reducing line_height to avoid truncated text on systems without TTFs.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ad2bdc6 and 51ae1f0.

📒 Files selected for processing (4)
  • .claude/settings.local.json (1 hunks)
  • dream_layer_backend/grid_exporter.py (1 hunks)
  • dream_layer_backend/settings.json (1 hunks)
  • dream_layer_backend/test_grid_exporter.py (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • dream_layer_backend/settings.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • .claude/settings.local.json
  • dream_layer_backend/test_grid_exporter.py

Comment on lines +158 to +166
if grid_size is not None:
return grid_size

# Auto-calculate grid size to be roughly square
cols = int(np.ceil(np.sqrt(num_images)))
rows = int(np.ceil(num_images / cols))

logger.debug(f"Calculated grid size: {cols}x{rows} for {num_images} images")
return (cols, rows)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Validate negative/zero grid_size values

calculate_grid_size() returns the provided tuple verbatim, so (0, n) or (-1, 2) flows through to later canvas maths and raises at runtime. Mirror the guard you already added in create_labeled_grid.

🤖 Prompt for AI Agents
In dream_layer_backend/grid_exporter.py around lines 158 to 166, the function
calculate_grid_size returns the provided grid_size tuple without validating its
values, allowing zero or negative dimensions to cause runtime errors later. Add
validation to check if grid_size is not None and both dimensions are positive
integers; if not, raise a ValueError or handle the invalid input appropriately
before returning grid_size. This mirrors the existing guard in
create_labeled_grid and prevents invalid grid sizes from propagating.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant