Skip to content

feat: albums backed by InvokeAI image-gallery boards#331

Merged
lstein merged 2 commits into
masterfrom
lstein/feature/invokeai-board-albums
Jun 12, 2026
Merged

feat: albums backed by InvokeAI image-gallery boards#331
lstein merged 2 commits into
masterfrom
lstein/feature/invokeai-board-albums

Conversation

@lstein

@lstein lstein commented Jun 12, 2026

Copy link
Copy Markdown
Owner

Summary

Adds a second album source type: an album can now mirror one or more InvokeAI gallery boards instead of scanning a local directory tree. When creating an album, a radio pair selects between Directory of Image Files (default, unchanged) and An InvokeAI Image Gallery Board.

For board albums, the form takes the InvokeAI backend URL (prefilled from Settings), the locally-accessible InvokeAI root directory (filetree picker — deliberately not fetched via the API), and optional credentials, then loads the board list into a multi-select checklist. Indexing fetches the boards' image names from the InvokeAI API, resolves them to <root>/outputs/images/<name>, and feeds the explicit file list through the existing Embeddings pipeline — so "Update Index" naturally picks up images added to or removed from the boards.

Design decisions

  • Deletion goes through the InvokeAI API (DELETE /api/v1/images/i/{name}), never send2trash — deleting files directly would leave dangling rows in InvokeAI's database. move_images is rejected for board albums for the same reason.
  • Indexes live in the platformdirs data dir (user_data_dir("photomap")/indexes/<album_key>/embeddings.npz), derived server-side; album keys are sanitized against path traversal, and deleting a board album removes its derived index directory.
  • Credentials never reach the browser. Album endpoints expose has_invokeai_password instead of the password; the probe/board-listing endpoints resolve stored passwords server-side and only ever pair a stored password with its own username. The form surfaces this by prefilling the Settings username and noting the saved password will be used (cleared when the URL points at a different backend).
  • Source type is immutable after creation (radios disabled on edit) — avoids index/path migration.
  • image_paths is derived as [<root>/outputs/images] so image serving and access validation work unchanged; HTTP helpers were extracted from routers/invoke.py into a shared invokeai_client.py so the indexing/curation layers don't import a router.

Robustness fixes found while testing against a live InvokeAI

  • The add-form entrance animation clamped the section at 600px (forwards fill), overflowing the taller board form and hiding the Add Album button.
  • Progress pollers held the card element captured at kickoff; card rebuilds mid-indexing left the visible card frozen at "Indexing in progress..." while the backend completed. Pollers now re-resolve the live card every tick, and freshly added albums are guarded against a duplicate racing kickoff (which also fixes occasional spurious 409 alerts for directory albums).
  • Indexing log lines no longer dump the full resolved file list (thousands of paths for board albums) — long explicit lists are summarized as a count + common parent.
  • Unreachable backend / wrong root fail fast with pointed progress errors and never touch an existing index.

Tests

  • Backend: board-album CRUD, YAML round-trip, legacy-config compatibility, password-leak guards, probe endpoints incl. credential-pairing rules, and end-to-end indexing / board-membership updates / API-routed deletion / move rejection against a stubbed InvokeAI client.
  • Frontend (Jest): source toggle, board checklist, add/edit payload shapes, settings-credential surfacing, animation clamp removal, and poller live-card resolution.
  • Verified manually against a real multi-user InvokeAI 5.x instance (2,093 images across 4 boards): connect → board select → index → re-index after board changes → delete-from-PhotoMap reflected in InvokeAI's gallery.

🤖 Generated with Claude Code

lstein and others added 2 commits June 11, 2026 22:30
Adds a second album source type: instead of scanning a local directory
tree, an album can mirror one or more boards on a running InvokeAI
instance. Board contents are fetched via the InvokeAI HTTP API and
resolved to local files under <invokeai_root>/outputs/images; the
existing Embeddings pipeline indexes the explicit file list unchanged,
so re-indexing naturally tracks board additions/removals.

Backend:
- New photomap/backend/invokeai_client.py: auth/token-cache helpers
  extracted from routers/invoke.py plus board-listing, image-name and
  image-delete wrappers usable outside the router layer.
- Album model: source_type discriminator + per-album InvokeAI
  connection fields. image_paths and the index path are derived
  server-side (index lives in user_data_dir/indexes/<key>/, album key
  sanitized against traversal). Legacy YAML loads unchanged.
- POST /invokeai/probe_status and /probe_boards let the album form
  validate a URL and list boards before anything is saved; stored
  passwords are resolved server-side, only ever paired with their own
  username, and never sent to the browser (album endpoints expose
  has_invokeai_password instead).
- Deletion in board albums goes through the InvokeAI API so its
  database stays consistent; move_images is rejected; deleting a board
  album cleans up its derived index directory.
- Indexing failures (unreachable backend, wrong root) fail fast with
  pointed progress errors and leave any existing index untouched.
- Log lines that previously interpolated the full image-path list now
  summarize explicit lists (count + common parent).

Frontend:
- Add/edit album forms get a Directory / InvokeAI Board source toggle
  (immutable after creation), connection check, root-dir filetree
  picker, optional credentials, and a board multi-select checklist.
  Username/password defaults from the settings panel are surfaced in
  the form and cleared when the URL points elsewhere.
- The add-form entrance animation no longer clamps the section at
  600px (the taller board form previously overflowed it, hiding the
  Add Album button).
- Indexing progress pollers re-resolve the album card on every tick,
  fixing a race where card rebuilds mid-indexing left the UI frozen at
  "Indexing in progress..."; freshly added albums are guarded against
  a duplicate, racing auto-index kickoff (stray 409 alerts).

Tests: board-album CRUD/round-trip/password-leak guards, probe
endpoints incl. credential-pairing rules, end-to-end board indexing /
membership-update / deletion / move-rejection against a stubbed
InvokeAI client, and Jest coverage for the form payloads, checklist,
animation clamp and poller card resolution.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The assertions hardcoded POSIX separators, but str(Path(...)) and
os.path.commonpath use backslashes on Windows. Build the expected
strings from the same Path round-trips instead of literals.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@lstein lstein merged commit 911fe26 into master Jun 12, 2026
10 checks passed
@lstein lstein deleted the lstein/feature/invokeai-board-albums branch June 12, 2026 02:53
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