Conversation
…OSSIE-Org#1501) * initial-fix * coderabbit-fixes * coderabbit-changes-2 * coderabbit-fixes-3 * UX-changes
Adds a nullable faces.frame_id referencing video_frames(id), so a face can come from a sampled keyframe instead of a photo. Image and video faces stay in one table because clustering must see every face in a single DBSCAN run. Nothing writes frame_id yet. Guarded ALTER migrates shipped databases; the exclusive arc is enforced in Python since SQLite cannot ALTER in a CHECK.
Route faces.py through a module-private _connect(), as images.py does. Tagging now skips an image deleted mid-inference instead of aborting.
Rows written before enforcement can point at deleted images, keyframes or clusters. A video face's NULL image_id is by design, not an orphan.
FaceDetector.detect_faces now takes only a path and returns a typed result; the image tagging loop persists the faces and owns the deleted-image guard. Face search reuses the detector's embedding instead of a second FaceNet.
Keyframes YOLO saw a person in are face-detected; faces are deduplicated, capped per video and stored against their keyframe. Off by default: a full recluster chains through them and fused 7 people on a real library. Keyframes are now saved at 1280px so faces clear the size gate.
Keyframe faces never reach DBSCAN and never move a cluster mean; they join the nearest photo cluster at the same-person threshold, one per keyframe per cluster. On the real library the photo clusters now match a photos-only recluster exactly, and 14 of 20 test videos attach to a known person.
VideoData and its converter move to the schema and utils modules so the face cluster surfaces can return videos in the videos routes' shape instead of declaring a near-identical model of their own.
Opening a person now lists the videos they were found in, played with the same card and player as the videos page. Face counts stay photo-only so the "N photos" label and the People ordering keep their meaning; videos are counted alongside.
Searching for people together now also finds the videos they appear in, ranked by how many of them are present, and the AI tagging page lists them under the photos. Video results only render while a search is active, so the videos page's own list never leaks in.
Searching with a photo or the webcam now also finds videos the same face appears in, each listed once and ranked by its best-matching keyframe. The home gallery shows them only while a search is active.
Video face detection moves from an env-only switch to a user preference in Settings under Video Tagging, defaulting to off: it runs a second detector over every keyframe showing a person, so it is opt-in.
Update the PR MyPy file-selection logic to diff with three-dot (BASE...HEAD) so checks run against changes since the merge base, not a direct base/head comparison. Added explicit commit resolution guards before diffing to fail clearly when SHAs are unavailable. Synced the same behavior and commands in CI gate reference docs and the pre-PR check skill.
Videos tagged before finding people in videos was turned on have no keyframe faces and no way to be found again: isTagged is already 1, so the tagging pass skips them forever. facesScanned records the face pass separately, and the queries here are what a backfill selects on.
Classifies the keyframes already on disk and re-samples only the ones showing a person, at the resolution their source allows: YOLO letterboxes to its own input size, so what is stored decides whether a face can be embedded, not whether a person is found. Frame rows and their SigLIP2 embeddings are left in place, which a re-tag would have thrown away.
The scan runs on the shared executor and reports its progress from the facesScanned counts, so a caller can poll a pass that takes over an hour. It also runs as part of any later tagging or sync, so a library tagged before the setting existed catches up on its own.
The switch only ever applied to videos tagged after it, which on an existing library means nothing happens. A button beside it starts the scan and reports progress from the backend's counts, so a scan another pass started reads correctly too.
Covers keyframe face detection, why video faces attach to photo clusters instead of being clustered, the backfill scan and its Settings button, and regenerates openapi.json. Also corrects face-pipeline figures that had drifted from the code: 128-D embeddings, 0.45 face confidence, the adaptive DBSCAN eps and the real reclustering triggers.
- Hide clusters left with only keyframe faces from the People listing - Count scan progress over tagged videos only, so it can reach 100% - Report whether the Settings scan is running or failed, and allow a retry - Keep scanning and tagging the remaining videos when one fails - Type the face search, multi-person and cluster image responses - Show AI Tagging's empty state only when no videos matched either
- Guard the scan's running check and submission with a lock - Render the videos a typed people search returns, even with no photos - Describe multi-person search results as photos and videos
…-embedding-processing- Feat: find people in videos
Root-relative runs mapped files to backend.app.* or bare names, so app.* imports went unresolved and errors were missed.
Plain 'backend/**/*.py' pathspecs skipped backend/main.py and sync-microservice/main.py.
…integration CI: add changed-file MyPy checks
…1561) * fix(backend): return HTTP 404 when image is not in album Return HTTP 404 NOT FOUND instead of HTTP 500 INTERNAL SERVER ERROR when attempting to remove an image that does not exist in an album. Added unit test test_remove_image_not_in_album_returns_404 to verify. Signed-off-by: Vijay <vjkumar2756@gmail.com> * style(backend): format test_albums.py with black --------- Signed-off-by: Vijay <vjkumar2756@gmail.com>
Removed duplicate logger initialization that was overwriting the custom logger configured via get_logger() with a standard logging.getLogger(). Changes: - Removed unused 'import logging' statement - Removed duplicate 'logger = logging.getLogger(__name__)' that overwrote the properly configured logger from get_logger() This restores consistent logging behavior with color formatting and component-specific prefixes.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. 🗂️ Base branches to auto review (1)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
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. Comment |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
Link your account with GitcordThanks for opening this PR, @Jah-yee! To receive Discord notifications and contributor tracking for this organization:
Once linked, Gitcord can notify you about reviews, merges, and more. — Posted by Gitcord |
Summary
Fixed duplicate logger initialization in
backend/app/utils/images.pythat was overwriting the project's custom logger.Changes
import loggingstatementlogger = logging.getLogger(__name__)on line 40 that was overwriting the properly configured logger fromget_logger(__name__)Impact
good-first-issueBUG: Duplicate Logger Initialization inbackend/app/utils/images.py#815