Skip to content

Conversation

@BKPatt
Copy link

@BKPatt BKPatt commented Aug 5, 2025

Description

Adds batch report generation functionality to create organized ZIP archives containing generated images with metadata, CSV reports, and configuration details for batch analysis and archival.

Changes Made

  • Added BatchReportGenerator backend utility class for creating batch
    reports
  • Implemented CSV export with required generation metadata columns
  • Created frontend React component for batch report UI
  • Added reportService for handling batch report API calls
  • Added comprehensive test suite for batch report generation
  • Integrated batch report endpoint into extras server

Evidence Required ✅

UI Screenshot

image

Generated Image

N/A - This feature creates reports from existing generated images, not new image generation.

Logs

🔄 Generating batch report with 3 images
BatchReportGenerator initialized with output directory: /tmp/tmpmjy_7bhy
✅ Batch report generated successfully: batch_report_20250805_164138.zip
📊 Report contains: 3 images, CSV metadata, configuration JSON

Tests (Optional)

============================= test session starts ==============================
platform linux -- Python 3.11.3, pytest-7.4.3, pluggy-1.0.0 --
cachedir: .pytest_cache
rootdir: omitted
plugins: anyio-3.7.1
collecting ... collected 11 items

test_batch_report_generator.py::TestBatchReportGenerator::test_initialization PASSED [ 9%]
test_batch_report_generator.py::TestBatchReportGenerator::test_csv_schema_validation PASSED [ 18%]
test_batch_report_generator.py::TestBatchReportGenerator::test_deterministic_file_naming PASSED [ 27%]
test_batch_report_generator.py::TestBatchReportGenerator::test_generate_report_creates_zip PASSED [ 36%]
test_batch_report_generator.py::TestBatchReportGenerator::test_validate_zip_contents PASSED [ 45%]
test_batch_report_generator.py::TestBatchReportGenerator::test_report_with_empty_images PASSED [ 54%]
test_batch_report_generator.py::TestBatchReportGenerator::test_report_name_generation PASSED [ 63%]
test_batch_report_generator.py::TestBatchReportIntegration::test_full_report_generation_workflow PASSED [ 72%]
test_batch_report_generator.py::TestBatchReportIntegration::test_scalability[1] PASSED [ 81%]
test_batch_report_generator.py::TestBatchReportIntegration::test_scalability[10] PASSED [ 90%]
test_batch_report_generator.py::TestBatchReportIntegration::test_scalability[100] PASSED [100%]

============================== 11 passed in 0.33s ==============================

Checklist

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

Summary by Sourcery

Add functionality to generate downloadable ZIP reports of image outputs, including metadata CSV, configuration JSON, image grids, and README documentation via both backend and frontend changes.

New Features:

  • Introduce BatchReportGenerator utility class for creating structured batch report archives.
  • Expose a new backend endpoint (/api/batch-report/generate) to produce and serve ZIP reports containing CSV, JSON, images, and README.
  • Implement a React BatchReportGenerator component and integrate it into the ExtrasPage under a new “Batch Report” tab.
  • Add reportService methods (generateBatchReport and downloadBatchReport) for handling report API calls and client-side downloads.

Enhancements:

  • Integrate batch report feature exports into project utilities and include CORS handling in the extras server.
  • Enhance ExtrasPage UI to allow selecting images from galleries and configure batch report generation options.

Tests:

  • Add comprehensive tests for BatchReportGenerator covering CSV schema validation, ZIP content verification, deterministic naming, empty inputs, report naming, full workflow, and scalability.

Summary by CodeRabbit

  • New Features

    • Introduced a batch report generation tool, allowing users to create and download a ZIP archive containing selected images, metadata (CSV), configuration (JSON), and a README.
    • Added a new "Batch Report" tab to the Extras page, enabling users to select images from galleries and generate comprehensive batch reports.
    • Provided an interactive frontend interface for customizing report content and initiating downloads.
    • Added a backend API endpoint to handle batch report creation and file delivery.
  • Tests

    • Implemented extensive automated tests to ensure the reliability and correctness of batch report generation and validation.

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Aug 5, 2025

Reviewer's Guide

This PR implements end-to-end batch report generation by introducing a BatchReportGenerator utility (handling CSV metadata, config JSON, image copying, README, and ZIP bundling), exposing a new backend endpoint to trigger report creation, integrating a dedicated React component into the UI, adding frontend service methods to POST and download reports, and validating the feature with a comprehensive suite of unit and integration tests.

Sequence diagram for batch report generation request (frontend to backend)

sequenceDiagram
    actor User
    participant Frontend as React UI (BatchReportGenerator)
    participant ReportService as reportService.ts
    participant Backend as Flask /api/batch-report/generate
    participant Generator as BatchReportGenerator (Python)
    User->>Frontend: Click 'Generate Batch Report'
    Frontend->>ReportService: generateBatchReport(images, config, reportName)
    ReportService->>Backend: POST /api/batch-report/generate (JSON)
    Backend->>Generator: generate_report(images_data, config, report_name)
    Generator-->>Backend: ZIP file path
    Backend-->>ReportService: ZIP file (as response)
    ReportService-->>Frontend: ZIP file (Blob)
    Frontend-->>User: Download ZIP file
Loading

Class diagram for BatchReportGenerator utility (backend)

classDiagram
    class BatchReportGenerator {
        +__init__(output_dir: Optional[str])
        +generate_report(images_data: List[Dict], config: Dict, report_name: Optional[str]) str
        +validate_csv_schema(csv_path: str) bool
        +validate_zip_contents(zip_path: str) bool
        -_create_csv(csv_path: str, images_data: List[Dict])
        -_create_config_json(config_path: str, config: Dict)
        -_copy_images(images_data: List[Dict], grids_dir: str) int
        -_create_readme(readme_path: str, images_data: List[Dict], config: Dict)
        -_create_zip(source_dir: str, zip_path: str)
    }
Loading

Class diagram for frontend batch report types and service

classDiagram
    class ImageReportData {
        +id: string
        +filename: string
        +url: string
        +prompt: string
        +negativePrompt?: string
        +timestamp: number
        +settings: GenerationSettings
    }
    class GenerationSettings {
        +model: string
        +sampler: string
        +steps: number
        +cfg_scale: number
        +seed: number
        +width: number
        +height: number
        +[key: string]: any
    }
    class GenerationConfig {
        +session_id?: string
        +generation_date?: string
        +total_images?: number
        +[key: string]: any
    }
    class BatchReportRequest {
        +images: ImageReportData[]
        +config: GenerationConfig
        +report_name?: string
    }
    class BatchReportResponse {
        +status: string
        +message?: string
        +download_url?: string
    }
    ImageReportData --> GenerationSettings
    BatchReportRequest --> ImageReportData
    BatchReportRequest --> GenerationConfig
Loading

File-Level Changes

Change Details Files
Introduce BatchReportGenerator class for assembling batch report archives
  • Defined required CSV schema and deterministic naming logic
  • Implemented methods to create CSV, config JSON, image grids, README, and ZIP packaging
  • Exported BatchReportGenerator in the backend utils package
dream_layer_backend/dream_layer_backend_utils/batch_report_generator.py
dream_layer_backend/dream_layer_backend_utils/__init__.py
Add batch report HTTP endpoint to extras server
  • Implemented /api/batch-report/generate with CORS preflight handling
  • Validated request payload, invoked the generator, and performed ZIP and CSV schema validation
  • Returned the generated ZIP via send_file and handled errors
dream_layer_backend/extras.py
Develop UI component for user-driven batch report configuration and generation
  • Created BatchReportGenerator React component with image selection and report options
  • Managed state for report name, includeConfig, includeReadme, and selected images
  • Integrated API calls to generate and download the ZIP report
dream_layer_frontend/src/components/batch-report/BatchReportGenerator.tsx
Embed batch report functionality into the existing ExtrasPage
  • Added a new 'Batch Report' tab and aggregated gallery images for reporting
  • Imported the component and adjusted Accordion titles based on active tab
  • Mapped image data to ImageReportData structure
dream_layer_frontend/src/features/Extras/ExtrasPage.tsx
Implement frontend service methods for report generation and download
  • Defined BatchReportRequest and GenerationConfig interfaces
  • Added generateBatchReport to POST data and return a Blob
  • Added downloadBatchReport utility to trigger client-side ZIP download
dream_layer_frontend/src/services/reportService.ts
Add tests covering batch report generator functionality and integration
  • Wrote unit tests for initialization, CSV schema validation, naming, report creation, and ZIP validation
  • Included integration tests for end-to-end report workflow and scalability scenarios
  • Used fixtures to mock served images directory and temporary output paths
dream_layer_backend/tests/test_batch_report_generator.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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 5, 2025

Walkthrough

A batch report generation feature was implemented across the backend and frontend. Backend changes introduce a BatchReportGenerator utility for creating ZIP archives containing CSV, JSON, images, and README, with a new Flask API endpoint to trigger report generation. The frontend adds a React component and supporting service to let users select images and download batch reports via the new API. Comprehensive tests cover the backend report generator.

Changes

Cohort / File(s) Change Summary
Backend: Batch Report Generator Utility
dream_layer_backend/dream_layer_backend_utils/batch_report_generator.py
Introduced BatchReportGenerator class with methods to create ZIP reports containing a CSV of image metadata, a JSON config, copied image files, and a README. Includes schema and content validation methods. Handles deterministic file naming, temporary directory management, and error logging.
Backend: Export Utility
dream_layer_backend/dream_layer_backend_utils/__init__.py
Added import and explicit export of BatchReportGenerator in the package's __init__.py by updating the __all__ list.
Backend: API Endpoint
dream_layer_backend/extras.py
Added a new Flask route /api/batch-report/generate for POST and OPTIONS. The endpoint parses input, calls BatchReportGenerator to create a ZIP report, validates output, and returns the file as an attachment. Handles CORS, errors, and logging.
Backend: Tests
dream_layer_backend/tests/test_batch_report_generator.py
New test module with fixtures and tests for BatchReportGenerator: initialization, CSV schema, deterministic naming, ZIP contents, empty input, auto-naming, integration, and scalability. Uses monkeypatching and temporary directories for isolation.
Frontend: Batch Report UI Component
dream_layer_frontend/src/components/batch-report/BatchReportGenerator.tsx
New React component for selecting images, configuring, and triggering batch report generation. Manages UI state, validates input, calls service to generate/download report, and provides user feedback.
Frontend: Extras Page Integration
dream_layer_frontend/src/features/Extras/ExtrasPage.tsx
Added "Batch Report" tab to ExtrasPage, aggregates images from galleries, normalizes data, and renders the BatchReportGenerator component. Updates subtab navigation and displays image data source counts.
Frontend: Report Service
dream_layer_frontend/src/services/reportService.ts
New TypeScript interfaces for report payloads and responses. Implements generateBatchReport to POST data and receive a ZIP blob, and downloadBatchReport to trigger client-side downloads. Handles errors and logs progress.

Sequence Diagram(s)

Batch Report Generation Flow (Frontend to Backend)

sequenceDiagram
    participant User
    participant BatchReportGenerator (React)
    participant reportService.ts
    participant Flask API (/api/batch-report/generate)
    participant BatchReportGenerator (Python)
    participant ZIP File

    User->>BatchReportGenerator (React): Select images, configure, click "Generate"
    BatchReportGenerator (React)->>reportService.ts: generateBatchReport(images, config, name)
    reportService.ts->>Flask API: POST /api/batch-report/generate (JSON)
    Flask API->>BatchReportGenerator (Python): generate_report(images, config, name)
    BatchReportGenerator (Python)->>ZIP File: Create ZIP with CSV, JSON, images, README
    Flask API->>reportService.ts: Return ZIP file (Blob)
    reportService.ts->>BatchReportGenerator (React): Resolve with Blob
    BatchReportGenerator (React)->>User: Trigger file download
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

A bunny hopped through code so bright,
As batch reports took off in flight.
With ZIPs and CSVs in tow,
Images lined up in a row.
Click, download, all with ease—
Backend, frontend, work in peace!
🐇✨

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.

✨ 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 @BKPatt - I've reviewed your changes and they look great!


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 +348 to +365
for i in range(num_images):
images_data.append({
'id': f'img_{i:04d}',
'filename': f'test_image_{i:04d}.png',
'url': f'http://localhost:5001/api/images/test_image_{i:04d}.png',
'prompt': f'Test prompt {i}',
'negativePrompt': 'negative',
'timestamp': 1704067200000 + i * 1000,
'settings': {
'model': 'test_model.safetensors',
'sampler': 'Euler',
'steps': 20,
'cfg_scale': 7.0,
'seed': 12345 + i,
'width': 512,
'height': 512
}
})
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


try:
# Create results.csv
csv_path = os.path.join(temp_dir, 'results.csv')
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): Extract code out into method (extract-method)

headers = reader.fieldnames or []

# Check if all required columns are present
missing_columns = set(REQUIRED_CSV_COLUMNS) - set(headers)
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 named expression to simplify assignment and conditional (use-named-expression)

try:
with zipfile.ZipFile(zip_path, 'r') as zipf:
# Get list of files in ZIP
zip_files = set(zipf.namelist())
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): Extract code out into method (extract-method)


try:
data = request.json
print(f"📊 Batch report generation request received")
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)


# Validate ZIP contents
with zipfile.ZipFile(zip_path, 'r') as zipf:
namelist = zipf.namelist()
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:

zip_path = os.path.join(temp_output_dir, 'test_validation.zip')
with zipfile.ZipFile(zip_path, 'w') as zipf:
# Create CSV content
csv_content = "filename,prompt,negative_prompt,model,sampler,steps,cfg_scale,seed,width,height,timestamp,grid_path\n"
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 assignment and augmented assignment with single assignment [×2] (merge-assign-and-aug-assign)

def test_scalability(self, temp_output_dir, sample_config, num_images):
"""Test report generation with varying numbers of images"""
# Generate many images
images_data = []
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): Convert for loop into list comprehension (list-comprehension)

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: 8

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

8-8: Remove unused import.

The tempfile module is imported but never used in this file.

-import tempfile
dream_layer_backend/tests/test_batch_report_generator.py (2)

1-19: LGTM! Comprehensive test module structure.

The test module is well-organized with proper imports and fixtures. The docstring clearly describes the test scope.

Remove unused import:

-from datetime import datetime

21-84: LGTM! Excellent fixture setup with minor cleanup needed.

The fixtures are well-designed with proper setup and teardown. The mocking approach for the served images directory is clever.

Clean up unused variables:

     # Also patch the _copy_images method to use our temp dir
-    original_copy_images = BatchReportGenerator._copy_images
     def mock_copy_images(self, images_data, grids_dir):
         # Use the stored temp dir instead of the default
         served_images_dir = self._served_images_dir
         copied_count = 0
         
         for idx, image_data in enumerate(images_data):
             try:
                 original_filename = image_data.get('filename')
                 if not original_filename:
                     continue
                     
                 src_path = os.path.join(served_images_dir, original_filename)
                 grid_filename = f"grid_{idx:04d}_{Path(original_filename).stem}.png"
                 dest_path = os.path.join(grids_dir, grid_filename)
                 
                 if os.path.exists(src_path):
                     shutil.copy2(src_path, dest_path)
                     copied_count += 1
                     
-            except Exception as e:
+            except Exception:
                 pass
dream_layer_backend/dream_layer_backend_utils/batch_report_generator.py (1)

194-236: Consider validating image format before copying

The method handles file copying well, but could benefit from validating that files are actually images before copying them.

Add image format validation:

 # Copy file if it exists
 if os.path.exists(src_path):
+    # Validate it's an image file
+    valid_extensions = {'.png', '.jpg', '.jpeg', '.gif', '.webp'}
+    if Path(src_path).suffix.lower() not in valid_extensions:
+        logger.warning(f"File {src_path} is not a valid image format")
+        continue
     shutil.copy2(src_path, dest_path)
     copied_count += 1
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 1e2bb83 and 0e7a7cc.

📒 Files selected for processing (7)
  • dream_layer_backend/dream_layer_backend_utils/__init__.py (2 hunks)
  • dream_layer_backend/dream_layer_backend_utils/batch_report_generator.py (1 hunks)
  • dream_layer_backend/extras.py (2 hunks)
  • dream_layer_backend/tests/test_batch_report_generator.py (1 hunks)
  • dream_layer_frontend/src/components/batch-report/BatchReportGenerator.tsx (1 hunks)
  • dream_layer_frontend/src/features/Extras/ExtrasPage.tsx (6 hunks)
  • dream_layer_frontend/src/services/reportService.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
dream_layer_backend/dream_layer_backend_utils/__init__.py (1)
dream_layer_backend/dream_layer_backend_utils/batch_report_generator.py (1)
  • BatchReportGenerator (35-364)
dream_layer_backend/tests/test_batch_report_generator.py (1)
dream_layer_backend/dream_layer_backend_utils/batch_report_generator.py (6)
  • BatchReportGenerator (35-364)
  • _copy_images (194-236)
  • validate_csv_schema (299-324)
  • _create_csv (126-166)
  • generate_report (60-124)
  • validate_zip_contents (326-364)
🪛 Ruff (0.12.2)
dream_layer_backend/tests/test_batch_report_generator.py

15-15: datetime.datetime imported but unused

Remove unused import: datetime.datetime

(F401)


55-55: Local variable original_copy_images is assigned to but never used

Remove assignment to unused variable original_copy_images

(F841)


75-75: Local variable e is assigned to but never used

Remove assignment to unused variable e

(F841)

dream_layer_backend/extras.py

8-8: tempfile imported but unused

Remove unused import: tempfile

(F401)


330-330: f-string without any placeholders

Remove extraneous f prefix

(F541)

dream_layer_backend/dream_layer_backend_utils/batch_report_generator.py

288-288: Loop control variable dirs not used within loop body

Rename unused dirs to _dirs

(B007)

🪛 Biome (2.1.2)
dream_layer_frontend/src/features/Extras/ExtrasPage.tsx

[error] 390-419: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 421-421: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

🔇 Additional comments (20)
dream_layer_backend/dream_layer_backend_utils/__init__.py (2)

11-11: LGTM! Clean import addition.

The import follows the established pattern and properly exposes the new BatchReportGenerator utility class.


20-22: LGTM! Proper package API exposure.

The BatchReportGenerator is correctly added to the all list, maintaining consistency with the existing public API structure.

dream_layer_frontend/src/features/Extras/ExtrasPage.tsx (3)

6-6: LGTM! Clean imports for batch report functionality.

The imports are well-organized and follow the established patterns for this component.

Also applies to: 24-26


54-55: LGTM! Proper subtab configuration.

The new subtabs are correctly added to the existing navigation structure.


472-478: LGTM! Dynamic accordion title logic.

The conditional title logic properly reflects the active subtab content.

dream_layer_backend/extras.py (1)

6-6: LGTM! Appropriate imports for batch report functionality.

The import changes correctly bring in send_file for ZIP file delivery and BatchReportGenerator for report creation.

Also applies to: 11-11

dream_layer_backend/tests/test_batch_report_generator.py (3)

87-141: LGTM! Well-structured test fixtures.

The sample data fixtures provide realistic test data with proper structure for comprehensive testing.


142-310: LGTM! Comprehensive unit test coverage.

Excellent test coverage including:

  • Initialization validation
  • CSV schema validation with positive/negative cases
  • Deterministic file naming verification
  • ZIP creation and content validation
  • Edge cases like empty image lists
  • Report name generation logic

The test methods are well-structured and cover all critical functionality.


312-382: LGTM! Excellent integration and scalability tests.

The integration tests properly validate the complete workflow, and the parametrized scalability tests ensure the system works with varying data sizes. This demonstrates thorough testing practices.

dream_layer_frontend/src/components/batch-report/BatchReportGenerator.tsx (4)

1-15: LGTM! Clean imports and interface definition.

The imports are well-organized and the component interface is properly typed with clear prop definitions.


16-35: LGTM! Proper state management and effects.

The component state is well-structured, and the useEffect properly handles auto-selection when images change. The select all/deselect all logic is intuitive.


37-83: LGTM! Robust report generation logic.

Excellent implementation with:

  • Proper validation before processing
  • Clean data preparation and configuration
  • Good error handling with user-friendly messages
  • Proper loading state management
  • Toast notifications for feedback

The async/await pattern and error handling follow best practices.


85-184: LGTM! Clean and intuitive UI implementation.

The component UI is well-structured with:

  • Clear visual hierarchy and descriptive elements
  • Proper form controls with appropriate disabled states
  • Good use of icons and loading indicators
  • Accessible labels and descriptions
  • Consistent styling with the design system

The conditional rendering and state-dependent UI updates provide excellent user experience.

dream_layer_frontend/src/services/reportService.ts (1)

41-41: LGTM!

The environment variable handling for the API base URL is correctly implemented using Vite's import.meta.env.

dream_layer_backend/dream_layer_backend_utils/batch_report_generator.py (6)

1-33: LGTM!

The module setup, imports, and constants are well-organized and appropriate.


43-58: LGTM!

The initialization properly handles default and custom output directories with appropriate logging.


126-166: LGTM!

The CSV creation correctly handles the data structure with proper error handling. The method appropriately accesses negativePrompt in camelCase to match the frontend data format.


168-192: LGTM!

The config JSON creation properly includes metadata and handles Unicode characters correctly.


238-276: LGTM!

The README creation provides comprehensive documentation with clear usage instructions.


299-364: LGTM!

The validation methods provide thorough checks for CSV schema and ZIP contents with appropriate error handling.

Comment on lines +84 to +86
temp_dir = os.path.join(self.output_dir, f"{report_name}_temp")
os.makedirs(temp_dir, exist_ok=True)

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

Use tempfile module for safer temporary directory creation

The current implementation could have race conditions if multiple reports are generated simultaneously. Consider using Python's tempfile module for safer temporary directory management.

+import tempfile
+
 # Create temporary directory for report contents
-temp_dir = os.path.join(self.output_dir, f"{report_name}_temp")
-os.makedirs(temp_dir, exist_ok=True)
+temp_dir = tempfile.mkdtemp(prefix=f"{report_name}_", dir=self.output_dir)

This ensures a unique temporary directory and avoids potential race conditions.

📝 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
temp_dir = os.path.join(self.output_dir, f"{report_name}_temp")
os.makedirs(temp_dir, exist_ok=True)
# at the top of the file, alongside the other imports
import tempfile
# Create temporary directory for report contents
temp_dir = tempfile.mkdtemp(prefix=f"{report_name}_", dir=self.output_dir)
🤖 Prompt for AI Agents
In dream_layer_backend/dream_layer_backend_utils/batch_report_generator.py
around lines 84 to 86, replace the manual creation of the temporary directory
using os.path.join and os.makedirs with the tempfile module's functions like
tempfile.mkdtemp or tempfile.TemporaryDirectory. This change will ensure the
temporary directory is uniquely created and managed safely, preventing race
conditions when multiple reports are generated simultaneously.

"""
try:
with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
for root, dirs, files in os.walk(source_dir):
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

Rename unused loop variable

The loop variable dirs is not used within the loop body.

-            for root, dirs, files in os.walk(source_dir):
+            for root, _dirs, files in os.walk(source_dir):
📝 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
for root, dirs, files in os.walk(source_dir):
for root, _dirs, files in os.walk(source_dir):
🧰 Tools
🪛 Ruff (0.12.2)

288-288: Loop control variable dirs not used within loop body

Rename unused dirs to _dirs

(B007)

🤖 Prompt for AI Agents
In dream_layer_backend/dream_layer_backend_utils/batch_report_generator.py at
line 288, the loop variable 'dirs' in the os.walk loop is unused. Rename 'dirs'
to '_' to indicate it is intentionally unused and improve code clarity.

Comment on lines +317 to +398
@app.route('/api/batch-report/generate', methods=['POST', 'OPTIONS'])
def generate_batch_report():
"""Generate a batch report ZIP file containing CSV, JSON, images, and README"""
if request.method == 'OPTIONS':
# Handle preflight request
response = jsonify({'status': 'ok'})
response.headers.add('Access-Control-Allow-Origin', 'http://localhost:8080')
response.headers.add('Access-Control-Allow-Headers', 'Content-Type')
response.headers.add('Access-Control-Allow-Methods', 'POST, OPTIONS')
return response

try:
data = request.json
print(f"📊 Batch report generation request received")

# Validate required fields
if not data:
return jsonify({
'status': 'error',
'message': 'No data provided'
}), 400

images_data = data.get('images', [])
config = data.get('config', {})
report_name = data.get('report_name', None)

if not images_data:
return jsonify({
'status': 'error',
'message': 'No images data provided'
}), 400

print(f"📸 Processing {len(images_data)} images for batch report")

# Initialize the batch report generator
generator = BatchReportGenerator()

# Generate the report
zip_path = generator.generate_report(
images_data=images_data,
config=config,
report_name=report_name
)

# Validate the generated ZIP
if not os.path.exists(zip_path):
return jsonify({
'status': 'error',
'message': 'Failed to generate report ZIP file'
}), 500

# Validate CSV schema
if not generator.validate_csv_schema(os.path.join(os.path.dirname(zip_path), 'results.csv')):
print("⚠️ Warning: CSV schema validation failed, but continuing...")

# Validate ZIP contents
if not generator.validate_zip_contents(zip_path):
print("⚠️ Warning: ZIP contents validation failed, but continuing...")

# Get file info
file_size = os.path.getsize(zip_path)
file_name = os.path.basename(zip_path)

print(f"✅ Batch report generated successfully: {file_name} ({file_size} bytes)")

# Return the file for download
return send_file(
zip_path,
mimetype='application/zip',
as_attachment=True,
download_name=file_name
)

except Exception as e:
print(f"❌ Error generating batch report: {str(e)}")
import traceback
traceback.print_exc()
return jsonify({
'status': 'error',
'message': str(e)
}), 500

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

Fix CSV validation path and f-string issues.

The endpoint implementation is well-structured with proper error handling, but has a few issues:

  1. Line 330: Unnecessary f-string without placeholders
  2. Line 369: CSV validation uses wrong path - the CSV file doesn't exist at that location

Apply these fixes:

-        print(f"📊 Batch report generation request received")
+        print("📊 Batch report generation request received")

         # Validate CSV schema
-        if not generator.validate_csv_schema(os.path.join(os.path.dirname(zip_path), 'results.csv')):
+        # Note: CSV validation should be done on extracted content from ZIP
+        # For now, skip this validation as the CSV is inside the ZIP
         print("⚠️ Warning: CSV schema validation failed, but continuing...")

The rest of the endpoint logic, including CORS handling, input validation, and file delivery, is well-implemented.

🧰 Tools
🪛 Ruff (0.12.2)

330-330: f-string without any placeholders

Remove extraneous f prefix

(F541)

🤖 Prompt for AI Agents
In dream_layer_backend/extras.py around lines 317 to 398, fix two issues: first,
remove the unnecessary f-string on line 330 by replacing it with a regular
string since it has no placeholders; second, correct the CSV validation path on
line 369 by providing the accurate location of the CSV file, ensuring it points
to the actual path where the CSV is generated rather than the incorrect
directory currently used.

Comment on lines +388 to +440
case "report":
// Batch Report tab - generate reports from gallery images
const galleryImages: ImageReportData[] = [...txt2imgImages, ...img2imgImages].map((img, index) => {
// Generate proper filename
let filename: string;
if (img.url.startsWith('data:')) {
// For data URLs, create a filename based on the ID
filename = `${img.id}.png`;
} else {
// For regular URLs, extract the filename
filename = img.url.split('/').pop() || `image_${index}.png`;
}

return {
id: img.id,
filename: filename,
url: img.url,
prompt: img.prompt,
negativePrompt: img.negativePrompt,
timestamp: img.timestamp,
settings: {
model: img.settings?.model || 'unknown',
sampler: img.settings?.sampler || 'unknown',
steps: img.settings?.steps || 20,
cfg_scale: img.settings?.cfg_scale || 7.0,
seed: img.settings?.seed || -1,
width: img.settings?.width || 512,
height: img.settings?.height || 512,
...img.settings
}
};
});

const allImages = galleryImages;

return (
<div className="space-y-4 mb-4">
<BatchReportGenerator
images={allImages}
config={{
session_id: new Date().getTime().toString(),
total_images: allImages.length
}}
/>

{/* Data source indicator */}
{allImages.length > 0 && (
<div className="text-xs text-muted-foreground p-2 bg-muted/50 rounded">
Images available: {txt2imgImages.length} from txt2img, {img2imgImages.length} from img2img
</div>
)}
</div>
);
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

Fix variable scope issue in switch case.

The variable declarations within the switch case can be accessed by other cases, which could lead to unexpected behavior.

Wrap the case content in a block to restrict variable scope:

      case "report":
+       {
        // Batch Report tab - generate reports from gallery images
        const galleryImages: ImageReportData[] = [...txt2imgImages, ...img2imgImages].map((img, index) => {
          // ... rest of the mapping logic
        });
        
        const allImages = galleryImages;
        
        return (
          <div className="space-y-4 mb-4">
            <BatchReportGenerator 
              images={allImages}
              config={{
                session_id: new Date().getTime().toString(),
                total_images: allImages.length
              }}
            />
            
            {/* Data source indicator */}
            {allImages.length > 0 && (
              <div className="text-xs text-muted-foreground p-2 bg-muted/50 rounded">
                Images available: {txt2imgImages.length} from txt2img, {img2imgImages.length} from img2img
              </div>
            )}
          </div>
        );
+       }

The image aggregation and normalization logic looks correct otherwise.

📝 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
case "report":
// Batch Report tab - generate reports from gallery images
const galleryImages: ImageReportData[] = [...txt2imgImages, ...img2imgImages].map((img, index) => {
// Generate proper filename
let filename: string;
if (img.url.startsWith('data:')) {
// For data URLs, create a filename based on the ID
filename = `${img.id}.png`;
} else {
// For regular URLs, extract the filename
filename = img.url.split('/').pop() || `image_${index}.png`;
}
return {
id: img.id,
filename: filename,
url: img.url,
prompt: img.prompt,
negativePrompt: img.negativePrompt,
timestamp: img.timestamp,
settings: {
model: img.settings?.model || 'unknown',
sampler: img.settings?.sampler || 'unknown',
steps: img.settings?.steps || 20,
cfg_scale: img.settings?.cfg_scale || 7.0,
seed: img.settings?.seed || -1,
width: img.settings?.width || 512,
height: img.settings?.height || 512,
...img.settings
}
};
});
const allImages = galleryImages;
return (
<div className="space-y-4 mb-4">
<BatchReportGenerator
images={allImages}
config={{
session_id: new Date().getTime().toString(),
total_images: allImages.length
}}
/>
{/* Data source indicator */}
{allImages.length > 0 && (
<div className="text-xs text-muted-foreground p-2 bg-muted/50 rounded">
Images available: {txt2imgImages.length} from txt2img, {img2imgImages.length} from img2img
</div>
)}
</div>
);
case "report":
{
// Batch Report tab - generate reports from gallery images
const galleryImages: ImageReportData[] = [...txt2imgImages, ...img2imgImages].map((img, index) => {
// Generate proper filename
let filename: string;
if (img.url.startsWith('data:')) {
// For data URLs, create a filename based on the ID
filename = `${img.id}.png`;
} else {
// For regular URLs, extract the filename
filename = img.url.split('/').pop() || `image_${index}.png`;
}
return {
id: img.id,
filename,
url: img.url,
prompt: img.prompt,
negativePrompt: img.negativePrompt,
timestamp: img.timestamp,
settings: {
model: img.settings?.model || 'unknown',
sampler: img.settings?.sampler || 'unknown',
steps: img.settings?.steps || 20,
cfg_scale: img.settings?.cfg_scale || 7.0,
seed: img.settings?.seed || -1,
width: img.settings?.width || 512,
height: img.settings?.height || 512,
...img.settings
}
};
});
const allImages = galleryImages;
return (
<div className="space-y-4 mb-4">
<BatchReportGenerator
images={allImages}
config={{
session_id: new Date().getTime().toString(),
total_images: allImages.length
}}
/>
{/* Data source indicator */}
{allImages.length > 0 && (
<div className="text-xs text-muted-foreground p-2 bg-muted/50 rounded">
Images available: {txt2imgImages.length} from txt2img, {img2imgImages.length} from img2img
</div>
)}
</div>
);
}
🧰 Tools
🪛 Biome (2.1.2)

[error] 390-419: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 421-421: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

🤖 Prompt for AI Agents
In dream_layer_frontend/src/features/Extras/ExtrasPage.tsx around lines 388 to
440, the variables declared inside the "report" case of the switch statement
have function-level scope, which can cause conflicts with other cases. To fix
this, wrap the entire content of the "report" case in curly braces {} to create
a block scope, ensuring variables like galleryImages and allImages are scoped
only within this case.

Comment on lines +1 to +15
export interface BatchReportRequest {
images: ImageReportData[];
config: GenerationConfig;
report_name?: string;
}

export interface ImageReportData {
id: string;
filename: string;
url: string;
prompt: string;
negativePrompt?: string;
timestamp: number;
settings: GenerationSettings;
}
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

Inconsistent naming conventions between interfaces

The interfaces mix snake_case (report_name) and camelCase (negativePrompt) for property names. This inconsistency could lead to confusion and maintenance issues. Consider using a consistent naming convention throughout the TypeScript code and handle the transformation to snake_case when sending requests to the Python backend.

Apply this diff to use consistent camelCase in TypeScript:

 export interface BatchReportRequest {
   images: ImageReportData[];
   config: GenerationConfig;
-  report_name?: string;
+  reportName?: string;
 }

 export interface ImageReportData {
   id: string;
   filename: string;
   url: string;
   prompt: string;
   negativePrompt?: string;
   timestamp: number;
   settings: GenerationSettings;
 }

Then update line 54 to transform the property name when creating the request:

-      report_name: reportName
+      report_name: reportName  // Transform to snake_case for backend

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In dream_layer_frontend/src/services/reportService.ts lines 1 to 15, the
interface properties use inconsistent naming conventions, mixing snake_case and
camelCase. Change all property names to camelCase, specifically rename
'report_name' to 'reportName' in the BatchReportRequest interface. Then, in the
code that sends requests to the Python backend (around line 54), transform
'reportName' back to 'report_name' to maintain compatibility with the backend
API.

Comment on lines +17 to +33
export interface GenerationSettings {
model: string;
sampler: string;
steps: number;
cfg_scale: number;
seed: number;
width: number;
height: number;
[key: string]: any;
}

export interface GenerationConfig {
session_id?: string;
generation_date?: string;
total_images?: number;
[key: string]: any;
}
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

Continue using camelCase for TypeScript interface properties

The GenerationSettings and GenerationConfig interfaces also use snake_case for properties like cfg_scale, session_id, generation_date, and total_images.

Apply this diff for consistency:

 export interface GenerationSettings {
   model: string;
   sampler: string;
   steps: number;
-  cfg_scale: number;
+  cfgScale: number;
   seed: number;
   width: number;
   height: number;
   [key: string]: any;
 }

 export interface GenerationConfig {
-  session_id?: string;
-  generation_date?: string;
-  total_images?: number;
+  sessionId?: string;
+  generationDate?: string;
+  totalImages?: number;
   [key: string]: any;
 }
📝 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
export interface GenerationSettings {
model: string;
sampler: string;
steps: number;
cfg_scale: number;
seed: number;
width: number;
height: number;
[key: string]: any;
}
export interface GenerationConfig {
session_id?: string;
generation_date?: string;
total_images?: number;
[key: string]: any;
}
export interface GenerationSettings {
model: string;
sampler: string;
steps: number;
cfgScale: number;
seed: number;
width: number;
height: number;
[key: string]: any;
}
export interface GenerationConfig {
sessionId?: string;
generationDate?: string;
totalImages?: number;
[key: string]: any;
}
🤖 Prompt for AI Agents
In dream_layer_frontend/src/services/reportService.ts between lines 17 and 33,
the interfaces GenerationSettings and GenerationConfig use snake_case property
names like cfg_scale, session_id, generation_date, and total_images. Rename
these properties to camelCase (cfgScale, sessionId, generationDate, totalImages)
to maintain consistent camelCase naming conventions throughout the TypeScript
codebase.

Comment on lines +43 to +79
export const generateBatchReport = async (
images: ImageReportData[],
config: GenerationConfig,
reportName?: string
): Promise<Blob> => {
try {
console.log('🔄 Generating batch report with', images.length, 'images');

const requestData: BatchReportRequest = {
images,
config,
report_name: reportName
};

const response = await fetch(`${EXTRAS_API_BASE_URL}/api/batch-report/generate`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(requestData),
});

if (!response.ok) {
const errorData = await response.json().catch(() => ({ message: 'Unknown error' }));
throw new Error(errorData.message || `Failed to generate report: ${response.statusText}`);
}

// The response should be a blob (ZIP file)
const blob = await response.blob();
console.log('✅ Batch report generated successfully, size:', blob.size, 'bytes');

return blob;
} catch (error) {
console.error('❌ Error generating batch report:', error);
throw error;
}
};
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

Add input validation and make console logging conditional

The function should validate inputs before making the API call. Also, consider making console logs conditional based on a debug flag to avoid cluttering production logs.

Add input validation at the beginning of the function:

 export const generateBatchReport = async (
   images: ImageReportData[],
   config: GenerationConfig,
   reportName?: string
 ): Promise<Blob> => {
+  // Validate inputs
+  if (!images || images.length === 0) {
+    throw new Error('At least one image is required for batch report generation');
+  }
+  
+  if (!config) {
+    throw new Error('Configuration is required for batch report generation');
+  }
+
   try {
-    console.log('🔄 Generating batch report with', images.length, 'images');
+    if (import.meta.env.DEV) {
+      console.log('🔄 Generating batch report with', images.length, 'images');
+    }

Also update line 72:

-    console.log('✅ Batch report generated successfully, size:', blob.size, 'bytes');
+    if (import.meta.env.DEV) {
+      console.log('✅ Batch report generated successfully, size:', blob.size, 'bytes');
+    }
📝 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
export const generateBatchReport = async (
images: ImageReportData[],
config: GenerationConfig,
reportName?: string
): Promise<Blob> => {
try {
console.log('🔄 Generating batch report with', images.length, 'images');
const requestData: BatchReportRequest = {
images,
config,
report_name: reportName
};
const response = await fetch(`${EXTRAS_API_BASE_URL}/api/batch-report/generate`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(requestData),
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({ message: 'Unknown error' }));
throw new Error(errorData.message || `Failed to generate report: ${response.statusText}`);
}
// The response should be a blob (ZIP file)
const blob = await response.blob();
console.log('✅ Batch report generated successfully, size:', blob.size, 'bytes');
return blob;
} catch (error) {
console.error('❌ Error generating batch report:', error);
throw error;
}
};
export const generateBatchReport = async (
images: ImageReportData[],
config: GenerationConfig,
reportName?: string
): Promise<Blob> => {
// Validate inputs
if (!images || images.length === 0) {
throw new Error('At least one image is required for batch report generation');
}
if (!config) {
throw new Error('Configuration is required for batch report generation');
}
try {
if (import.meta.env.DEV) {
console.log('🔄 Generating batch report with', images.length, 'images');
}
const requestData: BatchReportRequest = {
images,
config,
report_name: reportName
};
const response = await fetch(`${EXTRAS_API_BASE_URL}/api/batch-report/generate`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(requestData),
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({ message: 'Unknown error' }));
throw new Error(errorData.message || `Failed to generate report: ${response.statusText}`);
}
// The response should be a blob (ZIP file)
const blob = await response.blob();
if (import.meta.env.DEV) {
console.log('✅ Batch report generated successfully, size:', blob.size, 'bytes');
}
return blob;
} catch (error) {
console.error('❌ Error generating batch report:', error);
throw error;
}
};
🤖 Prompt for AI Agents
In dream_layer_frontend/src/services/reportService.ts between lines 43 and 79,
add input validation at the start of the generateBatchReport function to check
that the images array is not empty and config is defined, throwing an error if
validation fails. Additionally, introduce a debug flag parameter or use an
existing one to conditionally enable console.log statements, wrapping all
console logs in checks for this flag to prevent cluttering production logs.

Comment on lines +81 to +91
export const downloadBatchReport = (blob: Blob, filename?: string) => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename || `report_${new Date().toISOString().split('T')[0]}.zip`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
console.log('📥 Batch report downloaded');
}; No newline at end of file
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

Add blob validation and make logging conditional

The function should validate the blob parameter and use conditional logging.

 export const downloadBatchReport = (blob: Blob, filename?: string) => {
+  if (!blob || blob.size === 0) {
+    throw new Error('Invalid or empty blob provided for download');
+  }
+
   const url = window.URL.createObjectURL(blob);
   const a = document.createElement('a');
   a.href = url;
   a.download = filename || `report_${new Date().toISOString().split('T')[0]}.zip`;
   document.body.appendChild(a);
   a.click();
   document.body.removeChild(a);
   window.URL.revokeObjectURL(url);
-  console.log('📥 Batch report downloaded');
+  if (import.meta.env.DEV) {
+    console.log('📥 Batch report downloaded');
+  }
 };
📝 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
export const downloadBatchReport = (blob: Blob, filename?: string) => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename || `report_${new Date().toISOString().split('T')[0]}.zip`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
console.log('📥 Batch report downloaded');
};
export const downloadBatchReport = (blob: Blob, filename?: string) => {
if (!blob || blob.size === 0) {
throw new Error('Invalid or empty blob provided for download');
}
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename || `report_${new Date().toISOString().split('T')[0]}.zip`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
if (import.meta.env.DEV) {
console.log('📥 Batch report downloaded');
}
};
🤖 Prompt for AI Agents
In dream_layer_frontend/src/services/reportService.ts around lines 81 to 91, the
downloadBatchReport function lacks validation for the blob parameter and always
logs a message. Add a check to ensure the blob is valid before proceeding with
the download logic. Also, modify the logging to be conditional, for example,
only logging if a debug flag is enabled or if the download succeeds, to avoid
unnecessary console output.

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