Videos were never part of the automated pipeline before -- only reachable
one at a time via a manual "Tag Now" button, and even that just grabbed
one static frame and ran it through the photo model. Now videos are
first-class:
- New extract_video_frames_b64(): samples up to 6 frames spread across
the clip's duration and passes them all to the video model in one
call, so it sees actual motion/progression instead of one snapshot.
Verified live: two different real test videos got distinct,
content-aware descriptions that correctly named what was actually
happening in each, not generic placeholders.
- ollama_generate() now accepts a list of images (photos still pass a
single one, unchanged) so the same call path serves both.
- process_loop merges S.video_files into the same pending queue as
photos, routes videos to a separate configurable video model
(default minicpm-v4.6:1b, a small dedicated vision model) and prompt,
skipping the photo/screenshot router entirely. redo_single (the
lightbox "AI Redo" button) updated the same way for consistency.
- S.total_images is now set to the actual combined pending count for
the run so the progress bar/ETA reflect videos too, not just photos.
- FOUND WHILE TESTING: write_metadata's video branch used "-Keywords"
for the category/photon-tagged marker, which is a silent no-op on
QuickTime/.mov files (exiftool has no mapping for it there) --
confirmed by direct testing. Every video "tagged" before this would
have gotten a description but never an actual category keyword
embedded. Switched to XMP-dc:Subject (the same tag family used for
photos, which QuickTime containers do support via an embedded XMP
packet) -- verified the category now lands and stays idempotent
across repeat writes.
- New frontend controls: video model dropdown and a "tag videos too"
toggle (on by default) in Engine Configurations.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- New "Smart Recategorize" panel: analyzes existing journal descriptions
(no vision re-run, no images touched) to propose a richer category list
when one bucket dominates the library, then reclassifies every tagged
photo into it using a fast local text-only model pass in batches of 25.
Verified end-to-end on the real library: correctly split "Objects &
Stuff" (35% of 15k photos) into specific categories like Electronics &
Hardware, Cannabis Cultivation, Minerals & Crystals, Tools & Workshop
based on what's actually in the descriptions.
- New ollama_generate_text() for text-only local model calls (the
existing ollama_generate always sent an "images" key, unsuitable for
pure text classification).
- FIX: write_metadata only ever appended category/photon-tagged keywords
(+=) to the list-type XMP/IPTC tags, so retagging a photo left every
category it ever had stacked in its metadata, and even rewriting with
the same category duplicated "photon-tagged" each time. Found via a
live test while building this feature (which recategorizes at library
scale). Now strips old values before adding, making every write
idempotent regardless of how many times a photo is retagged. Wired
through all four write sites (pipeline, write_single, redo_single,
bulk_recategorize).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Each source folder now has its own recursive flag (checkbox on add,
toggle badge on its chip). scan_folder/sync_metadata_from_folder both
honor it, so "top-level only" actually excludes subfolders end-to-end
instead of just the tagging queue while sync still scanned recursively.
- New /api/set_folder_recursive to flip an existing folder's mode without
removing/re-adding it.
- SAFETY FIX: found while testing — when the configured folder list is
empty, the app fell back to the parent directory of wherever server.py
lives, which for a typical install (PHOTON dropped directly in the
user's home folder) means defaulting to the entire home directory.
Caught this before any scan/start actually ran against it. Fixed so an
explicitly-configured empty list (config file exists, list is empty)
is respected as "zero folders" instead of silently substituted with a
guessed default — the guessed default now only applies on a genuinely
fresh install where no config file exists yet at all.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Server: S.folder (singular) -> S.folders (list). New /api/add_folder
and /api/remove_folder endpoints; /api/scan and /api/choose_folder
updated to work with the list (choose_folder now appends instead of
replacing). Legacy single-folder config migrates transparently.
- All folders feed one combined pending queue/journal/search, per the
simpler of the two designs discussed.
- organize_alias now resolves each photo's own source folder via
find_owning_folder(), so category aliases land next to the original
instead of in one designated folder -- verified live with two
configured folders that the alias for each photo lands in its own
folder and nothing leaks into the other.
- Delete path-safety, thumbnail/photo serving, resolve_portable_path,
undo_all, and sync-on-scan all extended to check/act across every
configured folder instead of just one.
- Frontend: folder list renders as removable chips; Add (typed path) and
Browse (native picker, now appends) both wired to the new endpoints;
Rescan All re-scans the current set without changing it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The api() helper only sends POST when a body argument is passed;
Browse Folder, Pause, Stop, Retry Failed (x2), Undo All, and Scan for
Duplicates were all called with no body, so they defaulted to GET
against POST-only server routes and 404'd. Verified live via the actual
browser: Pause/Stop now correctly transition server status
(running -> paused -> idle) instead of silently failing.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Search & Edit becomes a multi-view library: Tagged/Untagged/Failed/Videos/Duplicates
- Bulk select (click, shift-click range, select-all-matching) with bulk recategorize,
CSV/JSON export, and original-quality ZIP download (verified byte-identical)
- Video browsing/tagging via ffmpeg frame extraction, native playback with range support
- Duplicate detection via a lightweight perceptual-hash index (no new dependencies)
- Full-resolution photo/video viewer with editable metadata, prev/next navigation
- Date range, file-type, and category quick-filters; saved searches (localStorage)
- Appearance settings: accent color picker, grid density, results-per-page; full dark mode
- Auto-detects its photo folder (CLI arg > env var > last used > parent directory),
so the app can be dropped into any photo collection and just work