From af2435a7958bfe11ce1725136b8c7c024b13eaee Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Mon, 27 Apr 2026 07:13:23 -0500 Subject: [PATCH 1/7] add ui to camera config update topics enum --- frigate/config/camera/updater.py | 1 + 1 file changed, 1 insertion(+) diff --git a/frigate/config/camera/updater.py b/frigate/config/camera/updater.py index 1965f3813..8da33a3ec 100644 --- a/frigate/config/camera/updater.py +++ b/frigate/config/camera/updater.py @@ -33,6 +33,7 @@ class CameraConfigUpdateEnum(str, Enum): lpr = "lpr" snapshots = "snapshots" timestamp_style = "timestamp_style" + ui = "ui" zones = "zones" From 18354aef6ca64d0727a550f346688ff9faa659f8 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Mon, 27 Apr 2026 07:20:46 -0500 Subject: [PATCH 2/7] add mqtt to camera config update enum --- frigate/config/camera/updater.py | 1 + 1 file changed, 1 insertion(+) diff --git a/frigate/config/camera/updater.py b/frigate/config/camera/updater.py index 8da33a3ec..a07d51b8e 100644 --- a/frigate/config/camera/updater.py +++ b/frigate/config/camera/updater.py @@ -20,6 +20,7 @@ class CameraConfigUpdateEnum(str, Enum): ffmpeg = "ffmpeg" live = "live" motion = "motion" # includes motion and motion masks + mqtt = "mqtt" notifications = "notifications" objects = "objects" object_genai = "object_genai" From 508f4509e17bcb6c75b3c07f2b9fa92b5e25c4d3 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Mon, 27 Apr 2026 09:32:00 -0500 Subject: [PATCH 3/7] ensure cleanup runs when an event end skips post-processing --- frigate/embeddings/maintainer.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frigate/embeddings/maintainer.py b/frigate/embeddings/maintainer.py index 33bef38f2..1a998febe 100644 --- a/frigate/embeddings/maintainer.py +++ b/frigate/embeddings/maintainer.py @@ -517,10 +517,16 @@ class EmbeddingMaintainer(threading.Thread): try: event: Event = Event.get(Event.id == event_id) except DoesNotExist: + for processor in self.post_processors: + if isinstance(processor, ObjectDescriptionProcessor): + processor.cleanup_event(event_id) continue # Skip the event if not an object if event.data.get("type") != "object": + for processor in self.post_processors: + if isinstance(processor, ObjectDescriptionProcessor): + processor.cleanup_event(event_id) continue # Extract valid thumbnail From 0de804892ba44499a0fdfe455e631b692b6f336e Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Mon, 27 Apr 2026 11:33:22 -0500 Subject: [PATCH 4/7] end any in-progress audio events when audio detection is disabled we already end in-progress audio events when we disable a camera, but this mirrors that logic for specifically disabling audio detection --- frigate/events/audio.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/frigate/events/audio.py b/frigate/events/audio.py index f6c41fa30..6a22b2251 100644 --- a/frigate/events/audio.py +++ b/frigate/events/audio.py @@ -205,6 +205,7 @@ class AudioEventMaintainer(threading.Thread): self.transcription_thread.start() self.was_enabled = camera.enabled + self.was_audio_enabled = camera.audio.enabled def detect_audio(self, audio: np.ndarray) -> None: if not self.camera_config.audio.enabled or self.stop_event.is_set(): @@ -363,6 +364,17 @@ class AudioEventMaintainer(threading.Thread): time.sleep(0.1) continue + audio_enabled = self.camera_config.audio.enabled + if audio_enabled != self.was_audio_enabled: + if not audio_enabled: + self.logger.debug( + f"Disabling audio detections for {self.camera_config.name}, ending events" + ) + self.requestor.send_data( + EXPIRE_AUDIO_ACTIVITY, self.camera_config.name + ) + self.was_audio_enabled = audio_enabled + self.read_audio() if self.audio_listener: From b0f4fcd6767a8ba7f4eac3282322c6d656fe0c13 Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Mon, 27 Apr 2026 15:16:14 -0600 Subject: [PATCH 5/7] Improve GenAI metadata --- frigate/data_processing/post/types.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frigate/data_processing/post/types.py b/frigate/data_processing/post/types.py index 41887a20e..0344c7616 100644 --- a/frigate/data_processing/post/types.py +++ b/frigate/data_processing/post/types.py @@ -27,7 +27,7 @@ class ReviewMetadata(BaseModel): ) title: str = Field( max_length=80, - description="A short title characterizing what took place and where, under 10 words.", + description="Under 10 words. Name the apparent purpose or outcome of the activity together with the location involved. Do not narrate or list the sequence of actions step by step.", ) scene: str = Field( min_length=150, @@ -36,7 +36,7 @@ class ReviewMetadata(BaseModel): ) shortSummary: str = Field( min_length=70, - max_length=100, + max_length=120, description="A brief 2-sentence summary of the scene, suitable for notifications.", ) confidence: float = Field( From 87501ba9708812e0dcf3b62726c4ee0ec7929b6d Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Tue, 28 Apr 2026 09:07:07 -0500 Subject: [PATCH 6/7] fix invalid recording segment topic being misrouted to the valid handler --- frigate/video/ffmpeg.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/frigate/video/ffmpeg.py b/frigate/video/ffmpeg.py index d30dc3b18..cc5b9a32b 100644 --- a/frigate/video/ffmpeg.py +++ b/frigate/video/ffmpeg.py @@ -317,16 +317,16 @@ class CameraWatchdog(threading.Thread): if camera != self.config.name: continue - if topic.endswith(RecordingsDataTypeEnum.valid.value): - self.logger.debug( - f"Latest valid recording segment time on {camera}: {segment_time}" - ) - self.latest_valid_segment_time = segment_time - elif topic.endswith(RecordingsDataTypeEnum.invalid.value): + if topic.endswith(RecordingsDataTypeEnum.invalid.value): self.logger.warning( f"Invalid recording segment detected for {camera} at {segment_time}" ) self.latest_invalid_segment_time = segment_time + elif topic.endswith(RecordingsDataTypeEnum.valid.value): + self.logger.debug( + f"Latest valid recording segment time on {camera}: {segment_time}" + ) + self.latest_valid_segment_time = segment_time elif topic.endswith(RecordingsDataTypeEnum.latest.value): if segment_time is not None: self.latest_cache_segment_time = segment_time From c22de09518a9e52baa88ed75373766d0253a3890 Mon Sep 17 00:00:00 2001 From: Nicolas Mowen Date: Tue, 28 Apr 2026 08:45:23 -0600 Subject: [PATCH 7/7] Add confidence default to avoid unnecessary field causing issues --- frigate/genai/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frigate/genai/__init__.py b/frigate/genai/__init__.py index 20bf1d6fb..e26b50757 100644 --- a/frigate/genai/__init__.py +++ b/frigate/genai/__init__.py @@ -201,9 +201,10 @@ Each line represents a detection state, not necessarily unique individuals. The except json.JSONDecodeError as je: logger.error("Failed to parse review description JSON: %s", je) return None - # observations is required on the model; fill an empty default + # observations and confidence are required on the model; fill an empty default # if the response omitted it so attribute access stays safe. raw.setdefault("observations", []) + raw.setdefault("confidence", 0.0) metadata = ReviewMetadata.model_construct(**raw) except Exception as e: logger.error(