diff --git a/frigate/data_processing/real_time/face.py b/frigate/data_processing/real_time/face.py index e1c11bf11..408a0456e 100644 --- a/frigate/data_processing/real_time/face.py +++ b/frigate/data_processing/real_time/face.py @@ -19,6 +19,7 @@ from frigate.comms.event_metadata_updater import ( ) from frigate.comms.inter_process import InterProcessRequestor from frigate.config import FrigateConfig +from frigate.config.classification import FaceRecognitionConfig from frigate.const import FACE_DIR, MODEL_CACHE_DIR from frigate.data_processing.common.face.model import ( ArcFaceRecognizer, @@ -95,6 +96,11 @@ class FaceRealTimeProcessor(RealTimeProcessorApi): self.recognizer.build() + def update_config(self, face_config: FaceRecognitionConfig) -> None: + """Update face recognition config at runtime.""" + self.face_config = face_config + logger.debug("Face recognition config updated dynamically") + def __download_models(self, path: str) -> None: try: file_name = os.path.basename(path) diff --git a/frigate/embeddings/maintainer.py b/frigate/embeddings/maintainer.py index 8e45af498..74b5310ac 100644 --- a/frigate/embeddings/maintainer.py +++ b/frigate/embeddings/maintainer.py @@ -99,6 +99,9 @@ class EmbeddingMaintainer(threading.Thread): self.classification_config_subscriber = ConfigSubscriber( "config/classification/custom/" ) + self.face_recognition_config_subscriber = ConfigSubscriber( + "config/face_recognition", exact=True + ) # Configure Frigate DB db = SqliteVecQueueDatabase( @@ -273,6 +276,7 @@ class EmbeddingMaintainer(threading.Thread): while not self.stop_event.is_set(): self.config_updater.check_for_updates() self._check_classification_config_updates() + self._check_face_recognition_config_updates() self._process_requests() self._process_updates() self._process_recordings_updates() @@ -284,6 +288,7 @@ class EmbeddingMaintainer(threading.Thread): self.config_updater.stop() self.classification_config_subscriber.stop() + self.face_recognition_config_subscriber.stop() self.event_subscriber.stop() self.event_end_subscriber.stop() self.recordings_subscriber.stop() @@ -356,6 +361,26 @@ class EmbeddingMaintainer(threading.Thread): f"Added classification processor for model: {model_name} (type: {type(processor).__name__})" ) + def _check_face_recognition_config_updates(self) -> None: + """Check for face recognition config updates.""" + topic, face_config = self.face_recognition_config_subscriber.check_for_update() + + if topic is None: + return + + previous_min_area = self.config.face_recognition.min_area + self.config.face_recognition = face_config + + for camera_config in self.config.cameras.values(): + if camera_config.face_recognition.min_area == previous_min_area: + camera_config.face_recognition.min_area = face_config.min_area + + for processor in self.realtime_processors: + if isinstance(processor, FaceRealTimeProcessor): + processor.update_config(face_config) + + logger.debug("Applied dynamic face recognition config update") + def _process_requests(self) -> None: """Process embeddings requests""" diff --git a/web/src/components/config-form/section-configs/face_recognition.ts b/web/src/components/config-form/section-configs/face_recognition.ts index 2f5b2dd46..18e963940 100644 --- a/web/src/components/config-form/section-configs/face_recognition.ts +++ b/web/src/components/config-form/section-configs/face_recognition.ts @@ -32,18 +32,7 @@ const faceRecognition: SectionConfigOverrides = { "blur_confidence_filter", "device", ], - restartRequired: [ - "enabled", - "model_size", - "unknown_score", - "detection_threshold", - "recognition_threshold", - "min_area", - "min_faces", - "save_attempts", - "blur_confidence_filter", - "device", - ], + restartRequired: ["enabled", "model_size", "device"], }, };