* tweak language

* show validation errors in json response

* fix export hwaccel args field in UI

* increase annotation offset consts

* fix save button race conditions, add reset spinner, and fix enrichments profile leak

- Disable both Save and SaveAll buttons while either operation is in progress so users cannot trigger concurrent saves
- Show activity indicator on Reset to Default/Global button during the API call
- Enrichments panes (semantic search, genai, face recognition) now always show base config fields regardless of profile selection in the header dropdown

* fix genai additional_concerns validation error with textarea array widget

The additional_concerns field is list[str] in the backend but was using the textarea widget which produces a string value, causing validation errors.
Created a TextareaArrayWidget that converts between array (one item per line) and textarea display, and switched additional_concerns to use it

* populate and sort global audio filters for all audio labels

* add column labels in profiles view

* enforce a minimum value of 2 for min_initialized

* reuse widget and refactor for multiline

* fix

* change record copy preset to transcode audio to aac
This commit is contained in:
Josh Hawkins
2026-03-26 13:47:24 -05:00
committed by GitHub
parent 909b40ba96
commit 4772e6a2ab
17 changed files with 264 additions and 69 deletions
+1
View File
@@ -71,6 +71,7 @@ class DetectConfig(FrigateBaseModel):
default=None,
title="Minimum initialization frames",
description="Number of consecutive detection hits required before creating a tracked object. Increase to reduce false initializations. Default value is fps divided by 2.",
ge=2,
)
max_disappeared: Optional[int] = Field(
default=None,
+21 -10
View File
@@ -614,6 +614,21 @@ class FrigateConfig(FrigateBaseModel):
if self.ffmpeg.hwaccel_args == "auto":
self.ffmpeg.hwaccel_args = auto_detect_hwaccel()
# Populate global audio filters for all audio labels
all_audio_labels = {
label
for label in load_labels("/audio-labelmap.txt", prefill=521).values()
if label
}
if self.audio.filters is None:
self.audio.filters = {}
for key in sorted(all_audio_labels - self.audio.filters.keys()):
self.audio.filters[key] = AudioFilterConfig()
self.audio.filters = dict(sorted(self.audio.filters.items()))
# Global config to propagate down to camera level
global_config = self.model_dump(
include={
@@ -672,12 +687,6 @@ class FrigateConfig(FrigateBaseModel):
detector_config.model = model
self.detectors[key] = detector_config
all_audio_labels = {
label
for label in load_labels("/audio-labelmap.txt", prefill=521).values()
if label
}
for name, camera in self.cameras.items():
modified_global_config = global_config.copy()
@@ -755,7 +764,7 @@ class FrigateConfig(FrigateBaseModel):
)
# Default min_initialized configuration
min_initialized = int(camera_config.detect.fps / 2)
min_initialized = max(int(camera_config.detect.fps / 2), 2)
if camera_config.detect.min_initialized is None:
camera_config.detect.min_initialized = min_initialized
@@ -801,11 +810,13 @@ class FrigateConfig(FrigateBaseModel):
if camera_config.audio.filters is None:
camera_config.audio.filters = {}
audio_keys = all_audio_labels
audio_keys = audio_keys - camera_config.audio.filters.keys()
for key in audio_keys:
for key in sorted(all_audio_labels - camera_config.audio.filters.keys()):
camera_config.audio.filters[key] = AudioFilterConfig()
camera_config.audio.filters = dict(
sorted(camera_config.audio.filters.items())
)
# Add default filters
object_keys = camera_config.objects.track
if camera_config.objects.filters is None: