diff --git a/src/ai/insight_generator.rs b/src/ai/insight_generator.rs index 632b504..1267628 100644 --- a/src/ai/insight_generator.rs +++ b/src/ai/insight_generator.rs @@ -119,8 +119,8 @@ impl InsightGenerator { location_dao: Arc>>, search_dao: Arc>>, tag_dao: Arc>>, - knowledge_dao: Arc>>, face_dao: Arc>>, + knowledge_dao: Arc>>, libraries: Vec, ) -> Self { Self { @@ -135,8 +135,8 @@ impl InsightGenerator { location_dao, search_dao, tag_dao, - knowledge_dao, face_dao, + knowledge_dao, libraries, } } @@ -2180,15 +2180,16 @@ Return ONLY the summary, nothing else."#, log::info!("tool_get_faces_in_photo: file_path='{}'", file_path); // Resolve content_hash from any library that has this rel_path. - // Walk libraries in their declared order and take the first hit. - let mut content_hash: Option = None; - for lib in &self.libraries { + // Hold the FaceDao lock once across all libraries — resolve_content_hash + // is synchronous and there's no await in the loop body. + let content_hash: Option = { let mut dao = self.face_dao.lock().expect("Unable to lock FaceDao"); - if let Ok(Some(h)) = dao.resolve_content_hash(cx, lib.id, &file_path) { - content_hash = Some(h); - break; - } - } + self.libraries.iter().find_map(|lib| { + dao.resolve_content_hash(cx, lib.id, &file_path) + .ok() + .flatten() + }) + }; let Some(content_hash) = content_hash else { return "No content_hash found for that file path (the photo may not be indexed yet, \ or the path doesn't match any library)." @@ -2215,9 +2216,11 @@ Return ONLY the summary, nothing else."#, let mut out = format!("Found {} face(s) in this photo:\n", faces.len()); for f in &bound { + // Invariant: `bound` is filtered on `person_name.is_some()` above. + let name = f.person_name.as_deref().expect("bound face must have a name"); out.push_str(&format!( "- {} (confidence {:.2}, bbox x={:.2} y={:.2} w={:.2} h={:.2}, source: {})\n", - f.person_name.as_deref().unwrap_or("?"), + name, f.confidence, f.bbox_x, f.bbox_y, diff --git a/src/bin/populate_knowledge.rs b/src/bin/populate_knowledge.rs index e72a27b..c2d1ade 100644 --- a/src/bin/populate_knowledge.rs +++ b/src/bin/populate_knowledge.rs @@ -201,8 +201,8 @@ async fn main() -> anyhow::Result<()> { location_dao, search_dao, tag_dao, - knowledge_dao, face_dao, + knowledge_dao, all_libs.clone(), ); diff --git a/src/faces.rs b/src/faces.rs index d92b7ae..5b7a232 100644 --- a/src/faces.rs +++ b/src/faces.rs @@ -1437,7 +1437,6 @@ impl FaceDao for SqliteFaceDao { } fn has_any_faces(&mut self, ctx: &opentelemetry::Context) -> anyhow::Result { - use anyhow::Context; let mut conn = self.connection.lock().expect("face dao lock"); trace_db_call(ctx, "query", "has_any_faces", |_span| { face_detections::table diff --git a/src/state.rs b/src/state.rs index 49d0b4c..adbf527 100644 --- a/src/state.rs +++ b/src/state.rs @@ -234,8 +234,8 @@ impl Default for AppState { location_dao.clone(), search_dao.clone(), tag_dao.clone(), - knowledge_dao, face_dao.clone(), + knowledge_dao, libraries_vec.clone(), ); @@ -376,8 +376,8 @@ impl AppState { location_dao.clone(), search_dao.clone(), tag_dao.clone(), - knowledge_dao, face_dao.clone(), + knowledge_dao, vec![test_lib], );