Skip to content

refactor(metadata): finish wiring invoke formatter to pydantic union#216

Merged
lstein merged 9 commits intomasterfrom
lstein/feature/refactor-invoke-metadata
Apr 11, 2026
Merged

refactor(metadata): finish wiring invoke formatter to pydantic union#216
lstein merged 9 commits intomasterfrom
lstein/feature/refactor-invoke-metadata

Conversation

@lstein
Copy link
Copy Markdown
Owner

@lstein lstein commented Apr 11, 2026

Summary

  • Completes the mid-flight refactor of InvokeAI metadata parsing by wiring invoke_formatter.py to the new GenerationMetadata2/3/5 discriminated union via a new InvokeMetadataView facade (the formatter was previously importing classes that no longer existed, so opening the drawer on any InvokeAI-generated image raised ImportError).
  • Rebuilds the drawer HTML rendering with cleaner empty-field handling (suppress empty negative prompt, drop copy icon on empty positive prompt, per-column suppression in tuple tables with 1.0 fallback for gaps) and surfaces Flux Redux imageInfluence (e.g. "Medium") in the weight column when no numeric weight is present.
  • Adds 33 regression tests covering view-level extraction and end-to-end HTML rendering for v2/v3/v5 (both ref_images and canvas_v2_metadata paths), plus Flux Redux, mixed weights, ref_images normalization, and empty-field edge cases.

What changed

Pydantic union plumbing

  • New photomap/backend/metadata_modules/invoke/invoke_metadata_view.py — version-agnostic facade that exposes positive_prompt, negative_prompt, model_name, seed, loras, reference_images, control_layers, raster_images. All isinstance-dispatch lives here; the formatter stays ignorant of which v2/v3/v5 shape it's looking at.
  • invoke_formatter.py rewritten as a thin HTML renderer over the view, preserving the existing drawer table layout. Falls back to <i>Unknown invoke metadata format.</i> on Pydantic ValidationError.
  • _normalize_ref_images moved out of GenerationMetadataAdapter.parse and onto GenerationMetadata5 as a @model_validator(mode="before") (addresses a # MOVE THIS CODE TODO).
  • metadata_modules/__init__.py re-exports (SlideSummary, format_exif_metadata, format_invoke_metadata) re-enabled — they had been commented out during the refactor, breaking metadata_formatting.py.
  • Deleted invoke/invoke_metadata_abc.py — dead code, not imported anywhere under photomap/.

Drawer HTML tweaks

  • Empty negative prompt → row suppressed entirely.
  • Empty positive prompt → row present, copy icon suppressed.
  • Tuple tables (loras / reference images / control layers): per-column suppression — drop columns that are empty in every row; drop fully-empty rows; missing weights in a surviving weight column default to 1.0 (InvokeAI's effective default).
  • Flux Redux fallback: IPAdapter.image_influence / RefImageConfig.image_influence (values like "Medium") is displayed in the weight column when no numeric weight is available.

Modernization

  • ruff check photomap/backend/metadata_modules/invoke/ --fix swept 227 typing.Optional/Union/List/Dict usages to PEP 604 / PEP 585 forms (X | None, list[T], dict[K, V]), plus one manual isinstance(x, (int, float))isinstance(x, int | float) fix.

Docs

  • Added CLAUDE.md with orientation for future Claude Code sessions (architecture, commands, metadata subsystem layout).

Test plan

  • pytest tests/backend — 82 passing (including 33 new tests in test_invoke_metadata.py)
  • ruff check photomap/backend/metadata_modules/invoke/ — clean
  • ruff check on all newly-authored / modified files — clean
  • Manual verification in the browser: open the metadata drawer on a representative v2, v3, and v5 (both ref_images and canvas) InvokeAI-generated image and confirm the rendered table matches what the pre-refactor formatter produced
  • Manual verification: open the drawer on a Flux Redux image and confirm the weight column shows the imageInfluence value (e.g. "Medium")

🤖 Generated with Claude Code

lstein and others added 9 commits February 4, 2026 17:42
…lstein/PhotoMapAI into lstein/feature/refactor-invoke-metadata
The invoke metadata refactor left `invoke_formatter.py` pointing at
classes that no longer existed, so opening the drawer on an
InvokeAI-generated image would raise ImportError. This change completes
the wiring and locks in the behavior with regression tests.

- Add `InvokeMetadataView`, a version-agnostic facade over the
  `GenerationMetadata2/3/5` discriminated union, so the formatter
  doesn't sprinkle `isinstance` checks across extraction logic.
- Rewrite `invoke_formatter.py` as a thin HTML renderer on top of the
  view, preserving the existing drawer table layout.
- Move `_normalize_ref_images` out of `GenerationMetadataAdapter.parse`
  and into `GenerationMetadata5` as a `@model_validator(mode="before")`,
  where it belongs.
- Re-enable `metadata_modules/__init__.py` re-exports that had been
  commented out during the refactor.
- Delete the now-unused `invoke/invoke_metadata_abc.py`.
- Drawer HTML tweaks: suppress empty negative-prompt row; keep positive
  prompt row but drop copy icon when empty; per-column suppression in
  tuple tables; fall back to `1.0` when a surviving weight column has
  gaps; surface Flux Redux `imageInfluence` (e.g. "Medium") in the
  weight column when no numeric weight is present.
- Add 33 regression tests in `tests/backend/test_invoke_metadata.py`
  covering view-level extraction and end-to-end HTML rendering for
  v2/v3/v5 (both `ref_images` and `canvas_v2_metadata` paths).
- Run ruff across `invoke/` to modernize `typing.Optional`/`Union`/
  `List`/`Dict` to PEP 604 / PEP 585 forms.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@lstein lstein merged commit b985b8b into master Apr 11, 2026
5 checks passed
@lstein lstein deleted the lstein/feature/refactor-invoke-metadata branch April 11, 2026 21:22
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