From 671b59d3633d6cec41fd35c5763bbc03a25add76 Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Sun, 10 Aug 2025 06:18:55 -0600 Subject: [PATCH] Add dynamic toggling --- docs/docs/integrations/mqtt.md | 16 ++++++-- frigate/comms/dispatcher.py | 38 ++++++++++++++++--- frigate/config/camera/review.py | 4 ++ frigate/config/config.py | 5 ++- .../post/review_descriptions.py | 6 ++- 5 files changed, 57 insertions(+), 12 deletions(-) diff --git a/docs/docs/integrations/mqtt.md b/docs/docs/integrations/mqtt.md index f4e540adc..ba1e1302f 100644 --- a/docs/docs/integrations/mqtt.md +++ b/docs/docs/integrations/mqtt.md @@ -411,13 +411,21 @@ Topic to turn review detections for a camera on or off. Expected values are `ON` Topic with current state of review detections for a camera. Published values are `ON` and `OFF`. -### `frigate//genai/set` +### `frigate//object_descriptions/set` -Topic to turn generative AI for a camera on or off. Expected values are `ON` and `OFF`. +Topic to turn generative AI object descriptions for a camera on or off. Expected values are `ON` and `OFF`. -### `frigate//genai/state` +### `frigate//object_descriptions/state` -Topic with current state of generative AI for a camera. Published values are `ON` and `OFF`. +Topic with current state of generative AI object descriptions for a camera. Published values are `ON` and `OFF`. + +### `frigate//review_descriptions/set` + +Topic to turn generative AI review descriptions for a camera on or off. Expected values are `ON` and `OFF`. + +### `frigate//review_descriptions/state` + +Topic with current state of generative AI review descriptions for a camera. Published values are `ON` and `OFF`. ### `frigate//birdseye/set` diff --git a/frigate/comms/dispatcher.py b/frigate/comms/dispatcher.py index 43c47fc51..4e35d4d97 100644 --- a/frigate/comms/dispatcher.py +++ b/frigate/comms/dispatcher.py @@ -75,7 +75,8 @@ class Dispatcher: "birdseye_mode": self._on_birdseye_mode_command, "review_alerts": self._on_alerts_command, "review_detections": self._on_detections_command, - "genai": self._on_genai_command, + "object_descriptions": self._on_object_description_command, + "review_descriptions": self._on_review_description_command, } self._global_settings_handlers: dict[str, Callable] = { "notifications": self._on_global_notification_command, @@ -752,8 +753,8 @@ class Dispatcher: ) self.publish(f"{camera_name}/review_detections/state", payload, retain=True) - def _on_genai_command(self, camera_name: str, payload: str) -> None: - """Callback for GenAI topic.""" + def _on_object_description_command(self, camera_name: str, payload: str) -> None: + """Callback for object description topic.""" genai_settings = self.config.cameras[camera_name].objects.genai if payload == "ON": @@ -764,15 +765,40 @@ class Dispatcher: return if not genai_settings.enabled: - logger.info(f"Turning on GenAI for {camera_name}") + logger.info(f"Turning on object descriptions for {camera_name}") genai_settings.enabled = True elif payload == "OFF": if genai_settings.enabled: - logger.info(f"Turning off GenAI for {camera_name}") + logger.info(f"Turning off object descriptions for {camera_name}") genai_settings.enabled = False self.config_updater.publish_update( CameraConfigUpdateTopic(CameraConfigUpdateEnum.genai, camera_name), genai_settings, ) - self.publish(f"{camera_name}/genai/state", payload, retain=True) + self.publish(f"{camera_name}/object_descriptions/state", payload, retain=True) + + def _on_review_description_command(self, camera_name: str, payload: str) -> None: + """Callback for review description topic.""" + genai_settings = self.config.cameras[camera_name].review.genai + + if payload == "ON": + if not self.config.cameras[camera_name].review.genai.enabled_in_config: + logger.error( + "GenAI Alerts or Detections must be enabled in the config to be turned on via MQTT." + ) + return + + if not genai_settings.enabled: + logger.info(f"Turning on review descriptions for {camera_name}") + genai_settings.enabled = True + elif payload == "OFF": + if genai_settings.enabled: + logger.info(f"Turning off review descriptions for {camera_name}") + genai_settings.enabled = False + + self.config_updater.publish_update( + CameraConfigUpdateTopic(CameraConfigUpdateEnum.genai, camera_name), + genai_settings, + ) + self.publish(f"{camera_name}/review_descriptions/state", payload, retain=True) diff --git a/frigate/config/camera/review.py b/frigate/config/camera/review.py index 8e3c0b01c..38e739530 100644 --- a/frigate/config/camera/review.py +++ b/frigate/config/camera/review.py @@ -63,6 +63,10 @@ class DetectionsConfig(FrigateBaseModel): class GenAIReviewConfig(FrigateBaseModel): + enabled: bool | None = Field( + default=None, + title="Internal field to represent if the review descriptions feature is enabled.", + ) alerts: bool = Field(default=False, title="Enable GenAI for alerts.") detections: bool = Field(default=False, title="Enable GenAI for detections.") debug_save_thumbnails: bool = Field( diff --git a/frigate/config/config.py b/frigate/config/config.py index 36e319410..73f6e1fa9 100644 --- a/frigate/config/config.py +++ b/frigate/config/config.py @@ -610,10 +610,13 @@ class FrigateConfig(FrigateBaseModel): camera_config.objects.genai.enabled_in_config = ( camera_config.objects.genai.enabled ) - camera_config.review.genai.enabled_in_config = ( + camera_config.review.genai.enabled = ( camera_config.review.genai.alerts or camera_config.review.genai.detections ) + camera_config.review.genai.enabled_in_config = ( + camera_config.review.genai.enabled + ) # Add default filters object_keys = camera_config.objects.track diff --git a/frigate/data_processing/post/review_descriptions.py b/frigate/data_processing/post/review_descriptions.py index 72ea0f9cb..3b7d1d6d9 100644 --- a/frigate/data_processing/post/review_descriptions.py +++ b/frigate/data_processing/post/review_descriptions.py @@ -46,6 +46,11 @@ class ReviewDescriptionProcessor(PostProcessorApi): if data_type != PostProcessDataEnum.review: return + camera = data["after"]["camera"] + + if not self.config.cameras[camera].review.genai.enabled: + return + id = data["after"]["id"] if data["type"] == "new" or data["type"] == "update": @@ -91,7 +96,6 @@ class ReviewDescriptionProcessor(PostProcessorApi): return final_data = data["after"] - camera = final_data["camera"] if ( final_data["severity"] == "alert"