pub struct FaceRepo<'a> { /* private fields */ }Expand description
Face database repository
Implementations§
Source§impl<'a> FaceRepo<'a>
impl<'a> FaceRepo<'a>
pub fn refresh_all_galleries(&self) -> SqliteResult<()>
Sourcepub fn face_thumbnail_candidates(
&self,
cluster_ids: &[i64],
max_per_cluster: usize,
) -> SqliteResult<HashMap<i64, Vec<i64>>>
pub fn face_thumbnail_candidates( &self, cluster_ids: &[i64], max_per_cluster: usize, ) -> SqliteResult<HashMap<i64, Vec<i64>>>
Return fallback face thumbnail candidates for the supplied clusters.
The rows are ordered by cluster, then by face confidence descending. Callers can check the corresponding crop files outside the shared DB mutex and then persist any representative replacement in one batch.
pub fn update_representative_faces( &self, updates: &[(i64, i64)], ) -> SqliteResult<()>
Sourcepub fn normalize_cluster_stats(&self) -> SqliteResult<()>
pub fn normalize_cluster_stats(&self) -> SqliteResult<()>
Recompute all cluster stats and prune empty clusters.
Sourcepub fn populate_face_thumbnails(
&self,
clusters: &mut [FaceClusterRecord],
drive_path: &Path,
) -> SqliteResult<()>
pub fn populate_face_thumbnails( &self, clusters: &mut [FaceClusterRecord], drive_path: &Path, ) -> SqliteResult<()>
Populate face thumbnail paths on cluster records.
Call this after get_all_clusters() with the drive root path. The
path written into each cluster is relative to drive_root (e.g.
.photovault/faces/42.jpg) so it round-trips through the same
frontend thumbUrl() helper as photos.thumbnail_path.
Source§impl<'a> FaceRepo<'a>
impl<'a> FaceRepo<'a>
Sourcepub fn count_pending_face_processing(&self) -> SqliteResult<i64>
pub fn count_pending_face_processing(&self) -> SqliteResult<i64>
Count of photos that haven’t yet had face detection run. Drives the “Resume face detection” banner on the People page.
Sourcepub fn get_unclustered_faces_with_photo_embeddings(
&self,
) -> SqliteResult<Vec<(i64, i64, FaceEmbedding)>>
pub fn get_unclustered_faces_with_photo_embeddings( &self, ) -> SqliteResult<Vec<(i64, i64, FaceEmbedding)>>
Get unclustered faces with photo_id and embeddings.
Sourcepub fn get_all_clusters(&self) -> SqliteResult<Vec<FaceClusterRecord>>
pub fn get_all_clusters(&self) -> SqliteResult<Vec<FaceClusterRecord>>
Get all clusters, ordered by photo count descending
pub fn get_gallery_embeddings(&self) -> SqliteResult<Vec<GalleryEmbedding>>
pub fn get_cluster_photo_ids(&self) -> SqliteResult<Vec<(i64, i64)>>
Sourcepub fn get_people_for_photo(
&self,
photo_id: i64,
) -> SqliteResult<Vec<(i64, String)>>
pub fn get_people_for_photo( &self, photo_id: i64, ) -> SqliteResult<Vec<(i64, String)>>
Get person names for a photo (faces detected in this photo with cluster names) Get (cluster_id, display_name) pairs for all people detected in a photo.
Sourcepub fn get_photos_for_cluster(&self, cluster_id: i64) -> SqliteResult<Vec<i64>>
pub fn get_photos_for_cluster(&self, cluster_id: i64) -> SqliteResult<Vec<i64>>
Get all photo IDs that contain faces from a given cluster
Sourcepub fn get_all_faces_with_paths(
&self,
) -> SqliteResult<Vec<(i64, String, i32, f32, f32, f32, f32)>>
pub fn get_all_faces_with_paths( &self, ) -> SqliteResult<Vec<(i64, String, i32, f32, f32, f32, f32)>>
Get all face IDs with bounding boxes and their photo file paths. Used for regenerating missing face crops.
Sourcepub fn get_contextual_cluster_candidates(
&self,
photo_id: i64,
folder_prefix_like: Option<&str>,
target_ts: i64,
window_secs: i64,
) -> SqliteResult<Vec<(i64, i64, i64, String)>>
pub fn get_contextual_cluster_candidates( &self, photo_id: i64, folder_prefix_like: Option<&str>, target_ts: i64, window_secs: i64, ) -> SqliteResult<Vec<(i64, i64, i64, String)>>
Find contextual candidate identities from nearby photos in the same folder.
Sourcepub fn get_unprocessed_photos_with_context(
&self,
) -> SqliteResult<Vec<(i64, String, i32, Option<i64>, String)>>
pub fn get_unprocessed_photos_with_context( &self, ) -> SqliteResult<Vec<(i64, String, i32, Option<i64>, String)>>
Get unprocessed photos with optional timestamp for contextual identity linking.
Sourcepub fn get_photo_brightness(&self, photo_id: i64) -> SqliteResult<Option<f32>>
pub fn get_photo_brightness(&self, photo_id: i64) -> SqliteResult<Option<f32>>
Read the cached photos.brightness value for a photo. Returns
None if the photo doesn’t exist OR brightness was never
computed (NULL in the column). Caller is expected to fall back
to on-disk recomputation in that case.
Sourcepub fn review_queue_size(&self) -> SqliteResult<i64>
pub fn review_queue_size(&self) -> SqliteResult<i64>
Count of unresolved entries in the face review queue.
Sourcepub fn get_review_queue_items(
&self,
limit: usize,
) -> SqliteResult<Vec<ReviewItem>>
pub fn get_review_queue_items( &self, limit: usize, ) -> SqliteResult<Vec<ReviewItem>>
Pull the top-N most informative unresolved review items.
Ordered by ambiguity ascending (closer top-2 scores first = higher information gain) then by candidate cluster size descending (resolving ambiguity on big clusters propagates to more photos).
Sourcepub fn get_photo_other_clusters(
&self,
photo_id: i64,
exclude_face_id: i64,
) -> SqliteResult<Vec<i64>>
pub fn get_photo_other_clusters( &self, photo_id: i64, exclude_face_id: i64, ) -> SqliteResult<Vec<i64>>
Cluster IDs of the already-assigned faces in the given photo (other than the face we’re resolving). Used as the “context” in co-occurrence.
Sourcepub fn cooccurrence_count(
&self,
cluster_a: i64,
cluster_b: i64,
) -> SqliteResult<i64>
pub fn cooccurrence_count( &self, cluster_a: i64, cluster_b: i64, ) -> SqliteResult<i64>
How many photos contain both cluster_a and cluster_b.
Used as the co-occurrence strength between two clusters. High values mean the two people appear together frequently and should bias retrieval toward whichever matches the rest of the photo’s cast.
Sourcepub fn temporal_neighbor_clusters(
&self,
photo_id: i64,
window_secs: i64,
) -> SqliteResult<Vec<(i64, i64)>>
pub fn temporal_neighbor_clusters( &self, photo_id: i64, window_secs: i64, ) -> SqliteResult<Vec<(i64, i64)>>
Clusters assigned to faces within a time window around date_taken,
excluding the photo itself. Returns (cluster_id, delta_seconds).
Used for temporal-chain propagation: if nearby-in-time photos contain high-confidence assignments for cluster X, an ambiguous face in our photo should be biased toward X.
Sourcepub fn get_faces_by_cluster(
&self,
cluster_id: i64,
status: FaceStatus,
cursor: Option<i64>,
limit: usize,
) -> SqliteResult<Vec<FaceDetail>>
pub fn get_faces_by_cluster( &self, cluster_id: i64, status: FaceStatus, cursor: Option<i64>, limit: usize, ) -> SqliteResult<Vec<FaceDetail>>
Get faces for a cluster filtered by status.
Sourcepub fn get_unclustered_faces(
&self,
cursor: Option<i64>,
limit: usize,
) -> SqliteResult<Vec<FaceDetail>>
pub fn get_unclustered_faces( &self, cursor: Option<i64>, limit: usize, ) -> SqliteResult<Vec<FaceDetail>>
Recently detected faces that are not assigned to a person yet. Used only as a live, in-progress surface while the face pipeline is still clustering. The final People grid remains cluster-based.
Sourcepub fn count_unconfirmed_in_cluster(&self, cluster_id: i64) -> SqliteResult<i64>
pub fn count_unconfirmed_in_cluster(&self, cluster_id: i64) -> SqliteResult<i64>
Count unconfirmed faces in a cluster.
Sourcepub fn count_unconfirmed_global(&self) -> SqliteResult<(i64, i64)>
pub fn count_unconfirmed_global(&self) -> SqliteResult<(i64, i64)>
Count unconfirmed faces across all clusters. Returns (total_unconfirmed, clusters_with_unconfirmed).
Sourcepub fn next_unconfirmed_face_batch(
&self,
limit: usize,
) -> SqliteResult<Vec<FaceDetail>>
pub fn next_unconfirmed_face_batch( &self, limit: usize, ) -> SqliteResult<Vec<FaceDetail>>
Return the next batch of unconfirmed faces from the cluster with the most pending review work. This keeps the review UI O(1) instead of probing every person until it finds one with faces.
Sourcepub fn next_unconfirmed_face_batch_excluding(
&self,
limit: usize,
excluded_face_ids: &[i64],
) -> SqliteResult<Vec<FaceDetail>>
pub fn next_unconfirmed_face_batch_excluding( &self, limit: usize, excluded_face_ids: &[i64], ) -> SqliteResult<Vec<FaceDetail>>
Return the next review batch while ignoring faces the current UI session has skipped. Skips are intentionally not persisted as a reject/confirm decision, but they still need to be excluded from the server-side cluster selection or the reviewer can be sent straight back to the same skipped-only cluster.
Sourcepub fn get_negatives_for_face(&self, face_id: i64) -> SqliteResult<Vec<i64>>
pub fn get_negatives_for_face(&self, face_id: i64) -> SqliteResult<Vec<i64>>
Get negatives for a face (clusters it should NOT be in).
Source§impl<'a> FaceRepo<'a>
impl<'a> FaceRepo<'a>
Sourcepub fn reset_if_no_faces(&self) -> SqliteResult<usize>
pub fn reset_if_no_faces(&self) -> SqliteResult<usize>
Reset faces_processed flags when no faces were actually detected.
This handles the case where a prior run marked all photos as processed but failed to actually detect faces (e.g., model loading error).
Sourcepub fn name_cluster(&self, cluster_id: i64, name: &str) -> SqliteResult<()>
pub fn name_cluster(&self, cluster_id: i64, name: &str) -> SqliteResult<()>
Name a cluster (set the person’s name)
Sourcepub fn delete_cluster(&self, cluster_id: i64) -> SqliteResult<()>
pub fn delete_cluster(&self, cluster_id: i64) -> SqliteResult<()>
Delete a face cluster — “this isn’t a real person” gesture.
Faces previously assigned to this cluster have their cluster_id
set to NULL so a future re-clustering pass can pick them up
again. Inferred-identity links and gallery embeddings rooted at
the cluster cascade away (FK ON DELETE CASCADE in the schema).
Sourcepub fn assign_face_to_cluster(
&self,
face_id: i64,
cluster_id: i64,
) -> SqliteResult<()>
pub fn assign_face_to_cluster( &self, face_id: i64, cluster_id: i64, ) -> SqliteResult<()>
Assign an existing face to an existing cluster and update cluster metadata.
Sourcepub fn create_cluster(&self, face_ids: &[i64]) -> SqliteResult<i64>
pub fn create_cluster(&self, face_ids: &[i64]) -> SqliteResult<i64>
Create a new face cluster from a set of face IDs
Sourcepub fn merge_clusters(&self, source_id: i64, target_id: i64) -> SqliteResult<()>
pub fn merge_clusters(&self, source_id: i64, target_id: i64) -> SqliteResult<()>
Merge source cluster into target cluster
Moves all faces from source to target, updates counts, deletes source. Refuses if a cannot-merge constraint exists between the two clusters.
Sourcepub fn get_cannot_merge_map(&self) -> SqliteResult<HashMap<i64, HashSet<i64>>>
pub fn get_cannot_merge_map(&self) -> SqliteResult<HashMap<i64, HashSet<i64>>>
Load all cannot-merge pairs (returns them in both directions for easy lookup).
Sourcepub fn enqueue_review(
&self,
face_id: i64,
candidate_cluster_id: i64,
score: f32,
ambiguity: Option<f32>,
) -> SqliteResult<()>
pub fn enqueue_review( &self, face_id: i64, candidate_cluster_id: i64, score: f32, ambiguity: Option<f32>, ) -> SqliteResult<()>
Add a face to the review queue with its top candidate cluster.
Idempotent via UNIQUE(face_id, candidate_cluster_id). Updates score and ambiguity on conflict.
Sourcepub fn resolve_review_same(&self, queue_id: i64) -> SqliteResult<()>
pub fn resolve_review_same(&self, queue_id: i64) -> SqliteResult<()>
User confirmed this face is the same person as the candidate cluster.
Atomic: assigns the face, marks user_confirmed=1, adds the face to the cluster’s gallery with source=‘user_confirmed’ (sticky), resolves the queue entry, refreshes cluster stats.
Sourcepub fn resolve_review_different(&self, queue_id: i64) -> SqliteResult<()>
pub fn resolve_review_different(&self, queue_id: i64) -> SqliteResult<()>
User rejected this candidate: the face is NOT the candidate cluster.
- Marks the face with user_confirmed = -1 (rejected for this candidate).
- If the face was previously assigned to a different cluster, records a cluster_cannot_merge pair.
- Resolves the queue entry.
Sourcepub fn resolve_review_skip(&self, queue_id: i64) -> SqliteResult<()>
pub fn resolve_review_skip(&self, queue_id: i64) -> SqliteResult<()>
User skipped this item: mark resolved_as = ‘skipped’ so it doesn’t resurface in the next review session (but can be re-queued on a future scan if the situation changes).
Sourcepub fn confirm_face(&self, face_id: i64) -> SqliteResult<()>
pub fn confirm_face(&self, face_id: i64) -> SqliteResult<()>
Confirm a face: set user_confirmed=1. Add to gallery if not already.
Sourcepub fn reject_face_to_unknown(
&self,
face_id: i64,
prev_cluster_id: i64,
) -> SqliteResult<()>
pub fn reject_face_to_unknown( &self, face_id: i64, prev_cluster_id: i64, ) -> SqliteResult<()>
Reject face to unknown: set cluster_id=NULL, user_confirmed=0. Write negative.
Sourcepub fn hide_face(&self, face_id: i64) -> SqliteResult<()>
pub fn hide_face(&self, face_id: i64) -> SqliteResult<()>
Hide face: set cluster_id=NULL, user_confirmed=-1. Excluded from future clustering.
Sourcepub fn reassign_face(
&self,
face_id: i64,
new_cluster_id: i64,
old_cluster_id: i64,
) -> SqliteResult<()>
pub fn reassign_face( &self, face_id: i64, new_cluster_id: i64, old_cluster_id: i64, ) -> SqliteResult<()>
Reassign a face to a different cluster. Marks user_confirmed=1, writes negative against the old cluster_id so it won’t come back.
Sourcepub fn confirm_face_to_cluster(
&self,
face_id: i64,
cluster_id: i64,
) -> SqliteResult<()>
pub fn confirm_face_to_cluster( &self, face_id: i64, cluster_id: i64, ) -> SqliteResult<()>
Confirm a currently-unassigned face into a cluster (used by K-similar flow).
Sourcepub fn unresolve_review(&self, queue_id: i64) -> SqliteResult<()>
pub fn unresolve_review(&self, queue_id: i64) -> SqliteResult<()>
Reverse a prior review resolution (for undo).
Auto Trait Implementations§
impl<'a> Freeze for FaceRepo<'a>
impl<'a> !RefUnwindSafe for FaceRepo<'a>
impl<'a> !Send for FaceRepo<'a>
impl<'a> !Sync for FaceRepo<'a>
impl<'a> Unpin for FaceRepo<'a>
impl<'a> UnsafeUnpin for FaceRepo<'a>
impl<'a> !UnwindSafe for FaceRepo<'a>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more