Compare commits

..
253 Commits
Author SHA1 Message Date
Josh Hawkins 6fce18f156 update network requirements docs 2026-09-22 12:29:40 -05:00
Josh Hawkins 7001623ba2 fixes 2026-09-22 12:15:33 -05:00
Josh Hawkins f8c180319c change wording 2026-09-22 11:03:24 -05:00
Josh Hawkins 8b5dc77891 Document anonymous analytics 2026-09-22 08:34:34 -05:00
Josh Hawkins 3990a64988 Show the analytics preview in telemetry settings 2026-09-22 08:31:00 -05:00
Josh Hawkins f185e64379 Record the image variant in each Dockerfile 2026-09-22 08:25:58 -05:00
Josh Hawkins 635aee552e Generate the analytics schema and check it in CI 2026-09-22 08:24:01 -05:00
Josh Hawkins 1834d9a22e Add the analytics preview API 2026-09-22 08:22:45 -05:00
Josh Hawkins f0d070899f Send the daily analytics report from the main process 2026-09-22 08:20:24 -05:00
Josh Hawkins 92e2a8b444 Add the analytics report transport 2026-09-22 08:18:03 -05:00
Josh Hawkins a8ed8b8592 Build analytics reports from the section collectors 2026-09-22 08:17:01 -05:00
Josh Hawkins 7f2fd71d12 Add the health analytics collector 2026-09-22 08:16:01 -05:00
Josh Hawkins 274277b85e Add the features analytics collector 2026-09-22 08:15:19 -05:00
Josh Hawkins faa0b68bc4 Add the cameras analytics collector 2026-09-22 08:14:20 -05:00
Josh Hawkins c252e07ffb Add the detection analytics collector 2026-09-22 08:13:13 -05:00
Josh Hawkins 90e1fa756d Add the install and hardware analytics collectors 2026-09-22 08:12:37 -05:00
Josh Hawkins ab43524fe2 Add the analytics state file 2026-09-22 08:10:10 -05:00
Josh Hawkins 51eb5058b3 Add the analytics report schema 2026-09-22 08:09:44 -05:00
Josh Hawkins aa72e555f5 Add analytics opt-in setting, prompt notice kind, and notice watermarks 2026-09-22 08:08:23 -05:00
A. AhmetGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
af0ba19196 Feat/deepx npu detector (#24336)
CI / AMD64 Build (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
* feat(deepx): add DEEPX NPU detector and runtime integration.

* feat(deepx): enforce model_format requirement when ppu is enabled and add integrity checks for driver installation

* Update frigate/detectors/plugins/deepx.py

Public method lacks docstring

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* Refactor DEEPX detector tests, support SSD and DAMO-YOLO

* feat(deepx): add anchor-free output decoding and corresponding tests

* Add tests and updates for DEEPX detector and refactor DEEPX accelerator code structure.

* fix: enhance model type validation and update documentation for DEEPX detector

* fix: add support for customizable score and NMS thresholds

* refactor: infer YOLO layout from the model, drop per-detector options and the dxrtd placeholder

* fix: keep only the anchor-free PPU verdict, re-read anchor-based each frame

* Update latency data for DEEPX NPU

* Expanding PPU support for DEEPX and set yolo-generic as default.

* enhance scale count resolution logic

* Extend PPU layout handling and YOLOX support to DEEPX detector

* fix: assume the largest PPU anchor table when the .dxnn has no layout

* Improve PPU decoding and introduce strides handling

* Improve PPU scope and fix box format mismatch

* Fix unnamed node issue that breaks traversal

* fix: update object detection model type description to remove outdated architecture

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-09-21 07:50:44 -05:00
Josh HawkinsandGitHub 52f50a7396 Tweaks (#24418)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
* don't display audio transcription provider message as health notice

* show remote provider for audio transcription in health pane

* adjust trigger and notifications messages to be consistent with the rest of the settings UI

* disable save buttons when there are no changes in config editor

* fix audio manager crash when a camera is added at runtime

The audio processor and the camera maintainer both poll the same `add` config update on their own one second timers, and the maintainer is what creates `camera_metrics[name]`. When the audio processor got there first it looked the new camera up before that entry existed, and the `KeyError` took down the whole `frigate.audio_manager` process. Whether it happens depends purely on which poll fires first, so cloning a camera from the UI fails or succeeds at random. `spawn_if_needed` now skips a camera whose metrics aren't there yet and picks it up on the next poll, the same way it already waits on a late ffmpeg update.

`AudioEventMaintainer` holds the `CameraMetrics` object now instead of indexing the manager dict on every audio chunk, which drops the IPC round trips and means a removed camera can't `KeyError` out of `detect_audio` after the maintainer pops the entry. The audio process is also registered with the watchdog, since a crash there previously left audio detection dead for every camera until a full restart, and it now receives the shared `DataProcessorMetrics` so `AudioTranscriptionRealTimeProcessor` gets the same type as the other real time processors.

* fix stationary max_frames dropping other tracked objects

When `max_frames` was set for a label, deregistering one object rebuilt norfair's list with a filter that kept an object only if it was both not the target and already on its way out, so every other healthy object of that label was dropped along with it. Any car leaving the frame took the rest of the cars with it and they came back as new tracked objects a few frames later. The filter now removes only the target, and objects that are expiring are still reaped by norfair on the next update.

* fix test

* fix skip_motion_threshold permanently disabling motion detection

The skip check returned before the two `accumulateWeighted` calls at the end of `detect`, so a skipped frame never made it into the background and setting `calibrating` there only picked a faster alpha for calls that never ran. `avg_frame` starts as an all zero image and a normally lit scene differs from black across nearly the whole frame, so the cameras I tested measure 0.84 to 0.98 against it. Any `skip_motion_threshold` below that number skips the first frame, leaves the background black, and skips every frame after it. Motion detection is dead for that camera until the setting is removed or Frigate restarts, with no motion boxes, no motion recordings, and no regions for the tracker since the detector stays calibrating.

Startup isn't the only way in. `update_mask` zeroes the background on any motion config change, and once a camera has calibrated the first IR switch or PTZ move freezes the background on the old scene, so it can't transition to the new one, which is the case the option exists for. The frame is now blended in before the early return at the same 0.2 alpha the calibrating path uses elsewhere, so a large scene change is still suppressed while the background catches up, about a second on a 5 fps camera, and then motion comes back.

* dump ffmpeg logs on every restart

The record watchdog restarted ffmpeg without flushing its `LogPipe`, so a camera whose recording segments went stale never showed a single line of ffmpeg output. The dump now happens in `start_or_restart_ffmpeg` right after the stop, which covers the stale record path, the record crash path, and the audio restart. `reset_capture_thread` and the audio `log_and_restart` fallback keep their own dumps since both pass `ffmpeg_process=None`.

* dump ffmpeg logs once per restart

The audio restart path dumped the log pipe itself before calling the helper, so the restart dump printed a second "last 100 lines" heading over an already drained deque and split the tail that `stop_ffmpeg` flushed into its own section. The heading is now only printed when there's something under it, and the audio path leaves the dump to the restart so each failure produces one section.

* keep all logpipe dumps consistent
2026-09-20 12:45:24 -06:00
+11 285dd5a461 Translations update from Hosted Weblate (#24333)
CI / AMD64 Build (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/components-player

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/components-player

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/components-player

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Translated using Weblate (Thai)

Currently translated at 86.0% (430 of 500 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: วรรณรุจ บุญแสง <wan.ball@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/th/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/audio
Translation: Frigate NVR/components-player

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (66 of 66 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 57.7% (436 of 755 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 57.7% (436 of 755 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 58.8% (83 of 141 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (129 of 129 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (24 of 24 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 57.4% (434 of 755 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (506 of 506 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 49.6% (70 of 141 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 49.8% (134 of 269 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 38.4% (518 of 1348 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (39 of 39 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (118 of 118 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (264 of 264 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (500 of 500 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Marco Cordeiro <marcoecordeiro@gmail.com>
Co-authored-by: webmaster mvfc <webmaster@mvfc.com.br>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-chat/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/pt_BR/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-chat
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/components-player

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Translated using Weblate (Danish)

Currently translated at 69.4% (347 of 500 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Martin Grüner <mrenurg@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/da/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/audio
Translation: Frigate NVR/components-player

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/components-player

* Translated using Weblate (Estonian)

Currently translated at 19.4% (148 of 759 strings)

Translated using Weblate (Estonian)

Currently translated at 14.7% (75 of 508 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (35 of 35 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (264 of 264 strings)

Translated using Weblate (Estonian)

Currently translated at 69.4% (347 of 500 strings)

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Translated using Weblate (Estonian)

Currently translated at 14.1% (20 of 141 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (66 of 66 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (24 of 24 strings)

Translated using Weblate (Estonian)

Currently translated at 29.5% (399 of 1348 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (68 of 68 strings)

Translated using Weblate (Estonian)

Currently translated at 69.2% (27 of 39 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (118 of 118 strings)

Translated using Weblate (Estonian)

Currently translated at 90.9% (240 of 264 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Kaius Karon <kaiuskaron@gmail.com>
Co-authored-by: Priit Jõerüüt <jrthwlate@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-chat/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/et/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-chat
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-settings

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Translated using Weblate (Russian)

Currently translated at 90.9% (240 of 264 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Павел Фролов <armagedetz@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/ru/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/common
Translation: Frigate NVR/components-player

* Translated using Weblate (Romanian)

Currently translated at 100.0% (66 of 66 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (24 of 24 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (759 of 759 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (508 of 508 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (269 of 269 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (1366 of 1366 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (119 of 119 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (87 of 87 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (68 of 68 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (35 of 35 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (118 of 118 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (264 of 264 strings)

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: lukasig <lukasig@hotmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-chat/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/ro/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-chat
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system

* Translated using Weblate (Belarusian)

Currently translated at 100.0% (264 of 264 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (269 of 269 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (1348 of 1348 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (119 of 119 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (60 of 60 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (87 of 87 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (68 of 68 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (66 of 66 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (24 of 24 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (755 of 755 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (506 of 506 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (35 of 35 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (118 of 118 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (264 of 264 strings)

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Uladz Maltsau <wldyslw@icloud.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-chat/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/be/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-chat
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/components-player

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Translated using Weblate (Ukrainian)

Currently translated at 90.5% (239 of 264 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Павел Фролов <armagedetz@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/uk/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/common
Translation: Frigate NVR/components-player

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/components-player

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/components-player

* Translated using Weblate (Catalan)

Currently translated at 100.0% (759 of 759 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (508 of 508 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1366 of 1366 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (118 of 118 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (757 of 757 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (508 of 508 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1350 of 1350 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (119 of 119 strings)

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Translated using Weblate (Catalan)

Currently translated at 100.0% (66 of 66 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (755 of 755 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (24 of 24 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (506 of 506 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (269 of 269 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1348 of 1348 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (87 of 87 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (68 of 68 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (39 of 39 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (118 of 118 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (264 of 264 strings)

Co-authored-by: Eduardo Pastor Fernández <123eduardoneko123@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-chat/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/ca/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-chat
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/components-player

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/components-player

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/components-player

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/components-player

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/components-player

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/components-player

* Translated using Weblate (Polish)

Currently translated at 92.4% (244 of 264 strings)

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: An Pa <andrzej.pasterczyk@googlemail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/common
Translation: Frigate NVR/components-player

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Translated using Weblate (Italian)

Currently translated at 92.1% (696 of 755 strings)

Translated using Weblate (Italian)

Currently translated at 90.9% (240 of 264 strings)

Translated using Weblate (Italian)

Currently translated at 92.0% (695 of 755 strings)

Translated using Weblate (Italian)

Currently translated at 94.1% (1269 of 1348 strings)

Translated using Weblate (Italian)

Currently translated at 91.5% (108 of 118 strings)

Co-authored-by: Gringo <ita.translations@tiscali.it>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/it/
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-settings

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/components-player

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Translated using Weblate (Indonesian)

Currently translated at 17.7% (134 of 755 strings)

Translated using Weblate (Indonesian)

Currently translated at 30.4% (154 of 506 strings)

Translated using Weblate (Indonesian)

Currently translated at 97.4% (38 of 39 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (74 of 74 strings)

Translated using Weblate (Indonesian)

Currently translated at 99.1% (117 of 118 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (264 of 264 strings)

Co-authored-by: Catto <sisharyadi@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/id/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/id/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-filter/id/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/id/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/id/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/id/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-filter
Translation: Frigate NVR/components-player

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Translated using Weblate (Dutch)

Currently translated at 73.5% (64 of 87 strings)

Translated using Weblate (Dutch)

Currently translated at 98.3% (116 of 118 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (264 of 264 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (264 of 264 strings)

Co-authored-by: Herik <wvdh2002@hotmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Rémon <remon@megelink.net>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/nl/
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-exports

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Translated using Weblate (Spanish)

Currently translated at 100.0% (264 of 264 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Santiago Burgues <santibur06@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/es/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/common
Translation: Frigate NVR/components-player

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/components-player

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Translated using Weblate (Swedish)

Currently translated at 95.0% (251 of 264 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Simon <simon.lappas2000@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/sv/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/common
Translation: Frigate NVR/components-player

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/components-player

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/components-player

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/components-player

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Translated using Weblate (Korean)

Currently translated at 100.0% (66 of 66 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (24 of 24 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (755 of 755 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (506 of 506 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (269 of 269 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (1348 of 1348 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (68 of 68 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (87 of 87 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (39 of 39 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (118 of 118 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (264 of 264 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: sinfancy <yujsjs@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-chat/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/ko/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-chat
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/components-player

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/components-player

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/components-player

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/components-player

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/components-player

* Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Translated using Weblate (Cantonese (Traditional Han script))

Currently translated at 47.7% (643 of 1348 strings)

Translated using Weblate (Cantonese (Traditional Han script))

Currently translated at 92.0% (243 of 264 strings)

Co-authored-by: ERK <sunnytse1@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/yue_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/yue_Hant/
Translation: Frigate NVR/common
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-settings

---------

Co-authored-by: วรรณรุจ บุญแสง <wan.ball@gmail.com>
Co-authored-by: Marco Cordeiro <marcoecordeiro@gmail.com>
Co-authored-by: webmaster mvfc <webmaster@mvfc.com.br>
Co-authored-by: Martin Grüner <mrenurg@gmail.com>
Co-authored-by: Kaius Karon <kaiuskaron@gmail.com>
Co-authored-by: Priit Jõerüüt <jrthwlate@users.noreply.hosted.weblate.org>
Co-authored-by: Павел Фролов <armagedetz@gmail.com>
Co-authored-by: lukasig <lukasig@hotmail.com>
Co-authored-by: Uladz Maltsau <wldyslw@icloud.com>
Co-authored-by: Eduardo Pastor Fernández <123eduardoneko123@gmail.com>
Co-authored-by: An Pa <andrzej.pasterczyk@googlemail.com>
Co-authored-by: Gringo <ita.translations@tiscali.it>
Co-authored-by: Catto <sisharyadi@gmail.com>
Co-authored-by: Herik <wvdh2002@hotmail.com>
Co-authored-by: Rémon <remon@megelink.net>
Co-authored-by: Santiago Burgues <santibur06@gmail.com>
Co-authored-by: Simon <simon.lappas2000@gmail.com>
Co-authored-by: sinfancy <yujsjs@gmail.com>
Co-authored-by: ERK <sunnytse1@gmail.com>
2026-09-19 07:16:00 -05:00
Josh HawkinsandGitHub 3d08bbe520 Miscellaneous fixes (#24402)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
* check for a valid frame before using its shape

With the camera offline, no preview frame, and `camera-error.jpg` missing, `latest_frame` read `frame.shape` before its `frame is None` check, so it raised `AttributeError` and answered 500 with a traceback instead of the intended "Unable to get valid frame". The check now runs first.

* fix the has_clip self-heal for events with no recordings

`vod_event` looked for a `(body, 404)` tuple, but `vod_ts` returns a `JSONResponse`, so the check never matched and an old event whose recordings are gone kept offering a clip that can't play. It now checks the response status code.

* return 403 for a snapshot or thumbnail on another camera

The broad `except Exception` handlers in `event_snapshot` and `event_thumbnail` caught the `HTTPException` from `require_camera_access`, so a restricted user asking for another camera's snapshot got a 404 instead of a 403, and for an object still being tracked the snapshot was rendered before the check ran. Both endpoints now look up the event and check access in their own block, the way the other endpoints do, so a denial propagates.

* find DST transitions to the second

`get_dst_transitions` probed the offset once every 24 hours from the start time and reported a change at the first probe after it, up to a day late, so events, review items and recordings near a transition were grouped into days with the old offset. A transition after the last daily probe wasn't found at all. The end of the range is probed too now, and a probe that sees the offset change bisects the interval to the second of the transition.

* don't run page shortcuts for keys a dialog already handled

Radix dismisses a dialog on Escape from a capture-phase keydown listener and calls `preventDefault()` without stopping propagation, so `useKeyboardListener` still ran the page's Escape shortcut: cancelling the delete dialog in the face library or a classification model also cleared the whole selection. Keys another shortcut hook handled still get through, since their listener order changes with every render.

* fix train image filtering for a class with a dash

The backend writes a class with a `-` as `_` in train file names, since it splits those names on `-`, while a dataset folder keeps the dash. Filtering the Train grid by `half-open` compared it with `half_open` and hid every attempt. Both sides are normalized the same way now.

* don't edit a chat message while a reply streams

The edit button stayed active while a reply streamed. `submitConversation` returns early while loading, but the message bubble still closed its editor, so the edit was silently lost. The edit button is hidden while a reply streams, and an editor that's already open keeps its draft with send disabled until the reply ends.

* fix restart failing under non-root

restart_frigate() called psutil.Process(1).terminate() to signal s6-svscan, but s6-svscan runs as root while frigate runs as uid 1000, so the call raised AccessDenied. That exception escaped every caller: the UI restart button dropped its websocket client, MQTT restart and Save & Restart just logged and did nothing, and the watchdog crashed its own monitoring thread on a dead detector. This catches AccessDenied and falls through to the existing SIGINT branch, which exits the process for s6 to restart it.

* show runtime overrides in the settings form

The settings form read a camera section's saved config value, but its dependent warnings (audio transcription requiring audio detection, snapshots requiring detect, etc.) read the live config instead. A runtime toggle from the live view, MQTT, or an active profile can turn a section off without touching yaml, and that override persists across restarts, so the Enable switch showed on while the warning said the feature wasn't enabled. This adds an "Overridden (Live)" badge to any field whose live value differs from what's saved, and swaps the affected warnings to runtime-specific wording when a runtime override is the actual cause instead of the config.

* fix mobile overflowing icons in system due to new health pane

* fix genai settings keeping a stale model and dropping roles after save

Switching a GenAI entry's provider left the previous provider's model selected, so saving wrote a model the new provider doesn't serve. llama.cpp can't find that model in `/v1/models`, so the backend reported every capability as false for the entry, and once the save refetched `genai/models` the roles widget stripped `transcribe` from the form on its own. The section showed unsaved changes right after saving, and saving again would have dropped the role. Switching provider now clears the model, and the roles widget only strips a role for a model or provider picked in the form, since the entry-level capability flags only describe the saved model. A selected role stays visible when the provider can't confirm it, so it can still be switched off. The llama.cpp model list also no longer repeats a model whose alias matches its id, which is what `--alias` produces.

* close onvif sessions on shutdown

`OnvifController.close()` only stopped its event loop, so the aiohttp sessions each `ONVIFCamera` holds and the `_poll_config_updates` task were left to be garbage collected during interpreter shutdown, when their warnings can no longer be logged. Every restart ended with a run of `Unclosed client session` and `Task was destroyed but it is pending!` logging errors, which only became visible once restart started exiting the process itself under non-root. `close()` now closes each camera's client and cancels the tasks on the loop before stopping it.

* fixes

* fixes
2026-09-18 07:33:23 -06:00
Nick DaviesandGitHub 0ca5cbbb63 Fix --validate-config exit code (#24398)
Validate config exists 0 regardless of if the config is valid or not.
This makes it not very useful for CI

Tiny fix to bail non-zero if the config is invalid
2026-09-18 07:52:39 -05:00
Nicolas MowenandGitHub 334073967b Support using GenAI for audio transcription (#24396)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
* Add support for running transcription with GenAI

* Improve audio joining

* Fix GenAI model capability reporting

* Support language correctly

* Migrate existing users to keep english selected

* Fix models

* Fix tests

* Fix accepted null model

* Handle slwo providers
2026-09-17 16:34:47 -05:00
Nicolas MowenandGitHub eccd10cd94 Implement annotated frames for GenAI Review (#24379)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
* Implement annotated frames mode for GenAI reviews to improve models with lacking temporal understanding

* Updates

* Improve debug sharing

* Do not number objects

* Fix assumptions

* Remove unhelpful content

* Improve object data sent as part of prompt

* Cleanup ollama dumbness

* Bind db

* Fixes

* Cleanup
2026-09-17 10:28:37 -06:00
Josh HawkinsandGitHub 10a0d5ea37 Improve UI zone operations (#24376)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
* improve zone renaming

Zone rename now saves as one JSON body via config/set, moving required_zones and profile overrides instead of leaving stale references

* fixes
2026-09-16 12:07:05 -06:00
Josh HawkinsandGitHub 64d6366ac4 Live streaming tech selection (#24374)
* allow users to select live streaming technology

* fix webrtc being downgraded to mse on load

`useUserPersistence` seeds state with the default and loads asynchronously, so the first render always used `mse` instead of the saved choice, and `useWebRTCGloballyAvailable` reports `checking` until the probe settles and re-enters that state on every consumer mount, so a saved `webrtc` was rewritten to `mse` even after the probe had already passed. On Safari the MSE player then timed out and latched the jsmpeg fallback. A pending probe now counts as available, the player waits on `autoLive` until the stored preferences load, and `handleError` gates on the mode in use since the fallback flag no longer implies webrtc is untried. A rejected IndexedDB read also resolves `loaded` now, so a blocked store can't leave the player waiting forever.

* add support for configurable ICE servers in WebRTC player

* add mic error state, fix dialog overwriting saved choice and dashboard ignoring stream

* tweaks
2026-09-16 09:12:06 -05:00
Josh HawkinsandGitHub 79ca18d439 fix build warnings from tailwind, fonts, and fast refresh (#24359)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
fix duplicated styles, move fonts to src/assets/fonts for vite to bundle (nginx already rewrites correctly), and fix fast refresh for PreviewController, auth context/provider, and statusbar context
2026-09-15 15:33:09 -06:00
Josh HawkinsandGitHub cabdffea20 Update more web deps and reformat with updated prettier (#24358)
* update date-fns, i18next, react-dropzone, react-markdown and @types/node

react-i18next 17 peers `i18next >= 26.2.0`, so the two move together. react-day-picker already depends on date-fns 4, so date-fns now dedupes to a single copy. react-dropzone 20 declares `node >=22` in `engines`, but npm only warns on Node 20 and nothing in the build needs Node 22.

* update js-yaml, @hookform/resolvers and prettier

js-yaml 5 has no default export, so `DictAsYamlField` imports `dump`, `load` and `YAMLException` by name. @hookform/resolvers 5 types `zodResolver` with the schema's input and output types separately, and fields with defaults are optional on input, so the zone and classification model forms pass both types to `useForm`. zod's range now starts at 3.25, which resolvers 5 requires.

* format with prettier 3.9
2026-09-15 15:18:49 -06:00
Josh HawkinsandGitHub ba41c90c07 Remove unused deps (#24355)
* remove unused web test deps

Nothing runs vitest. The CI step that called `npm run test` is commented out, `web/__test__/` was deleted in https://github.com/blakeblackshear/frigate/pull/8983 so `setupFiles` points at a missing file, and there are no unit tests, so `npx vitest run` only picks up the Playwright specs and fails. jsdom, `@testing-library/jest-dom`, msw and fake-indexeddb were only there for vitest.

* update contributing docs

* remove unused deps
2026-09-15 14:02:02 -06:00
Josh HawkinsandGitHub 0c52a3175d update radix, react, konva and other web dependencies (#24354)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
konva 10.5 removed the private `Node._lastPos`, so `PolygonCanvas` now reads the dragged point from `getAbsolutePosition()`, which returns the position konva just applied. monaco-yaml 5.5 takes formatter options instead of a boolean for `format`. The radix packages move together so every shared primitive stays a single copy under the `react-slot` and `compose-refs` overrides.
2026-09-15 12:39:31 -05:00
Josh HawkinsandGitHub 4c648f8147 bump copy-to-clipboard to 4.0.2 (#24353) 2026-09-15 12:03:20 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
e0d4337a25 Update memray requirement from ==1.15.* to ==1.20.* in /docker/main (#24343)
Updates the requirements on [memray](https://github.com/bloomberg/memray) to permit the latest version.
- [Release notes](https://github.com/bloomberg/memray/releases)
- [Changelog](https://github.com/bloomberg/memray/blob/main/NEWS.rst)
- [Commits](https://github.com/bloomberg/memray/compare/v1.15.0...v1.20.0)

---
updated-dependencies:
- dependency-name: memray
  dependency-version: 1.20.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-15 10:16:45 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
5e689f2d85 Update uvicorn requirement from ==0.46.* to ==0.52.* in /docker/main (#24341)
Updates the requirements on [uvicorn](https://github.com/Kludex/uvicorn) to permit the latest version.
- [Release notes](https://github.com/Kludex/uvicorn/releases)
- [Changelog](https://github.com/Kludex/uvicorn/blob/main/docs/release-notes.md)
- [Commits](https://github.com/Kludex/uvicorn/compare/0.46.0...0.52.4)

---
updated-dependencies:
- dependency-name: uvicorn
  dependency-version: 0.52.4
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-15 10:16:40 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
57a2765d00 Update netaddr requirement from ==0.8.* to ==1.3.* in /docker/main (#24346)
Updates the requirements on [netaddr](https://github.com/netaddr/netaddr) to permit the latest version.
- [Release notes](https://github.com/netaddr/netaddr/releases)
- [Changelog](https://github.com/netaddr/netaddr/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/netaddr/netaddr/compare/0.8.0...1.3.0)

---
updated-dependencies:
- dependency-name: netaddr
  dependency-version: 1.3.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-15 10:16:33 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
dd77bae4f7 Bump @radix-ui/react-progress from 1.1.8 to 1.1.16 in /web (#24342)
Bumps [@radix-ui/react-progress](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/progress) from 1.1.8 to 1.1.16.
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/progress/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/progress)

---
updated-dependencies:
- dependency-name: "@radix-ui/react-progress"
  dependency-version: 1.1.16
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-15 10:16:16 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
8a98d7c9b1 Bump @radix-ui/react-radio-group from 1.3.8 to 1.4.7 in /web (#24339)
Bumps [@radix-ui/react-radio-group](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/radio-group) from 1.3.8 to 1.4.7.
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/radio-group/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/radio-group)

---
updated-dependencies:
- dependency-name: "@radix-ui/react-radio-group"
  dependency-version: 1.4.7
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-15 10:00:33 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
8a8da663c0 Bump lucide-react from 0.577.0 to 1.45.0 in /web (#24337)
Bumps [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) from 0.577.0 to 1.45.0.
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/1.45.0/packages/lucide-react)

---
updated-dependencies:
- dependency-name: lucide-react
  dependency-version: 1.45.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-15 10:00:26 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
eddc9fccd1 Bump autoprefixer from 10.4.20 to 10.5.6 in /web (#24340)
Bumps [autoprefixer](https://github.com/postcss/autoprefixer) from 10.4.20 to 10.5.6.
- [Release notes](https://github.com/postcss/autoprefixer/releases)
- [Changelog](https://github.com/postcss/autoprefixer/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/autoprefixer/compare/10.4.20...10.5.6)

---
updated-dependencies:
- dependency-name: autoprefixer
  dependency-version: 10.5.6
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-15 10:00:19 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
84f981a77c Bump @radix-ui/react-toggle from 1.1.10 to 1.1.18 in /web (#24344)
Bumps [@radix-ui/react-toggle](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/toggle) from 1.1.10 to 1.1.18.
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/toggle/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/toggle)

---
updated-dependencies:
- dependency-name: "@radix-ui/react-toggle"
  dependency-version: 1.1.18
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-15 10:00:12 -05:00
Josh HawkinsandGitHub 4100383738 Miscellaneous fixes (#24352)
* fix recordings unavailable endpoint when no params are provided

we already import the datetime class directly, so those attribute lookups raised AttributeError and the request returned 500

* reject JWTs whose role is no longer in the config

`/auth` trusted the role inside the JWT and re-signed it on refresh without checking the config, so a user whose restricted role was deleted kept a session carrying a role that isn't in `auth.roles`. The media, clip, recording, export and go2rtc checks treat a missing role the same as a role with no camera list, so that session could open every camera. `/auth` now returns 401 for a token whose role isn't configured, which sends the user back through login, and login already falls back to `viewer` for a role that's gone.

* delete the deleted camera group's layout, not the open one's

Deleting a camera group removed the layout of the group being viewed, because the dialog's delete was bound to `${activeGroup}-draggable-layout`. It also cleared the saved group, and both ran before the `config/set` request whether or not it succeeded, so deleting one group while viewing another lost the open group's layout and left the deleted group's layout behind. The deleted group's own layout is now removed after a successful save, and the saved group is only cleared when it was the open group.

* don't block API when querying PTZ info

camera_ptz_info is async but waited on the ONVIF controller's future with future.result(), blocking the API event loop for as long as a slow or unreachable ONVIF camera took to answer (including reconnect attempts), so every other async request stalled with it. Await the future with asyncio.wrap_future instead. The coroutine runs on the controller's own loop and thread, so this cannot deadlock.

* for custom exports, only allow admin users to add to existing cases

follows the existing convention where attaching an export to an existing case is admin-only on `POST /export/{camera}/...` and `POST /exports/batch`

* drop pending edits for a camera or profile that no longer exists

* match cached preview frames to their camera exactly

https://github.com/blakeblackshear/frigate/pull/22594 added a trailing `-` to the `preview_{camera}` prefix so `camera` stopped matching `camera2`'s frames, but camera names can contain `-`, so `front` still matched `front-door`'s. After a restart, `front`'s preview recorder deleted this hour's frames of a matching camera that sorted before it and added the timestamps of one that sorted after it, so ffmpeg was asked for files that don't exist and that hour's preview was lost. The offline fallback for `latest.jpg` could also return `front-door`'s frame for `front`, even to a user without access to `front-door`, and a short export could take its fallback thumbnail from the other camera. These now compare the full camera name taken from the file name.
2026-09-15 07:48:30 -05:00
Josh HawkinsandGitHub fa30a7e1ae Replace react-logviewer with virtua (#24334)
* bump react-logviewer to 6.5.5

* use virtua for UI logs
2026-09-15 05:44:04 -06:00
Josh HawkinsandGitHub eecc43ccef bump rjsf to 6.10.0 and add e2e test (#24332)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
2026-09-14 13:36:27 -05:00
Nicolas MowenandGitHub 7821ecbb43 Migrate Hailo detector key and support hailo device (#24327)
* Migrate Hailo detector key and support hailo device

* Fix missing check
2026-09-14 08:23:36 -06:00
Josh HawkinsandGitHub caa6edecac Migrate web to ESLint 10 flat config (#24326)
* migrate web to eslint 10 flat config

ESLint 10 dropped `.eslintrc` support, so `.eslintrc.cjs` is replaced with `eslint.config.js` and the lint scripts no longer pass `--ext` or `--ignore-path`. typescript-eslint moves to 8, react-hooks to 7, and react-refresh to 0.5, and the unused jest and vitest-globals plugins are removed. Lint behaves as it did before: catch variables aren't checked, unused disable directives aren't reported, and rules newly added to the recommended sets are off until the code passes them. typescript-eslint 8 flags constants used only in `typeof`, so those are now exported, or replaced with a union type where the export would trip react-refresh.

* fix lint findings from the eslint 10 recommended rules

Remove the rule overrides from the flat config migration and fix what they were hiding. Unused catch bindings are dropped, 20 disable directives that suppressed nothing are removed (react-hooks 5.2 and 7.1.1 report identical exhaustive-deps findings with inline config ignored), dead initial values are dropped, short-circuit calls become if statements or optional calls, rethrown errors pass `cause`, and the disabled "No recordings" tooltip in `ReviewTimeline` is removed along with its memo and the `getRecordingAvailability` prop. The 3 react-refresh warnings for files that export contexts or classes are left for a later refactor.
2026-09-14 07:53:45 -06:00
Josh HawkinsandGitHub acc740a976 Update deps (#24324)
* update docusaurus to 3.10.2

* bump @types/node to 25.9.6 and ES2022

target ES2022, which already includes ES2020 and ES2021.String, so the lib list was also trimmed

* bump vite to 8.3.0 and vitest to 4.1.11

Swap `@vitejs/plugin-react-swc` for `@vitejs/plugin-react` and add `esbuild` as a devDependency, since `vite-plugin-monaco-editor` requires it and Vite 8 no longer ships it. `keepNames` moves to `build.rolldownOptions.output` because Vite 8 ignores the `esbuild` block. Rolldown's minifier now writes the preload helper's base path as a template literal instead of a double-quoted string, so the nginx `sub_filter` for `return"/BASE_PATH/"` stopped matching and lazy-loaded chunks and their CSS were requested from a literal `/BASE_PATH/` under Home Assistant ingress. The rule now matches the backtick form.

* bump apexcharts to 7.3.0 and react-apexcharts to 2.1.1

Under Vite 8, a default import from a CommonJS package resolves to its whole `module.exports` when `package.json` has `"type": "module"`, so react-apexcharts 1.4.1 handed React an object and every chart crashed. 2.x ships an ESM build. apexcharts 7 no longer sets `window.ApexCharts`, so the chart components now import it for `ApexCharts.exec`, and `ApexAxisChartSeries` is derived in `types/graph.ts` because it's no longer a global type.

* remove unused immer dep

* remove unused cython pin from tensorrt requirements

The pin was added alongside tensorrt 8.5.3 and cuda-python 11.8, which needed Cython to build, and both have since been dropped from this file. Nothing imports Cython at runtime, and `pip3 wheel` runs with build isolation, so any source build gets its own build dependencies. The pin only installed an unused Cython wheel into the TensorRT image.

* require node 20.19 for docs
2026-09-14 07:16:31 -06:00
Josh HawkinsandGitHub 3931ab74a8 fix mypy errors from types-peewee 4.0 (#24323)
types-peewee 4.0 types model fields precisely, so 17 `type: ignore` comments and 2 `cast(str, ...)` calls are no longer needed. Its stubs type `.namedtuples()` and `.dicts()` queries as returning model instances, so the review cleanup reads namedtuple fields by name and the storage usage query casts its dict rows. `start_time` is declared `DateTimeField` but stores unix timestamps, so two reads cast it like `debug_replay.py` already does. `Export` gets an annotation for the `export_case_id` attribute peewee adds at runtime.
2026-09-14 07:52:23 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
5be162a22c Update sherpa-onnx requirement from ==1.12.* to ==1.13.* in /docker/main (#24303)
Updates the requirements on [sherpa-onnx](https://github.com/k2-fsa/sherpa-onnx) to permit the latest version.
- [Changelog](https://github.com/k2-fsa/sherpa-onnx/blob/master/CHANGELOG.md)
- [Commits](https://github.com/k2-fsa/sherpa-onnx/compare/v1.12.0...v1.13.8)

---
updated-dependencies:
- dependency-name: sherpa-onnx
  dependency-version: 1.13.8
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-14 07:29:35 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
e57eeb8288 Update unidecode requirement from ==1.3.* to ==1.4.* in /docker/main (#24320)
Updates the requirements on [unidecode](https://github.com/kmike/text-unidecode) to permit the latest version.
- [Release notes](https://github.com/kmike/text-unidecode/releases)
- [Commits](https://github.com/kmike/text-unidecode/commits)

---
updated-dependencies:
- dependency-name: unidecode
  dependency-version: 1.4.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-14 07:29:30 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
cf03df8a98 Update prometheus-client requirement in /docker/main (#24313)
Updates the requirements on [prometheus-client](https://github.com/prometheus/client_python) to permit the latest version.
- [Release notes](https://github.com/prometheus/client_python/releases)
- [Commits](https://github.com/prometheus/client_python/compare/v0.21.0...v0.26.0)

---
updated-dependencies:
- dependency-name: prometheus-client
  dependency-version: 0.26.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-14 07:29:25 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
fa36fa403b Update starlette-context requirement in /docker/main (#24305)
Updates the requirements on [starlette-context](https://github.com/tomwojcik/starlette-context) to permit the latest version.
- [Release notes](https://github.com/tomwojcik/starlette-context/releases)
- [Commits](https://github.com/tomwojcik/starlette-context/compare/v0.4.0...v0.5.1)

---
updated-dependencies:
- dependency-name: starlette-context
  dependency-version: 0.5.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-14 07:29:20 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
069315be33 Bump @radix-ui/react-aspect-ratio from 1.1.2 to 1.1.15 in /web (#24314)
Bumps [@radix-ui/react-aspect-ratio](https://github.com/radix-ui/primitives/tree/HEAD/packages/react/aspect-ratio) from 1.1.2 to 1.1.15.
- [Changelog](https://github.com/radix-ui/primitives/blob/main/packages/react/aspect-ratio/CHANGELOG.md)
- [Commits](https://github.com/radix-ui/primitives/commits/HEAD/packages/react/aspect-ratio)

---
updated-dependencies:
- dependency-name: "@radix-ui/react-aspect-ratio"
  dependency-version: 1.1.15
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-14 07:28:06 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
c583e21b70 Bump framer-motion from 12.38.0 to 13.2.0 in /web (#24307)
Bumps [framer-motion](https://github.com/motiondivision/motion) from 12.38.0 to 13.2.0.
- [Changelog](https://github.com/motiondivision/motion/blob/main/CHANGELOG.md)
- [Commits](https://github.com/motiondivision/motion/compare/v12.38.0...v13.2.0)

---
updated-dependencies:
- dependency-name: framer-motion
  dependency-version: 13.2.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-14 07:28:01 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
bb6c2e98eb Bump docker/login-action from 3.5.0 to 4.6.0 (#23872)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
Bumps [docker/login-action](https://github.com/docker/login-action) from 3.5.0 to 4.6.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/184bdaa0721073962dff0199f1fb9940f07167d1...dbcb813823bdd20940b903addbd779551569679f)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: 4.6.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 17:39:20 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
0570a9c4eb Bump actions/checkout from 6 to 7 (#23510)
Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 17:36:45 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
ced95a1a31 Bump actions/setup-python from 5.4.0 to 7.0.0 (#23768)
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5.4.0 to 7.0.0.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v5.4.0...v7.0.0)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 17:27:51 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1f340f389f Bump actions/setup-node from 6 to 7 (#23715)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 6 to 7.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 17:27:44 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
94422ff24f Update click requirement from ==8.1.* to ==8.5.* in /docker/main (#23067)
Updates the requirements on [click](https://github.com/pallets/click) to permit the latest version.
- [Release notes](https://github.com/pallets/click/releases)
- [Changelog](https://github.com/pallets/click/blob/main/CHANGES.md)
- [Commits](https://github.com/pallets/click/compare/8.1.0...8.5.0)

---
updated-dependencies:
- dependency-name: click
  dependency-version: 8.3.3
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 17:13:38 -05:00
06ff2ced5d bump cryptography to 46 and pin py-vapid to 1.9.4 (#24292)
Co-authored-by: t <t@t>
2026-09-13 15:52:19 -06:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
35b9c4978d Bump python-multipart from 0.0.26 to 0.0.31 in /docker/main (#23497)
Bumps [python-multipart](https://github.com/Kludex/python-multipart) from 0.0.26 to 0.0.31.
- [Release notes](https://github.com/Kludex/python-multipart/releases)
- [Changelog](https://github.com/Kludex/python-multipart/blob/main/CHANGELOG.md)
- [Commits](https://github.com/Kludex/python-multipart/compare/0.0.26...0.0.31)

---
updated-dependencies:
- dependency-name: python-multipart
  dependency-version: 0.0.31
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 16:16:50 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2106d10e2e Update faster-whisper requirement in /docker/main (#23075)
Updates the requirements on [faster-whisper](https://github.com/SYSTRAN/faster-whisper) to permit the latest version.
- [Release notes](https://github.com/SYSTRAN/faster-whisper/releases)
- [Commits](https://github.com/SYSTRAN/faster-whisper/compare/v1.1.0...v1.2.1)

---
updated-dependencies:
- dependency-name: faster-whisper
  dependency-version: 1.2.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 16:16:45 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
8b8c90ee1a Update aiofiles requirement from ==24.1.* to ==25.1.* in /docker/main (#23074)
Updates the requirements on [aiofiles](https://github.com/Tinche/aiofiles) to permit the latest version.
- [Release notes](https://github.com/Tinche/aiofiles/releases)
- [Changelog](https://github.com/Tinche/aiofiles/blob/main/CHANGELOG.md)
- [Commits](https://github.com/Tinche/aiofiles/compare/v24.1.0...v25.1.0)

---
updated-dependencies:
- dependency-name: aiofiles
  dependency-version: 25.1.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 16:16:41 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
d462aeb068 Update uvicorn requirement from ==0.35.* to ==0.46.* in /docker/main (#23073)
Updates the requirements on [uvicorn](https://github.com/Kludex/uvicorn) to permit the latest version.
- [Release notes](https://github.com/Kludex/uvicorn/releases)
- [Changelog](https://github.com/Kludex/uvicorn/blob/main/docs/release-notes.md)
- [Commits](https://github.com/Kludex/uvicorn/compare/0.35.0...0.46.0)

---
updated-dependencies:
- dependency-name: uvicorn
  dependency-version: 0.46.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 16:16:37 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
828ecdd0ea Update joserfc requirement from ==1.2.* to ==1.6.* in /docker/main (#23071)
Updates the requirements on [joserfc](https://github.com/authlib/joserfc) to permit the latest version.
- [Release notes](https://github.com/authlib/joserfc/releases)
- [Changelog](https://github.com/authlib/joserfc/blob/main/docs/changelog.rst)
- [Commits](https://github.com/authlib/joserfc/compare/1.2.0...1.6.4)

---
updated-dependencies:
- dependency-name: joserfc
  dependency-version: 1.6.4
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 16:16:33 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
d5e3fed130 Update requests requirement from ==2.32.* to ==2.33.* in /docker/main (#23068)
Updates the requirements on [requests](https://github.com/psf/requests) to permit the latest version.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](https://github.com/psf/requests/compare/v2.32.0...v2.33.1)

---
updated-dependencies:
- dependency-name: requests
  dependency-version: 2.33.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 16:16:28 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
3e7cb396e2 Update pyzmq requirement from ==26.2.* to ==27.1.* in /docker/main (#23064)
Updates the requirements on [pyzmq](https://github.com/zeromq/pyzmq) to permit the latest version.
- [Release notes](https://github.com/zeromq/pyzmq/releases)
- [Commits](https://github.com/zeromq/pyzmq/compare/v26.2.0...v27.1.0)

---
updated-dependencies:
- dependency-name: pyzmq
  dependency-version: 27.1.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 16:16:24 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
d71d573edf Update pyclipper requirement from ==1.3.* to ==1.4.* in /docker/main (#23063)
Updates the requirements on [pyclipper](https://github.com/fonttools/pyclipper) to permit the latest version.
- [Release notes](https://github.com/fonttools/pyclipper/releases)
- [Commits](https://github.com/fonttools/pyclipper/compare/1.3.0...1.4.0)

---
updated-dependencies:
- dependency-name: pyclipper
  dependency-version: 1.4.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 16:16:20 -05:00
4b71cb76dd bump i18next-http-backend to 4.0.2 (#24290)
Co-authored-by: t <t@t>
2026-09-13 15:05:41 -06:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
cf59d9ad56 Bump browserslist from 4.23.3 to 4.28.9 in /web (#24287)
Bumps [browserslist](https://github.com/browserslist/browserslist) from 4.23.3 to 4.28.9.
- [Release notes](https://github.com/browserslist/browserslist/releases)
- [Changelog](https://github.com/browserslist/browserslist/blob/main/CHANGELOG.md)
- [Commits](https://github.com/browserslist/browserslist/compare/4.23.3...4.28.9)

---
updated-dependencies:
- dependency-name: browserslist
  dependency-version: 4.28.9
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 15:27:19 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
94b37ceb6e Bump nanoid from 3.3.11 to 3.3.19 in /web (#24286)
Bumps [nanoid](https://github.com/ai/nanoid) from 3.3.11 to 3.3.19.
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/3.3.11...3.3.19)

---
updated-dependencies:
- dependency-name: nanoid
  dependency-version: 3.3.19
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 15:27:14 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
ea84b1be82 Bump js-yaml from 4.1.1 to 4.3.2 in /web (#24273)
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 4.1.1 to 4.3.2.
- [Changelog](https://github.com/nodeca/js-yaml/blob/4.3.2/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/4.1.1...4.3.2)

---
updated-dependencies:
- dependency-name: js-yaml
  dependency-version: 4.3.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 15:27:09 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
105b7bb79d Bump micromatch from 4.0.5 to 4.0.8 in /web (#23840)
Bumps [micromatch](https://github.com/micromatch/micromatch) from 4.0.5 to 4.0.8.
- [Release notes](https://github.com/micromatch/micromatch/releases)
- [Changelog](https://github.com/micromatch/micromatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/micromatch/compare/4.0.5...4.0.8)

---
updated-dependencies:
- dependency-name: micromatch
  dependency-version: 4.0.8
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 15:27:05 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
c46b099e14 Bump braces from 3.0.2 to 3.0.3 in /web (#23839)
Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3.
- [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3)

---
updated-dependencies:
- dependency-name: braces
  dependency-version: 3.0.3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 15:26:59 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
05ebab80b6 Bump form-data from 4.0.5 to 4.0.6 in /web (#23532)
Bumps [form-data](https://github.com/form-data/form-data) from 4.0.5 to 4.0.6.
- [Changelog](https://github.com/form-data/form-data/blob/master/CHANGELOG.md)
- [Commits](https://github.com/form-data/form-data/compare/v4.0.5...v4.0.6)

---
updated-dependencies:
- dependency-name: form-data
  dependency-version: 4.0.6
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 15:26:53 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
6d2bf59aa6 Bump tmp from 0.2.5 to 0.2.7 in /web (#23334)
Bumps [tmp](https://github.com/raszi/node-tmp) from 0.2.5 to 0.2.7.
- [Changelog](https://github.com/raszi/node-tmp/blob/master/CHANGELOG.md)
- [Commits](https://github.com/raszi/node-tmp/compare/v0.2.5...v0.2.7)

---
updated-dependencies:
- dependency-name: tmp
  dependency-version: 0.2.7
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 15:26:48 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1dd5ec312b Bump eslint-plugin-vitest-globals from 1.5.0 to 1.6.1 in /web (#23058)
Bumps [eslint-plugin-vitest-globals](https://github.com/saqqdy/eslint-plugin-vitest-globals) from 1.5.0 to 1.6.1.
- [Release notes](https://github.com/saqqdy/eslint-plugin-vitest-globals/releases)
- [Changelog](https://github.com/saqqdy/eslint-plugin-vitest-globals/blob/master/CHANGELOG.md)
- [Commits](https://github.com/saqqdy/eslint-plugin-vitest-globals/compare/1.5.0...1.6.1)

---
updated-dependencies:
- dependency-name: eslint-plugin-vitest-globals
  dependency-version: 1.6.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 15:26:42 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
cd8a159cc6 Bump postcss from 8.5.8 to 8.5.12 in /web (#23051)
Bumps [postcss](https://github.com/postcss/postcss) from 8.5.8 to 8.5.12.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.5.8...8.5.12)

---
updated-dependencies:
- dependency-name: postcss
  dependency-version: 8.5.12
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 15:26:37 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
3da100af62 Bump react-icons from 5.5.0 to 5.6.0 in /web (#23072)
Bumps [react-icons](https://github.com/react-icons/react-icons) from 5.5.0 to 5.6.0.
- [Release notes](https://github.com/react-icons/react-icons/releases)
- [Commits](https://github.com/react-icons/react-icons/compare/v5.5.0...v5.6.0)

---
updated-dependencies:
- dependency-name: react-icons
  dependency-version: 5.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 15:26:32 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
d25dbb69e1 Bump uuid and @rjsf/shadcn in /web (#23120)
Bumps [uuid](https://github.com/uuidjs/uuid) to 14.0.0 and updates ancestor dependency [@rjsf/shadcn](https://github.com/rjsf-team/react-jsonschema-form). These dependencies need to be updated together.


Updates `uuid` from 13.0.0 to 14.0.0
- [Release notes](https://github.com/uuidjs/uuid/releases)
- [Changelog](https://github.com/uuidjs/uuid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/uuidjs/uuid/compare/v13.0.0...v14.0.0)

Updates `@rjsf/shadcn` from 6.4.1 to 6.5.2
- [Release notes](https://github.com/rjsf-team/react-jsonschema-form/releases)
- [Changelog](https://github.com/rjsf-team/react-jsonschema-form/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rjsf-team/react-jsonschema-form/compare/6.4.1...6.5.2)

---
updated-dependencies:
- dependency-name: uuid
  dependency-version: 14.0.0
  dependency-type: indirect
- dependency-name: "@rjsf/shadcn"
  dependency-version: 6.5.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 15:26:27 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
049263eb42 Bump axios from 1.13.6 to 1.18.0 in /web (#23782)
Bumps [axios](https://github.com/axios/axios) from 1.13.6 to 1.18.0.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.13.6...v1.18.0)

---
updated-dependencies:
- dependency-name: axios
  dependency-version: 1.18.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 15:26:22 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
9182d07f12 Bump react-router-dom from 6.30.3 to 6.30.6 in /web (#24282)
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.30.3 to 6.30.6.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/react-router-dom@6.30.6/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@6.30.6/packages/react-router-dom)

---
updated-dependencies:
- dependency-name: react-router-dom
  dependency-version: 6.30.6
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 15:26:18 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
8d652ce6e4 Bump @ai-sdk/provider-utils, @ai-sdk/react and ai in /docs (#24284)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
Bumps [@ai-sdk/provider-utils](https://github.com/vercel/ai/tree/HEAD/packages/provider-utils), [@ai-sdk/react](https://github.com/vercel/ai/tree/HEAD/packages/react) and [ai](https://github.com/vercel/ai/tree/HEAD/packages/ai). These dependencies needed to be updated together.

Updates `@ai-sdk/provider-utils` from 3.0.19 to 3.0.37
- [Release notes](https://github.com/vercel/ai/releases)
- [Changelog](https://github.com/vercel/ai/blob/@ai-sdk/provider-utils@3.0.37/packages/provider-utils/CHANGELOG.md)
- [Commits](https://github.com/vercel/ai/commits/@ai-sdk/provider-utils@3.0.37/packages/provider-utils)

Updates `@ai-sdk/react` from 2.0.113 to 2.0.260
- [Release notes](https://github.com/vercel/ai/releases)
- [Changelog](https://github.com/vercel/ai/blob/@ai-sdk/react@2.0.260/packages/react/CHANGELOG.md)
- [Commits](https://github.com/vercel/ai/commits/@ai-sdk/react@2.0.260/packages/react)

Updates `ai` from 5.0.111 to 5.0.257
- [Release notes](https://github.com/vercel/ai/releases)
- [Changelog](https://github.com/vercel/ai/blob/ai@5.0.257/packages/ai/CHANGELOG.md)
- [Commits](https://github.com/vercel/ai/commits/ai@5.0.257/packages/ai)

---
updated-dependencies:
- dependency-name: "@ai-sdk/provider-utils"
  dependency-version: 3.0.37
  dependency-type: indirect
- dependency-name: "@ai-sdk/react"
  dependency-version: 2.0.260
  dependency-type: indirect
- dependency-name: ai
  dependency-version: 5.0.257
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 12:58:35 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
9056696ee5 Bump fast-uri from 3.1.2 to 3.1.7 in /web (#24283)
Bumps [fast-uri](https://github.com/fastify/fast-uri) from 3.1.2 to 3.1.7.
- [Release notes](https://github.com/fastify/fast-uri/releases)
- [Commits](https://github.com/fastify/fast-uri/compare/v3.1.2...v3.1.7)

---
updated-dependencies:
- dependency-name: fast-uri
  dependency-version: 3.1.7
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 12:57:45 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
94c9cdbe9b Bump colord from 2.9.3 to 2.10.0 in /docs (#24281)
Bumps [colord](https://github.com/omgovich/colord) from 2.9.3 to 2.10.0.
- [Release notes](https://github.com/omgovich/colord/releases)
- [Changelog](https://github.com/omgovich/colord/blob/master/CHANGELOG.md)
- [Commits](https://github.com/omgovich/colord/commits/v2.10)

---
updated-dependencies:
- dependency-name: colord
  dependency-version: 2.10.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 12:54:44 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
95bdc232d3 Bump fast-uri from 3.1.4 to 3.1.7 in /docs (#24280)
Bumps [fast-uri](https://github.com/fastify/fast-uri) from 3.1.4 to 3.1.7.
- [Release notes](https://github.com/fastify/fast-uri/releases)
- [Commits](https://github.com/fastify/fast-uri/compare/v3.1.4...v3.1.7)

---
updated-dependencies:
- dependency-name: fast-uri
  dependency-version: 3.1.7
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 12:48:41 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
8d648756d2 Bump baseline-browser-mapping from 2.9.6 to 2.11.23 in /docs (#24276)
Bumps [baseline-browser-mapping](https://github.com/web-platform-dx/baseline-browser-mapping) from 2.9.6 to 2.11.23.
- [Release notes](https://github.com/web-platform-dx/baseline-browser-mapping/releases)
- [Commits](https://github.com/web-platform-dx/baseline-browser-mapping/compare/v2.9.6...v2.11.23)

---
updated-dependencies:
- dependency-name: baseline-browser-mapping
  dependency-version: 2.11.23
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 12:48:37 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
89cc76680c Bump joi from 17.13.3 to 17.13.8 in /docs (#24275)
Bumps [joi](https://github.com/hapijs/joi) from 17.13.3 to 17.13.8.
- [Commits](https://github.com/hapijs/joi/compare/v17.13.3...v17.13.8)

---
updated-dependencies:
- dependency-name: joi
  dependency-version: 17.13.8
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 12:48:33 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
fc57dc3b36 Bump svgo from 3.3.2 to 3.3.5 in /docs (#24274)
Bumps [svgo](https://github.com/svg/svgo) from 3.3.2 to 3.3.5.
- [Release notes](https://github.com/svg/svgo/releases)
- [Commits](https://github.com/svg/svgo/compare/v3.3.2...v3.3.5)

---
updated-dependencies:
- dependency-name: svgo
  dependency-version: 3.3.5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 12:48:29 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
97a2697587 Bump js-yaml from 4.1.1 to 4.3.2 in /docs (#24277)
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 4.1.1 to 4.3.2.
- [Changelog](https://github.com/nodeca/js-yaml/blob/4.3.2/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/4.1.1...4.3.2)

---
updated-dependencies:
- dependency-name: js-yaml
  dependency-version: 4.3.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 12:48:25 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
021c12d707 Bump ws in /docs (#23830)
Bumps  and [ws](https://github.com/websockets/ws). These dependencies needed to be updated together.

Updates `ws` from 7.5.10 to 7.5.13
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/7.5.10...7.5.13)

Updates `ws` from 8.18.3 to 8.21.1
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/7.5.10...7.5.13)

---
updated-dependencies:
- dependency-name: ws
  dependency-version: 7.5.13
  dependency-type: indirect
- dependency-name: ws
  dependency-version: 8.21.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 12:32:09 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
4cdcb51571 Bump postcss from 8.5.6 to 8.5.23 in /docs (#23813)
Bumps [postcss](https://github.com/postcss/postcss) from 8.5.6 to 8.5.23.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.5.6...8.5.23)

---
updated-dependencies:
- dependency-name: postcss
  dependency-version: 8.5.23
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 12:32:05 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
c2b9e1222f Bump body-parser from 1.20.4 to 1.20.6 in /docs (#23812)
Bumps [body-parser](https://github.com/expressjs/body-parser) from 1.20.4 to 1.20.6.
- [Release notes](https://github.com/expressjs/body-parser/releases)
- [Changelog](https://github.com/expressjs/body-parser/blob/master/HISTORY.md)
- [Commits](https://github.com/expressjs/body-parser/compare/1.20.4...1.20.6)

---
updated-dependencies:
- dependency-name: body-parser
  dependency-version: 1.20.6
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 12:32:00 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
eaad3cdad7 Bump fast-uri from 3.1.2 to 3.1.4 in /docs (#23811)
Bumps [fast-uri](https://github.com/fastify/fast-uri) from 3.1.2 to 3.1.4.
- [Release notes](https://github.com/fastify/fast-uri/releases)
- [Commits](https://github.com/fastify/fast-uri/compare/v3.1.2...v3.1.4)

---
updated-dependencies:
- dependency-name: fast-uri
  dependency-version: 3.1.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 12:31:56 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
cce23c1983 Bump immutable from 5.1.5 to 5.1.9 in /docs (#23797)
Bumps [immutable](https://github.com/immutable-js/immutable-js) from 5.1.5 to 5.1.9.
- [Release notes](https://github.com/immutable-js/immutable-js/releases)
- [Changelog](https://github.com/immutable-js/immutable-js/blob/main/CHANGELOG.md)
- [Commits](https://github.com/immutable-js/immutable-js/compare/v5.1.5...v5.1.9)

---
updated-dependencies:
- dependency-name: immutable
  dependency-version: 5.1.9
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 12:31:50 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
c5e9ff6f67 Bump websocket-driver from 0.7.4 to 0.7.5 in /docs (#23729)
Bumps [websocket-driver](https://github.com/faye/websocket-driver-node) from 0.7.4 to 0.7.5.
- [Changelog](https://github.com/faye/websocket-driver-node/blob/main/CHANGELOG.md)
- [Commits](https://github.com/faye/websocket-driver-node/compare/0.7.4...0.7.5)

---
updated-dependencies:
- dependency-name: websocket-driver
  dependency-version: 0.7.5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 12:31:42 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
177e0b73c0 Bump @babel/plugin-transform-modules-systemjs in /docs (#23148)
Bumps [@babel/plugin-transform-modules-systemjs](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-modules-systemjs) from 7.28.5 to 7.29.4.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.29.4/packages/babel-plugin-transform-modules-systemjs)

---
updated-dependencies:
- dependency-name: "@babel/plugin-transform-modules-systemjs"
  dependency-version: 7.29.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 12:31:38 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
54d2c99f6f Bump follow-redirects from 1.15.11 to 1.16.0 in /docs (#22892)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.11 to 1.16.0.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.11...v1.16.0)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-version: 1.16.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 12:31:35 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
54c63c485a Bump brace-expansion in /docs (#22682)
Bumps  and [brace-expansion](https://github.com/juliangruber/brace-expansion). These dependencies needed to be updated together.

Updates `brace-expansion` from 1.1.12 to 1.1.13
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](https://github.com/juliangruber/brace-expansion/compare/v1.1.12...v1.1.13)

Updates `brace-expansion` from 2.0.2 to 2.0.3
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](https://github.com/juliangruber/brace-expansion/compare/v1.1.12...v1.1.13)

---
updated-dependencies:
- dependency-name: brace-expansion
  dependency-version: 1.1.13
  dependency-type: indirect
- dependency-name: brace-expansion
  dependency-version: 2.0.3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 12:31:31 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
7627008c11 Bump mermaid from 11.12.2 to 11.16.1 in /docs (#23935)
Bumps [mermaid](https://github.com/mermaid-js/mermaid) from 11.12.2 to 11.16.1.
- [Release notes](https://github.com/mermaid-js/mermaid/releases)
- [Commits](https://github.com/mermaid-js/mermaid/compare/mermaid@11.12.2...mermaid@11.16.1)

---
updated-dependencies:
- dependency-name: mermaid
  dependency-version: 11.16.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 12:30:48 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
0987024856 Bump webpack-dev-server from 5.2.2 to 5.2.6 in /docs (#23819)
Bumps [webpack-dev-server](https://github.com/webpack/webpack-dev-server) from 5.2.2 to 5.2.6.
- [Release notes](https://github.com/webpack/webpack-dev-server/releases)
- [Changelog](https://github.com/webpack/webpack-dev-server/blob/v5.2.6/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack-dev-server/compare/v5.2.2...v5.2.6)

---
updated-dependencies:
- dependency-name: webpack-dev-server
  dependency-version: 5.2.6
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 12:29:55 -05:00
Josh HawkinsandGitHub a9eb286db9 Tweaks (#24260)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
* update versions in discussion templates

* make /run writable by the runtime user under docker's user
2026-09-12 17:07:02 -05:00
Hosted WeblateandJosh Hawkins 9af22e0c2f Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins 9f50aae966 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-filter/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-motionsearch/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-search/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-filter
Translation: Frigate NVR/components-player
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-motionSearch
Translation: Frigate NVR/views-search
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins 9b0c06afda Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-filter/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-motionsearch/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-search/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-filter
Translation: Frigate NVR/components-player
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-motionSearch
Translation: Frigate NVR/views-search
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins 87d04687de Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-motionsearch/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/audio
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-motionSearch
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins 138eb65ac8 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins d418ba4a8d Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/audio
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
11bbb2d45e Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Translated using Weblate (Slovak)

Currently translated at 100.0% (50 of 50 strings)

Translated using Weblate (Slovak)

Currently translated at 73.1% (79 of 108 strings)

Translated using Weblate (Slovak)

Currently translated at 98.7% (237 of 240 strings)

Translated using Weblate (Slovak)

Currently translated at 99.8% (499 of 500 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Miroslav Kravec <kravec.miroslav@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/sk/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/sk/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/sk/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/sk/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins fd31941089 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translation: Frigate NVR/views-settings
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins 292cc648a2 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins 078b1e6bb3 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/audio
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
d2e5de3863 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Translated using Weblate (Finnish)

Currently translated at 34.4% (172 of 500 strings)

Translated using Weblate (Finnish)

Currently translated at 29.7% (55 of 185 strings)

Translated using Weblate (Finnish)

Currently translated at 40.2% (27 of 67 strings)

Translated using Weblate (Finnish)

Currently translated at 36.1% (39 of 108 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Tobbana <tobbana@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/fi/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/fi/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/fi/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/fi/
Translation: Frigate NVR/audio
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins 4717db79a0 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/audio
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins 2cfdb6cb34 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-filter/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/audio
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-filter
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
8846495e16 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Translated using Weblate (French)

Currently translated at 21.5% (172 of 800 strings)

Translated using Weblate (French)

Currently translated at 59.9% (284 of 474 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: jl3r <jl3r@proton.me>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-filter/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-search/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-filter
Translation: Frigate NVR/components-player
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-search
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins c639e58dad Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-filter/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-motionsearch/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-search/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-filter
Translation: Frigate NVR/components-player
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-motionSearch
Translation: Frigate NVR/views-search
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins aab79dc4cd Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translation: Frigate NVR/components-player
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins 33f8caf31e Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-filter/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-motionsearch/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-search/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-filter
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-motionSearch
Translation: Frigate NVR/views-search
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins 0f86a00afa Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-motionsearch/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/audio
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-motionSearch
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins 853d8b0c07 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins de5c18af38 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-motionsearch/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-motionSearch
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins acafd8712c Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-motionsearch/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-search/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-motionSearch
Translation: Frigate NVR/views-search
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
b5106863df Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Translated using Weblate (Hebrew)

Currently translated at 54.6% (59 of 108 strings)

Translated using Weblate (Hebrew)

Currently translated at 96.0% (48 of 50 strings)

Translated using Weblate (Hebrew)

Currently translated at 100.0% (240 of 240 strings)

Translated using Weblate (Hebrew)

Currently translated at 49.3% (639 of 1295 strings)

Translated using Weblate (Hebrew)

Currently translated at 98.7% (237 of 240 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Nick Burdilov <nick.bordilov0405@gmail.com>
Co-authored-by: Nimrod Milo <nimrod@honeybook.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/he/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/he/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/he/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/he/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins 7e69bc2dc2 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins eb5e166ee6 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins 48fc9f2083 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/audio
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins fa78baef94 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins 0d3ece336f Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-filter/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-search/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-filter
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-search
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
5a9f1153c5 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Translated using Weblate (Czech)

Currently translated at 88.8% (96 of 108 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (240 of 240 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: KZeliop <kzeliop@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/cs/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/cs/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins 2a1c087234 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-motionsearch/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/audio
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-motionSearch
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins dfaf3ebe1b Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-motionsearch/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/audio
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-motionSearch
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins bd0ab2a71c Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-motionsearch/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/audio
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-motionSearch
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins 7ff5ff717c Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins 3d5f14e79e Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-live
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins 6a0e8a851b Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins e31592ab2b Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-motionsearch/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/audio
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-motionSearch
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins 74fb3111dc Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-filter/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-search/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-filter
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-search
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins 7108d24d8b Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins 07c15079a3 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins 5e8c70f24c Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins 590b0c9d2d Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-motionsearch/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-search/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-motionSearch
Translation: Frigate NVR/views-search
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
f26f9c467a Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Translated using Weblate (Portuguese (Brazil))

Currently translated at 50.0% (400 of 800 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (474 of 474 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (240 of 240 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (500 of 500 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Marco Cordeiro <marcoecordeiro@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
b29fb3431b Translated using Weblate (Tamil)
Currently translated at 16.6% (1 of 6 strings)

Translated using Weblate (Tamil)

Currently translated at 100.0% (62 of 62 strings)

Translated using Weblate (Tamil)

Currently translated at 0.2% (1 of 474 strings)

Translated using Weblate (Tamil)

Currently translated at 100.0% (74 of 74 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: தமிழ்நேரம் <tamilneram247@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-filter/ta/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/ta/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-motionsearch/ta/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-recording/ta/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/components-filter
Translation: Frigate NVR/views-motionSearch
Translation: Frigate NVR/views-recording
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins c3750ffc80 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins 75d22a436c Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/audio
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins a466d46476 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-live
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins 6aacb47c34 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-filter/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-search/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-filter
Translation: Frigate NVR/components-player
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-search
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-12 16:32:31 -05:00
Hosted WeblateandJosh Hawkins c5093e6668 Update translation files
Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Update translation files

Updated by "Cleanup translation files" add-on in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-settings
2026-09-12 16:32:31 -05:00
Josh HawkinsandGitHub 9cba1c2963 remove deepstack detector and all references to it (#24259)
the 0.18 release notes indicated this was being removed in 0.19
2026-09-12 16:20:50 -05:00
Josh HawkinsandGitHub d59c28e53a Add command menu to frontend (#24256)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
* add command menu to quickly jump between pages, cameras, settings, and quick actions

* access tweaks
2026-09-12 10:57:17 -06:00
Josh HawkinsandGitHub 4861a668b1 Add error boundary to frontend (#24255)
* add error boundary

on frontend errors, show a page-level recovery panel and a separate compact strip for the sidebar/status/bottombar so failures there don't take down the rest of the page

* tweaks

* fix test
2026-09-12 10:32:22 -06:00
Josh HawkinsandGitHub dcfe5307c9 fix CI smoke test (#24254) 2026-09-12 10:12:57 -06:00
Josh HawkinsandNicolas Mowen 37f338d5d6 fix save_attempts trimming (#24246) 2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 7bc32fd4c9 Refactor Notices and System Health pane (#24243)
* refactor notices

* show startup message for enrichments in health pane

* tweaks
2026-09-12 07:30:04 -06:00
Nicolas Mowen 5cef6823a6 Revamp Face Recognition (#24236)
* Rename face model to face recognizer

* Refactor face detection into own module

* Return face and face landmarks

* Align faces with 5 points instead of just the eyes

* Add landmark validation to throw out images which do not fit a landmark

* Fix circular import and lock face detector for concurrent runs across threads

* Fix mypy
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen e3029beba5 Report skipped detections in status bar (#24223)
* report skipped detections in the system notices pane

* revert notices and move to status bar

* shorten string
2026-09-12 07:30:04 -06:00
Nicolas Mowen f9347967eb Add ability to manually run Review Descriptions from the UI / API (#24222)
* Add ability to manually run Review Descriptions from the UI / API

* Fix not handling None type for call
2026-09-12 07:30:04 -06:00
Nicolas Mowen 82be9fff5e Support main+sub stream exports (#24193)
* Support multi resolution exports

* Fix decoder text

* Add dropdown and ability to select export stream selection

* Fix for review comments

* Fix mypy

* Cleanup wording
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 70ce193e09 Improve System Health pane (#24188)
* build out system health pane

* tweaks

* fixes

* fix notice link so it opens the correct camera

* tweak language
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 6d33b31bc6 show disk space reclaimed by media sync (#24189) 2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen d6b93301e2 Miscellaneous fixes (#24179)
* rename migration

* use ASC composite index for event camera and start_time

the planner still picks for newest-first single-camera queries but doesn't slow down full per-camera scans on a cold cache

* pause playback while the timeline range handles are up

* reduce multi camera seeded export range to 30m

allows both handlebars to fit within most desktop windows
2026-09-12 07:30:04 -06:00
11b4d34f93 Misc backend performance improvements (#23244)
* Add additional indicies on event and review tables.  Every events or timeline endpoint filters on event start time and camera, this should speed things up by avoiding a range scan on the table.

* Rewrite to use a CTE to leverage speedups by using sqllite internal optimization to do a single query instead of a starter query to get distinct labels and a subsequent loop of querys per distinct event labels.

Frigate is currently shipping sqlite 3.46.1, which is above the minimum version 3.25 needed for CTEs.

* Collapse a few sequential queries into a single one.

* Use peewee instead of rw sql for the CTE query.

* Slightly simplify review logic and avoid duplicating the json response for empty review IDs.

* Rerun ruff formatting.

* Remove 2x unnecessary index on reviewsegment, remove reference to prior code implementation in comment in event.py

* Editor fail, re-ruff format.

* Remove the CTE and restore the generator with sub-queries, which is more performance (thanks Nick and Blake for testing against your larger DB!)

* Update peewee index migration description

* Add on_conflict_ignore, replacing the try/catch/pass on IntegrityError

* Add a testcase for validating that on_conflict_ignore bypasses what was formerly an IntegrityError

* Change testcase to clarify that it covers the peewee behavior of on_conflict_ignore

---------

Co-authored-by: Greg <{ID}+{username}@users.noreply.github.com>
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen f3a31e2fb4 Add a notice registry and System Health tab (#24178)
* add a notice registry and System Health tab

Problems Frigate detects on its own (ffmpeg crash loops, stuck detectors, failed model downloads, recordings deleted before their retention period) only ever existed as log lines. This adds a `NoticeRegistry` in the main process backed by two tables, an `update_notice` IPC topic so producers in other processes can reach it through the dispatcher, an admin-only API and websocket topic, and a Health tab that lists them. Kinds declare their own mode, severity, and category in one place: state notices are resolved by their producer, event notices are dismissed by the user.

* treat a prerelease as behind its final release

* fix notices clearing early

* rename menu items and update docs

* don't resolve the update notice on a failed version lookup
2026-09-12 07:30:04 -06:00
Nicolas Mowen af60d2db48 GenAI Chat Improvements (#24173)
* Initial tool approval implementation

* Cleanups and fixes

* Improve robustness of loading case
2026-09-12 07:30:04 -06:00
Nicolas Mowen 76708e7fa6 Add options for review prompt style (#24166)
* Add script for testing genai review prompts

* Add option for prompt styling

* Add tests

* Update docs
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 6bd6d3383f fix hardware stats crash when audio transcription is enabled (#24164) 2026-09-12 07:30:04 -06:00
Li XingyuandNicolas Mowen 8cd36416e2 Avoid killing recovered detector during restart (#24146) 2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 9eef369dd0 fix latched loading spinner after cancelling a timeline selection (#24162)
isLoading and isBuffering only clear on playback progress, and scrubbing holds the player paused, so a source rebuild during a timeline selection left them set with nothing able to clear them. Cancelling made them visible as a spinner over an already-loaded frame, which stayed until the next manual seek. Leaving a scrub now clears them when the source is loaded and the element holds a frame.
2026-09-12 07:30:04 -06:00
Nicolas Mowen d183f03fee Dynamically install and load detector dependencies (#24156)
* Dynamically install and load detector dependencies

* Cleanup

* Cleanup
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 53b04f44ef Fix preview players at the hour rollover (#24157)
* fix preview players at the hour rollover

* clean up
2026-09-12 07:30:04 -06:00
Nicolas Mowen 6ae8050974 Refactor Hardware Stats (#24150)
* Refactor hardware stats to have consolidated ffmpeg, detector, and enrichments running.

* Cleanup hardware access that is not passed into the container

* Remove network stats from hardware refactor
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 8370e205da add network isolation docs (#24148) 2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 9416e74aeb fix frozen time bounds on the recordings API (#24121)
`after` and `before` defaulted to `datetime.now()` in the function signature, so they were evaluated once at import. Requests that omitted them got a window ending at process start. They now resolve in the handler.
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen e2da7aae99 Add a deny option for the proxy default role (#24145)
* backend

* frontend

* docs

* fix none default role casing and name reserved roles in the error

* reserve every casing of none as a role name
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 41bc1a5844 Container security hardening (phase 4) (#24140)
* Support read-only rootfs with self-signed certs in /config/tls

* Support read-only rootfs in s6 and pre-compile bytecode

* Assert read-only rootfs support in CI

* Document hardened read-only deployment

* keep certsync's cert selection identical to nginx's

* note the uid trade-off in user: mode

* fail fast when EXTRA_GROUPS or a missing media volume meets read_only

* keep nosuid and nodev on the /run tmpfs

* support read_only in the default mode

* don't take go2rtc down when the homekit file isn't writable

* lead with the hardware consequence of switching to user:

* refuse to write TLS material through a symlink as root

* note that memryx writes models to the root filesystem

* certsync watches whichever cert path nginx loaded
2026-09-12 07:30:04 -06:00
Nicolas Mowen b99c87f272 Fix NPU turbo key and priviledges set (#24138) 2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 3be59c9c18 Container security hardening (phase 3, breaking) (#24081)
* Run the frigate service as the frigate user

* Run go2rtc as its own restricted user

* Run nginx as the frigate user with writable state in /tmp/nginx

* Disable bandwidth stats gracefully when not running as root

* Hand TensorRT model cache ownership to the runtime user

* Document non-root operation and per-hardware device access

* Create /media/frigate after the ownership sweep

* Assert non-root services, JWT migration, and escape hatch in CI

* only write the sweep sentinel when a media volume is mounted

* tolerate homekit config chown failures in the go2rtc run script

* chown the s6 log pipe so non-root nginx can reopen /dev/stdout

* set HOME to /config for non-root services

* run smoke nginx -t and the write probe as the runtime user

* re-own the nginx shm cache on service restart

* discard stdout for the unprivileged smoke nginx -t

* unwrap hard-wrapped prose in the installation docs

* report progress during the ownership sweep

* document EXTRA_GROUPS as the only device access path for dropped services

* expand the non-root device access docs with diagnosis steps and udev rules

* document network storage ownership and the remaining detector hardware

* skip lost+found during the ownership sweep

* hand /tmp/cache to the runtime user before services start

* make bundled models readable by the runtime user

* reload nginx by signaling the master instead of parsing its config as root

* harden root writes into unprivileged-owned paths

Restrict the sweep sentinel to a mount at or below /media/frigate so a
parent /media mount cannot bless a later-shadowed volume. Rebuild
/tmp/nginx root-owned each start so root's cp and tempio writes cannot
follow a symlink an unprivileged nginx planted in the previous run.

* collapse the duplicated sentinel comment

* add a service-runs-as-root helper for granular root services

* validate FRIGATE_ROOT_SERVICES and fail fast on unknown names

* let services listed in FRIGATE_ROOT_SERVICES skip the privilege drop

* record the root-services mode in the sentinel and sweep small trees each boot

* cache the runtime ids in the ownership helper

* chown recordings, previews, and exports to the runtime user at create

* chown the database files after init

* recommend FRIGATE_ROOT_SERVICES in the bandwidth stats warning

* assert granular root services in CI

* document FRIGATE_ROOT_SERVICES

* own every directory level created for a recording segment

* clear the cached runtime ids when ownership tests finish

* skip missing media paths in the per-boot ownership sweep

* clarify granular root services docs

* clean up

* install acl for device access grants

* grant runtime users access to mapped device nodes at boot

* assert device access grants in CI

* document automatic device access grants

* stop telling users device access needs host side setup

* clarify the non-root docs

* link the migration script to the repo

* group the manual device setup under one section

* harden against symlink attacks

/config is owned by the unprivileged runtime user after the ownership sweep, so root operations on files there could be redirected by a planted symlink.

- go2rtc HomeKit setup: replace the root yq/jq normalization and chown with an O_NOFOLLOW helper (prepare_homekit.py), so a symlink at go2rtc_homekit.yml can't redirect a root write or chown onto another file
- go2rtc binary override: ignore /config/go2rtc whenever the service runs as root, so a planted binary can't exec as root under FRIGATE_ROOT_SERVICES
- sweep sentinel: read and write it through safe-sentinel, which trusts only a root-owned regular file and never follows a symlink, so it can't be forged to skip the migration or symlinked to clobber a root file
- ownership sweep: chown with -execdir so a parent directory swapped for a symlink mid-walk can't redirect the chown out of the volume
- validate inputs: restrict DEVICE_ACL_PATHS to /dev, require nonzero numeric EXTRA_GROUPS, and reject PUID/PGID that collide with the go2rtc ids
- docs: correct the TLS key ownership note to match what actually happens

* tweak docs

* stop the ownership sweep chasing entries other mechanisms own

* keep custom binaries out of root services only under granular root
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 1693415375 switch nginx-vod-module to the maintained dio-az fork (#24123)
The `v1.x` line is the same muxed fMP4 code as Kaltura's 1.31 with fixes backported, so the mapping JSON, manifest routes, and ffmpeg consumers are unchanged. The `MAX_CLIPS` patch applies as-is and the HEVC workaround is rewritten for the fork's reformatted source.

`vod_hls_version 6` is now explicit because the fork replaced Kaltura's automatic version calculation with a directive that defaults to 4 and only warns when fmp4 needs 6, so playlists were being stamped `EXT-X-VERSION:4` while carrying `EXT-X-MAP`. The `error_page 502 =404` hack is gone: https://github.com/kaltura/nginx-vod-module/issues/468 is a `vod_mode remote` bug and we're `mapped`, so those 502s were really `_vod_response` returning 404 upstream. The fork maps that through now, and the hack was also turning real 5xx into "no recordings".
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen aaf18b81b2 Fix LPR vehicle message for multiple models (#24119)
* use the camera's model for the lpr vehicle check

`FrigateConfig.model` became `models[]` in the detector refactor, so this didn't compile on 0.19. Each camera has its own detector/model pair now, so the check resolves the camera's scene with `getModelForCamera` instead of looking at every model.

* use camera config model

* fix export test
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 98706482f5 Add Apple compatibility switch to the camera wizard (#24115)
* add apple compatibility switch to the camera wizard

* don't require every record stream to be h265
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen fb8ab56c41 Add onboarding wizard for new installations (#24102)
* add onboarding wizard for new users

* resolve hwaccel per camera and clarify recording retention

The hwaccel step listed every preset Frigate ships, so an Intel box was offered Raspberry Pi and Rockchip decoding, and the codec specific presets (`preset-intel-qsv-h264` vs `-h265`) were offered as global values that break as soon as two cameras use different codecs. `/hardware/hwaccel` now returns the decoding families the probed hardware can actually use, each carrying a preset per codec, and the wizard resolves the family against the detect stream codec the camera wizard already probed: one global `ffmpeg.hwaccel_args` when every camera agrees, per-camera `cameras.<name>.ffmpeg.hwaccel_args` when they don't. The global stays on `auto` in that case so cameras added later still resolve at startup. A gen13+ Intel machine keeps its QuickSync recommendation with mixed h264 and h265 cameras instead of dropping to vaapi.

The recording step's "Days to retain recordings" only wrote alert and detection retention, and the storage estimate under it assumed continuous recording. It now asks what to record in plain language, writes `record.continuous.days` to match, shows the estimate only for continuous, and drops the spinner arrows on the number input.

* clean up

* add light/dark mode icon switcher

* use yml as default config file extension when not found

* i18n tweaks

* gate the setup wizard on cameras instead of a config key

* render setup wizard steps by key

* share the setup wizard e2e helpers and mock users

* add an account step to the setup wizard

* add setup wizard account step e2e coverage

* cover the account step's restart behavior

* button consistency

* fix test

* docs

* fixes
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 96013a0487 Fix 500 when an event thumbnail file is empty (#24110)
* fix 500 when an event thumbnail file is empty

* fix test
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 0aa086eefd Fix inconsistent export download filenames (#24111)
* fix inconsistent export download filenames

Zip entries in a case download were named from `Export.name`, the friendly display name, while an individual download uses the file name on disk. The two have always been formatted differently, so one export came out as `front_door_20260823_020615-20260823_020734_abc123.mp4` on its own and `front door 2026-08-23 020615 2026-08-23 020734.mp4` inside a zip. Zip entries now use the on-disk file name, and renaming an export renames its file, so there's only one name to download under. The rename is blocked while ffmpeg still holds the file.

* cap filename length and catch duplicate names

* fix export rename and stop blocking the event loop

* move the rename rollback off the event loop

* no awaits
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 53fb6c8daa Recording fixes (#24072)
* pin genai review frames to the main stream

* retain previews as long as either stream has recordings

* watch sub stream recording health separately from main

* reject record_sub on the same input as record and document the role

* derive recording paths from the cache segment timestamp

Recording paths carry one second of resolution, but since sub stream recording start times are resolved to fractional wall clock, anchored to the cache file mtime and chained to the previous segment's end. A stream cutting segments faster than once a second resolves consecutive segments into the same second, so two rows collide on the unique path index and the batch insert fails. The cache segment name is unique per camera stream and second by construction because ffmpeg names segments with strftime, so the recording path is now built from that timestamp while the row keeps the resolved start time. This also restores the path semantics from before sub stream recording, when start times came straight from the cache filename.

Nothing derives times from recording paths: playback offsets, stream switching, and export all use the row's start time, which is unchanged, and the recordings sync matches files by exact path string.

* keep the rest of a recording batch when one row conflicts

* only publish record_sub status when a sub stream is configured

* don't shadow camera_cfg when publishing empty cache streams

* back off restarts when a recording stream goes stale

* give the shared sub stream grace on any capture thread reset

* include segment details in recording discard warnings
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 40793b8478 Container security hardening (phase 2) (#24068)
* Create frigate and go2rtc runtime users in the image

* Add single fix-ownership helper for volume permission migration

* Add init-usermod oneshot for PUID and PGID remapping

* Chown newly created runtime directories to the frigate user

* Run sentinel-guarded ownership sweep during prepare

* Add host-side volume permission migration script

* Guard log directory ownership for user-mode startup

* Fall back to plain s6-log when running without root

* Assert PUID remapping and sweep sentinel in CI smoke test

* Skip the ownership sweep in the devcontainer

* Pin FRIGATE_RUN_AS_ROOT in ownership tests

* Do not record the sweep as complete when a chown failed

* Validate PUID and PGID in the migration script

* Treat a failed ownership scan as an incomplete sweep

* Reject PUID and PGID of 0 during remapping

* Handle symlinks, dry runs, and sentinel write failures in the sweep

* Treat an absent sweep root as an incomplete sweep
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen c004d0a1c9 Container security hardening (phase 1) (#24061)
* Verify s6-overlay downloads against pinned checksums

* Verify go2rtc download against pinned checksums

The v1.9.14 release publishes no checksums file, just the bare per-platform binaries, so these digests come from a one-time fetch rather than upstream. That pins the artifact against later substitution, which is the realistic threat for a version we stay on for months, but it does not verify the original download. The stage moves from `ADD --link` to a script because `ADD --checksum` can't express an architecture-dependent URL.

* Verify main image downloads against pinned checksums

Covers everything the main image downloads on the default path: tempio, the hailort runtime tarball and wheel, the six ffmpeg builds, the libedgetpu deb, and the thirteen Intel driver debs. The hailort tarball was streamed straight into `tar`, which can't be verified before extraction, so it downloads to `/tmp` first. The three ffmpeg blocks per arch collapse into one `install_ffmpeg` helper since they only differed by URL and install dir, and the Intel debs go through a `fetch_intel_deb` helper for the same reason.

The Intel debs are the ones that mattered most here. They're installed as root with `dpkg` on the default amd64 path and had no verification at all. compute-runtime publishes a `ww<week>.sum` asset with every release and npu-driver published `checksum.sha256` on v1.19.0, so those eight digests came from upstream rather than from us. intel-graphics-compiler and level-zero publish none, so those five and everything else here come from a one-time fetch, which pins the artifact against later substitution but doesn't verify the original download. The comment above the map says which is which and how to refresh them, since npu-driver has stopped publishing sums since v1.19.0 and that provenance won't survive the next bump.

Still unpinned: `get-pip.py`, which is a rolling URL where a digest would just break the build on pypa's next edit, and the per-variant artifacts for Axera, Synaptics, and Jetson. apt repositories are out of scope since apt already verifies signatures.

* Restrict generated TLS key permissions

OpenSSL 3.x already writes the key at 600 on its own, so this pins the guarantee rather than fixing an observed leak: the mode no longer depends on the openssl version or the umask the service happens to start with. Only the generated pair is touched. User-mounted certs take the other branch and are never chmod'd, which matters when they're mounted read-only.

* Add security headers and server_tokens off

Adds `X-Content-Type-Options: nosniff` and `Referrer-Policy: strict-origin-when-cross-origin`, and turns off nginx version disclosure.

No `X-Frame-Options` and no CSP `frame-ancestors`. HA's Webpage card and iframe panels frame Frigate's own address cross-origin, and either header would break them silently with nothing in Frigate's logs to explain it. Ingress is same-origin and would survive `SAMEORIGIN`, but Frigate can't tell the two apart from inside the container. `security_headers.conf` is a plain file in the image rather than a generated one, so anyone who does want framing restrictions can bind-mount it.

`add_header` doesn't inherit into a block that declares its own, so the include goes in per block, all nine of them, including the four nested static-asset locations that serve the JS bundles. Those are the ones nosniff actually matters for.

The run script now reads `get_nginx_settings.py` once into a variable instead of shelling out per template. That script imports the frigate config machinery, which is noticeable on an SBC.

Not fixed here: `listen.conf` is included at server level and carries `Strict-Transport-Security`, so those same nine blocks already drop HSTS under TLS today. Folding it into this file would change existing TLS behavior on nine paths, so it needs its own PR.

* Restrict go2rtc config file permissions

* Log failed login attempts with source address

Failed logins returned a bare 401 and left nothing behind, so credential stuffing was invisible unless you were already watching nginx access logs. Both failure branches now log a warning with the attempted username and the client address.

The address comes from `get_remote_addr()`, the same helper the login rate limiter keys on, so the two agree on who the client is and the trusted-proxy handling is consistent. Logging a raw `x-forwarded-for` instead would let an attacker forge the source address in the very log line meant to catch them.

The response is unchanged and identical either way. Which factor failed is only visible in the log, never to the client, and the password is never logged.

* Recommend least-privilege container options in install docs

The compose generator pushed `privileged: true` into every file it produced, no matter what hardware you picked, and it's the default tab on the install page so it's what most people copy. It now emits `security_opt: no-new-privileges:true` instead, and only adds `privileged: true` for hardware that actually needs it, with the reason inline. MemryX is the only one today, since it needs to reach the max-manager. Rockchip and Synaptics only want privileged during initial setup and their documented end state is device mappings, so neither gets it.

`no-new-privileges` merges into the same `security_opt` block as any device-specific entries, so Rockchip still gets its `apparmor=unconfined` and `systempaths=unconfined` without a duplicate key.

The static example now has `privileged` commented out, and there's a short section on the options worth adding, with a note that `cap_drop: ALL` breaks `telemetry.stats.network_bandwidth` since nethogs needs NET_ADMIN/NET_RAW.

* Add amd64 container smoke test to CI

Boots the built amd64 image against a minimal config and asserts the two security headers, that the Server header no longer carries a version, that no frame-ancestors is present, that nginx accepts its own config, and the two file modes. This is also the harness the rest of the hardening work extends.

The two negative assertions are written as `if grep; then exit 1; fi` rather than `! grep`. Bash exempts a negated command from `set -e`, so the `!` form would have passed even with the version and frame-ancestors both present, which is the opposite of what a regression net is for.
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 396a2156b2 Tweaks (#24067)
* improve keyframes messages

* don't pad the labelmap with unknown

`load_labels()` prefilled 91 `unknown` entries before reading the label file, so any model with fewer than 91 classes kept that padding in `merged_labelmap` and `unknown` showed up as a selectable object type in the objects settings UI. The padding only existed so `RemoteObjectDetector.detect` could index the labelmap without a KeyError, and it didn't even cover the empty-file case or Frigate+, which never had a prefill. Both lookups now skip class ids the labelmap doesn't name and warn once per id.
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 853840dfd4 Add secrets.yaml and unify variable substitution sources (#24044)
* add secrets.yaml and merge substitution sources by precedence

FRIGATE_ENV_VARS was built once at import from container env and /run/secrets, and the environment_vars validator overwrote it unconditionally, so the block beat the deployment and nothing could be re-read. Sources are now separate dicts merged lowest to highest (environment_vars, secrets.yaml, container env, credentials directory), re-read at the top of every parse, and a collision warns once naming the winner. An undefined {FRIGATE_*} raises a ValueError subclass so pydantic reports the field instead of a KeyError traceback.

* use the shared substitution namespace in go2rtc config

The generator rebuilt the namespace itself from os.environ and a hardcoded /run/secrets, so it never saw environment_vars or CREDENTIALS_DIRECTORY, and str.format made any stray brace fatal. It now installs the FRIGATE_ names from environment_vars and substitutes streams the same way every other field does.

* read the exec override from an import time snapshot

environment_vars is exported into os.environ, and is_go2rtc_arbitrary_exec_allowed read os.environ live, so the config file could enable exec sources. Snapshot the variable at import, which runs before any config is loaded.

* docs

* clarify docs
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen c9c6a923ef add recognized plate picker to lpr known plates in settings (#24059) 2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen a16ca285f7 fix clip download deadlock from unread ffmpeg stderr (#24032)
ffmpeg's stderr was piped but never read, so recording segments that generate more than 64 KB of ffmpeg warnings blocked ffmpeg mid-write, stranding the streaming thread and its anyio threadpool token for good. Enough of those and every sync endpoint stops responding until restart. The trigger is how noisy the segments are, not how long the clip is.

Send stderr to a temp file instead, and guarantee ffmpeg teardown and playlist cleanup on every exit path, including client disconnect.

Also fixes two bugs the deadlock hid: the failure branch was unreachable because returncode is None mid-loop, so the playlist file leaked and ffmpeg's logs were never reported. Playlist files now get a unique name so concurrent requests for one range cannot delete each other's input.

Extracts the terminate helper motion search already had into frigate/util/ffmpeg.py, now shared by both streaming call sites.
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 46796fe9ef fix the model lookup KeyError for cameras added at runtime (#24026) 2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 257a05a7e2 Add import/export for camera group layouts and per-camera streaming settings (#24025)
* add import/export for camera group layouts and streaming settings

Camera group layouts and per-camera streaming settings are stored in the browser's IndexedDB, so they are tied to a single browser on a single device. Users with more than one device have to rebuild every group layout and re-pick every camera's stream settings by hand, and clearing browser data loses the work.

Add a Backup & Restore card to Settings > UI Settings that exports these settings to a JSON file and imports that file on another device. Import shows a confirmation dialog with per-section counts, switches for layouts, streaming settings, and UI preferences, and warnings about camera groups or cameras in the file that are not on this server.

Server-side storage is deliberately avoided. These are per-device presentation settings: a layout arranged for a desktop is wrong on a tablet, and continuous full-resolution streams that are free on a wired LAN are not on a phone. An explicit file moves settings only when the user chooses to move them.

Implementation notes:

- web/src/utils/uiSettingsTransfer.ts owns a registry of transferable IndexedDB keys. Each entry records whether the key is user-namespaced, matching which persistence hook wrote it, plus a zod schema for its value.
- Only registry-known keys are ever written, and only when their value passes that schema. The file format deliberately lets unknown keys survive parsing, so this filter is what prevents a hand-edited file from writing arbitrary storage keys or out-of-range values.
- Export falls back to the legacy un-namespaced key, because the username migration runs lazily on first mount of each owning hook.
- Streaming settings merge per group rather than replacing the whole map, so groups configured only on the receiving device survive.
- Import writes storage and then reloads, because useUserPersistence reads a key only on mount and StreamingSettingsProvider would otherwise write its stale in-memory state back over the import.
- playbackBandwidthEstimate, frigate-search-history, and live-layout are excluded: the first two are measurements and user data rather than preferences, and live-layout's default is derived from the device.

* merge imported streaming settings per camera instead of per group
2026-09-12 07:30:04 -06:00
Nicolas Mowen 27a40a507b Implement UI for managing multiple models (#24023)
* Implement hardware detection and UI management

* Cleanup Frigate+ detection

* Don't count model as changed

* Fixes for audio map error

* Add descriptions

* Enforce that all model must exist

* Fix hardware picking

* Docs fixes

* WebUI cleanup

* Cleanup handling of scenes

* UI refinement

* Cleanup recommended UI

* test fixews
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 3f20209339 Base emergency cleanup on the streams a camera is currently recording (#24022)
* gate emergency cleanup bandwidth on the streams a camera currently records

* settle bandwidth samples per stream instead of per camera

* fix mypy
2026-09-12 07:30:04 -06:00
Nicolas Mowen 8fe35ace3b Refactor detector and model management (#23995)
* Refactor detector and model management

* Fix model resolution field
2026-09-12 07:30:04 -06:00
Ersa Oktavian RamadanandNicolas Mowen fd76eb6c6f Add audio labelmap grouping (#24004)
Allow audio classes to be grouped under a shared configured label.

Keep audio overrides separate from object labels and retain only the highest-scoring grouped detection.

Refs #23967
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 6ba9dd92e4 Show main and sub stream usage separately in Storage Metrics (#24015)
* backend

* frontend

* docs

* test

* report null instead of 0 for a stream with no cached bandwidth sample
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen ad04101c76 Refactor MQTT (#24010)
* refactor mqtt so that Frigate owns the transport lifecycle instead of delegating it to paho

* release the shutdown barrier on worker crash and replay retained publishes the broker never acked

* collapse in-flight retained values by topic and release the shutdown barrier from a finally

* replay the outage buffer before the publish queue so newer values are not reverted
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen f4cf1e1539 Refactor birdseye activity modes as a list and add alerts/detections (#24012)
* backend

* tests

* frontend and i18n

* e2e test schema

* docs
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen e77155a4f1 Improve History's seek startup time and recordings query performance (#24011)
* serve a segment startup ladder so seeks begin playing sooner

nginx-vod was handed one 10s segment per recording file, so every playlist start had to download and decode a full segment before the first frame. Declare real keyframe data per clip and let nginx cut short leading segments from it.

- add vod_bootstrap_segment_durations 1000/2000/4000 so each playlist starts with 1s/2s/4s segments before settling at 10s
- emit real clip-relative keyFrameDurations (plus firstKeyFrameOffset when nonzero) from the recording keyframe index; rows without an index keep the whole-clip declaration, the only safe cut without keyframe knowledge
- drop the manifest's segment_duration field, which was always inert: nginx-vod parses only camelCase segmentDuration
- rebuild the player source at the seek target, quantized to a 10s grid, so the ladder applies to every seek and seek URLs stay repeatable for nginx's mapping and response caches
- route the seek model, in-range checks, and the stale-report guard through the source window rather than the chunk range
- bridge repositioning seeks (>2s from the last played timestamp) through the preview player and hold the release anchor one commit, so neither path paints a stale frame
- clear a pending loading timer before replacing it; an orphaned timer escaped onPlaying's clearTimeout and flashed loading mid-playback

* keep recordings queries on their indexes

Several recordings queries degraded into full scans or large sorts on big databases: the planner ignored index order, or the query shape gave it nothing tight to seek on. Reshape them into bounded seeks and add the composite index the per-stream lookups need.

- index recordings on (camera, stream_type, start_time DESC) and drop the (camera, stream_type) index it supersedes
- walk the recordings summary day by day with EXISTS probes and per-camera MIN/MAX seeks, skipping ahead over empty gaps instead of bucketing every row for the requested cameras
- run the summary endpoint on the event loop rather than the threadpool
- bound the unavailable-recordings query by start_time per camera and merge the results in Python
- bound the expire query's start_time so it seeks the retention window instead of scanning a camera's whole history
- enumerate deleted cameras with one index seek each rather than a camera NOT IN (...) scan
- compute bandwidth with segment_size filtered in a CASE projection; as a WHERE predicate it baited the planner into the (camera, segment_size) index plus a full sort of the camera's history
- fall back to a 1000-segment window when the recent 100 are all zero-size, so an ingest glitch doesn't report zero bandwidth
- limit the needs_refresh count instead of counting every segment
- cover sub-only and sparse calendar days, midnight-spanning day attribution, multi-camera gap merging, deleted-camera expiry, and zero-size segment runs

* fix mypy
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 50e7b76eb5 Enable PTZ control setup in the Add Camera Wizard (#23444)
* add ptz controls to camera via wizard when onvif has already been probed

* i18n

* add e2e test

* backend add and remove subscriber

* tweaks

* turn on switch by default if pan and/or tilt capability is available

* fix test
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 1498231eb9 Add sub stream recording with adaptive quality playback (#24009)
* add sub stream recording with adaptive quality playback

Optionally record a second, lower bitrate stream alongside the main
recording stream via a `record_sub` input role and `record.sub` config block, with its own retention windows.
Recordings rows now carry the stream type plus the media details needed to serve both streams from one manifest: video codec, audio presence, audio codec and rate, and a record-time keyframe index.

Playback resolves coverage across both streams and merges them into a single VOD sequence, falling back to a discontinuity manifest with per-clip init segments when the media signatures differ. The player exposes a quality selector, and an auto governor picks the stream from stall time, bandwidth, codec support, and the save-data hint.

* fix tests and i18n
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen f7c5500ea8 stop creating a config subscriber per capture thread (#24002) 2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen d78f6a7a98 Guard lookups when adding/deleting cameras at runtime (#23994)
* Guard object processor queue handlers against unknown cameras

* Skip embeddings post processing for removed cameras

* End review segments for removed cameras

* Drop queued autotracker moves for removed cameras

* Release tracked event thumbnails when skipping a removed camera

* Add locked accessors for camera states

* Read camera states through the processor accessors

* Guard output and recording paths against cameras not yet known

* Resolve camera state once in ONVIF, notification, and transcription paths
2026-09-12 07:30:04 -06:00
Ersa Oktavian RamadanandNicolas Mowen d6a18e79aa Refactor Birdseye activity types as composable booleans (#23940)
* Add combined motion and object Birdseye mode

Add a motion_objects mode that keeps Birdseye active when motion is detected or a confirmed tracked object is present, including stationary objects.

Wire the mode through configuration, runtime commands, API schemas, documentation, and UI labels. Exclude false-positive trackers and add regression coverage for Birdseye activation and MQTT validation.

* Refactor Birdseye activity types as booleans

Replace combination-specific Birdseye modes with composable boolean activity types for motion, active objects, stationary objects, and continuous display.

Preserve legacy single-mode configuration and MQTT inputs, support canonical comma-separated MQTT combinations, and allow scalar YAML values to be replaced by nested settings through the config API.

* Preserve OpenVINO config translations

Regenerate the configuration translations with the OpenVINO detector schema available so the unrelated production detector labels remain intact.

* Preserve partial Birdseye mode overrides

Allow an empty activity selection with a canonical NONE MQTT state so partial camera and profile overrides can disable inherited flags without failing validation.

Add regression coverage for camera and profile inheritance, document the NONE contract, and keep the generated schema fixture scoped to Birdseye.

* Address Birdseye activity review feedback

Move scalar mode compatibility into the 0.18-1 config migration and reject empty activity selections instead of publishing a NONE state.

Pass activity signals through a frozen dataclass, preserve existing active-object tracker behavior, and require confirmed stationary objects. Revert the generic YAML mutation and cover migration, inheritance, MQTT, and activation regressions.

* Move Birdseye migration to 0.19

Use the 0.19-0 configuration revision for converting scalar Birdseye modes to composable activity flags, and update the migration regression coverage accordingly.

* Remove Birdseye migration test

Drop the dedicated config migration test as requested during review while retaining the 0.19-0 migration implementation.
2026-09-12 07:30:04 -06:00
Josh HawkinsandNicolas Mowen 7841d41bea Fix birdseye layout overlap with mixed landscape/portrait cameras (#22917)
* fix birdseye layout calculation

replace the two pass layout with a single pass pixel space algorithm

* add test
2026-09-12 07:30:04 -06:00
Nicolas Mowen 15c41c9850 Don't require object type for parameter in categorized names tool 2026-09-12 07:30:04 -06:00
3dffa52eac Dynamically resolve Intel NPU (#23761)
* Add support for newer Intel NPU busy time counter

* Resolve Intel NPU device dynamically

---------

Co-authored-by: Filious Louis <1417132+fjlouis@users.noreply.github.com>
2026-09-12 07:30:04 -06:00
DoFabienandNicolas Mowen 8fe8e20d68 Improve recording timeline and VOD query performance (#23862)
* Improve recording timeline and VOD query performance

* Add recording query boundary tests
2026-09-12 07:30:04 -06:00
Nicolas Mowen b2345cdd0b GenAI Chat Prompt Refinements (#23864)
* Prompt refactoring and optimization

* Update spec
2026-09-12 07:30:04 -06:00
Nicolas Mowen c881b346a7 Update to 0.19 2026-09-12 07:30:04 -06:00
Dermot DuffyandGitHub 77a66e75c6 Fix Content-Type for webp, png, and jpeg files in /clips/ (#24208)
CI / AMD64 Build (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
2026-09-06 13:32:44 -06:00
Josh HawkinsandGitHub 4ac92dac72 Sync PWA status bar theme-color with resolved app theme (#24203)
CI / AMD64 Build (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
* sync PWA status bar theme-color with resolved app theme

* update tags on login page too

* track system theme preference

* revert
2026-09-05 15:57:39 -06:00
6ceb370abb Translated using Weblate (Korean)
CI / AMD64 Build (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
Currently translated at 100.0% (54 of 54 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (474 of 474 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (141 of 141 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (1295 of 1295 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (145 of 145 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (129 of 129 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (60 of 60 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (50 of 50 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (10 of 10 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (86 of 86 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (100 of 100 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (26 of 26 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (108 of 108 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (500 of 500 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (500 of 500 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (60 of 60 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (1295 of 1295 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (86 of 86 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (474 of 474 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (240 of 240 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (2 of 2 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (50 of 50 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (500 of 500 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (6 of 6 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (141 of 141 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (62 of 62 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (46 of 46 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (10 of 10 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (129 of 129 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (800 of 800 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (185 of 185 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (145 of 145 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (74 of 74 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (100 of 100 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (10 of 10 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (49 of 49 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (54 of 54 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (108 of 108 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (67 of 67 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (25 of 25 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (26 of 26 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: ecomen <skymbj@naver.com>
Co-authored-by: sinfancy <yujsjs@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-auth/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-filter/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-icons/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-groups/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-chat/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-configeditor/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-motionsearch/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-recording/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-replay/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-search/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/ko/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/ko/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Groups
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-auth
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-filter
Translation: Frigate NVR/components-icons
Translation: Frigate NVR/components-player
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-chat
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-configeditor
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-motionSearch
Translation: Frigate NVR/views-recording
Translation: Frigate NVR/views-replay
Translation: Frigate NVR/views-search
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-05 06:33:55 -05:00
dfefc5a64b Translated using Weblate (Swedish)
Currently translated at 64.6% (517 of 800 strings)

Translated using Weblate (Swedish)

Currently translated at 100.0% (474 of 474 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Jonatan Nyberg <nickwick@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/sv/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/sv/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
2026-09-05 06:33:55 -05:00
97dec9d046 Translated using Weblate (Hungarian)
Currently translated at 7.3% (35 of 474 strings)

Translated using Weblate (Hungarian)

Currently translated at 97.0% (485 of 500 strings)

Translated using Weblate (Hungarian)

Currently translated at 97.0% (485 of 500 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Laszlo Bana <banalac@yahoo.com>
Co-authored-by: Martin Rácz <raczmartinroland@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/hu/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/hu/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/audio
2026-09-05 06:33:55 -05:00
ffcadb440e Translated using Weblate (Portuguese)
Currently translated at 57.4% (62 of 108 strings)

Translated using Weblate (Portuguese)

Currently translated at 99.8% (499 of 500 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: cantarol CR <cr1996@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/pt/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/pt/
Translation: Frigate NVR/audio
Translation: Frigate NVR/components-dialog
2026-09-05 06:33:55 -05:00
a381a88b29 Translated using Weblate (Ukrainian)
Currently translated at 4.3% (35 of 800 strings)

Translated using Weblate (Ukrainian)

Currently translated at 9.7% (46 of 474 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: wkornilow <the.wkornilow@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/uk/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/uk/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
2026-09-05 06:33:55 -05:00
Nicolas MowenandGitHub 9e74adf812 Guard against memory allocation in graph capture (#24192)
CI / AMD64 Build (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
2026-09-04 09:13:30 -06:00
Josh HawkinsandGitHub 287fc42404 Miscellaneous fixes (#24172)
CI / AMD64 Build (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
* fix frigate+ submission state bleeding onto the next tracked object

* add Korean

* fix tests
2026-09-03 06:44:18 -05:00
b4d5035b79 Docs: fix Synaptics default model path and warn about v4l2m2m kernel Oops on GT-BE19000AI (#24008)
CI / AMD64 Build (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
* Docs: fix Synaptics default model path in object detector docs

The model is installed at /synaptics/mobilenet.synap by docker/synaptics/Dockerfile,
matching the config examples in the same section.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Docs: warn about kernel Oops with v4l2m2m hwaccel on ASUS GT-BE19000AI

Enabling the recommended h264_v4l2m2m hwaccel args on the GT-BE19000AI AI
board (SL1680, firmware kernel 5.15.140) triggers a LIST_POISON dereference
Oops in the vendor vpu driver during decoder teardown, requiring a reboot.
Observed and captured on real hardware. Also fixes a Synaptics typo.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Docs: drop GT-BE19000AI hwaccel warning per review

Remove the device-specific v4l2m2m kernel Oops warning as requested by
maintainer review; upstream/vendor gotchas are not documented here. The
Synaptics typo fix and model path correction remain.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-09-02 10:39:30 -05:00
7497ef7506 Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (46 of 46 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (62 of 62 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (49 of 49 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (6 of 6 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (108 of 108 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (1295 of 1295 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (240 of 240 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: OverTheHillsAndFarAway <prosjektx@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-motionsearch/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-recording/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-replay/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-search/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/nb_NO/
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/views-motionSearch
Translation: Frigate NVR/views-recording
Translation: Frigate NVR/views-replay
Translation: Frigate NVR/views-search
Translation: Frigate NVR/views-settings
2026-09-02 08:24:47 -06:00
0d5038c7a0 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (67 of 67 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (1295 of 1295 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (240 of 240 strings)

Co-authored-by: GuoQing Liu <842607283@qq.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/zh_Hans/
Translation: Frigate NVR/common
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-settings
2026-09-02 08:24:47 -06:00
c71939acc2 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (46 of 46 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (62 of 62 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (54 of 54 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (800 of 800 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (474 of 474 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (141 of 141 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (185 of 185 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (1295 of 1295 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (145 of 145 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (108 of 108 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (50 of 50 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (10 of 10 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (240 of 240 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (46 of 46 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (54 of 54 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (800 of 800 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (474 of 474 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (141 of 141 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (185 of 185 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (1295 of 1295 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (100 of 100 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (60 of 60 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (145 of 145 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (67 of 67 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (129 of 129 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (108 of 108 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (500 of 500 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (46 of 46 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (54 of 54 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (800 of 800 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (1295 of 1295 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (49 of 49 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (100 of 100 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (145 of 145 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (67 of 67 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (10 of 10 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (26 of 26 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (108 of 108 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (240 of 240 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (240 of 240 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (500 of 500 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: windasd <me@windasd.tw>
Co-authored-by: 蘭蘭露 <flandrescarlettw@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-auth/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-chat/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-configeditor/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-motionsearch/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-replay/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-search/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/zh_Hant/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-auth
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-player
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-chat
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-configeditor
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-motionSearch
Translation: Frigate NVR/views-replay
Translation: Frigate NVR/views-search
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-02 08:24:47 -06:00
e983825781 Translated using Weblate (Korean)
Currently translated at 87.4% (437 of 500 strings)

Translated using Weblate (Korean)

Currently translated at 85.6% (428 of 500 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: ecomen <skymbj@naver.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/ko/
Translation: Frigate NVR/audio
2026-09-02 08:24:47 -06:00
25681444d4 Translated using Weblate (French)
Currently translated at 21.3% (171 of 800 strings)

Translated using Weblate (French)

Currently translated at 59.7% (283 of 474 strings)

Translated using Weblate (French)

Currently translated at 65.4% (847 of 1295 strings)

Translated using Weblate (French)

Currently translated at 30.2% (26 of 86 strings)

Translated using Weblate (French)

Currently translated at 100.0% (108 of 108 strings)

Translated using Weblate (French)

Currently translated at 99.1% (238 of 240 strings)

Translated using Weblate (French)

Currently translated at 18.3% (147 of 800 strings)

Translated using Weblate (French)

Currently translated at 54.8% (260 of 474 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Thomas DAGET <tdaget@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/fr/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-settings
2026-09-02 08:24:47 -06:00
47d25254e9 Translated using Weblate (Indonesian)
Currently translated at 59.4% (44 of 74 strings)

Translated using Weblate (Indonesian)

Currently translated at 94.4% (102 of 108 strings)

Co-authored-by: Akos <asep.tmt@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/id/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-filter/id/
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-filter
2026-09-02 08:24:47 -06:00
3e6d60fcac Added translation using Weblate (Azerbaijani)
Added translation using Weblate (Azerbaijani)

Added translation using Weblate (Azerbaijani)

Added translation using Weblate (Azerbaijani)

Added translation using Weblate (Azerbaijani)

Added translation using Weblate (Azerbaijani)

Added translation using Weblate (Azerbaijani)

Added translation using Weblate (Azerbaijani)

Added translation using Weblate (Azerbaijani)

Added translation using Weblate (Azerbaijani)

Added translation using Weblate (Azerbaijani)

Added translation using Weblate (Azerbaijani)

Added translation using Weblate (Azerbaijani)

Added translation using Weblate (Azerbaijani)

Added translation using Weblate (Azerbaijani)

Added translation using Weblate (Azerbaijani)

Added translation using Weblate (Azerbaijani)

Added translation using Weblate (Azerbaijani)

Added translation using Weblate (Azerbaijani)

Update translation files

Updated by "Squash Git commits" add-on in Weblate.

Co-authored-by: Akus <orxanrecebov05@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/
Translation: Frigate NVR/common
2026-09-02 08:24:47 -06:00
77d6b0540d Translated using Weblate (Italian)
Currently translated at 100.0% (1295 of 1295 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (240 of 240 strings)

Co-authored-by: Gringo <ita.translations@tiscali.it>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/it/
Translation: Frigate NVR/common
Translation: Frigate NVR/views-settings
2026-09-02 08:24:47 -06:00
632af09f73 Translated using Weblate (Polish)
Currently translated at 100.0% (46 of 46 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (62 of 62 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (54 of 54 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (800 of 800 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (474 of 474 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (141 of 141 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (185 of 185 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (1295 of 1295 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (100 of 100 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (60 of 60 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (108 of 108 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (86 of 86 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (67 of 67 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (129 of 129 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (240 of 240 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Mieszko Stelmach <mieszko.stelmach@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-chat/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-motionsearch/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-replay/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/pl/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-chat
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-motionSearch
Translation: Frigate NVR/views-replay
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-09-02 08:24:47 -06:00
10eb677e4c Translated using Weblate (Catalan)
Currently translated at 100.0% (1295 of 1295 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (240 of 240 strings)

Co-authored-by: Eduardo Pastor Fernández <123eduardoneko123@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/ca/
Translation: Frigate NVR/common
Translation: Frigate NVR/views-settings
2026-09-02 08:24:47 -06:00
bc3e4a0b35 Translated using Weblate (Belarusian)
Currently translated at 100.0% (240 of 240 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Uladz Maltsau <wldyslw@icloud.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/be/
Translation: Frigate NVR/common
2026-09-02 08:24:47 -06:00
08a13d955e Translated using Weblate (Romanian)
Currently translated at 100.0% (240 of 240 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: lukasig <lukasig@hotmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/ro/
Translation: Frigate NVR/common
2026-09-02 08:24:47 -06:00
ac16decf05 Translated using Weblate (Estonian)
Currently translated at 30.8% (399 of 1295 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (240 of 240 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Priit Jõerüüt <jrthwlate@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/et/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/et/
Translation: Frigate NVR/common
Translation: Frigate NVR/views-settings
2026-09-02 08:24:47 -06:00
6e106854e4 Translated using Weblate (German)
Currently translated at 100.0% (1295 of 1295 strings)

Translated using Weblate (German)

Currently translated at 100.0% (240 of 240 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Viktor Stier <viktor-stier@gmx.de>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/de/
Translation: Frigate NVR/common
Translation: Frigate NVR/views-settings
2026-09-02 08:24:47 -06:00
c6688c8ce7 Translated using Weblate (Tamil)
Currently translated at 1.6% (1 of 60 strings)

Translated using Weblate (Tamil)

Currently translated at 100.0% (145 of 145 strings)

Translated using Weblate (Tamil)

Currently translated at 100.0% (100 of 100 strings)

Translated using Weblate (Tamil)

Currently translated at 100.0% (129 of 129 strings)

Translated using Weblate (Tamil)

Currently translated at 5.0% (25 of 500 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: தமிழ்நேரம் <tamilneram247@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/ta/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/ta/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/ta/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/ta/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/ta/
Translation: Frigate NVR/audio
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
2026-09-02 08:24:47 -06:00
149362c77f Translated using Weblate (Lithuanian)
Currently translated at 1.2% (10 of 800 strings)

Translated using Weblate (Lithuanian)

Currently translated at 2.5% (12 of 474 strings)

Translated using Weblate (Lithuanian)

Currently translated at 42.8% (555 of 1295 strings)

Translated using Weblate (Lithuanian)

Currently translated at 100.0% (6 of 6 strings)

Translated using Weblate (Lithuanian)

Currently translated at 100.0% (145 of 145 strings)

Translated using Weblate (Lithuanian)

Currently translated at 100.0% (108 of 108 strings)

Translated using Weblate (Lithuanian)

Currently translated at 100.0% (240 of 240 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: MaBeniu <runnerm@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/lt/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/lt/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/lt/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/lt/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/lt/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-recording/lt/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/lt/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-recording
Translation: Frigate NVR/views-settings
2026-09-02 08:24:47 -06:00
Nicolas MowenandGitHub 2117b58aba Adjust audio striping (#24161) 2026-09-02 07:29:46 -06:00
Josh HawkinsandGitHub a529656a90 Fix jumping timeline handles in debug replay range selection (#24158)
CI / AMD64 Build (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
* fix jumping timeline handles in debug replay range selection

The timeline mirrored the export range into local state that was never reset when the range cleared, so starting a second selection after cancelling one left the stale mirror disagreeing with the new range. The sync effect and the draggable position effect then rewrote each other's values every commit until React hit its update limit. The handles now write the range directly.

* add mobile test
2026-09-01 20:17:29 -05:00
Nicolas MowenandGitHub c1b56b51b0 Backport 0.19 iOS HLS fixes (#24147)
CI / AMD64 Build (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
2026-08-31 12:17:56 -05:00
Josh HawkinsandGitHub d37dff1b49 Docs update (#24131)
* fix incorrect backchannel docs

`#backchannel=0` is a native rtsp source param, not an ffmpeg one, and the troubleshooting warning had it listed as ffmpeg-only. Any `#` modifier on a bare `rtsp://` source turns the backchannel off unless the URL explicitly contains `#backchannel=1`, so a dedicated two-way talk stream can't carry `#video=h264` or anything else.

* add rotation faq
2026-08-29 07:01:11 -06:00
UladzislauandGitHub a745070b76 proper belarusian locale support (#24112)
CI / AMD64 Build (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
2026-08-28 07:08:54 -05:00
4ffe687c44 Translated using Weblate (Finnish)
Currently translated at 25.9% (48 of 185 strings)

Co-authored-by: Harri Avellan <hhamalai@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/fi/
Translation: Frigate NVR/views-system
2026-08-28 07:01:48 -05:00
59269238ed Translated using Weblate (Swedish)
Currently translated at 64.6% (517 of 800 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Kristian Johansson <knmjohansson@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/sv/
Translation: Frigate NVR/Config - Global
2026-08-28 07:01:48 -05:00
02da563712 Translated using Weblate (Dutch)
Currently translated at 97.1% (777 of 800 strings)

Translated using Weblate (Dutch)

Currently translated at 88.6% (420 of 474 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: InSaNiTy87 <M.vanderlinden@hotmail.nl>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/nl/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
2026-08-28 07:01:48 -05:00
a670972a4f Translated using Weblate (Indonesian)
Currently translated at 87.0% (94 of 108 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Naufal F <fadhlurrahmannf0812@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/id/
Translation: Frigate NVR/components-dialog
2026-08-28 07:01:48 -05:00
c4d46b7ed3 Translated using Weblate (Catalan)
Currently translated at 100.0% (800 of 800 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (474 of 474 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (185 of 185 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (1295 of 1295 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (129 of 129 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (500 of 500 strings)

Co-authored-by: Eduardo Pastor Fernández <123eduardoneko123@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/ca/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-08-28 07:01:48 -05:00
baa1ba718c Translated using Weblate (Belarusian)
Currently translated at 100.0% (23 of 23 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (60 of 60 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (800 of 800 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (67 of 67 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (239 of 239 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (129 of 129 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (74 of 74 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (86 of 86 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (2 of 2 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (108 of 108 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (474 of 474 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (10 of 10 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (46 of 46 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (500 of 500 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (185 of 185 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (2 of 2 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (26 of 26 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (100 of 100 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (62 of 62 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (10 of 10 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (54 of 54 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (25 of 25 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (141 of 141 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (50 of 50 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (49 of 49 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (1295 of 1295 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (145 of 145 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (6 of 6 strings)

Translated using Weblate (Belarusian)

Currently translated at 10.0% (1 of 10 strings)

Added translation using Weblate (Belarusian)

Added translation using Weblate (Belarusian)

Added translation using Weblate (Belarusian)

Added translation using Weblate (Belarusian)

Added translation using Weblate (Belarusian)

Added translation using Weblate (Belarusian)

Added translation using Weblate (Belarusian)

Added translation using Weblate (Belarusian)

Added translation using Weblate (Belarusian)

Added translation using Weblate (Belarusian)

Added translation using Weblate (Belarusian)

Added translation using Weblate (Belarusian)

Added translation using Weblate (Belarusian)

Added translation using Weblate (Belarusian)

Added translation using Weblate (Belarusian)

Added translation using Weblate (Belarusian)

Added translation using Weblate (Belarusian)

Added translation using Weblate (Belarusian)

Added translation using Weblate (Belarusian)

Added translation using Weblate (Belarusian)

Added translation using Weblate (Belarusian)

Added translation using Weblate (Belarusian)

Added translation using Weblate (Belarusian)

Added translation using Weblate (Belarusian)

Added translation using Weblate (Belarusian)

Added translation using Weblate (Belarusian)

Added translation using Weblate (Belarusian)

Added translation using Weblate (Belarusian)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Uladz Maltsau <wldyslw@icloud.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-auth/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-filter/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-icons/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-input/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-player/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-groups/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-validation/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-chat/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-configeditor/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-motionsearch/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-recording/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-replay/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-search/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/be/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/be/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Groups
Translation: Frigate NVR/Config - Validation
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-auth
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-filter
Translation: Frigate NVR/components-icons
Translation: Frigate NVR/components-input
Translation: Frigate NVR/components-player
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-chat
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-configeditor
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-motionSearch
Translation: Frigate NVR/views-recording
Translation: Frigate NVR/views-replay
Translation: Frigate NVR/views-search
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-08-28 07:01:48 -05:00
359d44fc8f Translated using Weblate (Romanian)
Currently translated at 100.0% (1295 of 1295 strings)

Co-authored-by: lukasig <lukasig@hotmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/ro/
Translation: Frigate NVR/views-settings
2026-08-28 07:01:48 -05:00
80efea2554 Translated using Weblate (Russian)
Currently translated at 99.7% (798 of 800 strings)

Co-authored-by: Artem Vladimirov <artyomka71@mail.ru>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/ru/
Translation: Frigate NVR/Config - Global
2026-08-28 07:01:48 -05:00
592775bd19 Translated using Weblate (Tamil)
Currently translated at 2.0% (2 of 100 strings)

Translated using Weblate (Tamil)

Currently translated at 100.0% (10 of 10 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: தமிழ்நேரம் <tamilneram247@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-auth/ta/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/ta/
Translation: Frigate NVR/components-auth
Translation: Frigate NVR/views-live
2026-08-28 07:01:48 -05:00
aee6aa1845 Translated using Weblate (Lithuanian)
Currently translated at 100.0% (46 of 46 strings)

Translated using Weblate (Lithuanian)

Currently translated at 100.0% (25 of 25 strings)

Translated using Weblate (Lithuanian)

Currently translated at 1.1% (9 of 800 strings)

Translated using Weblate (Lithuanian)

Currently translated at 2.1% (10 of 474 strings)

Translated using Weblate (Lithuanian)

Currently translated at 100.0% (141 of 141 strings)

Translated using Weblate (Lithuanian)

Currently translated at 100.0% (185 of 185 strings)

Translated using Weblate (Lithuanian)

Currently translated at 42.7% (553 of 1295 strings)

Translated using Weblate (Lithuanian)

Currently translated at 100.0% (86 of 86 strings)

Translated using Weblate (Lithuanian)

Currently translated at 100.0% (67 of 67 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: MaBeniu <runnerm@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/lt/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/lt/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-groups/lt/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/lt/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/lt/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/lt/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-replay/lt/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/lt/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/lt/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/Config - Groups
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-exports
Translation: Frigate NVR/views-replay
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2026-08-28 07:01:48 -05:00
1063 changed files with 48695 additions and 32201 deletions
-1
View File
@@ -55,7 +55,6 @@ Dahua
datasheet datasheet
debconf debconf
deci deci
deepstack
defragment defragment
devcontainer devcontainer
DEVICEMAP DEVICEMAP
+2 -2
View File
@@ -26,8 +26,8 @@ body:
id: version id: version
attributes: attributes:
label: Beta Version label: Beta Version
description: Visible on the System Metrics page in the Web UI. Please include the full version including the build identifier (eg. 0.18.0-beta1, 0.18.0-8b72c7a, etc.) description: Visible on the System Metrics page in the Web UI. Please include the full version including the build identifier (eg. 0.19.0-beta1, 0.19.0-8b72c7a, etc.)
placeholder: "0.18.0-beta1" placeholder: "0.19.0-beta1"
validations: validations:
required: true required: true
- type: dropdown - type: dropdown
+3 -1
View File
@@ -6,7 +6,9 @@ body:
value: | value: |
Use this form to submit a reproducible bug in Frigate or Frigate's UI. Use this form to submit a reproducible bug in Frigate or Frigate's UI.
**⚠️ If you are running a beta version (0.18.0-beta or similar), please use the [Beta Support template](https://github.com/blakeblackshear/frigate/discussions/new?category=beta-support) instead.** If you are running on Proxmox, please see the [Proxmox FAQ](https://github.com/blakeblackshear/frigate/discussions/23916) and reproduce the issue on a standard Docker install first (bare metal, or a VM running plain Debian/Ubuntu) before submitting here.
**⚠️ If you are running a beta version (0.19.0-beta or similar), please use the [Beta Support template](https://github.com/blakeblackshear/frigate/discussions/new?category=beta-support) instead.**
Before submitting your bug report, please ask the AI with the "Ask AI" button on the [official documentation site][ai] about your issue, [search the discussions][discussions], look at recent open and closed [pull requests][prs], read the [official Frigate documentation][docs], and read the [Frigate FAQ][faq] pinned at the Discussion page to see if your bug has already been fixed by the developers or reported by the community. Before submitting your bug report, please ask the AI with the "Ask AI" button on the [official documentation site][ai] about your issue, [search the discussions][discussions], look at recent open and closed [pull requests][prs], read the [official Frigate documentation][docs], and read the [Frigate FAQ][faq] pinned at the Discussion page to see if your bug has already been fixed by the developers or reported by the community.
+17 -15
View File
@@ -23,7 +23,7 @@ jobs:
name: AMD64 Build name: AMD64 Build
steps: steps:
- name: Check out code - name: Check out code
uses: actions/checkout@v6 uses: actions/checkout@v7
with: with:
persist-credentials: false persist-credentials: false
- name: Set up QEMU and Buildx - name: Set up QEMU and Buildx
@@ -49,7 +49,7 @@ jobs:
- amd64_build - amd64_build
steps: steps:
- name: Check out code - name: Check out code
uses: actions/checkout@v6 uses: actions/checkout@v7
with: with:
persist-credentials: false persist-credentials: false
- name: Set up QEMU and Buildx - name: Set up QEMU and Buildx
@@ -144,9 +144,11 @@ jobs:
done' done'
- name: Assert device access grants - name: Assert device access grants
run: | run: |
# a fake accelerator node created after boot, then the oneshot re-run # a fake accelerator node created after boot, then the oneshot re-run.
# /command is on PATH only for s6-supervised services, and the
# with-contenv shebang resolves its execline helpers through PATH
docker exec frigate mknod /dev/apex_9 c 120 99 docker exec frigate mknod /dev/apex_9 c 120 99
docker exec frigate /etc/s6-overlay/s6-rc.d/init-devices/run docker exec frigate sh -c 'export PATH=/command:$PATH; exec /etc/s6-overlay/s6-rc.d/init-devices/run'
acl=$(docker exec frigate getfacl -p /dev/apex_9) acl=$(docker exec frigate getfacl -p /dev/apex_9)
echo "$acl" echo "$acl"
echo "$acl" | grep -q "user:frigate:rw-" echo "$acl" | grep -q "user:frigate:rw-"
@@ -154,7 +156,7 @@ jobs:
# the usb tree gets recursive grants plus a default ACL that # the usb tree gets recursive grants plus a default ACL that
# newly created nodes inherit (the Coral re-enumeration path) # newly created nodes inherit (the Coral re-enumeration path)
docker exec frigate sh -c 'mkdir -p /dev/bus/usb/001 && mknod /dev/bus/usb/001/002 c 189 1' docker exec frigate sh -c 'mkdir -p /dev/bus/usb/001 && mknod /dev/bus/usb/001/002 c 189 1'
docker exec frigate /etc/s6-overlay/s6-rc.d/init-devices/run docker exec frigate sh -c 'export PATH=/command:$PATH; exec /etc/s6-overlay/s6-rc.d/init-devices/run'
docker exec frigate getfacl -p /dev/bus/usb/001 | grep -q "user:frigate:rwx" docker exec frigate getfacl -p /dev/bus/usb/001 | grep -q "user:frigate:rwx"
docker exec frigate sh -c 'mknod /dev/bus/usb/001/099 c 189 98 && chmod 664 /dev/bus/usb/001/099' docker exec frigate sh -c 'mknod /dev/bus/usb/001/099 c 189 98 && chmod 664 /dev/bus/usb/001/099'
inherited=$(docker exec frigate getfacl -p /dev/bus/usb/001/099) inherited=$(docker exec frigate getfacl -p /dev/bus/usb/001/099)
@@ -171,7 +173,7 @@ jobs:
# hardware that is absent must stay silent: the literal table entries # hardware that is absent must stay silent: the literal table entries
# are not globs, so nullglob does not drop them and only an existence # are not globs, so nullglob does not drop them and only an existence
# check keeps them from warning on every boot # check keeps them from warning on every boot
out=$(docker exec frigate /etc/s6-overlay/s6-rc.d/init-devices/run) out=$(docker exec frigate sh -c 'export PATH=/command:$PATH; exec /etc/s6-overlay/s6-rc.d/init-devices/run')
echo "$out" echo "$out"
if echo "$out" | grep -q "WARN"; then if echo "$out" | grep -q "WARN"; then
echo "grant warned about device nodes that do not exist"; exit 1 echo "grant warned about device nodes that do not exist"; exit 1
@@ -301,7 +303,7 @@ jobs:
# /run must allow exec: S6_READ_ONLY_ROOT has s6 copy its service # /run must allow exec: S6_READ_ONLY_ROOT has s6 copy its service
# scripts there and run them, and --tmpfs defaults to noexec # scripts there and run them, and --tmpfs defaults to noexec
docker run -d --name frigate-ro --shm-size 256m \ docker run -d --name frigate-ro --shm-size 256m \
--read-only --tmpfs /tmp:rw,size=1g --tmpfs /run:exec,nosuid,nodev,mode=0755 \ --read-only --tmpfs /tmp:rw,size=1g --tmpfs /run:exec,nosuid,nodev,mode=0755,uid=1000,gid=1000 \
--user 1000:1000 \ --user 1000:1000 \
--security-opt no-new-privileges:true \ --security-opt no-new-privileges:true \
-v /tmp/frigate-config-ro:/config \ -v /tmp/frigate-config-ro:/config \
@@ -395,7 +397,7 @@ jobs:
# setfacl under a read-only rootfs, which nothing else covers: # setfacl under a read-only rootfs, which nothing else covers:
# init-devices exits early under --user, so that path is never reached # init-devices exits early under --user, so that path is never reached
docker exec frigate-rod mknod /dev/apex_9 c 120 99 docker exec frigate-rod mknod /dev/apex_9 c 120 99
docker exec frigate-rod /etc/s6-overlay/s6-rc.d/init-devices/run docker exec frigate-rod sh -c 'export PATH=/command:$PATH; exec /etc/s6-overlay/s6-rc.d/init-devices/run'
docker exec frigate-rod getfacl -p /dev/apex_9 | grep -q "user:frigate:rw-" docker exec frigate-rod getfacl -p /dev/apex_9 | grep -q "user:frigate:rw-"
docker rm -f frigate-rod docker rm -f frigate-rod
- name: "Assert switching that install to user: still starts" - name: "Assert switching that install to user: still starts"
@@ -403,7 +405,7 @@ jobs:
# the config dir above now holds a go2rtc-owned go2rtc_homekit.yml, # the config dir above now holds a go2rtc-owned go2rtc_homekit.yml,
# which user: keeps readable but not writable (no supplementary groups) # which user: keeps readable but not writable (no supplementary groups)
docker run -d --name frigate-rod-user --shm-size 256m \ docker run -d --name frigate-rod-user --shm-size 256m \
--read-only --tmpfs /tmp:rw,size=1g --tmpfs /run:exec,nosuid,nodev,mode=0755 \ --read-only --tmpfs /tmp:rw,size=1g --tmpfs /run:exec,nosuid,nodev,mode=0755,uid=1000,gid=1000 \
--user 1000:1000 \ --user 1000:1000 \
-v /tmp/frigate-config-rod:/config \ -v /tmp/frigate-config-rod:/config \
-v /tmp/frigate-media-rod:/media/frigate \ -v /tmp/frigate-media-rod:/media/frigate \
@@ -424,7 +426,7 @@ jobs:
name: ARM Build name: ARM Build
steps: steps:
- name: Check out code - name: Check out code
uses: actions/checkout@v6 uses: actions/checkout@v7
with: with:
persist-credentials: false persist-credentials: false
- name: Set up QEMU and Buildx - name: Set up QEMU and Buildx
@@ -459,7 +461,7 @@ jobs:
name: Jetson Jetpack 6 name: Jetson Jetpack 6
steps: steps:
- name: Check out code - name: Check out code
uses: actions/checkout@v6 uses: actions/checkout@v7
with: with:
persist-credentials: false persist-credentials: false
- name: Set up QEMU and Buildx - name: Set up QEMU and Buildx
@@ -490,7 +492,7 @@ jobs:
- amd64_build - amd64_build
steps: steps:
- name: Check out code - name: Check out code
uses: actions/checkout@v6 uses: actions/checkout@v7
with: with:
persist-credentials: false persist-credentials: false
- name: Set up QEMU and Buildx - name: Set up QEMU and Buildx
@@ -531,7 +533,7 @@ jobs:
- arm64_build - arm64_build
steps: steps:
- name: Check out code - name: Check out code
uses: actions/checkout@v6 uses: actions/checkout@v7
with: with:
persist-credentials: false persist-credentials: false
- name: Set up QEMU and Buildx - name: Set up QEMU and Buildx
@@ -556,7 +558,7 @@ jobs:
- arm64_build - arm64_build
steps: steps:
- name: Check out code - name: Check out code
uses: actions/checkout@v6 uses: actions/checkout@v7
with: with:
persist-credentials: false persist-credentials: false
- name: Set up QEMU and Buildx - name: Set up QEMU and Buildx
@@ -588,7 +590,7 @@ jobs:
with: with:
string: ${{ github.repository }} string: ${{ github.repository }}
- name: Log in to the Container registry - name: Log in to the Container registry
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}
+12 -13
View File
@@ -16,10 +16,10 @@ jobs:
name: Web - Lint name: Web - Lint
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v7
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-node@v6 - uses: actions/setup-node@v7
with: with:
node-version: 20.x node-version: 20.x
- run: npm install - run: npm install
@@ -35,10 +35,10 @@ jobs:
name: Web - Test name: Web - Test
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v7
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-node@v6 - uses: actions/setup-node@v7
with: with:
node-version: 20.x node-version: 20.x
- run: npm install - run: npm install
@@ -46,18 +46,15 @@ jobs:
- name: Build web - name: Build web
run: npm run build run: npm run build
working-directory: ./web working-directory: ./web
# - name: Test
# run: npm run test
# working-directory: ./web
web_e2e: web_e2e:
name: Web - E2E Tests name: Web - E2E Tests
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v7
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-node@v6 - uses: actions/setup-node@v7
with: with:
node-version: 20.x node-version: 20.x
- run: npm install - run: npm install
@@ -86,11 +83,11 @@ jobs:
name: Python Checks name: Python Checks
steps: steps:
- name: Check out the repository - name: Check out the repository
uses: actions/checkout@v6 uses: actions/checkout@v7
with: with:
persist-credentials: false persist-credentials: false
- name: Set up Python ${{ env.DEFAULT_PYTHON }} - name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v5.4.0 uses: actions/setup-python@v7.0.0
with: with:
python-version: ${{ env.DEFAULT_PYTHON }} python-version: ${{ env.DEFAULT_PYTHON }}
- name: Install requirements - name: Install requirements
@@ -109,10 +106,10 @@ jobs:
name: Python Tests name: Python Tests
steps: steps:
- name: Check out code - name: Check out code
uses: actions/checkout@v6 uses: actions/checkout@v7
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-node@v6 - uses: actions/setup-node@v7
with: with:
node-version: 20.x node-version: 20.x
- name: Install devcontainer cli - name: Install devcontainer cli
@@ -127,5 +124,7 @@ jobs:
run: devcontainer exec --workspace-folder . bash -lc "python3 -u -m mypy --config-file frigate/mypy.ini frigate" run: devcontainer exec --workspace-folder . bash -lc "python3 -u -m mypy --config-file frigate/mypy.ini frigate"
- name: Check API spec is up to date - name: Check API spec is up to date
run: devcontainer exec --workspace-folder . bash -lc "python3 generate_api_auth_spec.py --check" run: devcontainer exec --workspace-folder . bash -lc "python3 generate_api_auth_spec.py --check"
- name: Check analytics schema is up to date
run: devcontainer exec --workspace-folder . bash -lc "python3 generate_analytics_schema.py --check"
- name: Run unit tests in devcontainer - name: Run unit tests in devcontainer
run: devcontainer exec --workspace-folder . bash -lc "python3 -u -m unittest" run: devcontainer exec --workspace-folder . bash -lc "python3 -u -m unittest"
+2 -2
View File
@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v7
with: with:
persist-credentials: false persist-credentials: false
- id: lowercaseRepo - id: lowercaseRepo
@@ -18,7 +18,7 @@ jobs:
with: with:
string: ${{ github.repository }} string: ${{ github.repository }}
- name: Log in to the Container registry - name: Log in to the Container registry
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}
+1 -1
View File
@@ -160,7 +160,7 @@ When reviewing code, do NOT comment on:
### Code Quality ### Code Quality
- **Linting**: ESLint (see `web/.eslintrc.cjs`) - **Linting**: ESLint (see `web/eslint.config.js`)
- **Formatting**: Prettier with Tailwind CSS plugin - **Formatting**: Prettier with Tailwind CSS plugin
- **Type Safety**: TypeScript strict mode enabled - **Type Safety**: TypeScript strict mode enabled
+1
View File
@@ -5,3 +5,4 @@
/docker/rockchip/ @MarcA711 /docker/rockchip/ @MarcA711
/docker/rocm/ @harakas /docker/rocm/ @harakas
/docker/hailo8l/ @spanner3003 /docker/hailo8l/ @spanner3003
/docker/deepx/ @sixfab
+131
View File
@@ -0,0 +1,131 @@
#!/bin/bash
# Installs the DEEPX NPU kernel driver and the DX-RT runtime on the Docker host,
# then enables the vendor's dxrt.service. A container cannot load kernel
# modules, so this runs outside the image; the driver creates the /dev/dxrt*
# nodes and the daemon multiplexes the NPU across host and container.
#
# Driver, runtime and firmware versions must agree or inference hangs instead
# of failing at startup. The set this script installs is pinned in
# driver_version, runtime_version and firmware_version below; move them
# together, never one at a time.
#
# DEEPX NPU support in Frigate is maintained by Sixfab (https://sixfab.com).
set -euo pipefail
driver_version="v2.6.0"
# the commit the tag resolves to, since DEEPX signs neither tags nor releases
# and this is compiled and installed as root. Update both together
driver_commit="7074748e7104f470b02f517583abba652b3f05fa"
firmware_version="v2.7.4"
sudo apt-get update
sudo apt-get install -y git build-essential "linux-headers-$(uname -r)" pciutils wget
if ! lspci -d 1ff4: | grep -q .; then
echo "No DEEPX device found on the PCIe bus (lspci -d 1ff4:)."
echo "Check that the module is seated correctly before continuing."
exit 1
fi
# fetch the pinned commit rather than cloning the tag, so a retag cannot swap
# in different source. The build directory is reused so a second run after a
# failure does not stop on the directory already being there
mkdir -p dx_rt_npu_linux_driver
cd dx_rt_npu_linux_driver
git init -q
git remote get-url origin > /dev/null 2>&1 ||
git remote add origin https://github.com/DEEPX-AI/dx_rt_npu_linux_driver.git
git fetch --depth 1 origin "${driver_commit}"
git checkout -q FETCH_HEAD
fetched_commit=$(git rev-parse HEAD)
if [[ "${fetched_commit}" != "${driver_commit}" ]]; then
echo "Fetched commit ${fetched_commit} does not match pinned driver_commit ${driver_commit}."
echo "Refusing to build unverified driver source."
exit 1
fi
cd modules
sudo ./build.sh -c install --reload
sudo depmod -A
# dx_dma is the PCIe transport, dxrt_driver the NPU driver on top of it
for module in dx_dma dxrt_driver; do
if ! sudo modprobe "${module}"; then
echo "Unable to load the ${module} kernel module, common reasons are:"
echo "- Secure Boot is enabled and is rejecting the unsigned module."
echo "- The running kernel does not match the installed linux-headers."
exit 1
fi
done
if ! compgen -G "/dev/dxrt*" > /dev/null; then
echo "Modules loaded but no /dev/dxrt* device node appeared."
echo "Run ./sanity_check.sh from the driver repo to diagnose."
exit 1
fi
runtime_version="v3.4.0"
declare -A runtime_sha256=(
[amd64]="736cfef009ce9e974ab1ab610d867239d19d72a426a53e367ddcbd53297b6e20"
[arm64]="eb6107f5f02f2ad76ae89f414e8b5f346f34fbc6f0888236136853a26be6f6a0"
)
runtime_release="${runtime_version#v}"
deb_arch=$(dpkg --print-architecture)
deb_file="/tmp/libdxrt-bin_${runtime_release}_${deb_arch}.deb"
wget -qO "${deb_file}" \
"https://raw.githubusercontent.com/DEEPX-AI/dx_rt/${runtime_version}/release/${runtime_release}/libdxrt-bin_${runtime_release}_${deb_arch}.deb"
expected_sha256="${runtime_sha256[${deb_arch}]:-}"
if [[ -z "${expected_sha256}" ]]; then
echo "No pinned SHA-256 for architecture ${deb_arch}; refusing to install."
exit 1
fi
if [[ "$(sha256sum "${deb_file}" | cut -d' ' -f1)" != "${expected_sha256}" ]]; then
echo "SHA-256 mismatch for ${deb_file}; refusing to install."
exit 1
fi
sudo dpkg -i "${deb_file}"
sudo ldconfig
rm -f "${deb_file}"
sudo cp /usr/share/libdxrt-bin/service/dxrt.service /etc/systemd/system/
# With an endpoint set, dxrtd binds that path only, so the socket goes in a
# directory Frigate can mount (kept across restarts so the mount stays valid)
# and a symlink at the default /tmp path keeps host tools that do not set the
# variable working through their own fallback.
sudo mkdir -p /etc/systemd/system/dxrt.service.d
sudo tee /etc/systemd/system/dxrt.service.d/frigate.conf > /dev/null <<'UNIT'
[Service]
RuntimeDirectory=dxrt
RuntimeDirectoryMode=0755
RuntimeDirectoryPreserve=yes
Environment=DXRT_DYNAMIC_IPC_ENDPOINT=/run/dxrt/dxrt_dynamic_ipc.sock
ExecStartPost=/bin/ln -sfn /run/dxrt/dxrt_dynamic_ipc.sock /tmp/dxrt_dynamic_ipc.sock
UNIT
sudo systemctl daemon-reload
sudo systemctl enable dxrt.service
sudo systemctl restart dxrt.service
if ! sudo systemctl is-active --quiet dxrt.service; then
echo "dxrt.service did not start. Check: sudo journalctl -u dxrt.service"
exit 1
fi
echo "DEEPX driver and runtime installation complete."
echo "Driver version: $(modinfo -F version dxrt_driver) (expected ${driver_version#v})"
echo "Runtime version: ${runtime_release}"
echo "Device node(s): $(echo /dev/dxrt*)"
echo
echo "This driver expects NPU firmware ${firmware_version}. Check it with:"
echo " dxrt-cli --status"
echo "Update the module if it does not match before starting Frigate."
+1
View File
@@ -381,6 +381,7 @@ FROM deps AS frigate
WORKDIR /opt/frigate/ WORKDIR /opt/frigate/
COPY --from=rootfs / / COPY --from=rootfs / /
ENV FRIGATE_IMAGE_VARIANT=standard
# Pre-compile bytecode so a read-only rootfs doesn't force re-parsing the # Pre-compile bytecode so a read-only rootfs doesn't force re-parsing the
# source tree on every boot (pip-installed packages are already compiled) # source tree on every boot (pip-installed packages are already compiled)
+1 -1
View File
@@ -1,4 +1,4 @@
ruff == 0.15.20 ruff == 0.15.20
# types # types
types-peewee == 3.17.* types-peewee == 4.0.*
+17 -17
View File
@@ -1,17 +1,17 @@
aiofiles == 24.1.* aiofiles == 25.1.*
click == 8.1.* click == 8.5.*
# FastAPI # FastAPI
aiohttp == 3.12.* aiohttp == 3.12.*
starlette == 0.47.* starlette == 0.47.*
starlette-context == 0.4.* starlette-context == 0.5.*
fastapi[standard-no-fastapi-cloud-cli] == 0.116.* fastapi[standard-no-fastapi-cloud-cli] == 0.116.*
uvicorn == 0.35.* uvicorn == 0.52.*
slowapi == 0.1.* slowapi == 0.1.*
joserfc == 1.2.* joserfc == 1.6.*
cryptography == 44.0.* cryptography == 46.0.*
pathvalidate == 3.3.* pathvalidate == 3.3.*
markupsafe == 3.0.* markupsafe == 3.0.*
python-multipart == 0.0.26 python-multipart == 0.0.31
# Classification Model Training # Classification Model Training
tensorflow == 2.19.* ; platform_machine == 'aarch64' tensorflow == 2.19.* ; platform_machine == 'aarch64'
tensorflow-cpu == 2.19.* ; platform_machine == 'x86_64' tensorflow-cpu == 2.19.* ; platform_machine == 'x86_64'
@@ -26,15 +26,15 @@ psutil == 7.1.*
pydantic == 2.10.* pydantic == 2.10.*
git+https://github.com/fbcotter/py3nvml#egg=py3nvml git+https://github.com/fbcotter/py3nvml#egg=py3nvml
pytz == 2025.* pytz == 2025.*
pyzmq == 26.2.* pyzmq == 27.1.*
ruamel.yaml == 0.18.* ruamel.yaml == 0.18.*
tzlocal == 5.2 tzlocal == 5.2
requests == 2.32.* requests == 2.33.*
types-requests == 2.32.* types-requests == 2.32.*
norfair == 2.3.* norfair == 2.3.*
setproctitle == 1.3.* setproctitle == 1.3.*
ws4py == 0.5.* ws4py == 0.5.*
unidecode == 1.3.* unidecode == 1.4.*
titlecase == 2.4.* titlecase == 2.4.*
# Image Manipulation # Image Manipulation
numpy == 1.26.* numpy == 1.26.*
@@ -51,26 +51,26 @@ google-genai == 1.58.*
ollama == 0.6.* ollama == 0.6.*
openai == 1.65.* openai == 1.65.*
# push notifications # push notifications
py-vapid == 1.9.* py-vapid == 1.9.4
pywebpush == 2.0.* pywebpush == 2.0.*
# alpr # alpr
pyclipper == 1.3.* pyclipper == 1.4.*
shapely == 2.0.* shapely == 2.0.*
rapidfuzz==3.12.* rapidfuzz==3.12.*
# HailoRT # HailoRT
argcomplete==2.0.* argcomplete==2.0.*
contextlib2==0.6.* contextlib2==0.6.*
future==0.18.* future==0.18.*
netaddr==0.8.* netaddr==1.3.*
netifaces==0.10.* netifaces==0.10.*
prometheus-client == 0.21.* prometheus-client == 0.26.*
# TFLite # TFLite
tflite_runtime @ https://github.com/frigate-nvr/TFlite-builds/releases/download/v2.17.1/tflite_runtime-2.17.1-cp311-cp311-linux_x86_64.whl; platform_machine == 'x86_64' tflite_runtime @ https://github.com/frigate-nvr/TFlite-builds/releases/download/v2.17.1/tflite_runtime-2.17.1-cp311-cp311-linux_x86_64.whl; platform_machine == 'x86_64'
tflite_runtime @ https://github.com/feranick/TFlite-builds/releases/download/v2.17.1/tflite_runtime-2.17.1-cp311-cp311-linux_aarch64.whl; platform_machine == 'aarch64' tflite_runtime @ https://github.com/feranick/TFlite-builds/releases/download/v2.17.1/tflite_runtime-2.17.1-cp311-cp311-linux_aarch64.whl; platform_machine == 'aarch64'
# audio transcription # audio transcription
sherpa-onnx==1.12.* sherpa-onnx==1.13.*
faster-whisper==1.1.* faster-whisper==1.2.*
librosa==0.11.* librosa==0.11.*
soundfile==0.13.* soundfile==0.13.*
# Memory profiling # Memory profiling
memray == 1.15.* memray == 1.20.*
@@ -37,6 +37,7 @@ device_globs=(
"/dev/nvmap" "/dev/nvmap"
"/dev/nvidia*" "/dev/nvidia*"
"/dev/memx*" "/dev/memx*"
"/dev/dxrt*"
) )
IFS=',' read -ra extra_globs <<< "${DEVICE_ACL_PATHS:-}" IFS=',' read -ra extra_globs <<< "${DEVICE_ACL_PATHS:-}"
@@ -166,7 +166,9 @@ http {
include auth_request.conf; include auth_request.conf;
types { types {
video/mp4 mp4; video/mp4 mp4;
image/jpeg jpg; image/jpeg jpg jpeg;
image/png png;
image/webp webp;
} }
expires 7d; expires 7d;
@@ -341,13 +343,6 @@ http {
add_header Cache-Control "public"; add_header Cache-Control "public";
} }
location /fonts/ {
access_log off;
expires 1y;
include security_headers.conf;
add_header Cache-Control "public";
}
location /locales/ { location /locales/ {
access_log off; access_log off;
include security_headers.conf; include security_headers.conf;
@@ -374,7 +369,7 @@ http {
sub_filter '"/BASE_PATH/assets/' '"$http_x_ingress_path/assets/'; sub_filter '"/BASE_PATH/assets/' '"$http_x_ingress_path/assets/';
sub_filter '"/BASE_PATH/locales/' '"$http_x_ingress_path/locales/'; sub_filter '"/BASE_PATH/locales/' '"$http_x_ingress_path/locales/';
sub_filter '"/BASE_PATH/monacoeditorwork/' '"$http_x_ingress_path/assets/'; sub_filter '"/BASE_PATH/monacoeditorwork/' '"$http_x_ingress_path/assets/';
sub_filter 'return"/BASE_PATH/"' 'return window.baseUrl'; sub_filter 'return`/BASE_PATH/`' 'return window.baseUrl';
sub_filter '<body>' '<body><script>window.baseUrl="$http_x_ingress_path/";</script>'; sub_filter '<body>' '<body><script>window.baseUrl="$http_x_ingress_path/";</script>';
sub_filter_types text/css application/javascript; sub_filter_types text/css application/javascript;
sub_filter_once off; sub_filter_once off;
+1
View File
@@ -25,6 +25,7 @@ RUN --mount=type=bind,from=rk-wheels,source=/rk-wheels,target=/deps/rk-wheels \
WORKDIR /opt/frigate/ WORKDIR /opt/frigate/
COPY --from=rootfs / / COPY --from=rootfs / /
ENV FRIGATE_IMAGE_VARIANT=rk
COPY docker/rockchip/COCO /COCO COPY docker/rockchip/COCO /COCO
COPY docker/rockchip/conv2rknn.py /opt/conv2rknn.py COPY docker/rockchip/conv2rknn.py /opt/conv2rknn.py
+1
View File
@@ -44,6 +44,7 @@ RUN echo "deb http://deb.debian.org/debian trixie main" > /etc/apt/sources.list.
WORKDIR /opt/frigate WORKDIR /opt/frigate
COPY --from=rootfs / / COPY --from=rootfs / /
ENV FRIGATE_IMAGE_VARIANT=rocm
RUN wget -q https://bootstrap.pypa.io/get-pip.py -O get-pip.py \ RUN wget -q https://bootstrap.pypa.io/get-pip.py -O get-pip.py \
&& sed -i 's/args.append("setuptools")/args.append("setuptools==77.0.3")/' get-pip.py \ && sed -i 's/args.append("setuptools")/args.append("setuptools==77.0.3")/' get-pip.py \
+1
View File
@@ -15,3 +15,4 @@ ENV INCLUDED_FFMPEG_VERSIONS="${DEFAULT_FFMPEG_VERSION}:${INCLUDED_FFMPEG_VERSIO
WORKDIR /opt/frigate/ WORKDIR /opt/frigate/
COPY --from=rootfs / / COPY --from=rootfs / /
ENV FRIGATE_IMAGE_VARIANT=rpi
+1
View File
@@ -22,6 +22,7 @@ pip3 install --no-deps -U /deps/synap-wheels/*.whl
WORKDIR /opt/frigate/ WORKDIR /opt/frigate/
COPY --from=rootfs / / COPY --from=rootfs / /
ENV FRIGATE_IMAGE_VARIANT=synaptics
COPY --from=synap1680-wheels /rootfs/usr/local/lib/*.so /usr/lib COPY --from=synap1680-wheels /rootfs/usr/local/lib/*.so /usr/lib
+1
View File
@@ -25,6 +25,7 @@ RUN --mount=type=bind,from=trt-wheels,source=/trt-wheels,target=/deps/trt-wheels
&& pip3 install -U /deps/trt-wheels/*.whl && pip3 install -U /deps/trt-wheels/*.whl
COPY --from=rootfs / / COPY --from=rootfs / /
ENV FRIGATE_IMAGE_VARIANT=tensorrt
COPY docker/tensorrt/detector/rootfs/etc/ld.so.conf.d /etc/ld.so.conf.d COPY docker/tensorrt/detector/rootfs/etc/ld.so.conf.d /etc/ld.so.conf.d
RUN ldconfig RUN ldconfig
+1
View File
@@ -151,6 +151,7 @@ RUN --mount=type=bind,from=trt-wheels,source=/trt-wheels,target=/deps/trt-wheels
WORKDIR /opt/frigate/ WORKDIR /opt/frigate/
COPY --from=rootfs / / COPY --from=rootfs / /
ENV FRIGATE_IMAGE_VARIANT=tensorrt-jp6
# Fixes "Error importing detector runtime: /usr/lib/aarch64-linux-gnu/libstdc++.so.6: cannot allocate memory in static TLS block" # Fixes "Error importing detector runtime: /usr/lib/aarch64-linux-gnu/libstdc++.so.6: cannot allocate memory in static TLS block"
ENV LD_PRELOAD /usr/lib/aarch64-linux-gnu/libstdc++.so.6 ENV LD_PRELOAD /usr/lib/aarch64-linux-gnu/libstdc++.so.6
-1
View File
@@ -1,6 +1,5 @@
# Nvidia ONNX Runtime GPU Support # Nvidia ONNX Runtime GPU Support
--extra-index-url 'https://pypi.nvidia.com' --extra-index-url 'https://pypi.nvidia.com'
cython==3.0.*; platform_machine == 'x86_64'
nvidia-cuda-cupti-cu12==12.8.90; platform_machine == 'x86_64' nvidia-cuda-cupti-cu12==12.8.90; platform_machine == 'x86_64'
nvidia-cublas-cu12==12.8.4.1; platform_machine == 'x86_64' nvidia-cublas-cu12==12.8.4.1; platform_machine == 'x86_64'
nvidia-cudnn-cu12==9.8.0.87; platform_machine == 'x86_64' nvidia-cudnn-cu12==9.8.0.87; platform_machine == 'x86_64'
+65 -24
View File
@@ -36,13 +36,13 @@ edgeTPU:
height: 320 # <--- should match the imgsize of the model, typically 320 height: 320 # <--- should match the imgsize of the model, typically 320
path: /config/model_cache/yolov9-s-relu6-best_320_int8_edgetpu.tflite path: /config/model_cache/yolov9-s-relu6-best_320_int8_edgetpu.tflite
labelmap_path: /config/labels-coco17.txt labelmap_path: /config/labels-coco17.txt
hailo8l: hailo:
title: Hailo-8/Hailo-8L title: Hailo
models: models:
- key: yolo - key: yolo
label: YOLO label: YOLO
recommended: true recommended: true
download: If no custom model path or URL is provided, the Hailo detector automatically downloads the default model (YOLOv6n) from the Hailo Model Zoo on first startup based on the detected hardware. Once cached under `/config/model_cache/hailo`, the model works fully offline. download: If no custom model path or URL is provided, the Hailo detector automatically downloads the default model (YOLOv6n) from the Hailo Model Zoo on first startup, choosing the build that matches the attached device. Once cached under `/config/model_cache`, the model works fully offline.
ui: |- ui: |-
Navigate to **Settings > System > Detection models** and select **Hailo** from the **Hardware** dropdown. Then, on the same model, open the **Custom Model** tab and configure the model settings: Navigate to **Settings > System > Detection models** and select **Hailo** from the **Hardware** dropdown. Then, on the same model, open the **Custom Model** tab and configure the model settings:
@@ -60,7 +60,7 @@ hailo8l:
yaml: |- yaml: |-
models: models:
- devices: - devices:
- hailo8l:PCIe - hailo:PCIe
width: 320 width: 320
height: 320 height: 320
input_tensor: nhwc input_tensor: nhwc
@@ -101,7 +101,7 @@ hailo8l:
yaml: |- yaml: |-
models: models:
- devices: - devices:
- hailo8l:PCIe - hailo:PCIe
width: 300 width: 300
height: 300 height: 300
input_tensor: nhwc input_tensor: nhwc
@@ -824,24 +824,6 @@ cpu:
models: models:
- devices: - devices:
- cpu:3 - cpu:3
deepstack:
title: DeepStack / CodeProject.AI
models:
- key: yolo
label: YOLO
recommended: true
download: This detector runs object detection over the network against a CodeProject.AI or DeepStack server, so no model is downloaded into Frigate itself. Visit the [CodeProject.AI official website](https://www.codeproject.com/Articles/5322557/CodeProject-AI-Server-AI-the-easy-way) to download and install the AI server on your preferred device (e.g. Raspberry Pi, Nvidia Jetson, or other compatible hardware) before configuring the detector.
ui: |-
Navigate to **Settings > System > Detection models** and add a model. The CodeProject.AI server is not reported by the hardware probe, so set `devices` to `deepstack:http://<your_codeproject_ai_server_ip>:<port>/v1/vision/detection` in YAML.
| Field | Value |
| ------------- | ---------------------------------------------------------------------- |
| **API URL** | `http://<your_codeproject_ai_server_ip>:<port>/v1/vision/detection` |
| **API Timeout** | `0.1` (seconds) |
yaml: |-
models:
- devices:
- deepstack:http://<your_codeproject_ai_server_ip>:<port>/v1/vision/detection
memryx: memryx:
title: MemryX title: MemryX
models: models:
@@ -985,6 +967,65 @@ memryx:
# The .zip file must contain: # The .zip file must contain:
# ├── ssdlite_mobilenet.dfp (a file ending with .dfp) # ├── ssdlite_mobilenet.dfp (a file ending with .dfp)
# └── ssdlite_mobilenet_post.onnx (optional; only if the model includes a cropped post-processing network) # └── ssdlite_mobilenet_post.onnx (optional; only if the model includes a cropped post-processing network)
deepx:
title: DEEPX NPU
models:
- key: yolo
label: YOLO
recommended: true
download: No model is bundled with Frigate. Download a pre-compiled YOLO `.dxnn` model from the [DEEPX ModelZoo](https://developer.deepx.ai/modelzoo) or compile your own with DX-COM, then bind-mount it into the container and point the model's `path` at it. The recommended model is `yolox-s_640x640_ppu.dxnn`. Its Post-Processing Unit (PPU) compile moves candidate selection onto the NPU, which makes it the fastest ModelZoo model measured through Frigate (about 13 ms on a DX-M1). The output layout is read from the compiled model, so anchor-based, anchor-free, NMS-in-head and PPU models (anchor-based or anchor-free) all need no extra configuration; prefer a `PPU` variant whenever the ModelZoo offers one. PPU models must be compiled with DX-COM 2.4.0 or later, which writes the head layout Frigate reads into the file.
ui: |-
Navigate to **Settings > System > Detection models** and select **DEEPX NPU** from the **Hardware** dropdown. Then, on the same model, open the **Custom Model** tab and configure:
| Field | Value |
| ---------------------------------------- | ---------------------------------------------------- |
| **Custom object detector model path** | `/config/model_cache/deepx/yolox-s_640x640_ppu.dxnn` |
| **Label map for custom object detector** | `/labelmap/coco-80.txt` |
| **Object detection model input width** | `640` |
| **Object detection model input height** | `640` |
| **Model Input Pixel Color Format** | `rgb` (Frigate's default value) |
| **Model Input Tensor Shape** | `nhwc` (Frigate's default value) |
| **Model Input D Type** | `int` (Frigate's default value) |
| **Object Detection Model Type** | `yolo-generic` |
Quantization is baked into the compiled model, so no normalization is applied on the host and the input defaults do not need to be overridden.
yaml: |-
models:
- devices:
- deepx:PCIe:0
path: /config/model_cache/deepx/yolox-s_640x640_ppu.dxnn
labelmap_path: /labelmap/coco-80.txt
model_type: yolo-generic
width: 640
height: 640
- key: yolox
label: YOLOX
recommended: false
download: No model is bundled with Frigate. Download a pre-compiled YOLOX `.dxnn` model from the [DEEPX ModelZoo](https://developer.deepx.ai/modelzoo), then bind-mount it into the container and point the model's `path` at it. The `_ppu` variant is faster and also works with the `yolo-generic` model type; the plain export needs `yolox` so its raw head is decoded.
ui: |-
Navigate to **Settings > System > Detection models** and select **DEEPX NPU** from the **Hardware** dropdown. Then, on the same model, open the **Custom Model** tab and configure:
| Field | Value |
| ---------------------------------------- | ---------------------------------------- |
| **Custom object detector model path** | `/config/model_cache/deepx/yolox-s_640x640.dxnn`|
| **Label map for custom object detector** | `/labelmap/coco-80.txt` |
| **Object detection model input width** | `640` |
| **Object detection model input height** | `640` |
| **Model Input Pixel Color Format** | `rgb` (Frigate's default value) |
| **Model Input Tensor Shape** | `nhwc` (Frigate's default value) |
| **Model Input D Type** | `int` (Frigate's default value) |
| **Object Detection Model Type** | `yolox` |
The width and height must match the resolution the `.dxnn` file was compiled for.
yaml: |-
models:
- devices:
- deepx:PCIe:0
path: /config/model_cache/deepx/yolox-s_640x640.dxnn
labelmap_path: /labelmap/coco-80.txt
model_type: yolox
width: 640
height: 640
tensorrt: tensorrt:
title: TensorRT title: TensorRT
models: models:
@@ -1033,7 +1074,7 @@ synaptics:
- key: ssd - key: ssd
label: SSD MobileNet label: SSD MobileNet
recommended: true recommended: true
download: A synap model is provided in the container at `/mobilenet.synap` and is used by this detector type by default. The model comes from the [Synap-release Github](https://github.com/synaptics-astra/synap-release/tree/v1.5.0/models/dolphin/object_detection/coco/model/mobilenet224_full80). download: A synap model is provided in the container at `/synaptics/mobilenet.synap` and is used by this detector type by default. The model comes from the [Synap-release Github](https://github.com/synaptics-astra/synap-release/tree/v1.5.0/models/dolphin/object_detection/coco/model/mobilenet224_full80).
ui: |- ui: |-
Navigate to **Settings > System > Detection models** and select **Synaptics NPU** from the **Hardware** dropdown. Then, on the same model, open the **Custom Model** tab and configure: Navigate to **Settings > System > Detection models** and select **Synaptics NPU** from the **Hardware** dropdown. Then, on the same model, open the **Custom Model** tab and configure:
@@ -0,0 +1,41 @@
---
id: analytics
title: Anonymous Analytics
---
import AnalyticsFields from "@site/src/components/AnalyticsFields";
import NavPath from "@site/src/components/NavPath";
Frigate can send one anonymous usage report a day. The reports show the maintainers which hardware to support, which features people use, and how releases perform. Sharing is off until you turn it on.
## Turning it on
Enable **Share anonymous analytics** at <NavPath path="Settings > System > Telemetry" />, or set it in your config:
```yaml
telemetry:
analytics: true
```
The same page has a **Preview the report** button that shows exactly what the next report contains.
## How it's sent
- Once a day, as a JSON POST to `https://analytics.frigate.video/report`
- The server looks up your country and region from your IP address and never stores the address
- Raw reports are kept for 60 days; only aggregate totals are published
- A random install ID, stored in `/config/.analytics.json`, keeps your install from being counted twice. Turning sharing off deletes it
## What's never sent
- Camera, zone, group, profile, or user names
- Object labels, face names, or license plate text
- IP addresses, hostnames, URLs, or stream paths
- Credentials or API keys
- Events, recordings, or anything from them
## Every field
Fields marked public appear in the published totals. The machine-readable schema is [frigate-analytics-schema.json](pathname:///frigate-analytics-schema.json).
<AnalyticsFields />
+15 -4
View File
@@ -800,7 +800,7 @@ lpr:
# to Google or OpenAI's LLMs to generate descriptions. GenAI features can be configured at # to Google or OpenAI's LLMs to generate descriptions. GenAI features can be configured at
# the camera level to enhance privacy for indoor cameras. # the camera level to enhance privacy for indoor cameras.
# NOTE: genai is a map of named providers. Each key is a name you choose for the provider, # NOTE: genai is a map of named providers. Each key is a name you choose for the provider,
# and each role (chat, descriptions, embeddings) may be assigned to exactly one provider. # and each role (chat, descriptions, embeddings, transcribe) may be assigned to exactly one provider.
genai: genai:
# Required: name of the provider (chosen by you, used to reference it elsewhere) # Required: name of the provider (chosen by you, used to reference it elsewhere)
my_provider: my_provider:
@@ -813,11 +813,13 @@ genai:
# Required: The model to use with the provider. # Required: The model to use with the provider.
model: gemini-1.5-flash model: gemini-1.5-flash
# Optional: Roles this provider handles (default: shown below) # Optional: Roles this provider handles (default: shown below)
# Each role (chat, descriptions, embeddings) must be assigned to exactly one provider. # Each role (chat, descriptions, embeddings, transcribe) must be assigned to exactly
# one provider.
roles: roles:
- chat - chat
- descriptions - descriptions
- embeddings - embeddings
- transcribe
# Optional additional args to pass to the GenAI Provider (default: None) # Optional additional args to pass to the GenAI Provider (default: None)
provider_options: provider_options:
keep_alive: -1 keep_alive: -1
@@ -830,13 +832,19 @@ genai:
audio_transcription: audio_transcription:
# Optional: Enable live and speech event audio transcription (default: shown below) # Optional: Enable live and speech event audio transcription (default: shown below)
enabled: False enabled: False
# Optional: The transcription backend (default: shown below)
# Either 'whisper' for Frigate's built-in local models, or the name of a genai
# provider that has 'transcribe' in its roles. device and model_size are ignored
# when a genai provider is named.
model: whisper
# Optional: The device to run the models on for live transcription. (default: shown below) # Optional: The device to run the models on for live transcription. (default: shown below)
device: CPU device: CPU
# Optional: Set the model size used for live transcription. (default: shown below) # Optional: Set the model size used for live transcription. (default: shown below)
model_size: small model_size: small
# Optional: Set the language used for transcription translation. (default: shown below) # Optional: Set the language used for transcription translation. (default: shown below)
# List of language codes: https://github.com/openai/whisper/blob/main/whisper/tokenizer.py#L10 # Use 'auto' to let the model detect the language, or a language code from
language: en # https://github.com/openai/whisper/blob/main/whisper/tokenizer.py#L10
language: auto
# Optional: Configuration for classification models # Optional: Configuration for classification models
classification: classification:
@@ -1186,6 +1194,9 @@ ui:
# Optional: Telemetry configuration # Optional: Telemetry configuration
telemetry: telemetry:
# Optional: Share one anonymous usage report a day (default: shown below)
# NOTE: See https://docs.frigate.video/configuration/advanced/analytics for what is sent
analytics: False
# Optional: Enabled network interfaces for bandwidth stats monitoring (default: empty list, let nethogs search all) # Optional: Enabled network interfaces for bandwidth stats monitoring (default: empty list, let nethogs search all)
network_interfaces: network_interfaces:
- eth - eth
+79 -7
View File
@@ -204,7 +204,7 @@ Frequently-heard labels like `speech` can generate a lot of events, and each eve
### Audio Transcription ### Audio Transcription
Frigate supports fully local audio transcription using either `sherpa-onnx` or OpenAI's open-source Whisper models via `faster-whisper`. The goal of this feature is to support Semantic Search for `speech` audio events. Frigate is not intended to act as a continuous, fully-automatic speech transcription service. Automatically transcribing all speech (or queuing many audio events for transcription) requires substantial CPU (or GPU) resources and is impractical on most systems. For this reason, transcriptions for events are initiated manually from the UI or the API rather than being run continuously in the background. Frigate supports fully local audio transcription using either `sherpa-onnx` or OpenAI's open-source Whisper models via `faster-whisper`, and can alternatively offload transcription to a [GenAI provider](#genai-provider). The goal of this feature is to support Semantic Search for `speech` audio events. Frigate is not intended to act as a continuous, fully-automatic speech transcription service. Automatically transcribing all speech (or queuing many audio events for transcription) requires substantial CPU (or GPU) resources and is impractical on most systems. For this reason, transcriptions for events are initiated manually from the UI or the API rather than being run continuously in the background.
:::info :::info
@@ -224,6 +224,7 @@ To enable transcription, configure it globally and optionally disable for specif
**Global:** Navigate to <NavPath path="Settings > Enrichments > Audio transcription" />. **Global:** Navigate to <NavPath path="Settings > Enrichments > Audio transcription" />.
- Set **Enable audio transcription** to on - Set **Enable audio transcription** to on
- Set **Audio transcription model or GenAI provider name** to `whisper` for Frigate's built-in local models, or to the name of a GenAI provider
- Set **Transcription device** to the desired device - Set **Transcription device** to the desired device
- Set **Model size** to the desired size - Set **Model size** to the desired size
@@ -235,6 +236,7 @@ To enable transcription, configure it globally and optionally disable for specif
```yaml ```yaml
audio_transcription: audio_transcription:
enabled: True enabled: True
model: whisper
device: ... device: ...
model_size: ... model_size: ...
``` ```
@@ -263,20 +265,88 @@ The optional config parameters that can be set at the global level include:
- **`enabled`**: Enable or disable the audio transcription feature. - **`enabled`**: Enable or disable the audio transcription feature.
- Default: `False` - Default: `False`
- It is recommended to only configure the features at the global level, and enable it at the individual camera level. - It is recommended to only configure the features at the global level, and enable it at the individual camera level.
- **`model`**: The transcription backend.
- Default: `whisper`
- `whisper` uses Frigate's built-in local models, described by `device` and `model_size` below.
- Any other value must name a key in your `genai` config whose entry has `transcribe` in its `roles`. See [GenAI Provider](#genai-provider).
- **`device`**: Device to use to run transcription and translation models. - **`device`**: Device to use to run transcription and translation models.
- Default: `CPU` - Default: `CPU`
- This can be `CPU` or `GPU`. The `sherpa-onnx` models are lightweight and run on the CPU only. The `whisper` models can run on GPU but are only supported on CUDA hardware. - This can be `CPU` or `GPU`. The `sherpa-onnx` models are lightweight and run on the CPU only. The `whisper` models can run on GPU but are only supported on CUDA hardware.
- Ignored when `model` names a GenAI provider.
- **`model_size`**: The size of the model used for live transcription. - **`model_size`**: The size of the model used for live transcription.
- Default: `small` - Default: `small`
- This can be `small` or `large`. The `small` setting uses `sherpa-onnx` models that are fast, lightweight, and always run on the CPU but are not as accurate as the `whisper` model. - This can be `small` or `large`. The `small` setting uses `sherpa-onnx` models that are fast, lightweight, and always run on the CPU but are not as accurate as the `whisper` model.
- This config option applies to **live transcription only**. Recorded `speech` events will always use a different `whisper` model (and can be accelerated for CUDA hardware if available with `device: GPU`). - This config option applies to **live transcription only**. With `model: whisper`, recorded `speech` events always use a different `whisper` model (and can be accelerated for CUDA hardware if available with `device: GPU`).
- **`language`**: Defines the language used by `whisper` to translate `speech` audio events (and live audio only if using the `large` model). - Ignored when `model` names a GenAI provider.
- Default: `en` - **`language`**: Defines the language used to transcribe and translate `speech` audio events (and live audio only if using the `large` model or a GenAI provider).
- You must use a valid [language code](https://github.com/openai/whisper/blob/main/whisper/tokenizer.py#L10). - Default: `auto`
- `auto` lets the model detect the language itself, which most models do well. Set an explicit language only if detection is picking the wrong one.
- Otherwise you must use a valid [language code](https://github.com/openai/whisper/blob/main/whisper/tokenizer.py#L10).
- Transcriptions for `speech` events are translated. - Transcriptions for `speech` events are translated.
- Live audio is translated only if you are using the `large` model. The `small` `sherpa-onnx` model is English-only. - Live audio is translated only if you are using the `large` model. The `small` `sherpa-onnx` model is English-only.
The only field that is valid at the camera level is `enabled`. The only field that is valid at the camera level is `enabled`. In particular `model` is global only: the transcription backend is a process-wide resource shared by every camera.
#### GenAI Provider
Frigate can send audio to a GenAI provider for transcription when that provider has the `transcribe` role. This is useful if you already run a GenAI provider, or if you do not have the CPU/GPU headroom for a local whisper model. Supported providers are **OpenAI**, **Azure OpenAI**, **Gemini**, and **llama.cpp** with an audio-capable model (a dedicated ASR model such as Qwen3-ASR, or a general multimodal model that accepts audio). Ollama is not supported as it has no audio input.
To use a GenAI provider for audio transcription:
1. Configure a GenAI provider with `transcribe` in its `roles`.
2. Set the audio transcription model to that GenAI config key (e.g. `whisper_cloud`).
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Enrichments > Audio transcription" />.
| Field | Description |
| ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| **Audio transcription model or GenAI provider name** | Set to the GenAI config key (e.g. `whisper_cloud`) to use a configured GenAI provider for transcription |
The GenAI provider must also be configured with the `transcribe` role under <NavPath path="Settings > Enrichments > Generative AI" />.
</TabItem>
<TabItem value="yaml">
```yaml
genai:
whisper_cloud:
provider: openai
api_key: your-api-key
model: gpt-transcribe
roles:
- transcribe
audio_transcription:
enabled: True
model: whisper_cloud
language: en
```
</TabItem>
</ConfigTabs>
:::warning
**Give `transcribe` its own `genai` entry.** A `genai` entry has a single `model` string that is shared by every role it holds, so `roles: [descriptions, transcribe]` would send the same model name to both the chat endpoint and the transcription endpoint. Transcription models and chat models are almost never the same model, so define a dedicated entry as shown above.
:::
:::warning
**Live transcription against a metered provider is billed continuously.** In live mode Frigate uploads an overlapping ~2 second window of audio roughly once per second, per camera, for as long as audio stays above that camera's `audio.min_volume`. Windows below that threshold are never uploaded, which is what keeps a quiet camera near zero requests, but a camera pointed at a busy street will keep sending.
Three things keep this opt-in: `transcribe` is not one of the default roles, live transcription is off by default, and the volume gate suppresses silence. Transcription of recorded `speech` events is unaffected - it remains a manual, one-request-per-event action.
:::
`device` and `model_size` have no effect on this path and no local model is ever downloaded.
`language` defaults to `auto`, which sends no language hint and lets the model detect it. Most audio models detect language well, so leave it on `auto` unless detection is picking the wrong one.
When set explicitly, it is sent as the transcription endpoint's native `language` parameter for OpenAI, Azure, and llama.cpp, and as part of the prompt for Gemini. This matters for dedicated ASR models such as Qwen3-ASR: they read the prompt as contextual biasing rather than as an instruction, so a language named in the prompt is ignored, while the endpoint parameter is honored.
#### Live transcription #### Live transcription
@@ -292,6 +362,8 @@ Results can be error-prone due to a number of factors, including:
For speech sources close to the camera with minimal background noise, use the `small` model. For speech sources close to the camera with minimal background noise, use the `small` model.
A [GenAI provider](#genai-provider) is generally the most accurate option for live transcription, at the cost of a network round trip per window. That round trip has to stay under about a second to keep up with the audio; if it does not, Frigate drops the oldest buffered audio rather than letting the backlog grow.
If you have CUDA hardware, you can experiment with the `large` `whisper` model on GPU. Performance is not quite as fast as the `sherpa-onnx` `small` model, but live transcription is far more accurate. Using the `large` model with CPU will likely be too slow for real-time transcription. If you have CUDA hardware, you can experiment with the `large` `whisper` model on GPU. Performance is not quite as fast as the `sherpa-onnx` `small` model, but live transcription is far more accurate. Using the `large` model with CPU will likely be too slow for real-time transcription.
#### Transcription and translation of `speech` audio events #### Transcription and translation of `speech` audio events
@@ -308,7 +380,7 @@ Only one `speech` event may be transcribed at a time. Frigate does not automatic
::: :::
Recorded `speech` events will always use a `whisper` model, regardless of the `model_size` config setting. Without a supported Nvidia GPU, generating transcriptions for longer `speech` events may take a fair amount of time, so be patient. With `model: whisper`, recorded `speech` events always use a `whisper` model, regardless of the `model_size` config setting. Without a supported Nvidia GPU, generating transcriptions for longer `speech` events may take a fair amount of time, so be patient. With a [GenAI provider](#genai-provider), the recorded clip is sent to the provider instead and no local model is used.
#### FAQ #### FAQ
+17 -6
View File
@@ -43,7 +43,7 @@ genai:
The examples on this page all use `my_provider`, but the name is arbitrary and is only used to reference the provider elsewhere in the config (for example, `semantic_search.model`). The examples on this page all use `my_provider`, but the name is arbitrary and is only used to reference the provider elsewhere in the config (for example, `semantic_search.model`).
Each provider handles one or more **roles**: `chat`, `descriptions`, and `embeddings`. A provider handles all three by default, and each role may be assigned to exactly one provider. Define a single provider if you want it to do everything, or split the roles across several providers using the `roles` option. Each provider handles one or more **roles**: `chat`, `descriptions`, `embeddings`, and `transcribe`. A provider handles the first three by default; `transcribe` must always be listed explicitly, and is not available on Ollama, which has no audio input. Each role may be assigned to exactly one provider. Define a single provider if you want it to do everything, or split the roles across several providers using the `roles` option.
If the provider you choose requires an API key, you may either directly paste it in your configuration, or store it in an environment variable prefixed with `FRIGATE_`. If the provider you choose requires an API key, you may either directly paste it in your configuration, or store it in an environment variable prefixed with `FRIGATE_`.
@@ -63,11 +63,11 @@ Running Generative AI models on CPU is not recommended, as high inference times
You must use a vision-capable model with Frigate. The following models are recommended for local deployment of the `descriptions` and `chat` roles: You must use a vision-capable model with Frigate. The following models are recommended for local deployment of the `descriptions` and `chat` roles:
| Model | Notes | | Model | Review [frame mode](/configuration/genai/genai_review#frame-mode) | Notes |
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ------------------- | --------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `qwen3-vl` | Strong visual and situational understanding, enhanced ability to identify smaller objects and interactions with object. | | `qwen3-vl` | `frames` | Strong visual and situational understanding, enhanced ability to identify smaller objects and interactions with object. Follows a sequence of frames on its own. |
| `qwen3.6`/`qwen3.8` | Strong situational understanding, but missing DeepStack from qwen3-vl leading to worse performance for identifying objects in people's hand and other small details. | | `qwen3.6`/`qwen3.8` | `frames` | Strong situational understanding, but missing DeepStack from qwen3-vl leading to worse performance for identifying objects in people's hand and other small details. |
| `gemma4` | Strong situational understanding, sometimes resorts to more vague terms like 'interacts' instead of assigning a specific action. | | `gemma4` | `annotated_frames` | Strong situational understanding, sometimes resorts to more vague terms like 'interacts' instead of assigning a specific action. Loses track of activity that repeats or reverses, so it benefits from annotated frames. |
#### Embedding models #### Embedding models
@@ -77,6 +77,17 @@ The `embeddings` role needs a different kind of model. Text queries are matched
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `qwen3-vl-embedding` | Multimodal embeddings for [Semantic Search](/configuration/semantic_search#genai-provider). Must be served by llama.cpp started with `--embeddings` and `--mmproj`. | | `qwen3-vl-embedding` | Multimodal embeddings for [Semantic Search](/configuration/semantic_search#genai-provider). Must be served by llama.cpp started with `--embeddings` and `--mmproj`. |
#### Transcription models
The `transcribe` role needs a model that accepts audio input. A text-only or vision-only model cannot serve this role. The following are recommended for local deployment of the `transcribe` role:
| Model | Notes |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `qwen3-asr` | Dedicated speech recognition model covering 30 languages, and the better choice for transcription quality. It only transcribes, so it cannot be shared with the `descriptions` or `chat` roles. |
| `gemma4` | General multimodal model that accepts audio as well as images, so one served model can cover `transcribe` alongside the other roles. Transcript quality is below `qwen3-asr`, particularly on noisy audio. |
Both must be served by llama.cpp started with the matching audio `--mmproj`. llama.cpp only reports audio support when an audio projector is loaded. Without it Frigate sees the model as text-only and the `transcribe` role is unavailable in the UI. Frigate transcribes through the server's `/v1/audio/transcriptions` route, which llama.cpp serves for any audio-capable model.
:::info :::info
Each model is available in multiple parameter sizes (3b, 4b, 8b, etc.). Larger sizes are more capable of complex tasks and understanding of situations, but requires more memory and computational resources. It is recommended to try multiple models and experiment to see which performs best. Each model is available in multiple parameter sizes (3b, 4b, 8b, etc.). Larger sizes are more capable of complex tasks and understanding of situations, but requires more memory and computational resources. It is recommended to try multiple models and experiment to see which performs best.
@@ -192,6 +192,43 @@ review:
</TabItem> </TabItem>
</ConfigTabs> </ConfigTabs>
### Frame Mode
Review items are sent to the model as a sequence of still frames. Some models follow that sequence well on their own; others lose track of activity that repeats or reverses, and describe a single trip when the subject actually made several. The `frame_mode` option controls how those frames are presented.
- `frames` (default): the prompt followed by the frames, exactly as earlier versions of Frigate sent them.
- `annotated_frames`: each frame is preceded by its frame number and elapsed time, along with notes describing what the object tracker recorded at that moment, such as an object being first detected, starting to move, turning around, stopping, or no longer being detected.
The notes come from tracking data rather than from the images, so they describe activity the model may not have picked up on its own. In testing with a person carrying three waste bins to the curb one at a time, `gemma4` described a single trip on every attempt with `frames`, and consistently described multiple trips with `annotated_frames`. Models that already handle these sequences well, such as the `qwen3-vl` family, gain little and should stay on `frames`.
Annotated mode also caps the number of frames, since the notes already establish the order of events and extra near-duplicate frames tend to crowd out the middle of a clip. Longer review items are sampled more sparsely as a result, and typically use fewer tokens than `frames` mode for the same item.
:::note
Annotated mode needs tracking data for the review item. If none is available, Frigate falls back to sending plain frames for that item.
:::
<ConfigTabs>
<TabItem value="ui">
Navigate to <NavPath path="Settings > Global configuration > Review" />.
- Set **GenAI config > Frame mode** to the desired mode (e.g., `annotated_frames`)
</TabItem>
<TabItem value="yaml">
```yaml {4}
review:
genai:
enabled: true
frame_mode: annotated_frames
```
</TabItem>
</ConfigTabs>
### Response Style ### Response Style
Different models respond to the built-in prompt with very different writing styles: some produce natural narration while others sound short and mechanical. The `response_style` option selects a writing style preset that rewords the prompt's instructions for the user-facing fields (the title, short summary, and scene description). Presets replace those instructions rather than adding extra ones, so the model never receives competing style directions. Different models respond to the built-in prompt with very different writing styles: some produce natural narration while others sound short and mechanical. The `response_style` option selects a writing style preset that rewords the prompt's instructions for the user-facing fields (the title, short summary, and scene description). Presets replace those instructions rather than adding extra ones, so the model never receives competing style directions.
@@ -499,7 +499,7 @@ cameras:
## Synaptics ## Synaptics
Hardware accelerated video de-/encoding is supported on Synpatics SL-series SoC. Hardware accelerated video de-/encoding is supported on Synaptics SL-series SoC.
### Prerequisites ### Prerequisites
+31
View File
@@ -28,6 +28,24 @@ WebRTC may use an external STUN server for NAT traversal. MSE and HLS streaming
::: :::
### Selecting a streaming technology
Frigate [defaults to MSE](#why-does-frigate-prefer-mse-over-webrtc-for-live-view) for restreamed cameras by design. To use WebRTC, select it explicitly from a camera's single-camera Live view settings (the settings menu in the camera's Live view header on desktop, or the settings drawer on mobile). Three related controls work together:
- **Stream**: _what_ to play. This lists the [streams you've configured](#setting-streams-for-live-ui) (for example `Main Stream` and `Sub Stream`).
- **Force low-bandwidth mode**: a switch that always plays Frigate's built-in low-bandwidth feed (the stream assigned the `detect` role, using JSMpeg) instead of the selected stream. It works anywhere without go2rtc and is useful on slow or metered connections. While it is enabled, the stream and streaming technology selectors are disabled; your stream and technology choices are restored when you turn it off.
- **Streaming Technology**: _how_ to play the selected stream, listing **MSE** and **WebRTC**. It is only shown for a restreamed stream.
- The choices are saved **per device, per camera** in your browser's local storage.
- **WebRTC is only selectable when it can actually work for that stream.** When it can't, the option is shown disabled with the reason inline, and a more detailed reason (the failing codecs, or why the connectivity check failed) is logged to your browser's console. Common reasons:
- **Not configured**: no `candidates` or `ice_servers` are set under `go2rtc.webrtc` (see [WebRTC extra configuration](#webrtc-extra-configuration)).
- **Could not connect**: e.g. port `8555` isn't reachable, or a STUN/TURN server is misconfigured. Frigate runs a one-time WebRTC connectivity check when the Live view opens; the option may briefly show as "checking" while it runs.
- **Unsupported video codec**: the stream's video codec can't be played over WebRTC in your browser, most commonly H.265/HEVC in Firefox or Edge.
- **Unsupported audio codec**: WebRTC needs opus or G.711 audio, so a stream whose playback audio is only AAC (without an added opus/G.711 track) can't carry audio over WebRTC. See [Audio Support](#audio-support) for how to add one.
- **Unsupported browser**: the browser doesn't support WebRTC.
When WebRTC isn't available, Frigate automatically uses MSE (or falls back to JSMpeg), so live view keeps working regardless of the selection.
### Camera Settings Recommendations ### Camera Settings Recommendations
If you are using go2rtc, you should adjust the following settings in your camera's firmware for the best experience with Live view: If you are using go2rtc, you should adjust the following settings in your camera's firmware for the best experience with Live view:
@@ -157,6 +175,17 @@ WebRTC works by creating a TCP or UDP connection on port `8555`. However, it req
- stun:8555 - stun:8555
``` ```
- The web UI uses the STUN and TURN servers in `ice_servers` and falls back to Google's public STUN server when none are set:
```yaml title="config.yml"
go2rtc:
webrtc:
ice_servers:
- urls: [turn:turn.example.com:3478]
username: frigate
credential: password
```
- For access through Tailscale, the Frigate system's Tailscale IP must be added as a WebRTC candidate. Tailscale IPs all start with `100.`, and are reserved within the `100.64.0.0/10` CIDR block. - For access through Tailscale, the Frigate system's Tailscale IP must be added as a WebRTC candidate. Tailscale IPs all start with `100.`, and are reserved within the `100.64.0.0/10` CIDR block.
- Note that some browsers may not support H.265 (HEVC). You can check your browser's current version for H.265 compatibility [here](https://github.com/AlexxIT/go2rtc?tab=readme-ov-file#codecs-madness). - Note that some browsers may not support H.265 (HEVC). You can check your browser's current version for H.265 compatibility [here](https://github.com/AlexxIT/go2rtc?tab=readme-ov-file#codecs-madness).
@@ -206,6 +235,8 @@ For devices that support two way talk, Frigate can be configured to use the feat
- Ensure you access Frigate via https (may require [opening port 8971](/frigate/installation/#ports)). - Ensure you access Frigate via https (may require [opening port 8971](/frigate/installation/#ports)).
- For the Home Assistant Frigate card, [follow the docs](http://card.camera/#/usage/2-way-audio) for the correct source. - For the Home Assistant Frigate card, [follow the docs](http://card.camera/#/usage/2-way-audio) for the correct source.
The two-way talk control in the single-camera Live view is only enabled when WebRTC is available; if WebRTC isn't configured or can't connect, the control is shown disabled.
To use the Reolink Doorbell with two way talk, you should use the [recommended Reolink configuration](/configuration/camera_specific#reolink-cameras) To use the Reolink Doorbell with two way talk, you should use the [recommended Reolink configuration](/configuration/camera_specific#reolink-cameras)
As a starting point to check compatibility for your camera, view the list of cameras supported for two-way talk on the [go2rtc repository](https://github.com/AlexxIT/go2rtc?tab=readme-ov-file#two-way-audio). For cameras in the category `ONVIF Profile T`, you can use the [ONVIF Conformant Products Database](https://www.onvif.org/conformant-products/)'s FeatureList to check for the presence of `AudioOutput`. A camera that supports `ONVIF Profile T` _usually_ supports this, but due to inconsistent support, a camera that explicitly lists this feature may still not work. If no entry for your camera exists on the database, it is recommended not to buy it or to consult with the manufacturer's support on the feature availability. As a starting point to check compatibility for your camera, view the list of cameras supported for two-way talk on the [go2rtc repository](https://github.com/AlexxIT/go2rtc?tab=readme-ov-file#two-way-audio). For cameras in the category `ONVIF Profile T`, you can use the [ONVIF Conformant Products Database](https://www.onvif.org/conformant-products/)'s FeatureList to check for the presence of `AudioOutput`. A camera that supports `ONVIF Profile T` _usually_ supports this, but due to inconsistent support, a camera that explicitly lists this feature may still not work. If no entry for your camera exists on the database, it is recommended not to buy it or to consult with the manufacturer's support on the feature availability.
+8
View File
@@ -313,8 +313,16 @@ To remove root from the container entirely, add Docker's `user:`:
```yaml ```yaml
user: "1000:1000" # NOT compatible with PUID/PGID, see the run modes table user: "1000:1000" # NOT compatible with PUID/PGID, see the run modes table
tmpfs:
- /tmp:size=256m
- /tmp/cache:size=1000000000
- /run:exec,nosuid,nodev,mode=0755,uid=1000,gid=1000,size=16m # uid must match user:
``` ```
`/run` has to be owned by that uid as well. s6 writes its runtime state there before anything else starts, and with no root in the container a root-owned `/run` stops it during init with `cannot create /run/test of writability`. Keep `uid` and `gid` in the tmpfs options matching `user:`, and don't carry that pair back into the default mode, where a root-owned `/run` is what keeps the unprivileged services out of s6's runtime state.
This only bites once root is genuinely gone. s6's init helper is setuid, so `user:` on its own still lets init regain root and correct `/run` itself. The `no-new-privileges:true` above is what blocks that, which is also what makes the `/run` ownership mandatory. Dropping it would hide the problem by handing init root again.
Two things change, and the first one will break a working install if you skip it. The startup device grants can't run, because there is no root left to run them, so every device you pass stops working until you grant that uid access yourself with `group_add:` or a udev rule; see [Manual setup](#manual-setup). Expect this to surface as a driver error rather than a permission error, like `No VA display found` from VAAPI. And every service then runs as that one uid, so go2rtc no longer gets its own restricted user. `/config` and `/media/frigate` have to be owned by that uid already, since Frigate never adjusts ownership in this mode. Switching an existing install over also leaves `/config/go2rtc_homekit.yml` owned by the go2rtc user, which this mode can't write; `chown` it to your uid or HomeKit pairing changes stop persisting. Frigate warns and starts either way. Two things change, and the first one will break a working install if you skip it. The startup device grants can't run, because there is no root left to run them, so every device you pass stops working until you grant that uid access yourself with `group_add:` or a udev rule; see [Manual setup](#manual-setup). Expect this to surface as a driver error rather than a permission error, like `No VA display found` from VAAPI. And every service then runs as that one uid, so go2rtc no longer gets its own restricted user. `/config` and `/media/frigate` have to be owned by that uid already, since Frigate never adjusts ownership in this mode. Switching an existing install over also leaves `/config/go2rtc_homekit.yml` owned by the go2rtc user, which this mode can't write; `chown` it to your uid or HomeKit pairing changes stop persisting. Frigate warns and starts either way.
This mode can also take `cap_drop: [ALL]`, which the default mode cannot: starting as root needs `CAP_CHOWN` for the ownership sweep, `CAP_SETUID` and `CAP_SETGID` to drop to the runtime user, and `CAP_FOWNER` for the device grants. This mode can also take `cap_drop: [ALL]`, which the default mode cannot: starting as root needs `CAP_CHOWN` for the ownership sweep, `CAP_SETUID` and `CAP_SETGID` to drop to the runtime user, and `CAP_FOWNER` for the device grants.
+64 -30
View File
@@ -22,8 +22,9 @@ Frigate supports multiple different detectors that work on different types of ha
**Most Hardware** **Most Hardware**
- [Coral EdgeTPU](#edge-tpu-detector): The Google Coral EdgeTPU is available in USB, Mini PCIe, and m.2 formats allowing for a wide range of compatibility with devices. - [Coral EdgeTPU](#edge-tpu-detector): The Google Coral EdgeTPU is available in USB, Mini PCIe, and m.2 formats allowing for a wide range of compatibility with devices.
- [Hailo](#hailo-8): The Hailo8 and Hailo8L AI Acceleration module is available in m.2 format with a HAT for RPi devices, offering a wide range of compatibility with devices. - [Hailo](#hailo): The Hailo-8, Hailo-8L and Hailo-8R AI Acceleration modules are available in m.2 format with a HAT for RPi devices, offering a wide range of compatibility with devices.
- <CommunityBadge /> [MemryX](#memryx-mx3): The MX3 Acceleration module is available in m.2 format, offering broad compatibility across various platforms. - <CommunityBadge /> [MemryX](#memryx-mx3): The MX3 Acceleration module is available in m.2 format, offering broad compatibility across various platforms.
- <CommunityBadge /> [DEEPX](#deepx-npu): The DEEPX NPU is available in m.2 format and as a HAT+ for the Raspberry Pi 5, offering broad compatibility across various platforms.
**AMD** **AMD**
@@ -285,9 +286,9 @@ models:
--- ---
## Hailo-8 ## Hailo
This detector is available for use with both Hailo-8 and Hailo-8L AI Acceleration Modules. The integration automatically detects your hardware architecture via the Hailo CLI and selects the appropriate default model if no custom model is specified. This detector is available for use with the Hailo-8, Hailo-8L and Hailo-8R AI Acceleration Modules. The integration identifies which of them is attached and selects the matching default model if no custom model is specified.
See the [installation docs](../frigate/installation.md#hailo-8) for information on configuring the Hailo hardware. See the [installation docs](../frigate/installation.md#hailo-8) for information on configuring the Hailo hardware.
@@ -308,11 +309,11 @@ The HailoRT runtime is not part of the Frigate image. It is downloaded and insta
When configuring the Hailo detector, you have two options to specify the model: a local **path** or a **URL**. When configuring the Hailo detector, you have two options to specify the model: a local **path** or a **URL**.
If both are provided, the detector will first check for the model at the given local path. If the file is not found, it will download the model from the specified URL. The model file is cached under `/config/model_cache/hailo`. If both are provided, the detector will first check for the model at the given local path. If the file is not found, it will download the model from the specified URL. The model file is cached under `/config/model_cache/hailo`.
<ModelConfigDropdown detectorTitle="Hailo-8/Hailo-8L" models={objectDetectorsModels.hailo8l.models} /> <ModelConfigDropdown detectorTitle="Hailo" models={objectDetectorsModels.hailo.models} />
For additional ready-to-use models, please visit: https://github.com/hailo-ai/hailo_model_zoo For additional ready-to-use models, please visit: https://github.com/hailo-ai/hailo_model_zoo
Hailo8 supports all models in the Hailo Model Zoo that include HailoRT post-processing. You're welcome to choose any of these pre-configured models for your implementation. Hailo supports all models in the Hailo Model Zoo that include HailoRT post-processing. You're welcome to choose any of these pre-configured models for your implementation.
> **Note:** > **Note:**
> The config.path parameter can accept either a local file path or a URL ending with .hef. When provided, the detector will first check if the path is a local file path. If the file exists locally, it will use it directly. If the file is not found locally or if a URL was provided, it will attempt to download the model from the specified URL. > The config.path parameter can accept either a local file path or a URL ending with .hef. When provided, the detector will first check if the path is a local file path. If the file exists locally, it will use it directly. If the file is not found locally or if a URL was provided, it will attempt to download the model from the specified URL.
@@ -362,7 +363,7 @@ Intel NPUs cannot be used under Home Assistant OS, which does not include the NP
:::warning :::warning
The network-based detectors (Deepstack and the Apple Silicon client) are being reworked. Their extra options no longer have a place in the config, so only the endpoint carried in the device string is honored right now: Deepstack ignores `api_key` and `api_timeout`, and the Apple Silicon client ignores `request_timeout_ms` and `linger_ms`. Anything else is dropped when your config is migrated. The Apple Silicon detector client is being reworked. Its extra options no longer have a place in the config, so only the endpoint carried in the device string is honored right now, and `request_timeout_ms` and `linger_ms` are ignored. Anything else is dropped when your config is migrated.
::: :::
@@ -540,30 +541,6 @@ A TensorFlow Lite model is provided in the container at `/cpu_model.tflite` and
When using CPU detectors, you can add one CPU detector per camera. Adding more detectors than the number of cameras should not improve performance. When using CPU detectors, you can add one CPU detector per camera. Adding more detectors than the number of cameras should not improve performance.
## Deepstack / CodeProject.AI Server Detector
:::warning
The network-based detectors (Deepstack and the Apple Silicon client) are being reworked. Their extra options no longer have a place in the config, so only the endpoint carried in the device string is honored right now: Deepstack ignores `api_key` and `api_timeout`, and the Apple Silicon client ignores `request_timeout_ms` and `linger_ms`. Anything else is dropped when your config is migrated.
:::
The Deepstack / CodeProject.AI Server detector for Frigate allows you to integrate Deepstack and CodeProject.AI object detection capabilities into Frigate. CodeProject.AI and DeepStack are open-source AI platforms that can be run on various devices such as the Raspberry Pi, Nvidia Jetson, and other compatible hardware. It is important to note that the integration is performed over the network, so the inference times may not be as fast as native Frigate detectors, but it still provides an efficient and reliable solution for object detection and tracking.
### Setup {#setup-deepstack}
To get started with CodeProject.AI, visit their [official website](https://www.codeproject.com/Articles/5322557/CodeProject-AI-Server-AI-the-easy-way) to follow the instructions to download and install the AI server on your preferred device. Detailed setup instructions for CodeProject.AI are outside the scope of the Frigate documentation.
To integrate CodeProject.AI into Frigate, configure the detector as follows:
### Configuration {#configuration-deepstack}
<ModelConfigDropdown detectorTitle="DeepStack" models={objectDetectorsModels.deepstack.models} />
Replace `<your_codeproject_ai_server_ip>` and `<port>` with the IP address and port of your CodeProject.AI server.
To verify that the integration is working correctly, start Frigate and observe the logs for any error messages related to CodeProject.AI. Additionally, you can check the Frigate web interface to see if the objects detected by CodeProject.AI are being displayed and tracked properly.
# Community Supported Detectors # Community Supported Detectors
## MemryX MX3 ## MemryX MX3
@@ -636,6 +613,63 @@ For detailed instructions on compiling models, refer to the [MemryX Compiler](ht
--- ---
## DEEPX NPU
This detector is available for use with the DEEPX NPU, both the DX-M1 M.2 module and the DX-M1M on the Sixfab AI HAT+ for the Raspberry Pi 5. The configuration below applies unchanged to either form factor. DEEPX NPU support in Frigate is developed and maintained by [Sixfab](https://sixfab.com).
See the [installation docs](../frigate/installation.md#deepx-npu) for information on installing the DEEPX kernel driver and runtime on the host and passing the NPU through to the container.
To run a model on a DEEPX NPU, list a `deepx` device on that model.
:::info
The DX-RT Python bindings are not part of the Frigate image. They are downloaded and installed into `/config/.local` the first time a DEEPX device is configured, verified against pinned checksums, and updated automatically when a Frigate release pins a new version. If the container has no internet access, see [Detector runtimes](/frigate/network_requirements#detector-runtimes) for how to provide the files yourself.
:::
### Configuration {#configuration-deepx}
<ModelConfigDropdown detectorTitle="DEEPX" models={objectDetectorsModels.deepx.models} />
Frigate does not bundle a model for this detector. Models must be compiled to DEEPX's `.dxnn` format. Two model types are supported:
- `yolo-generic` for YOLO object detection models, the recommended default. The detector reads the model's output layout from the compiled file, so anchor-based, anchor-free and NMS-in-head models all work with the same configuration, as do models compiled with DEEPX's Post-Processing Unit (PPU) support.
- `yolox` for YOLOX models compiled without PPU support, whose raw head needs Frigate's YOLOX decoder. A YOLOX model compiled with PPU support works under either `yolox` or `yolo-generic`.
The quickest way to get one is the [DEEPX ModelZoo](https://developer.deepx.ai/modelzoo), which publishes pre-compiled `.dxnn` files for a range of YOLO object detection models. Download the `.dxnn`, bind-mount it into the container, and point the model's `path` at it. Alternatively, compile your own model with the DX-COM compiler. The recommended starting point is `yolox-s_640x640_ppu.dxnn`, the fastest ModelZoo model measured through Frigate:
```yaml
models:
- devices:
- deepx:PCIe:0
path: /config/model_cache/deepx/yolox-s_640x640_ppu.dxnn
labelmap_path: /labelmap/coco-80.txt
model_type: yolo-generic
width: 640
height: 640
```
For PPU models, use a `.dxnn` compiled with DX-COM 2.4.0 or later. Frigate reads the PPU head layout the compiler writes into the file and refuses to load a PPU model without it.
`model_type` must be set to `yolo-generic` or `yolox` to match the model; `yolo-generic` is the recommended default unless the model is a raw YOLOX export. Frigate defaults it to `ssd`, which this detector does not support, so the detector refuses to start on a model that leaves it unset.
`width` and `height` must match the resolution the model was compiled for. Quantization parameters are baked into the `.dxnn` file at compile time, so no normalization is applied on the host and Frigate's default `input_tensor`, `input_pixel_format`, and `input_dtype` values do not need to be overridden.
A DEEPX device is `PCIe:<index>`, as reported on the detector settings page. The NPU daemon multiplexes across processes, so the same device may be listed more than once to run additional inference processes against it:
```yaml
models:
- devices:
- deepx:PCIe:0
- deepx:PCIe:0
```
#### Label maps
The object detection models in the DEEPX ModelZoo are trained on the standard 80-class COCO label set, so `labelmap_path` must be set to `/labelmap/coco-80.txt`. Frigate's default label map uses an extended 91-class COCO scheme, and leaving it in place will cause detections to be reported as the wrong object type. For `yolo-generic` models the label map is also what the detector uses to tell the output layout, so a label map with the wrong number of classes is reported as an error at startup.
---
## NVidia TensorRT Detector ## NVidia TensorRT Detector
Nvidia Jetson devices may be used for object detection using the TensorRT libraries. Due to the size of the additional libraries, this detector is only provided in images with the `-tensorrt-jp6` tag suffix, e.g. `ghcr.io/blakeblackshear/frigate:stable-tensorrt-jp6`. This detector is designed to work with Yolo models for object detection. Nvidia Jetson devices may be used for object detection using the TensorRT libraries. Due to the size of the additional libraries, this detector is only provided in images with the `-tensorrt-jp6` tag suffix, e.g. `ghcr.io/blakeblackshear/frigate:stable-tensorrt-jp6`. This detector is designed to work with Yolo models for object detection.
+1 -1
View File
@@ -450,7 +450,7 @@ For advanced use cases, the [custom export HTTP API](../integrations/api/export-
POST /export/custom/{camera_name}/start/{start_time}/end/{end_time} POST /export/custom/{camera_name}/start/{start_time}/end/{end_time}
``` ```
The request body accepts `ffmpeg_input_args` and `ffmpeg_output_args` to control encoding, frame rate, filters, and other FFmpeg options. If neither is provided, Frigate defaults to time-lapse output settings (25x speed, 30 FPS). The request body accepts `ffmpeg_input_args` and `ffmpeg_output_args` to control encoding, frame rate, filters, and other FFmpeg options. If neither is provided, Frigate defaults to time-lapse output settings (25x speed, 30 FPS) with audio removed (`-an`). When providing your own `ffmpeg_input_args`, include `-an` if you want audio stripped from the export.
The following example exports a time-lapse at 60x speed with 25 FPS: The following example exports a time-lapse at 60x speed with 25 FPS:
+3 -1
View File
@@ -197,7 +197,7 @@ For cameras that support two-way talk, go2rtc will automatically establish an au
To prevent this, you must configure two separate stream instances: To prevent this, you must configure two separate stream instances:
1. One stream instance with `#backchannel=0` for Frigate's viewing, recording, and detection (prevents go2rtc from establishing the blocking backchannel) 1. One stream instance with `#backchannel=0` for Frigate's viewing, recording, and detection (prevents go2rtc from establishing the blocking backchannel)
2. A second stream instance without `#backchannel=0` for two-way talk functionality (can be used by Frigate's WebRTC viewer or other applications) 2. A second stream instance with no `#` parameters at all for two-way talk functionality (can be used by Frigate's WebRTC viewer or other applications)
Configuration example: Configuration example:
@@ -215,6 +215,8 @@ In this configuration:
- `front_door` stream is used by Frigate for viewing, recording, and detection. The `#backchannel=0` parameter prevents go2rtc from establishing the audio output backchannel, so it won't block two-way talk access. - `front_door` stream is used by Frigate for viewing, recording, and detection. The `#backchannel=0` parameter prevents go2rtc from establishing the audio output backchannel, so it won't block two-way talk access.
- `front_door_twoway` stream is used for two-way talk functionality. This stream can be used by Frigate's WebRTC viewer when two-way talk is enabled, or by other applications (like Home Assistant Advanced Camera Card) that need access to the camera's audio output channel. - `front_door_twoway` stream is used for two-way talk functionality. This stream can be used by Frigate's WebRTC viewer when two-way talk is enabled, or by other applications (like Home Assistant Advanced Camera Card) that need access to the camera's audio output channel.
Any `#` parameter on a bare `rtsp://` source disables the backchannel unless the URL explicitly contains `#backchannel=1`. A two-way talk stream with something like `#video=h264` on it silently loses two-way audio, and Frigate will report that two-way talk is unavailable for that stream.
## Security: Restricted Stream Sources ## Security: Restricted Stream Sources
For security reasons, the `echo:`, `expr:`, and `exec:` stream sources are disabled by default in go2rtc. These sources allow arbitrary command execution and can pose security risks if misconfigured. For security reasons, the `echo:`, `expr:`, and `exec:` stream sources are disabled by default in go2rtc. These sources allow arbitrary command execution and can pose security risks if misconfigured.
+12 -3
View File
@@ -204,11 +204,20 @@ Light guidelines and advice:
npm run lint npm run lint
``` ```
- Add to unit tests and ensure they pass. As much as possible, you should strive to _increase_ test coverage whenever making changes. This will help ensure features do not accidentally become broken in the future. - Ensure the backend [unit tests](#unit-tests) pass. Your PR cannot be merged unless tests pass.
- If you run into error messages like "TypeError: Cannot read properties of undefined (reading 'context')" when running tests, this may be due to these issues (https://github.com/vitest-dev/vitest/issues/1910, https://github.com/vitest-dev/vitest/issues/1652) in vitest, but I haven't been able to resolve them.
```shell
python3 -u -m unittest
```
- Ensure the end-to-end tests pass. They run in Playwright against a production build with mocked API data, so they don't need a running Frigate instance. Add or update tests in `web/e2e/specs/` when you change UI behavior.
```console ```console
npm run test # First-time setup
npx playwright install chromium
# Build the app and run all tests
npm run e2e:build && npm run e2e
``` ```
- Test in different browsers. Firefox, Chrome, and Safari all have different quirks that make them unique targets to interact with. - Test in different browsers. Firefox, Chrome, and Safari all have different quirks that make them unique targets to interact with.
+36 -4
View File
@@ -54,7 +54,7 @@ Frigate supports multiple different detectors that work on different types of ha
**Most Hardware** **Most Hardware**
- [Hailo](#hailo-8): The Hailo8 and Hailo8L AI Acceleration module is available in m.2 format with a HAT for RPi devices offering a wide range of compatibility with devices. - [Hailo](#hailo-8): The Hailo-8, Hailo-8L and Hailo-8R AI Acceleration modules are available in m.2 format with a HAT for RPi devices offering a wide range of compatibility with devices.
- [Supports many model architectures](../../configuration/object_detectors#configuration-hailo) - [Supports many model architectures](../../configuration/object_detectors#configuration-hailo)
- Runs best with tiny or small size models - Runs best with tiny or small size models
@@ -65,6 +65,11 @@ Frigate supports multiple different detectors that work on different types of ha
- [Supports many model architectures](../../configuration/object_detectors#memryx-mx3) - [Supports many model architectures](../../configuration/object_detectors#memryx-mx3)
- Runs best with tiny, small, or medium-size models - Runs best with tiny, small, or medium-size models
- <CommunityBadge /> [DEEPX](#deepx-npu): The DEEPX NPU is available in m.2 format and as a HAT+ for the Raspberry Pi 5, allowing for a wide range of compatibility with devices.
- [Supports YOLO model architectures](../../configuration/object_detectors#deepx-npu)
- Runs best with tiny or small size models
- Runs efficiently on low power hardware
**AMD** **AMD**
- [ROCm](#rocm---amd-gpu): ROCm can run on AMD Discrete GPUs to provide efficient object detection - [ROCm](#rocm---amd-gpu): ROCm can run on AMD Discrete GPUs to provide efficient object detection
@@ -111,12 +116,13 @@ Frigate supports multiple different detectors that work on different types of ha
### Hailo-8 ### Hailo-8
Frigate supports both the Hailo-8 and Hailo-8L AI Acceleration Modules on compatible hardware platforms, including the Raspberry Pi 5 with the PCIe hat from the AI kit. The Hailo detector integration in Frigate automatically identifies your hardware type and selects the appropriate default model when a custom model isn’t provided. Frigate supports the Hailo-8, Hailo-8L and Hailo-8R AI Acceleration Modules on compatible hardware platforms, including the Raspberry Pi 5 with the PCIe hat from the AI kit. The Hailo detector integration in Frigate identifies which of them is attached and selects the matching default model when a custom model isn’t provided.
**Default Model Configuration:** **Default Model Configuration:**
- **Hailo-8L:** Default model is **YOLOv6n**. - **Hailo-8L:** Default model is **YOLOv6n**, compiled for the Hailo-8L.
- **Hailo-8:** Default model is **YOLOv6n**. - **Hailo-8:** Default model is **YOLOv6n**, compiled for the Hailo-8.
- **Hailo-8R:** Default model is the **Hailo-8** build of **YOLOv6n**, since the Hailo Model Zoo publishes no Hailo-8R build.
In real-world deployments, even with multiple cameras running concurrently, Frigate has demonstrated consistent performance. Testing on x86 platforms, with dual PCIe lanes, yields further improvements in FPS, throughput, and latency compared to the Raspberry Pi setup. In real-world deployments, even with multiple cameras running concurrently, Frigate has demonstrated consistent performance. Testing on x86 platforms, with dual PCIe lanes, yields further improvements in FPS, throughput, and latency compared to the Raspberry Pi setup.
@@ -256,6 +262,32 @@ The MX3 is a pipelined architecture, where the maximum frames per second support
Inference speeds may vary depending on the host platform. The above data was measured on an **Intel 13700 CPU**. Platforms like Raspberry Pi, Orange Pi, and other ARM-based SBCs have different levels of processing capability, which may limit total FPS. Inference speeds may vary depending on the host platform. The above data was measured on an **Intel 13700 CPU**. Platforms like Raspberry Pi, Orange Pi, and other ARM-based SBCs have different levels of processing capability, which may limit total FPS.
### DEEPX NPU
Frigate supports the DEEPX NPU in both of its form factors: the **DX-M1** M.2 module, which works on x86 (Intel/AMD) and ARM-based SBCs such as the Raspberry Pi 5, and the **DX-M1M** on the [Sixfab AI HAT+](https://docs.sixfab.com/docs/ai-hat-plus-raspberry-pi-5-quickstart) for the Raspberry Pi 5. Both use the same driver and runtime, so the configuration is identical for either one. DEEPX NPU support in Frigate is developed and maintained by [Sixfab](https://sixfab.com).
The DEEPX driver and runtime run on the Docker host rather than inside the Frigate container and must be installed before the NPU can be used. See the [installation docs](installation.md#deepx-npu) for the setup steps and [the detector docs](/configuration/object_detectors#deepx-npu) for the configuration.
Frigate does not bundle a model for this detector. Models use DEEPX's `.dxnn` format, and pre-compiled YOLO models can be downloaded from the [DEEPX ModelZoo](https://developer.deepx.ai/modelzoo). Prefer a model with a `_ppu` suffix whenever one is available for the architecture you want: these run part of the post-processing on the NPU itself and are considerably faster, roughly 2.5x for the same architecture and input size. **YOLOX-S with PPU is the recommended starting point.**
Inference times for a few recommended models, measured through Frigate's own stats on a DX-M1:
| Model | Input Size | DX-M1 Inference Time |
| ----------------- | ---------- | -------------------- |
| YOLOX-S (PPU) | 640 | ~ 13 ms |
| YOLOv9-t (PPU) | 640 | ~ 18 ms |
| YOLOv4 (PPU) | 512 | ~ 20 ms |
| YOLOX-S | 640 | ~ 34 ms |
| YOLOv9-s | 640 | ~ 39 ms |
Other ModelZoo YOLO variants are also supported but have not been measured. Inference speeds vary with the host platform, so a slower host such as a Raspberry Pi 5 will report higher times than those above.
:::note
A few ModelZoo models can not be used with Frigate: SSD models (they are trained on Pascal VOC, so their labels do not match Frigate's), DAMO-YOLO models, face and pose models, and the PPU builds of YOLOv7.
:::
### Nvidia Jetson ### Nvidia Jetson
Jetson devices are supported via the TensorRT or ONNX detectors when running Jetpack 6. It will [make use of the Jetson's hardware media engine](/configuration/hardware_acceleration_video#nvidia-jetson) when configured with the [appropriate presets](/configuration/ffmpeg_presets#hwaccel-presets), and will make use of the Jetson's GPU and DLA for object detection when configured with the [TensorRT detector](/configuration/object_detectors#nvidia-tensorrt-detector). Jetson devices are supported via the TensorRT or ONNX detectors when running Jetpack 6. It will [make use of the Jetson's hardware media engine](/configuration/hardware_acceleration_video#nvidia-jetson) when configured with the [appropriate presets](/configuration/ffmpeg_presets#hwaccel-presets), and will make use of the Jetson's GPU and DLA for object detection when configured with the [TensorRT detector](/configuration/object_detectors#nvidia-tensorrt-detector).
+95 -2
View File
@@ -122,7 +122,7 @@ Additionally, the USB Coral draws a considerable amount of power. If using any o
### Hailo-8 ### Hailo-8
The Hailo-8 and Hailo-8L AI accelerators are available in both M.2 and HAT form factors for the Raspberry Pi. The M.2 version typically connects to a carrier board for PCIe, which then interfaces with the Raspberry Pi 5 as part of the AI Kit. The HAT version can be mounted directly onto compatible Raspberry Pi models. Both form factors have been successfully tested on x86 platforms as well, making them versatile options for various computing environments. The Hailo-8, Hailo-8L and Hailo-8R AI accelerators are available in both M.2 and HAT form factors for the Raspberry Pi. The M.2 version typically connects to a carrier board for PCIe, which then interfaces with the Raspberry Pi 5 as part of the AI Kit. The HAT version can be mounted directly onto compatible Raspberry Pi models. Both form factors have been successfully tested on x86 platforms as well, making them versatile options for various computing environments.
The HailoRT runtime is not part of the Frigate image; Frigate downloads and installs it at first start once a Hailo detector is configured. Containers without internet access can provide the files themselves, see [Detector runtimes](/frigate/network_requirements#detector-runtimes). The HailoRT runtime is not part of the Frigate image; Frigate downloads and installs it at first start once a Hailo detector is configured. Containers without internet access can provide the files themselves, see [Detector runtimes](/frigate/network_requirements#detector-runtimes).
@@ -300,7 +300,7 @@ If you are using `docker run`, add this option to your command `--device /dev/ha
#### Configuration #### Configuration
Finally, configure [hardware object detection](/configuration/object_detectors#hailo-8) to complete the setup. Finally, configure [hardware object detection](/configuration/object_detectors#hailo) to complete the setup.
### MemryX MX3 ### MemryX MX3
@@ -381,6 +381,99 @@ If you can't use Docker Compose, you can run the container with something simila
Finally, configure [hardware object detection](/configuration/object_detectors#memryx-mx3) to complete the setup. Finally, configure [hardware object detection](/configuration/object_detectors#memryx-mx3) to complete the setup.
### DEEPX NPU
The DEEPX NPU is available in two form factors, and Frigate supports both:
- **DX-M1** in the M.2 2280 form factor (like an NVMe SSD), for x86 (Intel/AMD) PCs, the Raspberry Pi 5, and other ARM SBCs with an exposed PCIe M.2 slot.
- **DX-M1M** on the [Sixfab AI HAT+](https://docs.sixfab.com/docs/ai-hat-plus-raspberry-pi-5-quickstart), a HAT+ board that connects to the Raspberry Pi 5 over PCIe Gen 3 x1.
Both present the NPU through the same PCIe driver and DX-RT runtime, so the setup below and the detector configuration are identical for either one. Nothing needs to change when moving between them.
DEEPX NPU support in Frigate is developed and maintained by [Sixfab](https://sixfab.com).
#### Versions
A DEEPX install has several separately versioned pieces, and they all have to agree. The driver, the runtime, and the daemon live on the Docker host; Frigate itself carries only the Python bindings, which it downloads on first start:
| Component | Version | Installed on | Installed by |
| -------------- | -------- | ------------ | ------------------------- |
| Kernel driver | `v2.6.0` | Host | `user_installation.sh` |
| DX-RT runtime | `v3.4.0` | Host | `user_installation.sh` |
| NPU firmware | `v2.7.4` | The module | Flashed from the host |
| DX-RT bindings | `v3.4.0` | Frigate | Downloaded at first start |
:::warning
A version mismatch does not produce a startup error. It typically shows up as inference requests that are accepted but never return a result, so detections simply stop appearing while Frigate looks healthy. If that happens after a Frigate upgrade, check every version in the table before anything else.
:::
The installation script installs the DX-RT runtime on the host and enables `dxrt.service`, so the daemon starts at boot and any other program on the host can share the NPU with Frigate. Check the firmware version with `dxrt-cli --status` and update the module if it does not match the table above.
#### Installation
The DEEPX kernel driver must be installed on the host rather than in the container, because containers share the host kernel and cannot load kernel modules. Installing it creates the `/dev/dxrt*` device nodes that are passed through to Frigate. The same script installs the DX-RT runtime and enables `dxrt.service`, the daemon that owns the NPU and hands work to it on behalf of Frigate and anything else on the host.
1. Copy or download [this script](https://github.com/blakeblackshear/frigate/blob/dev/docker/deepx/user_installation.sh).
2. Ensure it has execution permissions with `sudo chmod +x user_installation.sh`
3. Run the script with `./user_installation.sh`
4. **Restart your computer** to complete driver installation.
Confirm the NPU is visible before continuing:
```bash
ls /dev/dxrt*
```
Then confirm the daemon is running and listening in `/run/dxrt`:
```bash
systemctl is-active dxrt.service
ls /run/dxrt/
```
#### Setup
To set up Frigate, follow the default installation instructions, for example: `ghcr.io/blakeblackshear/frigate:stable`
#### Docker configuration
Frigate needs the NPU device node and the directory holding the daemon's socket:
```yaml
services:
frigate:
devices:
- /dev/dxrt0:/dev/dxrt0
volumes:
- /run/dxrt:/run/dxrt
```
If you can't use Docker Compose, add `--device /dev/dxrt0:/dev/dxrt0 -v /run/dxrt:/run/dxrt` to your `docker run` command.
Add one `--device` per NPU, contiguously from `/dev/dxrt0`, since the client stops enumerating at the first gap.
The installation script configures `dxrt.service` to place its socket in `/run/dxrt` through a systemd drop-in. Mounting the directory rather than the socket file means the container sees the new socket after `dxrt.service` is restarted, rather than holding on to a deleted one.
`dxrtd` listens on an abstract socket as well, but that one does not cross into a container, so Frigate names the filesystem socket through `DXRT_DYNAMIC_IPC_ENDPOINT` on your behalf. Set that variable on the container yourself only if the daemon listens somewhere else, which means you also set it for `dxrtd` through its own systemd drop-in. The script writes `/etc/systemd/system/dxrt.service.d/frigate.conf` for exactly that, and has `dxrt.service` link the socket to `/tmp/dxrt_dynamic_ipc.sock` when it starts, so the host's own `dxrt-cli` and `dxtop` keep finding it at the default path they fall back to.
:::note
The DX-RT client exits when `dxrt.service` stops, so restart the Frigate container after restarting `dxrt.service`.
:::
The device node is needed as well as the socket, because the client opens the NPU directly even though the daemon arbitrates access. Without it, inference fails with `Device not found`.
`/dev/shm` does not need sharing.
The DX-RT python bindings are not shipped in the Frigate image. Frigate downloads them on first start when a DEEPX detector is configured, and caches them under `/config`.
#### Configuration
Finally, configure [hardware object detection](/configuration/object_detectors#deepx-npu) to complete the setup.
### Rockchip platform ### Rockchip platform
Make sure that you use a linux distribution that comes with the rockchip BSP kernel 5.10 or 6.1 and necessary drivers (especially rkvdec2 and rknpu). To check, enter the following commands: Make sure that you use a linux distribution that comes with the rockchip BSP kernel 5.10 or 6.1 and necessary drivers (especially rkvdec2 and rknpu). To check, enter the following commands:
+18 -13
View File
@@ -47,7 +47,7 @@ If you are using one of the following hardware detectors and have not provided y
| Detector | Model Downloaded | Source | | Detector | Model Downloaded | Source |
| ------------------------------------------------------------------ | -------------------- | ------------------------ | | ------------------------------------------------------------------ | -------------------- | ------------------------ |
| [Rockchip RKNN](/configuration/object_detectors#rockchip-platform) | RKNN detection model | GitHub | | [Rockchip RKNN](/configuration/object_detectors#rockchip-platform) | RKNN detection model | GitHub |
| [Hailo 8 / 8L](/configuration/object_detectors#hailo-8) | YOLOv6n (.hef) | Hailo Model Zoo (AWS S3) | | [Hailo 8 / 8L / 8R](/configuration/object_detectors#hailo) | YOLOv6n (.hef) | Hailo Model Zoo (AWS S3) |
| [AXERA AXEngine](/configuration/object_detectors) | Detection model | HuggingFace | | [AXERA AXEngine](/configuration/object_detectors) | Detection model | HuggingFace |
:::note :::note
@@ -60,16 +60,16 @@ The default CPU, EdgeTPU, and OpenVINO object detection models are bundled into
The SDKs for a few hardware detectors are not shipped in the Frigate image. They are downloaded the first time that detector is configured, verified against checksums pinned in the Frigate release, and installed into the Frigate user's home directory (`/config/.local` by default). Once installed they are not downloaded again until a Frigate release pins a new version. The SDKs for a few hardware detectors are not shipped in the Frigate image. They are downloaded the first time that detector is configured, verified against checksums pinned in the Frigate release, and installed into the Frigate user's home directory (`/config/.local` by default). Once installed they are not downloaded again until a Frigate release pins a new version.
| Detector | Version | Files | Source | | Detector | Version | Files | Source |
| -------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | | ---------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| [Hailo 8 / 8L](/configuration/object_detectors#hailo-8) | 4.21.0 | `hailort-debian12-amd64.tar.gz` and `hailort-4.21.0-cp311-cp311-linux_x86_64.whl` on x86, `hailort-debian12-arm64.tar.gz` and `hailort-4.21.0-cp311-cp311-linux_aarch64.whl` on arm64 | [GitHub release](https://github.com/frigate-nvr/hailort/releases/tag/v4.21.0) | | [Hailo 8 / 8L / 8R](/configuration/object_detectors#hailo) | 4.21.0 | `hailort-debian12-amd64.tar.gz` and `hailort-4.21.0-cp311-cp311-linux_x86_64.whl` on x86, `hailort-debian12-arm64.tar.gz` and `hailort-4.21.0-cp311-cp311-linux_aarch64.whl` on arm64 | [GitHub release](https://github.com/frigate-nvr/hailort/releases/tag/v4.21.0) |
| [MemryX MX3](/configuration/object_detectors#memryx-mx3) | 2.1.0 | `mx_accl_frigate-2.1.0.zip` (the release source archive, renamed) | [GitHub archive](https://github.com/memryx/mx_accl_frigate/archive/refs/tags/v2.1.0.zip) | | [MemryX MX3](/configuration/object_detectors#memryx-mx3) | 2.1.0 | `mx_accl_frigate-2.1.0.zip` (the release source archive, renamed) | [GitHub archive](https://github.com/memryx/mx_accl_frigate/archive/refs/tags/v2.1.0.zip) |
| [AXERA AXEngine](/configuration/object_detectors#axera) | 0.1.3 | `axengine-0.1.3-py3-none-any.whl` | [GitHub release](https://github.com/AXERA-TECH/pyaxengine/releases/tag/0.1.3-frigate) | | [AXERA AXEngine](/configuration/object_detectors#axera) | 0.1.3 | `axengine-0.1.3-py3-none-any.whl` | [GitHub release](https://github.com/AXERA-TECH/pyaxengine/releases/tag/0.1.3-frigate) |
If the container cannot reach GitHub, provide the files yourself: If the container cannot reach GitHub, provide the files yourself:
1. Download the files for your architecture on a machine with internet access. 1. Download the files for your architecture on a machine with internet access.
2. Place them, with exactly the file names listed above, in `/config/model_cache/runtimes/<detector>/`, where `<detector>` is the detector `type` from your config (`hailo8l`, `memryx`, or `axengine`). 2. Place them, with exactly the file names listed above, in `/config/model_cache/runtimes/<detector>/`, where `<detector>` is the detector named in your config's `devices` (`hailo`, `memryx`, or `axengine`).
3. Start Frigate. Files whose checksum matches are installed without any download; a file with the wrong checksum is discarded and downloaded again, so a failed startup log names the file to replace. 3. Start Frigate. Files whose checksum matches are installed without any download; a file with the wrong checksum is discarded and downloaded again, so a failed startup log names the file to replace.
The `GITHUB_ENDPOINT` mirror variable below applies to these downloads as well. The `GITHUB_ENDPOINT` mirror variable below applies to these downloads as well.
@@ -134,6 +134,15 @@ telemetry:
version_check: false version_check: false
``` ```
### Anonymous Analytics
If [anonymous analytics](/configuration/advanced/analytics) sharing is turned on, Frigate sends one report a day to `https://analytics.frigate.video`. It's off by default, so no outbound connection happens unless you enable it:
```yaml
telemetry:
analytics: true
```
### Push Notifications ### Push Notifications
When [notifications](/configuration/notifications) are enabled and users have registered for push notifications in the web UI, Frigate sends push messages through the browser vendor's push service (e.g., Google FCM, Mozilla autopush). This requires internet access from the Frigate server to these push endpoints. When [notifications](/configuration/notifications) are enabled and users have registered for push notifications in the web UI, Frigate sends push messages through the browser vendor's push service (e.g., Google FCM, Mozilla autopush). This requires internet access from the Frigate server to these push endpoints.
@@ -142,16 +151,12 @@ When [notifications](/configuration/notifications) are enabled and users have re
If an [MQTT broker](/integrations/mqtt) is configured, Frigate maintains a connection to the broker's host and port. This is typically a local network connection, but will require internet if you use a cloud-hosted MQTT broker. If an [MQTT broker](/integrations/mqtt) is configured, Frigate maintains a connection to the broker's host and port. This is typically a local network connection, but will require internet if you use a cloud-hosted MQTT broker.
### DeepStack / CodeProject.AI
When using the [DeepStack detector plugin](/configuration/object_detectors), Frigate sends images to the configured API endpoint for inference. This is typically local but depends on where the service is hosted.
## WebRTC (STUN) ## WebRTC (STUN)
For [WebRTC live streaming](/configuration/live), Frigate uses STUN for NAT traversal: For [WebRTC live streaming](/configuration/live), Frigate uses STUN for NAT traversal:
- **go2rtc** defaults to a local STUN listener (`stun:8555`), no internet required. - **go2rtc** defaults to a local STUN listener (`stun:8555`), no internet required.
- **The web UI's WebRTC player** includes a fallback to Google's public STUN server (`stun:stun.l.google.com:19302`), which requires internet. - **The web UI** uses the servers in `go2rtc.webrtc.ice_servers` for its WebRTC player and for the WebRTC connectivity check it runs when the Live view loads. If none are set, it uses Google's public STUN server (`stun:stun.l.google.com:19302`), which requires internet access from the browser. Set `ice_servers` to a STUN or TURN server on your network to avoid this.
## Home Assistant Supervisor ## Home Assistant Supervisor
@@ -174,7 +179,7 @@ To run Frigate in an air-gapped or offline environment:
2. **Pre-download the training base weights**: If you plan to train custom classification models, set `TF_KERAS_MOBILENET_V2_WEIGHTS_URL` before training, then run one training job while online. Without this variable the base weights are cached outside `/config/` and are lost whenever the container is recreated, so a later training run will fail offline. If the machine never has internet access, copy the weights in manually as described below. 2. **Pre-download the training base weights**: If you plan to train custom classification models, set `TF_KERAS_MOBILENET_V2_WEIGHTS_URL` before training, then run one training job while online. Without this variable the base weights are cached outside `/config/` and are lost whenever the container is recreated, so a later training run will fail offline. If the machine never has internet access, copy the weights in manually as described below.
3. **Disable version check**: Set `telemetry.version_check: false` in your configuration. 3. **Disable version check**: Set `telemetry.version_check: false` in your configuration.
4. **Block outbound model requests**: Set the `HF_HUB_OFFLINE=1` and `TRANSFORMERS_OFFLINE=1` environment variables to prevent HuggingFace and Transformers from attempting any network requests. 4. **Block outbound model requests**: Set the `HF_HUB_OFFLINE=1` and `TRANSFORMERS_OFFLINE=1` environment variables to prevent HuggingFace and Transformers from attempting any network requests.
5. **Avoid cloud features**: Do not configure Frigate+, Generative AI providers that require internet, or cloud MQTT brokers. 5. **Avoid cloud features**: Do not configure Frigate+, Generative AI providers that require internet, or cloud MQTT brokers, and leave anonymous analytics off (its default).
6. **Use local model mirrors**: If limited internet is available, set the `HF_ENDPOINT`, `GITHUB_ENDPOINT`, `GITHUB_RAW_ENDPOINT`, and `TF_KERAS_MOBILENET_V2_WEIGHTS_URL` environment variables to point to local mirrors. 6. **Use local model mirrors**: If limited internet is available, set the `HF_ENDPOINT`, `GITHUB_ENDPOINT`, `GITHUB_RAW_ENDPOINT`, and `TF_KERAS_MOBILENET_V2_WEIGHTS_URL` environment variables to point to local mirrors.
After these steps, Frigate will operate with no outbound internet connections. After these steps, Frigate will operate with no outbound internet connections.
+2 -2
View File
@@ -41,7 +41,7 @@ Rockchip models are automatically converted as of 0.17. For 0.16, YOLOv9 onnx mo
## Supported detector types ## Supported detector types
Currently, Frigate+ models support CPU (`cpu`), Google Coral (`edgetpu`), OpenVino (`openvino`), ONNX (`onnx`), Hailo (`hailo8l`), and Rockchip (`rknn`) detectors. Currently, Frigate+ models support CPU (`cpu`), Google Coral (`edgetpu`), OpenVino (`openvino`), ONNX (`onnx`), Hailo (`hailo`), and Rockchip (`rknn`) detectors.
| Hardware | Recommended Detector Type | Recommended Model Type | | Hardware | Recommended Detector Type | Recommended Model Type |
| -------------------------------------------------------------------------------- | ------------------------- | ---------------------- | | -------------------------------------------------------------------------------- | ------------------------- | ---------------------- |
@@ -50,7 +50,7 @@ Currently, Frigate+ models support CPU (`cpu`), Google Coral (`edgetpu`), OpenVi
| [Intel](/configuration/object_detectors.md#openvino-detector) | `openvino` | `yolov9` | | [Intel](/configuration/object_detectors.md#openvino-detector) | `openvino` | `yolov9` |
| [NVidia GPU](/configuration/object_detectors#onnx) | `onnx` | `yolov9` | | [NVidia GPU](/configuration/object_detectors#onnx) | `onnx` | `yolov9` |
| [AMD ROCm GPU](/configuration/object_detectors#amdrocm-gpu-detector) | `onnx` | `yolov9` | | [AMD ROCm GPU](/configuration/object_detectors#amdrocm-gpu-detector) | `onnx` | `yolov9` |
| [Hailo8/Hailo8L/Hailo8R](/configuration/object_detectors#hailo-8) | `hailo8l` | `yolov9` | | [Hailo8/Hailo8L/Hailo8R](/configuration/object_detectors#hailo) | `hailo` | `yolov9` |
| [Rockchip NPU](/configuration/object_detectors#rockchip-platform) | `rknn` | `yolov9` | | [Rockchip NPU](/configuration/object_detectors#rockchip-platform) | `rknn` | `yolov9` |
## Improving your model ## Improving your model
+15 -1
View File
@@ -39,6 +39,20 @@ To do this efficiently the following setup is required:
When this is done correctly, the GPU will do the decoding and scaling which will result in a small increase in CPU usage but with better results. When this is done correctly, the GPU will do the decoding and scaling which will result in a small increase in CPU usage but with better results.
### How can I rotate my camera's video feed?
Rotation is best done in the camera's firmware settings (usually called rotate, flip, or corridor mode) so the video arrives already rotated and no extra processing is needed. Check there first.
If your camera does not support rotation, go2rtc's ffmpeg module can rotate the stream with the `#rotate` parameter (`90`, `180`, `270`, or `-90`), but this is not recommended: rotation requires transcoding (re-encoding) the video, which significantly increases CPU usage, especially for high resolution streams.
```yaml
go2rtc:
streams:
my_camera: "ffmpeg:rtsp://user:password@192.168.1.10:554/stream#video=h264#hardware#rotate=90"
```
Point the camera's inputs at the restream as described in the [restream docs](/configuration/restream.md), and swap `detect -> width` and `detect -> height` to match the rotated resolution.
### My mjpeg stream or snapshots look green and crazy ### My mjpeg stream or snapshots look green and crazy
This almost always means that the width/height defined for your camera are not correct. Double check the resolution with VLC or another player. Also make sure you don't have the width and height values backwards. This almost always means that the width/height defined for your camera are not correct. Double check the resolution with VLC or another player. Also make sure you don't have the width and height values backwards.
@@ -170,6 +184,6 @@ Filters and masks only hide the incorrect result - they don't teach Frigate what
### Where do I see problems Frigate has detected? ### Where do I see problems Frigate has detected?
Open System > Health. The Notices list shows problems the backend has noticed on its own, such as a camera whose ffmpeg keeps crashing, a detector that had to be restarted, a model download that failed, or recordings being deleted before their retention period. Entries that describe a one-time event can be dismissed; entries that describe an ongoing condition clear themselves once it is fixed. Open System > Health. The Notices list keeps a record of problems Frigate has found, and you can dismiss any entry to acknowledge it. Ongoing conditions, such as an offline camera or recordings deleted before their retention period, appear in the status bar for admins until they clear, and the status bar links to the Notices list while it has undismissed entries. On mobile, tap the warning icon in the bottom navigation bar to see them.
The Hardware section below the notices shows whether the detection hardware, hardware acceleration, and enrichment devices in your config were found and are being used, so a GPU that silently fell back to the CPU shows up as a warning. Run stream checks to probe every camera's streams for the same problems the camera wizard reports. The Hardware section below the notices shows whether the detection hardware, hardware acceleration, and enrichment devices in your config were found and are being used, so a GPU that silently fell back to the CPU shows up as a warning. Run stream checks to probe every camera's streams for the same problems the camera wizard reports.
+4 -2
View File
@@ -78,7 +78,9 @@ go2rtc:
:::warning :::warning
The `#`-modifiers (`#video=`, `#audio=`, `#hardware`, `#backchannel=0`, …) **only take effect on a source that is prefixed with `ffmpeg:`**. Adding them to a bare `rtsp://…#audio=opus` source does nothing: go2rtc ignores them. Likewise, when a source references another stream by name (e.g. `ffmpeg:back#audio=aac`), the name must match the stream key **exactly** (it is case sensitive), or the transcode is silently never produced. This is the single most common configuration mistake. In the Frigate UI, the **Use compatibility mode (ffmpeg)** toggle adds the `ffmpeg:` prefix for you. The transcoding modifiers (`#video=`, `#audio=`, `#hardware`, …) **only take effect on a source that is prefixed with `ffmpeg:`**. Adding them to a bare `rtsp://…#audio=opus` source does nothing: go2rtc ignores them. Likewise, when a source references another stream by name (e.g. `ffmpeg:back#audio=aac`), the name must match the stream key **exactly** (it is case sensitive), or the transcode is silently never produced. This is the single most common configuration mistake. In the Frigate UI, the **Use compatibility mode (ffmpeg)** toggle adds the `ffmpeg:` prefix for you.
A bare `rtsp://` source reads a different set of modifiers: `#backchannel=`, `#media=`, `#timeout=`, and `#transport=`. These do nothing on an `ffmpeg:` source. Adding **any** modifier to a bare `rtsp://` source also disables the camera's backchannel unless the URL explicitly contains `#backchannel=1`, so a stream dedicated to two-way talk should carry no modifiers at all.
::: :::
@@ -153,7 +155,7 @@ WebRTC is only attempted when MSE fails or when using a camera's two-way talk fe
- **Codec mismatch**: WebRTC cannot carry H.265 or AAC. The stream backing the WebRTC view must provide Opus (or PCMA/PCMU) audio and H.264 video. Add an `ffmpeg:back#audio=opus` source as shown above. - **Codec mismatch**: WebRTC cannot carry H.265 or AAC. The stream backing the WebRTC view must provide Opus (or PCMA/PCMU) audio and H.264 video. Add an `ffmpeg:back#audio=opus` source as shown above.
- **Port `8555` not reachable, or no candidates set**: WebRTC needs port `8555` (both TCP and UDP) open and a reachable candidate advertised. On Docker installs running on a custom/overlay network, go2rtc may advertise unreachable container IPs as ICE candidates; setting `webrtc.filters.candidates: []` and supplying only your host's LAN IP resolves this. See [WebRTC extra configuration](/configuration/live#webrtc-extra-configuration). - **Port `8555` not reachable, or no candidates set**: WebRTC needs port `8555` (both TCP and UDP) open and a reachable candidate advertised. On Docker installs running on a custom/overlay network, go2rtc may advertise unreachable container IPs as ICE candidates; setting `webrtc.filters.candidates: []` and supplying only your host's LAN IP resolves this. See [WebRTC extra configuration](/configuration/live#webrtc-extra-configuration).
- **Two-way talk** additionally requires a secure context (HTTPS or the authenticated port `8971`, because browsers block microphone access on plain HTTP). The camera's RTSP backchannel must also be handled correctly: go2rtc seizes the backchannel by default, which blocks two-way audio for other consumers and can inject static. Disable it on the primary stream with `#backchannel=0` and use a separate dedicated stream for talk, as documented in [preventing go2rtc from blocking two-way audio](/configuration/restream#two-way-talk-restream). - **Two-way talk** additionally requires a secure context (HTTPS or the authenticated port `8971`, because browsers block microphone access on plain HTTP). The camera's RTSP backchannel must also be handled correctly: go2rtc seizes the backchannel by default, which blocks two-way audio for other consumers and can inject static. Disable it on the primary stream with `#backchannel=0` and use a separate dedicated stream for talk, carrying no `#` modifiers of any kind, as documented in [preventing go2rtc from blocking two-way audio](/configuration/restream#two-way-talk-restream).
## High CPU usage ## High CPU usage
+2070 -3902
View File
File diff suppressed because it is too large Load Diff
+10 -10
View File
@@ -18,17 +18,17 @@
"write-heading-ids": "docusaurus write-heading-ids" "write-heading-ids": "docusaurus write-heading-ids"
}, },
"dependencies": { "dependencies": {
"@docusaurus/core": "^3.7.0", "@docusaurus/core": "^3.10.2",
"@docusaurus/plugin-content-docs": "^3.7.0", "@docusaurus/plugin-content-docs": "^3.10.2",
"@docusaurus/preset-classic": "^3.7.0", "@docusaurus/preset-classic": "^3.10.2",
"@docusaurus/theme-mermaid": "^3.7.0", "@docusaurus/theme-mermaid": "^3.10.2",
"@inkeep/docusaurus": "^2.0.16", "@inkeep/docusaurus": "^2.0.16",
"@mdx-js/react": "^3.1.0", "@mdx-js/react": "^3.1.0",
"@types/js-yaml": "^4.0.9", "@types/js-yaml": "^4.0.9",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"docusaurus-plugin-openapi-docs": "^4.5.1", "docusaurus-plugin-openapi-docs": "^5.2.0",
"docusaurus-theme-openapi-docs": "^4.5.1", "docusaurus-theme-openapi-docs": "^5.2.0",
"js-yaml": "^4.1.1", "js-yaml": "^4.3.2",
"marked": "^16.4.2", "marked": "^16.4.2",
"prism-react-renderer": "^2.4.1", "prism-react-renderer": "^2.4.1",
"raw-loader": "^4.0.2", "raw-loader": "^4.0.2",
@@ -48,11 +48,11 @@
] ]
}, },
"devDependencies": { "devDependencies": {
"@docusaurus/module-type-aliases": "^3.7.0", "@docusaurus/module-type-aliases": "^3.10.2",
"@docusaurus/types": "^3.7.0", "@docusaurus/types": "^3.10.2",
"@types/react": "^18.3.27" "@types/react": "^18.3.27"
}, },
"engines": { "engines": {
"node": ">=18.0" "node": ">=20.19"
} }
} }
+1
View File
@@ -130,6 +130,7 @@ const sidebars: SidebarsConfig = {
label: "Advanced Configuration", label: "Advanced Configuration",
items: [ items: [
"configuration/advanced/system", "configuration/advanced/system",
"configuration/advanced/analytics",
"configuration/advanced/reference", "configuration/advanced/reference",
{ {
type: "link", type: "link",
@@ -0,0 +1,60 @@
import React from "react";
import schema from "@site/static/frigate-analytics-schema.json";
function resolve(node) {
if (!node) return node;
if (node.$ref) return schema.$defs[node.$ref.split("/").pop()];
if (node.anyOf) {
const inner = node.anyOf.find((option) => option.type !== "null");
return inner ? resolve(inner) : node;
}
return node;
}
function rows(properties, prefix = "") {
return Object.entries(properties).flatMap(([name, field]) => {
const path = prefix ? `${prefix}.${name}` : name;
const row = {
path,
description: field.description,
isPublic: field["x-public"],
};
const target = resolve(field);
if (target?.properties) return [row, ...rows(target.properties, path)];
const values = resolve(target?.additionalProperties);
if (values?.properties)
return [row, ...rows(values.properties, `${path}.<key>`)];
const items = resolve(target?.items);
if (items?.properties) return [row, ...rows(items.properties, `${path}[]`)];
return [row];
});
}
export default function AnalyticsFields() {
return (
<table>
<thead>
<tr>
<th>Field</th>
<th>Description</th>
<th>Public</th>
</tr>
</thead>
<tbody>
{rows(schema.properties).map((row) => (
<tr key={row.path}>
<td>
<code>{row.path}</code>
</td>
<td>{row.description}</td>
<td>{row.isPublic ? "Yes" : "No"}</td>
</tr>
))}
</tbody>
</table>
);
}
File diff suppressed because it is too large Load Diff
+63 -4
View File
@@ -10,6 +10,25 @@ servers:
- url: https://demo.frigate.video/api - url: https://demo.frigate.video/api
- url: http://localhost:5001/api - url: http://localhost:5001/api
paths: paths:
/analytics/preview:
get:
tags:
- Analytics
summary: Get Analytics Preview
description: |-
**Access:** Admin role required.
Get the analytics report Frigate would send next, without sending it.
operationId: get_analytics_preview_analytics_preview_get
responses:
'200':
description: Successful Response
content:
application/json:
schema: {}
security:
- frigateAdminAuth: []
x-required-role: admin
/auth/first_time_login: /auth/first_time_login:
get: get:
tags: tags:
@@ -4171,13 +4190,13 @@ paths:
description: |- description: |-
**Access:** Admin role required. **Access:** Admin role required.
Get the active notices, most severe first. Get notices, most severe first.
Args: Args:
include_dismissed: Also return event notices the user has dismissed include_dismissed: Also return dismissed notices, for the history view
Returns: Returns:
The active notices The notices
operationId: get_notices_notices_get operationId: get_notices_notices_get
parameters: parameters:
- name: include_dismissed - name: include_dismissed
@@ -4221,6 +4240,44 @@ paths:
security: security:
- frigateAdminAuth: [] - frigateAdminAuth: []
x-required-role: admin x-required-role: admin
/notices/dismissed_checks:
get:
tags:
- Notices
summary: Get Dismissed Checks
description: |-
**Access:** Admin role required.
Get the dismissed config and stream check rows, newest first.
operationId: get_dismissed_checks_notices_dismissed_checks_get
responses:
'200':
description: Successful Response
content:
application/json:
schema: {}
security:
- frigateAdminAuth: []
x-required-role: admin
/notices/dismissed:
delete:
tags:
- Notices
summary: Purge Dismissed
description: |-
**Access:** Admin role required.
Delete every dismissed notice and check row so each can show again.
operationId: purge_dismissed_notices_dismissed_delete
responses:
'200':
description: Successful Response
content:
application/json:
schema: {}
security:
- frigateAdminAuth: []
x-required-role: admin
/notices/{notice_id}/dismiss: /notices/{notice_id}/dismiss:
post: post:
tags: tags:
@@ -4229,7 +4286,9 @@ paths:
description: |- description: |-
**Access:** Admin role required. **Access:** Admin role required.
Hide an event notice until it is raised again. Hide a notice or a config or stream check row.
It stays hidden if the same problem happens again.
operationId: dismiss_notice_notices__notice_id__dismiss_post operationId: dismiss_notice_notices__notice_id__dismiss_post
parameters: parameters:
- name: notice_id - name: notice_id
+4
View File
@@ -99,6 +99,10 @@ def main() -> None:
print("*** End Config Validation Errors ***") print("*** End Config Validation Errors ***")
print("*************************************************************") print("*************************************************************")
# force a non-zero exit code for config failures
if args.validate_config:
sys.exit(1)
# attempt to start Frigate in recovery mode # attempt to start Frigate in recovery mode
try: try:
config = FrigateConfig.load(install=True, safe_load=True) config = FrigateConfig.load(install=True, safe_load=True)
+1
View File
@@ -0,0 +1 @@
"""Opt-in anonymous analytics reports."""
+1
View File
@@ -0,0 +1 @@
"""One collector per report section."""
+223
View File
@@ -0,0 +1,223 @@
"""Cameras section: counts and histograms across cameras, never per camera."""
from collections import Counter
from typing import Any
from urllib.parse import urlsplit
from frigate.analytics.collectors.common import closed, histogram
from frigate.analytics.context import ReportContext
from frigate.analytics.schema import (
CamerasSection,
ConnectionQuality,
FpsBucket,
HeightBucket,
HwaccelKey,
InputPresetKey,
RetainBucket,
RetainDays,
)
from frigate.config import CameraConfig
from frigate.config.camera.camera import CameraTypeEnum
from frigate.config.camera.ffmpeg import CameraInput, CameraRoleEnum
from frigate.const import REPLAY_CAMERA_PREFIX
# the upper edge of every height bucket but the last
HEIGHT_BUCKETS = (
(360, HeightBucket.le_360),
(540, HeightBucket.h480),
(900, HeightBucket.h720),
(1260, HeightBucket.h1080),
(1800, HeightBucket.h1440),
)
RESTREAM_HOSTS = frozenset({"127.0.0.1", "localhost"})
RESTREAM_PORT = 8554
QUALITIES = frozenset(ConnectionQuality)
def height_bucket(height: int) -> HeightBucket:
for limit, bucket in HEIGHT_BUCKETS:
if height <= limit:
return bucket
return HeightBucket.ge_2160
def fps_bucket(fps: int) -> FpsBucket:
if fps <= 5:
return FpsBucket.le_5
if fps <= 10:
return FpsBucket.f6_10
return FpsBucket.gt_10
def retain_bucket(days: float) -> RetainBucket:
if days <= 0:
return RetainBucket.zero
if days <= 7:
return RetainBucket.d1_7
if days <= 30:
return RetainBucket.d8_30
return RetainBucket.gt_30
def preset_key(args: str | list[str], enum: Any) -> Any:
"""The preset's name, custom for hand written args, or none."""
if not args:
return enum("none")
if isinstance(args, str) and args.startswith("preset-"):
return closed(enum, args.removeprefix("preset-"), enum("custom"))
return enum("custom")
def is_restream(path: str) -> bool:
try:
url = urlsplit(path)
return url.hostname in RESTREAM_HOSTS and url.port == RESTREAM_PORT
except ValueError:
return False
def role_input(camera: CameraConfig, role: CameraRoleEnum) -> CameraInput | None:
return next((i for i in camera.ffmpeg.inputs if role in i.roles), None)
def object_masks(camera: CameraConfig) -> int:
# parsing copies camera-wide masks into every filter as global_<id>
own = sum(1 for mask in camera.objects.mask.values() if mask is not None)
per_label = sum(
1
for label_filter in camera.objects.filters.values()
for mask_id, mask in label_filter.mask.items()
if mask is not None and not mask_id.startswith("global_")
)
return own + per_label
def collect(ctx: ReportContext) -> CamerasSection:
cameras = {
name: camera
for name, camera in ctx.config.cameras.items()
if not name.startswith(REPLAY_CAMERA_PREFIX)
}
camera_stats = ctx.stats.get("cameras", {})
flags: Counter[str] = Counter()
types: Counter[CameraTypeEnum] = Counter()
heights: Counter[HeightBucket] = Counter()
fps: Counter[FpsBucket] = Counter()
hwaccel: Counter[Any] = Counter()
input_presets: Counter[Any] = Counter()
quality: Counter[ConnectionQuality] = Counter()
retain: dict[str, Counter[RetainBucket]] = {
period: Counter() for period in ("continuous", "motion", "alerts", "detections")
}
for name, camera in cameras.items():
detect_input = role_input(camera, CameraRoleEnum.detect)
record_input = role_input(camera, CameraRoleEnum.record)
# config validation requires a detect input, so this never skips
if detect_input is None:
continue
types[camera.type] += 1
fps[fps_bucket(camera.detect.fps)] += 1
hwaccel[
preset_key(
detect_input.hwaccel_args or camera.ffmpeg.hwaccel_args, HwaccelKey
)
] += 1
input_presets[
preset_key(
detect_input.input_args or camera.ffmpeg.input_args, InputPresetKey
)
] += 1
if camera.detect.height:
heights[height_bucket(camera.detect.height)] += 1
state = camera_stats.get(name, {}).get("connection_quality")
if state in QUALITIES:
quality[ConnectionQuality(state)] += 1
if camera.record.enabled:
retain["continuous"][retain_bucket(camera.record.continuous.days)] += 1
retain["motion"][retain_bucket(camera.record.motion.days)] += 1
retain["alerts"][retain_bucket(camera.record.alerts.retain.days)] += 1
retain["detections"][
retain_bucket(camera.record.detections.retain.days)
] += 1
zones = len(camera.zones)
flags["enabled"] += camera.enabled
flags["go2rtc_restream"] += any(
is_restream(i.path) for i in camera.ffmpeg.inputs
)
flags["separate_detect_stream"] += (
record_input is not None and record_input.path != detect_input.path
)
flags["detect"] += camera.detect.enabled
flags["record"] += camera.record.enabled
flags["sub_stream_record"] += camera.record.sub.enabled
flags["snapshots"] += camera.snapshots.enabled
flags["audio"] += camera.audio.enabled
flags["audio_transcription"] += camera.audio_transcription.enabled
flags["birdseye"] += camera.birdseye.enabled
flags["onvif"] += bool(camera.onvif.host)
flags["autotracking"] += camera.onvif.autotracking.enabled
flags["face_recognition"] += camera.face_recognition.enabled
flags["lpr"] += camera.lpr.enabled
flags["review_genai"] += camera.review.genai.enabled
flags["object_genai"] += camera.objects.genai.enabled
flags["notifications"] += camera.notifications.enabled
flags["zones"] += zones
flags["cameras_with_zones"] += zones > 0
flags["motion_masks"] += sum(
1 for mask in camera.motion.mask.values() if mask is not None
)
flags["object_masks"] += object_masks(camera)
return CamerasSection(
total=len(cameras),
enabled=flags["enabled"],
types=histogram(types),
detect_height=histogram(heights),
detect_fps=histogram(fps),
hwaccel=histogram(hwaccel),
input_preset=histogram(input_presets),
go2rtc_restream=flags["go2rtc_restream"],
separate_detect_stream=flags["separate_detect_stream"],
detect=flags["detect"],
record=flags["record"],
sub_stream_record=flags["sub_stream_record"],
snapshots=flags["snapshots"],
audio=flags["audio"],
audio_transcription=flags["audio_transcription"],
birdseye=flags["birdseye"],
onvif=flags["onvif"],
autotracking=flags["autotracking"],
face_recognition=flags["face_recognition"],
lpr=flags["lpr"],
review_genai=flags["review_genai"],
object_genai=flags["object_genai"],
notifications=flags["notifications"],
zones=flags["zones"],
cameras_with_zones=flags["cameras_with_zones"],
motion_masks=flags["motion_masks"],
object_masks=flags["object_masks"],
connection_quality=histogram(quality),
retain_days=RetainDays(
continuous=histogram(retain["continuous"]),
motion=histogram(retain["motion"]),
alerts=histogram(retain["alerts"]),
detections=histogram(retain["detections"]),
),
)
+37
View File
@@ -0,0 +1,37 @@
"""Helpers the section collectors share."""
import math
from collections import Counter
from enum import Enum
from typing import Any, TypeVar
E = TypeVar("E", bound=Enum)
def closed(enum: type[E], value: Any, fallback: E) -> E:
"""The member for a value, or the fallback for one the enum doesn't know."""
try:
return enum(str(value))
except ValueError:
return fallback
def rate(value: Any) -> float:
"""A finite, non-negative number rounded to 2 decimals, else 0.
A NaN would serialize as null and fail the schema's number type.
"""
try:
number = float(value)
except (TypeError, ValueError):
return 0.0
if not math.isfinite(number):
return 0.0
return round(max(number, 0.0), 2)
def histogram(counter: "Counter[E]") -> dict[E, int]:
"""Drop the empty buckets, since an absent key means zero."""
return {key: total for key, total in counter.items() if total > 0}
+65
View File
@@ -0,0 +1,65 @@
"""Detection section: models, the detectors they run on, and inference speed."""
import os
from frigate.analytics.collectors.common import rate
from frigate.analytics.context import ReportContext
from frigate.analytics.schema import DetectionModel, DetectionSection, ModelSource
from frigate.config.config import DEFAULT_MODEL
from frigate.const import MODEL_CACHE_DIR
from frigate.detectors.detector_config import SceneEnum
from frigate.detectors.detector_types import DetectorTypeEnum
from frigate.detectors.device import runner_names
# the paths FrigateConfig fills in for a model that sets none
BUNDLED_MODEL_PATHS = frozenset(
{"/cpu_model.tflite", "/edgetpu_model.tflite", str(DEFAULT_MODEL["path"])}
)
def model_source(path: str | None) -> ModelSource:
"""Default, Frigate+ (a cached model next to its info file), or custom.
Parsing rewrites plus://<id> to the model cache, so the prefix is gone by now.
"""
if path is None or path in BUNDLED_MODEL_PATHS:
return ModelSource.default
if path.startswith(f"{MODEL_CACHE_DIR}/") and os.path.isfile(f"{path}.json"):
return ModelSource.plus
return ModelSource.custom
def collect(ctx: ReportContext) -> DetectionSection:
config = ctx.config
detectors = ctx.stats.get("detectors", {})
model_specs = [(model, config.devices_for_model(model)) for model in config.models]
# FrigateApp.start_detectors names the processes in this same order
names = iter(runner_names([spec for _, specs in model_specs for spec in specs]))
models: dict[SceneEnum, DetectionModel] = {}
for model, specs in model_specs:
speeds: list[float] = []
for _ in specs:
speed = detectors.get(next(names), {}).get("inference_speed")
if isinstance(speed, int | float) and speed > 0:
speeds.append(float(speed))
models[model.scene] = DetectionModel(
detector=DetectorTypeEnum(specs[0].detector),
devices=len(specs),
model_type=model.model_type,
input=f"{model.width}x{model.height}",
source=model_source(model.path),
inference_ms=rate(sum(speeds) / len(speeds)) if speeds else None,
)
return DetectionSection(
models=models,
detection_fps=rate(ctx.stats.get("detection_fps")),
skipped_fps=rate(ctx.stats.get("skipped_fps")),
)
+145
View File
@@ -0,0 +1,145 @@
"""Features section: enrichments, GenAI, integrations, and users."""
from collections import Counter
from frigate.analytics.collectors.common import closed, histogram
from frigate.analytics.context import ReportContext
from frigate.analytics.schema import (
BirdseyeUsage,
ClassificationUsage,
EnrichmentDevice,
EnrichmentUsage,
FeaturesSection,
GenAIUsage,
SemanticSearchModel,
SemanticSearchUsage,
TranscriptionModel,
TranscriptionUsage,
UserRole,
)
from frigate.config.camera.genai import GenAIProviderEnum, GenAIRoleEnum
from frigate.const import REPLAY_CAMERA_PREFIX
from frigate.models import User
RUNTIME_DEVICES = {
"cpu": EnrichmentDevice.cpu,
"cuda": EnrichmentDevice.cuda,
"tensorrt": EnrichmentDevice.tensorrt,
"migraphx": EnrichmentDevice.migraphx,
}
OPENVINO_DEVICES = {
"cpu": EnrichmentDevice.openvino_cpu,
"gpu": EnrichmentDevice.openvino_gpu,
"npu": EnrichmentDevice.openvino_npu,
}
def enrichment_device(label: object) -> EnrichmentDevice | None:
"""Map a runner's device label, like "CUDA" or "OpenVINO GPU.0,CPU"."""
if not isinstance(label, str) or not label:
return None
runtime, _, target = label.partition(" ")
if runtime == "OpenVINO":
first = target.split(",")[0].split(".")[0].strip().lower()
return OPENVINO_DEVICES.get(first, EnrichmentDevice.other)
return RUNTIME_DEVICES.get(label.lower(), EnrichmentDevice.other)
def model_name(model: object) -> str | None:
if model is None:
return None
return str(getattr(model, "value", model))
def semantic_model(model: object) -> SemanticSearchModel | None:
# any string that isn't a built-in model names a GenAI provider
name = model_name(model)
if name is None:
return None
if name in ("jinav1", "jinav2"):
return SemanticSearchModel(name)
return SemanticSearchModel.genai
def transcription_model(model: object) -> TranscriptionModel | None:
name = model_name(model)
if name is None:
return None
return TranscriptionModel.whisper if name == "whisper" else TranscriptionModel.genai
def users() -> dict[UserRole, int]:
roles: Counter[UserRole] = Counter(
closed(UserRole, user.role, UserRole.custom) for user in User.select(User.role)
)
return histogram(roles)
def collect(ctx: ReportContext) -> FeaturesSection:
config = ctx.config
devices = ctx.stats.get("embeddings", {}).get("devices", {})
cameras = [
camera
for name, camera in config.cameras.items()
if not name.startswith(REPLAY_CAMERA_PREFIX)
]
providers: Counter[GenAIProviderEnum] = Counter(
genai.provider for genai in config.genai.values()
)
roles: Counter[GenAIRoleEnum] = Counter(
role for genai in config.genai.values() for role in genai.roles
)
custom = list(config.classification.custom.values())
return FeaturesSection(
face_recognition=EnrichmentUsage(
enabled=config.face_recognition.enabled,
model_size=config.face_recognition.model_size,
device=enrichment_device(devices.get("face_recognition")),
),
lpr=EnrichmentUsage(
enabled=config.lpr.enabled,
model_size=config.lpr.model_size,
device=enrichment_device(devices.get("lpr")),
),
semantic_search=SemanticSearchUsage(
enabled=config.semantic_search.enabled,
model=semantic_model(config.semantic_search.model),
model_size=config.semantic_search.model_size,
device=enrichment_device(devices.get("semantic_search")),
triggers=sum(len(camera.semantic_search.triggers) for camera in cameras),
),
audio_transcription=TranscriptionUsage(
enabled=config.audio_transcription.enabled,
model=transcription_model(config.audio_transcription.model),
model_size=config.audio_transcription.model_size,
),
genai=GenAIUsage(providers=histogram(providers), roles=histogram(roles)),
classification_models=ClassificationUsage(
state=sum(1 for model in custom if model.state_config is not None),
object=sum(1 for model in custom if model.object_config is not None),
),
birdseye=BirdseyeUsage(
enabled=config.birdseye.enabled,
modes=list(config.birdseye.modes),
restream=config.birdseye.restream,
),
mqtt=config.mqtt.enabled,
notifications=config.notifications.enabled,
auth=config.auth.enabled,
proxy_auth=config.proxy.header_map.user is not None,
tls=config.tls.enabled,
users=users(),
camera_groups=len(config.camera_groups),
profiles=len(config.profiles),
plus_api_key=config.plus_api.is_active(),
)
+107
View File
@@ -0,0 +1,107 @@
"""Hardware section: CPU, memory, GPUs, decode and detection hardware, storage."""
import os
from collections import Counter
from typing import Any
import psutil
from frigate.analytics.collectors.common import closed, histogram
from frigate.analytics.context import ReportContext
from frigate.analytics.schema import (
DecodeFamily,
GpuInfo,
GpuVendor,
HardwareKey,
HardwareSection,
StorageInfo,
)
from frigate.const import RECORD_DIR
from frigate.detectors.hardware import hardware_prober
from frigate.util.hwaccel import hwaccel_options
DEVICE_TREE_MODEL = "/proc/device-tree/model"
CPUINFO = "/proc/cpuinfo"
def cpu_model() -> str:
"""The board model on ARM boards, else the CPU's model name."""
try:
with open(DEVICE_TREE_MODEL) as f:
board = f.read().strip("\x00\n ")
if board:
return board[:64]
except OSError:
pass
try:
with open(CPUINFO) as f:
for line in f:
key, _, value = line.partition(":")
if key.strip() == "model name" and value.strip():
return value.strip()[:64]
except OSError:
pass
return "unknown"
def gpus(stats: dict[str, Any]) -> list[GpuInfo]:
found: list[GpuInfo] = []
for name, entry in stats.get("gpu_usages", {}).items():
vendor = entry.get("vendor") if isinstance(entry, dict) else None
found.append(
GpuInfo(
vendor=closed(GpuVendor, vendor, GpuVendor.other),
name=str(name)[:64],
)
)
return found
def decode_families() -> list[DecodeFamily]:
_, available = hwaccel_options()
families = [
closed(DecodeFamily, family.key, DecodeFamily.other) for family in available
]
return list(dict.fromkeys(families))
def detection_hardware() -> dict[HardwareKey, int]:
units: Counter[HardwareKey] = Counter()
for found in hardware_prober.probe():
units[closed(HardwareKey, found.key, HardwareKey.other)] += found.count
return histogram(units)
def storage(stats: dict[str, Any]) -> StorageInfo:
# stats report sizes in MB
entry = stats.get("service", {}).get("storage", {}).get(RECORD_DIR) or {}
total_mb = float(entry.get("total") or 0)
used_mb = float(entry.get("used") or 0)
return StorageInfo(
record_fs=str(entry.get("mount_type") or "unknown")[:16],
record_total_gb=round(total_mb / 1024),
record_used_pct=min(round(used_mb / total_mb * 100), 100)
if total_mb > 0
else 0,
)
def collect(ctx: ReportContext) -> HardwareSection:
return HardwareSection(
cpu_model=cpu_model(),
cpu_cores=os.cpu_count() or 0,
memory_gb=round(psutil.virtual_memory().total / 2**30),
gpus=gpus(ctx.stats),
decode_families=decode_families(),
detection_hardware=detection_hardware(),
storage=storage(ctx.stats),
)
+59
View File
@@ -0,0 +1,59 @@
"""Health section: uptime, CPU, enrichment speed, and notice counts."""
from typing import Any
from frigate.analytics.collectors.common import rate
from frigate.analytics.context import ReportContext
from frigate.analytics.schema import (
EnrichmentTiming,
HealthSection,
NoticeCounts,
NoticeKindKey,
)
TIMING_STATS = {
EnrichmentTiming.face: "face_recognition_speed",
EnrichmentTiming.lpr: "plate_recognition_speed",
EnrichmentTiming.plate_detection: "yolov9_plate_detection_speed",
EnrichmentTiming.image_embedding: "image_embedding_speed",
EnrichmentTiming.text_embedding: "text_embedding_speed",
EnrichmentTiming.review_description: "review_description_speed",
EnrichmentTiming.object_description: "object_description_speed",
}
REPORTABLE_KINDS = frozenset(key.value for key in NoticeKindKey)
def notice_deltas(notice_stats: list[dict[str, Any]]) -> dict[Any, NoticeCounts]:
"""What changed since the last accepted report, per reportable kind."""
deltas: dict[Any, NoticeCounts] = {}
for row in notice_stats:
if row["kind"] not in REPORTABLE_KINDS:
continue
occurrences = max(row["occurrences"] - row["reported_occurrences"], 0)
dismissals = max(row["dismissals"] - row["reported_dismissals"], 0)
if occurrences or dismissals:
deltas[NoticeKindKey(row["kind"])] = NoticeCounts(
occurrences=occurrences, dismissals=dismissals
)
return deltas
def collect(ctx: ReportContext) -> HealthSection:
service = ctx.stats.get("service", {})
embeddings = ctx.stats.get("embeddings", {})
cpu = ctx.stats.get("cpu_usages", {}).get("frigate.full_system", {}).get("cpu")
timings = {
timing: rate(embeddings.get(key)) for timing, key in TIMING_STATS.items()
}
return HealthSection(
uptime_hours=int(rate(service.get("uptime")) // 3600),
cpu_percent=min(round(rate(cpu)), 100),
enrichment_ms={timing: value for timing, value in timings.items() if value > 0},
retention_unmet=bool(service.get("retention_unmet", False)),
notices=notice_deltas(ctx.notice_stats),
)
+63
View File
@@ -0,0 +1,63 @@
"""Install section: version, image variant, install type, platform."""
import os
import platform
import re
from frigate.analytics.collectors.common import closed
from frigate.analytics.context import ReportContext
from frigate.analytics.schema import Arch, ImageVariant, InstallSection, InstallType
from frigate.version import VERSION
KERNEL_PATTERN = re.compile(r"^(\d{1,3})\.(\d{1,3})")
def image_variant(value: str | None) -> ImageVariant:
"""The published image from the build-time FRIGATE_IMAGE_VARIANT, dev when unset."""
if not value:
return ImageVariant.dev
return closed(ImageVariant, value, ImageVariant.other)
def install_type() -> InstallType:
# the add-on is a container too, so it has to be checked first
if os.path.isfile("/data/options.json"):
return InstallType.ha_addon
if os.environ.get("KUBERNETES_SERVICE_HOST"):
return InstallType.kubernetes
if os.path.exists("/run/.containerenv"):
return InstallType.podman
if os.path.exists("/.dockerenv"):
return InstallType.docker
return InstallType.unknown
def arch(machine: str) -> Arch:
match machine.lower():
case "x86_64" | "amd64":
return Arch.x86_64
case "aarch64" | "arm64":
return Arch.aarch64
case _:
return Arch.other
def kernel(release: str) -> str:
match = KERNEL_PATTERN.match(release)
return f"{match.group(1)}.{match.group(2)}" if match else "unknown"
def collect(ctx: ReportContext) -> InstallSection:
return InstallSection(
version=VERSION[:32],
image_variant=image_variant(os.environ.get("FRIGATE_IMAGE_VARIANT")),
install_type=install_type(),
arch=arch(platform.machine()),
kernel=kernel(platform.release()),
run_as_root=os.geteuid() == 0,
)
+13
View File
@@ -0,0 +1,13 @@
"""What the collectors read, gathered once per report."""
from dataclasses import dataclass, field
from typing import Any
from frigate.config import FrigateConfig
@dataclass(frozen=True)
class ReportContext:
config: FrigateConfig
stats: dict[str, Any]
notice_stats: list[dict[str, Any]] = field(default_factory=list)
+88
View File
@@ -0,0 +1,88 @@
"""Build a report from the section collectors."""
import logging
import time
from collections.abc import Callable
from typing import TYPE_CHECKING, Any
from uuid import uuid4
from pydantic import BaseModel
from frigate.analytics.collectors import (
cameras,
detection,
features,
hardware,
health,
install,
)
from frigate.analytics.context import ReportContext
from frigate.analytics.schema import SCHEMA_VERSION, AnalyticsReport
from frigate.analytics.state import load_state
from frigate.config import FrigateConfig
if TYPE_CHECKING:
from frigate.notices.registry import NoticeRegistry
from frigate.stats.emitter import StatsEmitter
logger = logging.getLogger(__name__)
COLLECTORS: dict[str, Callable[[ReportContext], BaseModel | None]] = {
"install": install.collect,
"hardware": hardware.collect,
"detection": detection.collect,
"cameras": cameras.collect,
"features": features.collect,
"health": health.collect,
}
# shown in the preview until the first report creates a real ID
PREVIEW_INSTALL_ID = "0" * 32
def build_report(
ctx: ReportContext, install_id: str, sent_at: int | None = None
) -> AnalyticsReport:
"""Run every collector; one that fails sends its section as null."""
sections: dict[str, Any] = {}
for name, collect in COLLECTORS.items():
try:
sections[name] = collect(ctx)
except Exception:
# a collector bug must cost one section, never the whole report
logger.warning("Analytics %s section failed", name, exc_info=True)
sections[name] = None
return AnalyticsReport.model_validate(
{
"schema_version": SCHEMA_VERSION,
"install_id": install_id,
"report_id": str(uuid4()),
"sent_at": int(time.time()) if sent_at is None else sent_at,
**sections,
}
)
def gather_context(
config: FrigateConfig,
stats_emitter: "StatsEmitter | None",
notice_registry: "NoticeRegistry | None",
) -> ReportContext:
return ReportContext(
config=config,
stats=stats_emitter.get_latest_stats() if stats_emitter is not None else {},
notice_stats=notice_registry.stats() if notice_registry is not None else [],
)
def preview_report(
config: FrigateConfig,
stats_emitter: "StatsEmitter | None",
notice_registry: "NoticeRegistry | None",
) -> AnalyticsReport:
"""The report the next send would carry, without sending it."""
state = load_state()
ctx = gather_context(config, stats_emitter, notice_registry)
return build_report(ctx, state.install_id if state else PREVIEW_INSTALL_ID)
+177
View File
@@ -0,0 +1,177 @@
"""Send one analytics report a day while the admin has opted in."""
import logging
import random
import threading
import time
from collections.abc import Callable
from multiprocessing.synchronize import Event as MpEvent
from typing import TYPE_CHECKING
from frigate.analytics.context import ReportContext
from frigate.analytics.report import build_report
from frigate.analytics.state import (
STATE_PATH,
AnalyticsState,
delete_state,
load_state,
new_state,
save_state,
)
from frigate.analytics.transport import SendOutcome, send_report
from frigate.config import FrigateConfig
from frigate.config.holder import ConfigHolder
from frigate.const import ANALYTICS_URL
from frigate.notices import raise_notice, resolve_notice
if TYPE_CHECKING:
from frigate.notices.registry import NoticeRegistry
from frigate.stats.emitter import StatsEmitter
logger = logging.getLogger(__name__)
WAKE_S = 10 * 60
INTERVAL_S = 24 * 60 * 60
JITTER_S = 60 * 60
FIRST_DELAY_S = (15 * 60, 45 * 60)
PROMPT_KIND = "analytics_prompt"
class AnalyticsReporter(threading.Thread):
"""Follows the live config, so a settings save needs no restart."""
def __init__(
self,
config_holder: ConfigHolder,
stats_emitter: "StatsEmitter",
notice_registry: "NoticeRegistry",
stop_event: MpEvent | threading.Event,
*,
state_path: str = STATE_PATH,
url: str = ANALYTICS_URL,
send: Callable[[str, str], SendOutcome] = send_report,
clock: Callable[[], float] = time.time,
rng: random.Random | None = None,
) -> None:
super().__init__(name="analytics_reporter", daemon=True)
self.config_holder = config_holder
self.stats_emitter = stats_emitter
self.notice_registry = notice_registry
self.stop_event = stop_event
self.state_path = state_path
self.url = url
self.send = send
self.clock = clock
self.rng = rng or random.Random()
self.first_due = clock() + self.rng.uniform(*FIRST_DELAY_S)
self.interval = self._next_interval()
self.opted_in: bool | None = None
self.warned_unwritable = False
# a settings save runs on an API thread while a wake may be mid-attempt
self._lock = threading.Lock()
config_holder.subscribe(self._on_config)
def _next_interval(self) -> float:
return INTERVAL_S + self.rng.uniform(-JITTER_S, JITTER_S)
def run(self) -> None:
while True:
try:
self.tick()
except Exception:
logger.exception("Analytics reporter failed")
if self.stop_event.wait(WAKE_S):
break
def _on_config(self, config: FrigateConfig) -> None:
# a save can turn sharing off and back on between two wakes, so an
# opt-out is handled when it's saved rather than at the next wake
with self._lock:
if not config.safe_mode:
self._apply_consent(config.telemetry.analytics)
def _apply_consent(self, opted_in: bool) -> None:
# called with the lock held
if opted_in == self.opted_in:
return
self.opted_in = opted_in
if opted_in:
resolve_notice(PROMPT_KIND)
else:
raise_notice(PROMPT_KIND)
delete_state(self.state_path)
def tick(self) -> None:
with self._lock:
config = self.config_holder.config
# safe mode parses a default config where analytics reads as off,
# and handling that as an opt-out would delete the install ID
if config.safe_mode:
return
self._apply_consent(config.telemetry.analytics)
if not config.telemetry.analytics:
return
now = self.clock()
if now < self.first_due:
return
state = load_state(self.state_path) or new_state()
if not self._due(state.last_attempt_at, now):
return
# saved before sending, so a failing endpoint or a crash mid-send
# still waits a full interval; without saved state every boot would
# send under a new install ID
if not save_state(AnalyticsState(state.install_id, now), self.state_path):
if not self.warned_unwritable:
logger.warning(
"Analytics is on, but %s isn't writable, so no report is sent",
self.state_path,
)
self.warned_unwritable = True
return
self.interval = self._next_interval()
# the lock stays free during the request, so a save never waits on it
self._send(state.install_id, now)
def _due(self, last_attempt_at: float, now: float) -> bool:
# a last attempt stamped in the future came from a wrong clock
return (
now >= last_attempt_at + self.interval or last_attempt_at > now + INTERVAL_S
)
def _send(self, install_id: str, now: float) -> None:
notice_stats = self.notice_registry.stats()
ctx = ReportContext(
config=self.config_holder.config,
stats=self.stats_emitter.get_latest_stats(),
notice_stats=notice_stats,
)
report = build_report(ctx, install_id, sent_at=int(now))
body = report.model_dump_json()
# consent can be withdrawn while the report builds
if not self.config_holder.config.telemetry.analytics:
return
if self.send(self.url, body) is not SendOutcome.accepted:
return
# a failed health section sent no notice counts, so they stay pending
if report.health is not None:
self.notice_registry.mark_reported(notice_stats)
logger.info("Sent the daily analytics report")
logger.debug("Analytics report: %s", body)
+407
View File
@@ -0,0 +1,407 @@
"""Models for the analytics report, the contract with the ingest endpoint.
Every field carries a description and an x-public flag, and no field accepts
user-entered text, so a report can't carry camera names or other free text.
"""
from enum import StrEnum
from typing import Any
from pydantic import BaseModel, ConfigDict, Field
from frigate.config.camera.birdseye import BirdseyeModeEnum
from frigate.config.camera.camera import CameraTypeEnum
from frigate.config.camera.genai import GenAIProviderEnum, GenAIRoleEnum
from frigate.config.classification import ModelSizeEnum
from frigate.detectors.detector_config import ModelTypeEnum, SceneEnum
from frigate.detectors.detector_types import DetectorTypeEnum
from frigate.ffmpeg_presets import PRESETS_HW_ACCEL_DECODE, PRESETS_INPUT
from frigate.notices.types import NOTICE_KINDS
SCHEMA_VERSION = 1
class ImageVariant(StrEnum):
standard = "standard"
rpi = "rpi"
tensorrt = "tensorrt"
tensorrt_jp6 = "tensorrt-jp6"
rocm = "rocm"
rk = "rk"
synaptics = "synaptics"
dev = "dev"
other = "other"
class InstallType(StrEnum):
ha_addon = "ha_addon"
docker = "docker"
podman = "podman"
kubernetes = "kubernetes"
unknown = "unknown"
class Arch(StrEnum):
x86_64 = "x86_64"
aarch64 = "aarch64"
other = "other"
class GpuVendor(StrEnum):
intel = "intel"
amd = "amd"
nvidia = "nvidia"
rockchip = "rockchip"
rpi = "rpi"
other = "other"
class DecodeFamily(StrEnum):
nvidia = "nvidia"
vaapi = "vaapi"
rkmpp = "rkmpp"
intel_qsv = "intel-qsv"
jetson = "jetson"
rpi = "rpi"
other = "other"
class HardwareKey(StrEnum):
edgetpu_pci = "edgetpu:pci"
edgetpu_usb = "edgetpu:usb"
openvino_gpu = "openvino:GPU"
openvino_npu = "openvino:NPU"
onnx_amd = "onnx:amd"
onnx_nvidia = "onnx:nvidia"
tensorrt = "tensorrt"
hailo = "hailo"
memryx = "memryx"
deepx = "deepx"
rknn = "rknn"
axengine = "axengine"
synaptics = "synaptics"
cpu = "cpu"
other = "other"
class ModelSource(StrEnum):
default = "default"
plus = "plus"
custom = "custom"
class HeightBucket(StrEnum):
le_360 = "le_360"
h480 = "480"
h720 = "720"
h1080 = "1080"
h1440 = "1440"
ge_2160 = "ge_2160"
class FpsBucket(StrEnum):
le_5 = "le_5"
f6_10 = "6_10"
gt_10 = "gt_10"
class RetainBucket(StrEnum):
zero = "0"
d1_7 = "1_7"
d8_30 = "8_30"
gt_30 = "gt_30"
class ConnectionQuality(StrEnum):
excellent = "excellent"
fair = "fair"
poor = "poor"
unusable = "unusable"
class EnrichmentDevice(StrEnum):
cpu = "cpu"
cuda = "cuda"
tensorrt = "tensorrt"
migraphx = "migraphx"
openvino_cpu = "openvino_cpu"
openvino_gpu = "openvino_gpu"
openvino_npu = "openvino_npu"
other = "other"
class SemanticSearchModel(StrEnum):
jinav1 = "jinav1"
jinav2 = "jinav2"
genai = "genai"
class TranscriptionModel(StrEnum):
whisper = "whisper"
genai = "genai"
class UserRole(StrEnum):
admin = "admin"
viewer = "viewer"
custom = "custom"
class EnrichmentTiming(StrEnum):
face = "face"
lpr = "lpr"
plate_detection = "plate_detection"
image_embedding = "image_embedding"
text_embedding = "text_embedding"
review_description = "review_description"
object_description = "object_description"
def _preset_keys(presets: dict[str, Any]) -> dict[str, str]:
keys = [name.removeprefix("preset-") for name in presets]
return {key: key for key in [*keys, "custom", "none"]}
# built from the registries they mirror, so a new preset or notice kind reaches
# the schema through generate_analytics_schema.py instead of a hand edit
HwaccelKey = StrEnum("HwaccelKey", _preset_keys(PRESETS_HW_ACCEL_DECODE)) # type: ignore[misc]
InputPresetKey = StrEnum("InputPresetKey", _preset_keys(PRESETS_INPUT)) # type: ignore[misc]
NoticeKindKey = StrEnum( # type: ignore[misc]
"NoticeKindKey",
{key: key for key, kind in NOTICE_KINDS.items() if kind.reportable},
)
class AnalyticsModel(BaseModel):
model_config = ConfigDict(extra="forbid")
def metric(description: str, *, public: bool = True, **kwargs: Any) -> Any:
"""Declare a report field; the description and flag land in the schema."""
return Field(
description=description, json_schema_extra={"x-public": public}, **kwargs
)
def count(description: str) -> Any:
return metric(description, ge=0)
class InstallSection(AnalyticsModel):
version: str = metric("Frigate version string", max_length=32)
image_variant: ImageVariant = metric("Published image the install runs")
install_type: InstallType = metric("How Frigate is installed")
arch: Arch = metric("CPU architecture")
kernel: str = metric(
"Host kernel as major.minor", pattern=r"^(\d{1,3}\.\d{1,3}|unknown)$"
)
run_as_root: bool = metric("Whether the main process runs as root")
class GpuInfo(AnalyticsModel):
vendor: GpuVendor = metric("GPU vendor")
name: str = metric("GPU name as the hardware reports it", max_length=64)
class StorageInfo(AnalyticsModel):
record_fs: str = metric("Filesystem of the recordings volume", max_length=16)
record_total_gb: int = count("Size of the recordings volume in GB")
record_used_pct: int = metric(
"Percent of the recordings volume in use", ge=0, le=100
)
class HardwareSection(AnalyticsModel):
cpu_model: str = metric(
"CPU or board model as the hardware reports it", max_length=64
)
cpu_cores: int = count("Logical CPU count")
memory_gb: int = count("Total memory in GB")
gpus: list[GpuInfo] = metric("GPUs the stats collector found")
decode_families: list[DecodeFamily] = metric(
"Hardware decode families this system can use"
)
detection_hardware: dict[HardwareKey, int] = metric(
"Detection hardware found, as unit counts by kind"
)
storage: StorageInfo = metric("Recordings storage")
class DetectionModel(AnalyticsModel):
detector: DetectorTypeEnum = metric("Detector type the model runs on")
devices: int = count("Devices the model runs on")
model_type: ModelTypeEnum = metric("Model architecture")
input: str = metric("Model input size as WxH", pattern=r"^\d{1,5}x\d{1,5}$")
source: ModelSource = metric("Where the model came from", public=False)
inference_ms: float | None = metric(
"Mean inference time across the model's detector processes, null before the first stats",
ge=0,
)
class DetectionSection(AnalyticsModel):
models: dict[SceneEnum, DetectionModel] = metric("Detection models keyed by scene")
detection_fps: float = metric("Detections per second across cameras", ge=0)
skipped_fps: float = metric("Frames per second skipped across cameras", ge=0)
class RetainDays(AnalyticsModel):
continuous: dict[RetainBucket, int] = metric(
"Recording cameras by continuous retention in days"
)
motion: dict[RetainBucket, int] = metric(
"Recording cameras by motion retention in days"
)
alerts: dict[RetainBucket, int] = metric(
"Recording cameras by alert retention in days"
)
detections: dict[RetainBucket, int] = metric(
"Recording cameras by detection retention in days"
)
class CamerasSection(AnalyticsModel):
total: int = count("Configured cameras")
enabled: int = count("Enabled cameras")
types: dict[CameraTypeEnum, int] = metric("Cameras by type")
detect_height: dict[HeightBucket, int] = metric(
"Cameras by detect resolution height"
)
detect_fps: dict[FpsBucket, int] = metric("Cameras by detect fps")
hwaccel: dict[HwaccelKey, int] = metric(
"Cameras by the resolved hwaccel preset of the detect input"
)
input_preset: dict[InputPresetKey, int] = metric(
"Cameras by the input preset of the detect input"
)
go2rtc_restream: int = count("Cameras with an input from the go2rtc restream")
separate_detect_stream: int = count(
"Cameras whose detect input differs from their record input"
)
detect: int = count("Cameras with detection on")
record: int = count("Cameras with recording on")
sub_stream_record: int = count("Cameras with sub stream recording on")
snapshots: int = count("Cameras with snapshots on")
audio: int = count("Cameras with audio detection on")
audio_transcription: int = count("Cameras with audio transcription on")
birdseye: int = count("Cameras in birdseye")
onvif: int = count("Cameras with an ONVIF host")
autotracking: int = count("Cameras with PTZ autotracking on")
face_recognition: int = count("Cameras with face recognition on")
lpr: int = count("Cameras with license plate recognition on")
review_genai: int = count("Cameras with GenAI review summaries on")
object_genai: int = count("Cameras with GenAI object descriptions on")
notifications: int = count("Cameras with notifications on")
zones: int = count("Zones across cameras")
cameras_with_zones: int = count("Cameras with at least one zone")
motion_masks: int = count("Motion masks across cameras")
object_masks: int = count("Object masks across cameras")
connection_quality: dict[ConnectionQuality, int] = metric(
"Cameras by connection quality at send time"
)
retain_days: RetainDays = metric("Recording retention")
class EnrichmentUsage(AnalyticsModel):
enabled: bool = metric("Whether the enrichment is on")
model_size: ModelSizeEnum = metric("Configured model size")
device: EnrichmentDevice | None = metric(
"Device the model loaded on, null when it isn't loaded"
)
class SemanticSearchUsage(AnalyticsModel):
enabled: bool = metric("Whether semantic search is on")
model: SemanticSearchModel | None = metric(
"Embedding model, genai for a GenAI provider"
)
model_size: ModelSizeEnum = metric("Configured model size")
device: EnrichmentDevice | None = metric(
"Device the model loaded on, null when it isn't loaded"
)
triggers: int = count("Semantic search triggers across cameras")
class TranscriptionUsage(AnalyticsModel):
enabled: bool = metric("Whether audio transcription is on")
model: TranscriptionModel | None = metric(
"Transcription model, genai for a GenAI provider"
)
model_size: ModelSizeEnum = metric("Configured model size")
class GenAIUsage(AnalyticsModel):
providers: dict[GenAIProviderEnum, int] = metric(
"Configured GenAI providers by type"
)
roles: dict[GenAIRoleEnum, int] = metric("Configured GenAI providers by role")
class ClassificationUsage(AnalyticsModel):
state: int = count("Custom state classification models")
object: int = count("Custom object classification models")
class BirdseyeUsage(AnalyticsModel):
enabled: bool = metric("Whether birdseye is on")
modes: list[BirdseyeModeEnum] = metric("Birdseye modes")
restream: bool = metric("Whether birdseye is restreamed")
class FeaturesSection(AnalyticsModel):
face_recognition: EnrichmentUsage = metric("Face recognition")
lpr: EnrichmentUsage = metric("License plate recognition")
semantic_search: SemanticSearchUsage = metric("Semantic search")
audio_transcription: TranscriptionUsage = metric("Audio transcription")
genai: GenAIUsage = metric("Generative AI providers")
classification_models: ClassificationUsage = metric("Custom classification models")
birdseye: BirdseyeUsage = metric("Birdseye")
mqtt: bool = metric("Whether MQTT is on")
notifications: bool = metric("Whether web push notifications are on")
auth: bool = metric("Whether authentication is on")
proxy_auth: bool = metric("Whether a proxy supplies the user header")
tls: bool = metric("Whether TLS is on")
users: dict[UserRole, int] = metric("Users by role")
camera_groups: int = count("Camera groups")
profiles: int = count("Profiles")
plus_api_key: bool = metric("Whether a Frigate+ API key is set", public=False)
class NoticeCounts(AnalyticsModel):
occurrences: int = count("Occurrences since the last accepted report")
dismissals: int = count("Dismissals since the last accepted report")
class HealthSection(AnalyticsModel):
uptime_hours: int = count("Hours since Frigate started")
cpu_percent: int = metric("System CPU use at send time", ge=0, le=100)
enrichment_ms: dict[EnrichmentTiming, float] = metric(
"Mean enrichment inference times in milliseconds"
)
retention_unmet: bool = metric(
"Whether storage can't keep the configured retention"
)
notices: dict[NoticeKindKey, NoticeCounts] = metric(
"Notice counts by kind since the last accepted report", public=False
)
class AnalyticsReport(AnalyticsModel):
schema_version: int = metric("Report format version", ge=1)
install_id: str = metric(
"Random install identifier", public=False, pattern=r"^[0-9a-f]{32}$"
)
report_id: str = metric(
"Random identifier of this report",
public=False,
pattern=r"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
)
sent_at: int = count("Unix time the report was built")
install: InstallSection | None = metric("Install, null if its collector failed")
hardware: HardwareSection | None = metric("Hardware, null if its collector failed")
detection: DetectionSection | None = metric(
"Object detection, null if its collector failed"
)
cameras: CamerasSection | None = metric("Cameras, null if its collector failed")
features: FeaturesSection | None = metric("Features, null if its collector failed")
health: HealthSection | None = metric("Health, null if its collector failed")
+85
View File
@@ -0,0 +1,85 @@
"""The install's analytics identity and last attempt time, kept under /config."""
import json
import logging
import os
import re
from dataclasses import dataclass
from uuid import uuid4
from frigate.const import CONFIG_DIR
logger = logging.getLogger(__name__)
STATE_PATH = os.path.join(CONFIG_DIR, ".analytics.json")
INSTALL_ID_PATTERN = re.compile(r"[0-9a-f]{32}")
@dataclass(frozen=True)
class AnalyticsState:
install_id: str
last_attempt_at: float
def new_state() -> AnalyticsState:
return AnalyticsState(install_id=uuid4().hex, last_attempt_at=0.0)
def load_state(path: str = STATE_PATH) -> AnalyticsState | None:
"""The saved state, or None when the file is missing or unusable."""
try:
with open(path) as f:
data = json.load(f)
except FileNotFoundError:
return None
except (OSError, ValueError):
logger.warning("Ignoring unreadable analytics state at %s", path)
return None
if not isinstance(data, dict):
return None
install_id = data.get("install_id")
last_attempt_at = data.get("last_attempt_at")
if (
not isinstance(install_id, str)
or not INSTALL_ID_PATTERN.fullmatch(install_id)
or isinstance(last_attempt_at, bool)
or not isinstance(last_attempt_at, int | float)
):
logger.warning("Ignoring invalid analytics state at %s", path)
return None
return AnalyticsState(install_id=install_id, last_attempt_at=float(last_attempt_at))
def save_state(state: AnalyticsState, path: str = STATE_PATH) -> bool:
"""Write the state atomically, returning False when it can't be written."""
temp_path = f"{path}.tmp"
try:
with open(temp_path, "w") as f:
json.dump(
{
"install_id": state.install_id,
"last_attempt_at": state.last_attempt_at,
},
f,
)
os.replace(temp_path, path)
except OSError:
return False
return True
def delete_state(path: str = STATE_PATH) -> None:
"""Forget the install ID, so a later opt-in starts a fresh identity."""
try:
os.remove(path)
except FileNotFoundError:
pass
except OSError:
logger.warning("Unable to delete analytics state at %s", path)
+54
View File
@@ -0,0 +1,54 @@
"""POST a report to the ingest endpoint."""
import logging
from enum import Enum
import requests
from frigate.version import VERSION
logger = logging.getLogger(__name__)
TIMEOUT_S = 30
class SendOutcome(Enum):
accepted = "accepted"
rejected = "rejected"
rate_limited = "rate_limited"
failed = "failed"
def send_report(url: str, body: str) -> SendOutcome:
"""Send one report. Never raises; the outcome says what happened."""
try:
# a redirect would turn the POST into a GET, so it counts as a failure
response = requests.post(
url,
data=body.encode(),
headers={
"Content-Type": "application/json",
"User-Agent": f"Frigate/{VERSION}",
},
timeout=TIMEOUT_S,
allow_redirects=False,
)
except requests.RequestException as err:
logger.warning("Unable to send the analytics report: %s", err)
return SendOutcome.failed
status = response.status_code
if 200 <= status < 300:
return SendOutcome.accepted
if status == 400:
logger.warning("The analytics report was rejected: %s", response.text[:200])
return SendOutcome.rejected
if status == 429:
logger.debug("The analytics endpoint is rate limiting this install")
return SendOutcome.rate_limited
logger.warning("The analytics endpoint returned %s", status)
return SendOutcome.failed
+25
View File
@@ -0,0 +1,25 @@
"""Analytics APIs."""
import logging
from fastapi import APIRouter, Depends, Request
from fastapi.responses import JSONResponse
from frigate.analytics.report import preview_report
from frigate.api.auth import require_role
from frigate.api.defs.tags import Tags
logger = logging.getLogger(__name__)
router = APIRouter(tags=[Tags.analytics])
@router.get("/analytics/preview", dependencies=[Depends(require_role(["admin"]))])
def get_analytics_preview(request: Request) -> JSONResponse:
"""Get the analytics report Frigate would send next, without sending it."""
report = preview_report(
request.app.frigate_config,
request.app.stats_emitter,
request.app.notice_registry,
)
return JSONResponse(content=report.model_dump(mode="json"))
+2 -9
View File
@@ -2,7 +2,6 @@
import asyncio import asyncio
import copy import copy
import json
import logging import logging
import os import os
import platform import platform
@@ -11,7 +10,6 @@ import urllib
from datetime import datetime, timedelta from datetime import datetime, timedelta
from functools import reduce from functools import reduce
from io import StringIO from io import StringIO
from pathlib import Path as FilePath
from typing import Any from typing import Any
import aiofiles import aiofiles
@@ -56,6 +54,7 @@ from frigate.jobs.media_sync import (
start_media_sync_job, start_media_sync_job,
) )
from frigate.models import Event, Timeline from frigate.models import Event, Timeline
from frigate.plus import load_plus_model_info
from frigate.stats.prometheus import get_metrics, update_metrics from frigate.stats.prometheus import get_metrics, update_metrics
from frigate.types import JobStatusTypesEnum from frigate.types import JobStatusTypesEnum
from frigate.util.builtin import ( from frigate.util.builtin import (
@@ -401,13 +400,7 @@ def config(request: Request):
model_dict["plus"] = None model_dict["plus"] = None
if model.path: if model.path:
model_json_path = FilePath(model.path).with_suffix(".json") model_dict["plus"] = load_plus_model_info(os.path.basename(model.path))
try:
with open(model_json_path) as f:
model_dict["plus"] = json.load(f)
except (FileNotFoundError, json.JSONDecodeError):
pass
return JSONResponse(content=config) return JSONResponse(content=config)
+63
View File
@@ -8,6 +8,7 @@ import logging
import os import os
import re import re
import secrets import secrets
import threading
import time import time
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
@@ -34,6 +35,7 @@ from frigate.api.media_auth import (
from frigate.config import AuthConfig, ProxyConfig from frigate.config import AuthConfig, ProxyConfig
from frigate.const import CONFIG_DIR, JWT_SECRET_ENV_VAR, PASSWORD_HASH_ALGORITHM from frigate.const import CONFIG_DIR, JWT_SECRET_ENV_VAR, PASSWORD_HASH_ALGORITHM
from frigate.models import User from frigate.models import User
from frigate.notices import raise_notice
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -253,6 +255,58 @@ class RateLimiter:
rateLimiter = RateLimiter() rateLimiter = RateLimiter()
# a failed login this long after the user's previous one opens a new burst
FAILED_LOGIN_BURST_GAP_S = 300
# the username comes from the request, so it is cut before it reaches a notice
MAX_NOTICE_USERNAME = 64
# unknown usernames are unbounded, so past this many open bursts a new one only
# reaches the log
MAX_OPEN_BURSTS = 100
class FailedLoginTracker:
"""Groups each user's failed logins into bursts, one notice per burst."""
def __init__(self) -> None:
self._lock = threading.Lock()
# user -> (burst start, last attempt), stalest attempt first
self._bursts: dict[str, tuple[int, float]] = {}
def record(self, user: str, now: float, *, known: bool = False) -> None:
"""Count a failed login toward the user's open burst, or open a new one.
Once MAX_OPEN_BURSTS are open, only a known user opens another.
"""
user = user[:MAX_NOTICE_USERNAME]
with self._lock:
# bursts that went quiet are over
while self._bursts:
stalest = next(iter(self._bursts))
if now - self._bursts[stalest][1] < FAILED_LOGIN_BURST_GAP_S:
break
del self._bursts[stalest]
if (
not known
and user not in self._bursts
and len(self._bursts) >= MAX_OPEN_BURSTS
):
return
start, _ = self._bursts.pop(user, (int(now), now))
self._bursts[user] = (start, now)
raise_notice("failed_login", scope=f"{user}:{start}", params={"user": user})
failed_logins = FailedLoginTracker()
def get_remote_addr(request: Request): def get_remote_addr(request: Request):
# fall back to the direct TCP peer when no proxy chain is present # fall back to the direct TCP peer when no proxy chain is present
@@ -732,6 +786,13 @@ def auth(request: Request):
user = token.claims.get("sub") user = token.claims.get("sub")
role = token.claims.get("role") role = token.claims.get("role")
# the token keeps the role it was issued with, so a role removed from
# the config since then must send the user back through login
if role not in auth_config.roles:
logger.debug("jwt role %s is not in the config", role)
return fail_response
current_time = int(time.time()) current_time = int(time.time())
# if the jwt is expired # if the jwt is expired
@@ -880,6 +941,7 @@ def login(request: Request, body: AppPostLoginBody):
db_user: User = User.get_by_id(user) db_user: User = User.get_by_id(user)
except DoesNotExist: except DoesNotExist:
logger.warning(f"Login failed for unknown user '{user}' from {remote_addr}") logger.warning(f"Login failed for unknown user '{user}' from {remote_addr}")
failed_logins.record(user, time.time())
return JSONResponse(content={"message": "Login failed"}, status_code=401) return JSONResponse(content={"message": "Login failed"}, status_code=401)
password_hash = db_user.password_hash password_hash = db_user.password_hash
@@ -911,6 +973,7 @@ def login(request: Request, body: AppPostLoginBody):
logger.warning( logger.warning(
f"Login failed for user '{user}' (invalid password) from {remote_addr}" f"Login failed for user '{user}' (invalid password) from {remote_addr}"
) )
failed_logins.record(user, time.time(), known=True)
return JSONResponse(content={"message": "Login failed"}, status_code=401) return JSONResponse(content={"message": "Login failed"}, status_code=401)
+1
View File
@@ -2,6 +2,7 @@ from enum import Enum
class Tags(Enum): class Tags(Enum):
analytics = "Analytics"
app = "App" app = "App"
auth = "Auth" auth = "Auth"
camera = "Camera" camera = "Camera"
+16 -5
View File
@@ -71,6 +71,7 @@ from frigate.jobs.export import (
from frigate.models import Export, ExportCase, Previews, Recordings from frigate.models import Export, ExportCase, Previews, Recordings
from frigate.record.export import ( from frigate.record.export import (
DEFAULT_TIME_LAPSE_FFMPEG_ARGS, DEFAULT_TIME_LAPSE_FFMPEG_ARGS,
DEFAULT_TIME_LAPSE_FFMPEG_INPUT_ARGS,
ChaptersEnum, ChaptersEnum,
ExportStreamEnum, ExportStreamEnum,
PlaybackSourceEnum, PlaybackSourceEnum,
@@ -1037,6 +1038,10 @@ def export_recording_custom(
if camera_validation_error is not None: if camera_validation_error is not None:
return camera_validation_error return camera_validation_error
# Validate user-provided ffmpeg args to prevent injection and add to cases.
# Admin users are trusted and skip validation.
is_admin = request.headers.get("remote-role", "") == "admin"
playback_source = body.source playback_source = body.source
friendly_name = body.name friendly_name = body.name
existing_image, image_validation_error = _sanitize_existing_image(body.image_path) existing_image, image_validation_error = _sanitize_existing_image(body.image_path)
@@ -1047,6 +1052,16 @@ def export_recording_custom(
cpu_fallback = body.cpu_fallback cpu_fallback = body.cpu_fallback
export_case_id = body.export_case_id export_case_id = body.export_case_id
if export_case_id is not None and not is_admin:
return JSONResponse(
content={
"success": False,
"message": "Only admins can attach exports to an existing case.",
},
status_code=403,
)
case_validation_error = _validate_export_case(export_case_id) case_validation_error = _validate_export_case(export_case_id)
if case_validation_error is not None: if case_validation_error is not None:
return case_validation_error return case_validation_error
@@ -1063,10 +1078,6 @@ def export_recording_custom(
status_code=400, status_code=400,
) )
# Validate user-provided ffmpeg args to prevent injection.
# Admin users are trusted and skip validation.
is_admin = request.headers.get("remote-role", "") == "admin"
if not is_admin: if not is_admin:
for args_label, args_value in [ for args_label, args_value in [
("input", ffmpeg_input_args), ("input", ffmpeg_input_args),
@@ -1087,7 +1098,7 @@ def export_recording_custom(
# Set default values if not provided (timelapse defaults) # Set default values if not provided (timelapse defaults)
if ffmpeg_input_args is None: if ffmpeg_input_args is None:
ffmpeg_input_args = "" ffmpeg_input_args = DEFAULT_TIME_LAPSE_FFMPEG_INPUT_ARGS
if ffmpeg_output_args is None: if ffmpeg_output_args is None:
ffmpeg_output_args = DEFAULT_TIME_LAPSE_FFMPEG_ARGS ffmpeg_output_args = DEFAULT_TIME_LAPSE_FFMPEG_ARGS
+3 -1
View File
@@ -12,8 +12,8 @@ from slowapi.middleware import SlowAPIMiddleware
from starlette_context import middleware, plugins from starlette_context import middleware, plugins
from starlette_context.plugins import Plugin from starlette_context.plugins import Plugin
from frigate.api import app as main_app
from frigate.api import ( from frigate.api import (
analytics,
auth, auth,
camera, camera,
chat, chat,
@@ -30,6 +30,7 @@ from frigate.api import (
record, record,
review, review,
) )
from frigate.api import app as main_app
from frigate.api.auth import get_jwt_secret, limiter, require_admin_by_default from frigate.api.auth import get_jwt_secret, limiter, require_admin_by_default
from frigate.comms.dispatcher import Dispatcher from frigate.comms.dispatcher import Dispatcher
from frigate.comms.event_metadata_updater import ( from frigate.comms.event_metadata_updater import (
@@ -140,6 +141,7 @@ def create_fastapi_app(
# Routes # Routes
# Order of include_router matters: https://fastapi.tiangolo.com/tutorial/path-params/#order-matters # Order of include_router matters: https://fastapi.tiangolo.com/tutorial/path-params/#order-matters
app.include_router(analytics.router)
app.include_router(auth.router) app.include_router(auth.router)
app.include_router(camera.router) app.include_router(camera.router)
app.include_router(chat.router) app.include_router(chat.router)
+83 -62
View File
@@ -189,7 +189,7 @@ async def camera_ptz_info(request: Request, camera_name: str):
future = asyncio.run_coroutine_threadsafe( future = asyncio.run_coroutine_threadsafe(
request.app.onvif.get_camera_info(camera_name), request.app.onvif.loop request.app.onvif.get_camera_info(camera_name), request.app.onvif.loop
) )
result = future.result() result = await asyncio.wrap_future(future)
return JSONResponse(content=result) return JSONResponse(content=result)
else: else:
return JSONResponse( return JSONResponse(
@@ -258,15 +258,15 @@ async def latest_frame(
frame = request.app.camera_error_image frame = request.app.camera_error_image
height = int(params.height or str(frame.shape[0]))
width = int(height * frame.shape[1] / frame.shape[0])
if frame is None: if frame is None:
return JSONResponse( return JSONResponse(
content={"success": False, "message": "Unable to get valid frame"}, content={"success": False, "message": "Unable to get valid frame"},
status_code=500, status_code=500,
) )
height = int(params.height or str(frame.shape[0]))
width = int(height * frame.shape[1] / frame.shape[0])
if height < 1 or width < 1: if height < 1 or width < 1:
return JSONResponse( return JSONResponse(
content="Invalid height / width requested :: {} / {}".format( content="Invalid height / width requested :: {} / {}".format(
@@ -886,9 +886,8 @@ async def vod_event(
# If the recordings are not found and the event started more than 5 minutes ago, set has_clip to false # If the recordings are not found and the event started more than 5 minutes ago, set has_clip to false
if ( if (
event.start_time < datetime.now().timestamp() - 300 event.start_time < datetime.now().timestamp() - 300
and type(vod_response) is tuple and isinstance(vod_response, JSONResponse)
and len(vod_response) == 2 and vod_response.status_code == 404
and vod_response[1] == 404
): ):
Event.update(has_clip=False).where(Event.id == event_id).execute() Event.update(has_clip=False).where(Event.id == event_id).execute()
@@ -956,64 +955,80 @@ async def event_snapshot(
event_complete = False event_complete = False
jpg_bytes = None jpg_bytes = None
frame_time = 0 frame_time = 0
try: try:
event = Event.get(Event.id == event_id, Event.end_time != None) event = Event.get(Event.id == event_id, Event.end_time != None)
event_complete = True
await require_camera_access(event.camera, request=request) await require_camera_access(event.camera, request=request)
except DoesNotExist:
event = None
if event is not None:
event_complete = True
if not event.has_snapshot: if not event.has_snapshot:
return JSONResponse( return JSONResponse(
content={"success": False, "message": "Snapshot not available"}, content={"success": False, "message": "Snapshot not available"},
status_code=404, status_code=404,
) )
snapshot_settings = _resolve_snapshot_settings(
request.app.frigate_config.cameras[event.camera].snapshots, params
)
jpg_bytes, frame_time = get_event_snapshot_bytes(
event,
ext="jpg",
timestamp=snapshot_settings["timestamp"],
bounding_box=snapshot_settings["bounding_box"],
crop=snapshot_settings["crop"],
height=snapshot_settings["height"],
quality=snapshot_settings["quality"],
timestamp_style=request.app.frigate_config.cameras[
event.camera
].timestamp_style,
colormap=request.app.frigate_config.model_for_camera(event.camera).colormap,
)
except DoesNotExist:
# see if the object is currently being tracked
try: try:
camera_states: list[CameraState] = ( snapshot_settings = _resolve_snapshot_settings(
request.app.detected_frames_processor.get_camera_states() request.app.frigate_config.cameras[event.camera].snapshots, params
)
jpg_bytes, frame_time = get_event_snapshot_bytes(
event,
ext="jpg",
timestamp=snapshot_settings["timestamp"],
bounding_box=snapshot_settings["bounding_box"],
crop=snapshot_settings["crop"],
height=snapshot_settings["height"],
quality=snapshot_settings["quality"],
timestamp_style=request.app.frigate_config.cameras[
event.camera
].timestamp_style,
colormap=request.app.frigate_config.model_for_camera(
event.camera
).colormap,
) )
for camera_state in camera_states:
if event_id in camera_state.tracked_objects:
tracked_obj = camera_state.tracked_objects.get(event_id)
if tracked_obj is not None:
snapshot_settings = _resolve_snapshot_settings(
camera_state.camera_config.snapshots, params
)
jpg_bytes, frame_time = tracked_obj.get_img_bytes(
ext="jpg",
timestamp=snapshot_settings["timestamp"],
bounding_box=snapshot_settings["bounding_box"],
crop=snapshot_settings["crop"],
height=snapshot_settings["height"],
quality=snapshot_settings["quality"],
)
await require_camera_access(camera_state.name, request=request)
except Exception: except Exception:
return JSONResponse( return JSONResponse(
content={"success": False, "message": "Ongoing event not found"}, content={"success": False, "message": "Unknown error occurred"},
status_code=404, status_code=404,
) )
except Exception: else:
return JSONResponse( # see if the object is currently being tracked
content={"success": False, "message": "Unknown error occurred"}, camera_states: list[CameraState] = (
status_code=404, request.app.detected_frames_processor.get_camera_states()
) )
for camera_state in camera_states:
tracked_obj = camera_state.tracked_objects.get(event_id)
if tracked_obj is None:
continue
await require_camera_access(camera_state.name, request=request)
try:
snapshot_settings = _resolve_snapshot_settings(
camera_state.camera_config.snapshots, params
)
jpg_bytes, frame_time = tracked_obj.get_img_bytes(
ext="jpg",
timestamp=snapshot_settings["timestamp"],
bounding_box=snapshot_settings["bounding_box"],
crop=snapshot_settings["crop"],
height=snapshot_settings["height"],
quality=snapshot_settings["quality"],
)
except Exception:
return JSONResponse(
content={"success": False, "message": "Ongoing event not found"},
status_code=404,
)
break
if jpg_bytes is None: if jpg_bytes is None:
return JSONResponse( return JSONResponse(
content={"success": False, "message": "Live frame not available"}, content={"success": False, "message": "Live frame not available"},
@@ -1062,19 +1077,25 @@ async def event_thumbnail(
if not thumbnail_bytes: if not thumbnail_bytes:
# see if the object is currently being tracked # see if the object is currently being tracked
try: camera_states = request.app.detected_frames_processor.get_camera_states()
camera_states = request.app.detected_frames_processor.get_camera_states()
for camera_state in camera_states: for camera_state in camera_states:
if event_id in camera_state.tracked_objects: tracked_obj = camera_state.tracked_objects.get(event_id)
tracked_obj = camera_state.tracked_objects.get(event_id)
if tracked_obj is not None: if tracked_obj is None:
await require_camera_access(camera_state.name, request=request) continue
thumbnail_bytes = tracked_obj.get_thumbnail(extension.value)
except Exception: await require_camera_access(camera_state.name, request=request)
return JSONResponse(
content={"success": False, "message": "Event not found"}, try:
status_code=404, thumbnail_bytes = tracked_obj.get_thumbnail(extension.value)
) except Exception:
return JSONResponse(
content={"success": False, "message": "Event not found"},
status_code=404,
)
break
if not thumbnail_bytes: if not thumbnail_bytes:
return JSONResponse( return JSONResponse(
+27 -17
View File
@@ -7,7 +7,6 @@ from fastapi.responses import JSONResponse
from frigate.api.auth import require_role from frigate.api.auth import require_role
from frigate.api.defs.tags import Tags from frigate.api.defs.tags import Tags
from frigate.notices.registry import DismissResult
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -16,13 +15,13 @@ router = APIRouter(tags=[Tags.notices])
@router.get("/notices", dependencies=[Depends(require_role(["admin"]))]) @router.get("/notices", dependencies=[Depends(require_role(["admin"]))])
def get_notices(request: Request, include_dismissed: bool = False) -> JSONResponse: def get_notices(request: Request, include_dismissed: bool = False) -> JSONResponse:
"""Get the active notices, most severe first. """Get notices, most severe first.
Args: Args:
include_dismissed: Also return event notices the user has dismissed include_dismissed: Also return dismissed notices, for the history view
Returns: Returns:
The active notices The notices
""" """
return JSONResponse( return JSONResponse(
content=request.app.notice_registry.active(include_dismissed=include_dismissed) content=request.app.notice_registry.active(include_dismissed=include_dismissed)
@@ -35,26 +34,37 @@ def get_notice_stats(request: Request) -> JSONResponse:
return JSONResponse(content=request.app.notice_registry.stats()) return JSONResponse(content=request.app.notice_registry.stats())
@router.get(
"/notices/dismissed_checks", dependencies=[Depends(require_role(["admin"]))]
)
def get_dismissed_checks(request: Request) -> JSONResponse:
"""Get the dismissed config and stream check rows, newest first."""
return JSONResponse(content=request.app.notice_registry.dismissed_checks())
@router.delete("/notices/dismissed", dependencies=[Depends(require_role(["admin"]))])
def purge_dismissed(request: Request) -> JSONResponse:
"""Delete every dismissed notice and check row so each can show again."""
request.app.notice_registry.purge_dismissed()
return JSONResponse(
content={"success": True, "message": "Dismissed notices cleared"}
)
# model notice ids contain a slash, so the id is a path parameter
@router.post( @router.post(
"/notices/{notice_id}/dismiss", dependencies=[Depends(require_role(["admin"]))] "/notices/{notice_id:path}/dismiss",
dependencies=[Depends(require_role(["admin"]))],
) )
def dismiss_notice(request: Request, notice_id: str) -> JSONResponse: def dismiss_notice(request: Request, notice_id: str) -> JSONResponse:
"""Hide an event notice until it is raised again.""" """Hide a notice or a config or stream check row.
result = request.app.notice_registry.dismiss(notice_id)
if result == DismissResult.not_found: It stays hidden if the same problem happens again.
"""
if not request.app.notice_registry.dismiss(notice_id):
return JSONResponse( return JSONResponse(
content={"success": False, "message": "Notice not found"}, content={"success": False, "message": "Notice not found"},
status_code=404, status_code=404,
) )
if result == DismissResult.not_dismissable:
return JSONResponse(
content={
"success": False,
"message": "This notice clears itself when the problem is fixed",
},
status_code=400,
)
return JSONResponse(content={"success": True, "message": "Notice dismissed"}) return JSONResponse(content={"success": True, "message": "Notice dismissed"})
+2 -5
View File
@@ -412,11 +412,8 @@ async def no_recordings(
if not camera_list: if not camera_list:
return JSONResponse(content=[]) return JSONResponse(content=[])
before = params.before or datetime.datetime.now().timestamp() before = params.before or datetime.now().timestamp()
after = ( after = params.after or (datetime.now() - timedelta(hours=1)).timestamp()
params.after
or (datetime.datetime.now() - datetime.timedelta(hours=1)).timestamp()
)
scale = params.scale scale = params.scale
recordings: list[tuple[float, float]] = [] recordings: list[tuple[float, float]] = []
+34 -13
View File
@@ -15,6 +15,7 @@ import uvicorn
from peewee_migrate import Router from peewee_migrate import Router
from playhouse.sqlite_ext import SqliteExtDatabase from playhouse.sqlite_ext import SqliteExtDatabase
from frigate.analytics.reporter import AnalyticsReporter
from frigate.api.auth import hash_password from frigate.api.auth import hash_password
from frigate.api.fastapi_app import create_fastapi_app from frigate.api.fastapi_app import create_fastapi_app
from frigate.camera import CameraMetrics, PTZMetrics from frigate.camera import CameraMetrics, PTZMetrics
@@ -73,6 +74,7 @@ from frigate.models import (
Trigger, Trigger,
User, User,
) )
from frigate.notices import install_registry
from frigate.notices.registry import NoticeRegistry from frigate.notices.registry import NoticeRegistry
from frigate.object_detection.base import ObjectDetectProcess from frigate.object_detection.base import ObjectDetectProcess
from frigate.object_detection.util import detection_frame_size from frigate.object_detection.util import detection_frame_size
@@ -310,10 +312,6 @@ class FrigateApp:
] ]
self.db.bind(models) self.db.bind(models)
self.notice_registry = NoticeRegistry()
# producers confirm state notices again at startup if they still hold
self.notice_registry.mark_state_notices_unconfirmed()
def check_db_data_migrations(self) -> None: def check_db_data_migrations(self) -> None:
# check if vacuum needs to be run # check if vacuum needs to be run
if not os.path.exists(f"{CONFIG_DIR}/.exports"): if not os.path.exists(f"{CONFIG_DIR}/.exports"):
@@ -325,6 +323,10 @@ class FrigateApp:
migrate_exports(self.config.ffmpeg, list(self.config.cameras.keys())) migrate_exports(self.config.ffmpeg, list(self.config.cameras.keys()))
def install_notice_registry(self) -> None:
self.notice_registry = NoticeRegistry()
install_registry(self.notice_registry)
def init_embeddings_client(self) -> None: def init_embeddings_client(self) -> None:
# Create a client for other processes to use # Create a client for other processes to use
self.embeddings = EmbeddingsContext(self.db) self.embeddings = EmbeddingsContext(self.db)
@@ -482,7 +484,7 @@ class FrigateApp:
def start_audio_processor(self) -> None: def start_audio_processor(self) -> None:
self.audio_process = AudioProcessor( self.audio_process = AudioProcessor(
self.config, self.camera_metrics, self.stop_event self.config, self.camera_metrics, self.embeddings_metrics, self.stop_event
) )
self.audio_process.start() self.audio_process.start()
self.processes["audio_detector"] = self.audio_process.pid or 0 self.processes["audio_detector"] = self.audio_process.pid or 0
@@ -510,9 +512,7 @@ class FrigateApp:
self.record_cleanup.start() self.record_cleanup.start()
def start_storage_maintainer(self) -> None: def start_storage_maintainer(self) -> None:
self.storage_maintainer = StorageMaintainer( self.storage_maintainer = StorageMaintainer(self.config, self.stop_event)
self.config, self.stop_event, self.notice_registry
)
self.storage_maintainer.start() self.storage_maintainer.start()
def start_stats_emitter(self) -> None: def start_stats_emitter(self) -> None:
@@ -524,16 +524,23 @@ class FrigateApp:
self.embeddings_metrics, self.embeddings_metrics,
self.detectors, self.detectors,
self.processes, self.processes,
self.storage_maintainer,
), ),
self.stop_event, self.stop_event,
notice_registry=self.notice_registry,
) )
self.stats_emitter.start() self.stats_emitter.start()
def start_watchdog(self) -> None: def start_analytics_reporter(self) -> None:
self.frigate_watchdog = FrigateWatchdog( self.analytics_reporter = AnalyticsReporter(
self.detectors, self.stop_event, self.notice_registry self.config_holder,
self.stats_emitter,
self.notice_registry,
self.stop_event,
) )
self.analytics_reporter.start()
def start_watchdog(self) -> None:
self.frigate_watchdog = FrigateWatchdog(self.detectors, self.stop_event)
# (attribute on self, key in self.processes, factory) # (attribute on self, key in self.processes, factory)
specs: list[tuple[str, str, Callable[[], FrigateProcess]]] = [ specs: list[tuple[str, str, Callable[[], FrigateProcess]]] = [
@@ -559,10 +566,20 @@ class FrigateApp:
"output", "output",
lambda: OutputProcess(self.config, self.stop_event), lambda: OutputProcess(self.config, self.stop_event),
), ),
(
"audio_process",
"audio_detector",
lambda: AudioProcessor(
self.config,
self.camera_metrics,
self.embeddings_metrics,
self.stop_event,
),
),
] ]
for attr, key, factory in specs: for attr, key, factory in specs:
if not hasattr(self, attr): if getattr(self, attr, None) is None:
continue continue
def on_restart( def on_restart(
@@ -644,6 +661,7 @@ class FrigateApp:
self.init_embeddings_manager() self.init_embeddings_manager()
self.bind_database() self.bind_database()
self.check_db_data_migrations() self.check_db_data_migrations()
self.install_notice_registry()
# Clean up any stale replay camera artifacts (filesystem + DB) # Clean up any stale replay camera artifacts (filesystem + DB)
cleanup_replay_cameras() cleanup_replay_cameras()
@@ -672,6 +690,7 @@ class FrigateApp:
self.start_audio_processor() self.start_audio_processor()
self.start_storage_maintainer() self.start_storage_maintainer()
self.start_stats_emitter() self.start_stats_emitter()
self.start_analytics_reporter()
self.start_timeline_processor() self.start_timeline_processor()
self.start_event_processor() self.start_event_processor()
self.start_event_cleanup() self.start_event_cleanup()
@@ -771,6 +790,8 @@ class FrigateApp:
self.event_cleanup.join() self.event_cleanup.join()
self.record_cleanup.join() self.record_cleanup.join()
self.stats_emitter.join() self.stats_emitter.join()
# a send in flight can hold the thread for the whole request timeout
self.analytics_reporter.join(timeout=5)
self.frigate_watchdog.join() self.frigate_watchdog.join()
self.camera_maintainer.join() self.camera_maintainer.join()
self.db.stop() self.db.stop()
+1 -14
View File
@@ -357,20 +357,7 @@ class Dispatcher:
return return
try: try:
action = payload.get("action") self.notice_registry.apply(payload)
kind = payload.get("kind")
scope = payload.get("scope")
if not isinstance(kind, str):
logger.warning("Ignoring notice update without a kind")
elif action == "raise":
self.notice_registry.raise_notice(
kind, scope=scope, params=payload.get("params") or {}
)
elif action == "resolve":
self.notice_registry.resolve(kind, scope)
else:
logger.warning("Ignoring notice update with action %s", action)
except Exception: except Exception:
# a raise here would kill the REP thread for every process # a raise here would kill the REP thread for every process
logger.exception("Failed to apply notice update") logger.exception("Failed to apply notice update")
+28 -3
View File
@@ -1,7 +1,7 @@
from enum import Enum from enum import Enum
from typing import Any from typing import Any, Self
from pydantic import Field from pydantic import Field, model_validator
from ..base import FrigateBaseModel from ..base import FrigateBaseModel
from ..env import EnvString from ..env import EnvString
@@ -21,6 +21,17 @@ class GenAIRoleEnum(str, Enum):
chat = "chat" chat = "chat"
descriptions = "descriptions" descriptions = "descriptions"
embeddings = "embeddings" embeddings = "embeddings"
transcribe = "transcribe"
# Providers that can accept audio input for the transcribe role. Ollama has no
# audio input support, so claiming the role there would fail at request time.
TRANSCRIBE_CAPABLE_PROVIDERS = {
GenAIProviderEnum.openai,
GenAIProviderEnum.azure_openai,
GenAIProviderEnum.gemini,
GenAIProviderEnum.llamacpp,
}
class GenAIConfig(FrigateBaseModel): class GenAIConfig(FrigateBaseModel):
@@ -52,7 +63,7 @@ class GenAIConfig(FrigateBaseModel):
GenAIRoleEnum.chat, GenAIRoleEnum.chat,
], ],
title="Roles", title="Roles",
description="GenAI roles (chat, descriptions, embeddings); one provider per role.", description="GenAI roles (chat, descriptions, embeddings, transcribe); one provider per role. Only chat, descriptions, and embeddings are granted by default; transcribe must be listed explicitly.",
) )
provider_options: dict[str, Any] = Field( provider_options: dict[str, Any] = Field(
default={}, default={},
@@ -66,3 +77,17 @@ class GenAIConfig(FrigateBaseModel):
description="Runtime options passed to the provider for each inference call.", description="Runtime options passed to the provider for each inference call.",
json_schema_extra={"additionalProperties": {}}, json_schema_extra={"additionalProperties": {}},
) )
@model_validator(mode="after")
def validate_transcribe_provider(self) -> Self:
"""Reject the transcribe role on providers that cannot accept audio input."""
if (
GenAIRoleEnum.transcribe in self.roles
and self.provider not in TRANSCRIBE_CAPABLE_PROVIDERS
):
raise ValueError(
f"GenAI provider '{self.provider.value}' does not support audio input "
"and cannot be given the 'transcribe' role."
)
return self
+13
View File
@@ -9,6 +9,7 @@ __all__ = [
"DetectionsConfig", "DetectionsConfig",
"AlertsConfig", "AlertsConfig",
"ImageSourceEnum", "ImageSourceEnum",
"ReviewFrameModeEnum",
"ReviewResponseStyleEnum", "ReviewResponseStyleEnum",
] ]
@@ -20,6 +21,13 @@ class ImageSourceEnum(str, Enum):
recordings = "recordings" recordings = "recordings"
class ReviewFrameModeEnum(str, Enum):
"""How review frames are presented to the GenAI provider."""
frames = "frames"
annotated_frames = "annotated_frames"
class ReviewResponseStyleEnum(str, Enum): class ReviewResponseStyleEnum(str, Enum):
"""Writing style presets for GenAI review descriptions.""" """Writing style presets for GenAI review descriptions."""
@@ -153,6 +161,11 @@ class GenAIReviewConfig(FrigateBaseModel):
description="Preferred language to request from the GenAI provider for generated responses.", description="Preferred language to request from the GenAI provider for generated responses.",
default=None, default=None,
) )
frame_mode: ReviewFrameModeEnum = Field(
default=ReviewFrameModeEnum.frames,
title="Frame mode",
description="How frames are presented to the model. 'frames' sends the prompt followed by the frames, which suits models that track a sequence well on their own. 'annotated_frames' labels each frame and interleaves notes derived from object tracking, which helps models that lose track of activity that repeats or reverses.",
)
response_style: ReviewResponseStyleEnum = Field( response_style: ReviewResponseStyleEnum = Field(
default=ReviewResponseStyleEnum.default, default=ReviewResponseStyleEnum.default,
title="Response style", title="Response style",
+32 -2
View File
@@ -5,6 +5,7 @@ from pydantic import ConfigDict, Field, field_validator
from .base import FrigateBaseModel from .base import FrigateBaseModel
__all__ = [ __all__ = [
"AudioTranscriptionModelEnum",
"CameraFaceRecognitionConfig", "CameraFaceRecognitionConfig",
"CameraLicensePlateRecognitionConfig", "CameraLicensePlateRecognitionConfig",
"CameraAudioTranscriptionConfig", "CameraAudioTranscriptionConfig",
@@ -20,6 +21,10 @@ class SemanticSearchModelEnum(str, Enum):
jinav2 = "jinav2" jinav2 = "jinav2"
class AudioTranscriptionModelEnum(str, Enum):
whisper = "whisper"
class EnrichmentsDeviceEnum(str, Enum): class EnrichmentsDeviceEnum(str, Enum):
GPU = "GPU" GPU = "GPU"
CPU = "CPU" CPU = "CPU"
@@ -53,10 +58,35 @@ class AudioTranscriptionConfig(FrigateBaseModel):
description="Enable or disable automatic audio transcription for all cameras; can be overridden per-camera.", description="Enable or disable automatic audio transcription for all cameras; can be overridden per-camera.",
) )
language: str = Field( language: str = Field(
default="en", default="auto",
title="Transcription language", title="Transcription language",
description="Language code used for transcription/translation (for example 'en' for English). See https://whisper-api.com/docs/languages/ for supported language codes.", description="Language code used for transcription/translation (for example 'en' for English), or 'auto' to let the model detect it. See https://whisper-api.com/docs/languages/ for supported language codes.",
) )
model: AudioTranscriptionModelEnum | str | None = Field(
default=AudioTranscriptionModelEnum.whisper,
title="Audio transcription model or GenAI provider name",
description="The transcription backend: 'whisper' for Frigate's built-in local models, or the name of a GenAI provider with the transcribe role.",
)
@field_validator("model", mode="before")
@classmethod
def coerce_model_enum(cls, v):
# An absent value ("model:" with nothing after it, or an explicit null)
# means unspecified, so fall back to the built-in backend. Left as None
# it would pass the GenAI-provider validation, which only inspects
# strings, and then be treated as a provider name that resolves to no
# client, turning transcription into a silent no-op.
if v is None or (isinstance(v, str) and not v.strip()):
return AudioTranscriptionModelEnum.whisper
if isinstance(v, str):
try:
return AudioTranscriptionModelEnum(v)
except ValueError:
return v
return v
device: EnrichmentsDeviceEnum = Field( device: EnrichmentsDeviceEnum = Field(
default=EnrichmentsDeviceEnum.CPU, default=EnrichmentsDeviceEnum.CPU,
title="Transcription device", title="Transcription device",
+31 -1
View File
@@ -56,6 +56,7 @@ from .camera.timestamp import TimestampStyleConfig
from .camera_group import CameraGroupConfig from .camera_group import CameraGroupConfig
from .classification import ( from .classification import (
AudioTranscriptionConfig, AudioTranscriptionConfig,
AudioTranscriptionModelEnum,
ClassificationConfig, ClassificationConfig,
FaceRecognitionConfig, FaceRecognitionConfig,
LicensePlateRecognitionConfig, LicensePlateRecognitionConfig,
@@ -884,7 +885,7 @@ class FrigateConfig(FrigateBaseModel):
# set notifications state # set notifications state
self.notifications.enabled_in_config = self.notifications.enabled self.notifications.enabled_in_config = self.notifications.enabled
# validate genai: each role (chat, descriptions, embeddings) at most once # validate genai: each role (chat, descriptions, embeddings, transcribe) at most once
role_to_name: dict[GenAIRoleEnum, str] = {} role_to_name: dict[GenAIRoleEnum, str] = {}
for name, genai_cfg in self.genai.items(): for name, genai_cfg in self.genai.items():
for role in genai_cfg.roles: for role in genai_cfg.roles:
@@ -1245,6 +1246,35 @@ class FrigateConfig(FrigateBaseModel):
for model in self.models: for model in self.models:
model.create_colormap(colored_labels) model.create_colormap(colored_labels)
# validate audio_transcription.model when it is a GenAI provider name.
# this runs here rather than beside the semantic_search check because the
# global->camera merge above is what resolves camera-level enablement.
transcription_active = self.audio_transcription.enabled or any(
camera.audio_transcription.enabled for camera in self.cameras.values()
)
if (
transcription_active
and isinstance(self.audio_transcription.model, str)
and not isinstance(
self.audio_transcription.model, AudioTranscriptionModelEnum
)
):
if self.audio_transcription.model not in self.genai:
raise ValueError(
f"audio_transcription.model '{self.audio_transcription.model}' is not a "
"valid GenAI config key. Must match a key in genai config."
)
if (
GenAIRoleEnum.transcribe
not in self.genai[self.audio_transcription.model].roles
):
raise ValueError(
f"GenAI provider '{self.audio_transcription.model}' must have "
"'transcribe' in its roles for audio transcription."
)
# Check audio transcription and audio detection requirements # Check audio transcription and audio detection requirements
if self.audio_transcription.enabled: if self.audio_transcription.enabled:
# If audio transcription is enabled globally, at least one camera must have audio detection enabled # If audio transcription is enabled globally, at least one camera must have audio detection enabled
+17
View File
@@ -1,9 +1,14 @@
"""Shared handle on the config object that is current for this instance.""" """Shared handle on the config object that is current for this instance."""
import logging
from collections.abc import Callable
from .config import FrigateConfig from .config import FrigateConfig
__all__ = ["ConfigHolder"] __all__ = ["ConfigHolder"]
logger = logging.getLogger(__name__)
class ConfigHolder: class ConfigHolder:
"""Indirection for the most recently parsed config. """Indirection for the most recently parsed config.
@@ -23,12 +28,24 @@ class ConfigHolder:
def __init__(self, config: FrigateConfig) -> None: def __init__(self, config: FrigateConfig) -> None:
self._config = config self._config = config
self._listeners: list[Callable[[FrigateConfig], None]] = []
@property @property
def config(self) -> FrigateConfig: def config(self) -> FrigateConfig:
"""The config as of the most recent successful save.""" """The config as of the most recent successful save."""
return self._config return self._config
def subscribe(self, listener: Callable[[FrigateConfig], None]) -> None:
"""Call listener on the saving thread with each config installed later."""
self._listeners.append(listener)
def set(self, config: FrigateConfig) -> None: def set(self, config: FrigateConfig) -> None:
"""Install a freshly parsed config as the current one.""" """Install a freshly parsed config as the current one."""
self._config = config self._config = config
for listener in self._listeners:
try:
listener(config)
except Exception:
# a listener bug must not fail the save that has already applied
logger.exception("Config listener failed")
+5
View File
@@ -29,6 +29,11 @@ class StatsConfig(FrigateBaseModel):
class TelemetryConfig(FrigateBaseModel): class TelemetryConfig(FrigateBaseModel):
analytics: bool = Field(
default=False,
title="Share anonymous analytics",
description="Send one anonymous usage report a day to help the Frigate maintainers decide what to support. Nothing is sent until this is on.",
)
network_interfaces: list[str] = Field( network_interfaces: list[str] = Field(
default=[], default=[],
title="Network interfaces", title="Network interfaces",
+3
View File
@@ -101,6 +101,9 @@ MAX_WAL_SIZE = 10 # MB
DEFAULT_FFMPEG_VERSION = os.environ.get("DEFAULT_FFMPEG_VERSION", "") DEFAULT_FFMPEG_VERSION = os.environ.get("DEFAULT_FFMPEG_VERSION", "")
INCLUDED_FFMPEG_VERSIONS = os.environ.get("INCLUDED_FFMPEG_VERSIONS", "").split(":") INCLUDED_FFMPEG_VERSIONS = os.environ.get("INCLUDED_FFMPEG_VERSIONS", "").split(":")
ANALYTICS_URL = os.environ.get(
"FRIGATE_ANALYTICS_URL", "https://analytics.frigate.video/report"
)
LIBAVFORMAT_VERSION_MAJOR = int(os.environ.get("LIBAVFORMAT_VERSION_MAJOR", "59")) LIBAVFORMAT_VERSION_MAJOR = int(os.environ.get("LIBAVFORMAT_VERSION_MAJOR", "59"))
FFMPEG_HWACCEL_NVIDIA = "preset-nvidia" FFMPEG_HWACCEL_NVIDIA = "preset-nvidia"
FFMPEG_HWACCEL_VAAPI = "preset-vaapi" FFMPEG_HWACCEL_VAAPI = "preset-vaapi"
@@ -10,6 +10,7 @@ from peewee import DoesNotExist
from frigate.comms.inter_process import InterProcessRequestor from frigate.comms.inter_process import InterProcessRequestor
from frigate.config import FrigateConfig from frigate.config import FrigateConfig
from frigate.config.classification import AudioTranscriptionModelEnum
from frigate.const import ( from frigate.const import (
CACHE_DIR, CACHE_DIR,
MODEL_CACHE_DIR, MODEL_CACHE_DIR,
@@ -18,8 +19,13 @@ from frigate.const import (
) )
from frigate.data_processing.types import PostProcessDataEnum from frigate.data_processing.types import PostProcessDataEnum
from frigate.embeddings.embeddings import Embeddings from frigate.embeddings.embeddings import Embeddings
from frigate.genai.manager import GenAIClientManager
from frigate.types import TrackedObjectUpdateTypesEnum from frigate.types import TrackedObjectUpdateTypesEnum
from frigate.util.audio import get_audio_from_recording from frigate.util.audio import (
clean_transcript,
get_audio_from_recording,
resolve_language,
)
from ..types import DataProcessorMetrics from ..types import DataProcessorMetrics
from .api import PostProcessorApi from .api import PostProcessorApi
@@ -34,15 +40,25 @@ class AudioTranscriptionPostProcessor(PostProcessorApi):
requestor: InterProcessRequestor, requestor: InterProcessRequestor,
embeddings: Embeddings, embeddings: Embeddings,
metrics: DataProcessorMetrics, metrics: DataProcessorMetrics,
genai_manager: GenAIClientManager | None = None,
): ):
super().__init__(config, metrics, None) super().__init__(config, metrics, None)
self.config = config self.config = config
self.requestor = requestor self.requestor = requestor
self.embeddings = embeddings self.embeddings = embeddings
self.genai_manager = genai_manager
self.recognizer = None self.recognizer = None
self.transcription_lock = threading.Lock() self.transcription_lock = threading.Lock()
self.transcription_thread: threading.Thread | None = None self.transcription_thread: threading.Thread | None = None
self.transcription_running = False self.transcription_running = False
self._use_genai = not isinstance(
config.audio_transcription.model, AudioTranscriptionModelEnum
)
if self._use_genai:
# never build the local recognizer on the GenAI path; WhisperModel
# downloads several hundred MB on first use
return
# faster-whisper handles model downloading automatically # faster-whisper handles model downloading automatically
self.model_path = os.path.join(MODEL_CACHE_DIR, "whisper") self.model_path = os.path.join(MODEL_CACHE_DIR, "whisper")
@@ -147,6 +163,31 @@ class AudioTranscriptionPostProcessor(PostProcessorApi):
logger.error(f"Error in audio transcription post-processing: {e}") logger.error(f"Error in audio transcription post-processing: {e}")
def __transcribe_audio(self, audio_data: bytes) -> str | None: def __transcribe_audio(self, audio_data: bytes) -> str | None:
"""Transcribe WAV audio data with the configured backend."""
if self._use_genai:
return self.__transcribe_audio_genai(audio_data)
return self.__transcribe_audio_whisper(audio_data)
def __transcribe_audio_genai(self, audio_data: bytes) -> str | None:
"""Hand the WAV bytes to the GenAI provider holding the transcribe role."""
client = self.genai_manager.transcribe_client if self.genai_manager else None
if not client:
logger.error(
"audio_transcription.model is '%s' (GenAI provider) but no transcribe "
"client is configured. Ensure the GenAI provider has 'transcribe' in its roles",
self.config.audio_transcription.model,
)
return None
text = client.transcribe(
audio_data,
language=resolve_language(self.config.audio_transcription.language),
)
return clean_transcript(text) or None
def __transcribe_audio_whisper(self, audio_data: bytes) -> str | None:
"""Transcribe WAV audio data using faster-whisper.""" """Transcribe WAV audio data using faster-whisper."""
if not self.recognizer: if not self.recognizer:
logger.debug("Recognizer not initialized") logger.debug("Recognizer not initialized")
@@ -160,7 +201,7 @@ class AudioTranscriptionPostProcessor(PostProcessorApi):
segments, info = self.recognizer.transcribe( segments, info = self.recognizer.transcribe(
temp_wav, temp_wav,
language=self.config.audio_transcription.language, language=resolve_language(self.config.audio_transcription.language),
beam_size=5, beam_size=5,
) )
@@ -253,7 +253,7 @@ class ObjectDescriptionProcessor(PostProcessorApi):
# Crop snapshot based on region # Crop snapshot based on region
# provide full image if region doesn't exist (manual events) # provide full image if region doesn't exist (manual events)
height, width = img.shape[:2] height, width = img.shape[:2]
x1_rel, y1_rel, width_rel, height_rel = event.data.get( # type: ignore[attr-defined] x1_rel, y1_rel, width_rel, height_rel = event.data.get(
"region", [0, 0, 1, 1] "region", [0, 0, 1, 1]
) )
x1, y1 = int(x1_rel * width), int(y1_rel * height) x1, y1 = int(x1_rel * width), int(y1_rel * height)
@@ -0,0 +1,394 @@
"""Frame annotations derived from object tracking data.
Builds short notes describing what changed during a review item, keyed to the
frames sampled from it. Everything here comes from tracked object data already
in the database (each event's `path_data` trajectory and the timeline's
stationary/active changes), so the notes can be stated to the model as fact
rather than as something it must perceive.
"""
import logging
import math
from collections.abc import Sequence
from typing import Any
from frigate.models import Event, Timeline
logger = logging.getLogger(__name__)
# Movement smaller than this (normalized frame units) between two path points
# is treated as the object holding still rather than travelling.
STILL_THRESHOLD = 0.02
# A heading change beyond this (dot product against the leg's own heading)
# counts as the object turning back rather than curving.
REVERSAL_DOT = -0.3
# A run of travel shorter than this (normalized frame units) is treated as
# milling about rather than going somewhere. Without it, a subject pacing in
# one spot produces a burst of contradictory "turns around" notes on a single
# frame.
MIN_LEG_DISTANCE = 0.08
# Movement that begins within this many seconds of detection is folded into
# the detection note, so each arrival reads as one event instead of several.
DETECT_MOVE_MERGE_SECONDS = 2.0
STATE_CHANGE_PHRASES = {
"stationary": "has stopped moving",
"active": "starts moving again",
}
Point = tuple[float, float, float]
Leg = tuple[int, int]
def describe_position(x: float, y: float) -> str:
"""Name a normalized frame position in plain terms."""
horizontal = "left" if x < 0.34 else ("right" if x > 0.66 else "center")
vertical = "top" if y < 0.34 else ("bottom" if y > 0.66 else "middle")
if horizontal == "center" and vertical == "middle":
return "the middle of the frame"
if horizontal == "center":
return f"the {vertical} of the frame"
if vertical == "middle":
return f"the {horizontal} of the frame"
return f"the {vertical} {horizontal} of the frame"
def describe_heading(dx: float, dy: float) -> str:
"""Name a direction of travel in frame terms.
y grows downward in normalized coordinates, so a falling y reads as moving
toward the top of the frame.
"""
parts = []
if abs(dy) > abs(dx) * 0.4:
parts.append("down" if dy > 0 else "up")
if abs(dx) > abs(dy) * 0.4:
parts.append("right" if dx > 0 else "left")
return " and ".join(parts) if parts else "in place"
def event_name(event: dict[str, Any]) -> str:
"""Name an object for the notes, e.g. 'a person' or 'waste bin "Compost"'.
Objects are never numbered or given track identifiers. Frigate opens a new
tracked object whenever a subject is re-detected, so the tracking data
cannot say whether two entries are the same subject, and the notes stay
ambiguous rather than implying either answer.
"""
label = str(event["label"]).replace("_", " ").replace("-verified", "")
sub_label = event.get("sub_label")
if sub_label:
return f'{label} "{sub_label}"'
article = "an" if label[:1].lower() in "aeiou" else "a"
return f"{article} {label}"
def path_legs(points: list[Point]) -> list[Leg]:
"""Split a trajectory into runs of travel in a consistent direction.
A leg ends when the subject starts moving back against the direction that
leg established, and only once the leg has covered MIN_LEG_DISTANCE, so
jitter around a standing subject does not register as a turn.
Returns (start, end) index pairs into `points`.
"""
legs: list[Leg] = []
start = 0
for i in range(1, len(points)):
lx = points[i][0] - points[start][0]
ly = points[i][1] - points[start][1]
leg_distance = (lx * lx + ly * ly) ** 0.5
if leg_distance < MIN_LEG_DISTANCE:
continue
sx = points[i][0] - points[i - 1][0]
sy = points[i][1] - points[i - 1][1]
step = (sx * sx + sy * sy) ** 0.5
if step < STILL_THRESHOLD:
continue
dot = (lx / leg_distance) * (sx / step) + (ly / leg_distance) * (sy / step)
if dot < REVERSAL_DOT:
legs.append((start, i - 1))
start = i - 1
if start < len(points) - 1:
legs.append((start, len(points) - 1))
return [
(a, b)
for a, b in legs
if ((points[b][0] - points[a][0]) ** 2 + (points[b][1] - points[a][1]) ** 2)
** 0.5
>= MIN_LEG_DISTANCE
]
def path_points(path_data: list[Any]) -> list[Point]:
"""Flatten path_data into (x, y, timestamp) tuples, or [] if malformed."""
try:
return [(p[0][0], p[0][1], p[1]) for p in path_data or []]
except (IndexError, TypeError):
logger.debug("Malformed path_data, skipping trajectory notes")
return []
def leg_start_time(points: list[Point], leg: Leg) -> float:
"""When a leg's movement actually began.
path_data always keeps an object's first two samples, so a leg can open
with points recorded long before the object moved. The first sample that
has left the leg's origin is the earliest evidence of movement.
"""
a, b = leg
x0, y0, t0 = points[a]
for x, y, t in points[a + 1 : b + 1]:
if math.hypot(x - x0, y - y0) >= STILL_THRESHOLD:
return t
return t0
def leg_heading(points: list[Point], leg: Leg) -> str:
a, b = leg
return describe_heading(points[b][0] - points[a][0], points[b][1] - points[a][1])
def leg_phrase(points: list[Point], leg: Leg, first: bool) -> str:
"""Describe the start of a leg, e.g. 'turns around at ... and heads left'."""
heading = leg_heading(points, leg)
place = describe_position(points[leg[0]][0], points[leg[0]][1])
if first:
return f"starts moving {heading} from {place}"
return f"turns around at {place} and heads {heading}"
def path_moments(path_data: list[Any]) -> list[tuple[float, str]]:
"""Key moments in one trajectory as (timestamp, phrase).
Emits one note per leg of travel. Where the last leg ends is left out:
path_data only records significant movement, so its final point cannot
distinguish an object coming to rest from one leaving the frame.
"""
points = path_points(path_data)
if len(points) < 2:
return []
return [
(leg_start_time(points, leg), leg_phrase(points, leg, index == 0))
for index, leg in enumerate(path_legs(points))
]
def build_timeline(
events: list[dict[str, Any]],
span_end: float,
state_changes: Sequence[dict[str, Any]] = (),
) -> list[tuple[float, str]]:
"""All annotated moments across every event, in time order.
Only changes are noted, since those are what sparse frames miss; an
object's state at the end of the clip is visible in the last frame.
`span_end` is the timestamp of the last sampled frame, and moments past it
describe nothing the model can see. A track ending means the object
stopped being detected, which may or may not mean it left the frame.
`state_changes` are timeline rows (timestamp, source_id, class_type); the
stationary and active ones become "has stopped moving" / "starts moving
again". Frigate only marks an object stationary after it has been still
for a while, which the past-tense wording reflects.
Each object keeps its own notes. Folding an object into the note of the
person moving it ("alongside ...") was tried and made models lose track of
where the object went.
"""
changes_by_event: dict[str, list[tuple[float, str]]] = {}
for change in state_changes:
phrase = STATE_CHANGE_PHRASES.get(change["class_type"])
if phrase:
changes_by_event.setdefault(change["source_id"], []).append(
(change["timestamp"], phrase)
)
timeline: list[tuple[float, str]] = []
for event in sorted(events, key=lambda e: e["start_time"]):
# Frame extraction can come up short at the end of a clip, leaving
# objects that only appear after the last frame we actually have.
if event["start_time"] > span_end:
continue
points = path_points(event.get("path_data") or [])
legs = path_legs(points) if len(points) >= 2 else []
name = event_name(event)
detected_at = event["start_time"]
where = describe_position(points[0][0], points[0][1]) if points else "the frame"
merges = bool(legs) and leg_start_time(points, legs[0]) - detected_at <= (
DETECT_MOVE_MERGE_SECONDS
)
remaining = list(enumerate(legs))
moments: list[tuple[float, str]] = []
if merges:
heading = leg_heading(points, legs[0])
timeline.append(
(detected_at, f"{name} first detected at {where}, moving {heading}")
)
remaining = remaining[1:]
else:
timeline.append((detected_at, f"{name} first detected at {where}"))
for index, leg in remaining:
moments.append(
(
leg_start_time(points, leg),
leg_phrase(points, leg, index == 0),
)
)
moments.extend(
(timestamp, phrase)
for timestamp, phrase in changes_by_event.get(event["id"], [])
if timestamp >= detected_at
)
for timestamp, phrase in moments:
if timestamp <= span_end:
timeline.append((timestamp, f"{name} {phrase}"))
if event["end_time"] and event["end_time"] <= span_end:
timeline.append((event["end_time"], f"{name} is no longer detected"))
return sorted(timeline, key=lambda m: m[0])
def annotations_by_frame(
timeline: list[tuple[float, str]], frame_times: list[float]
) -> dict[int, list[str]]:
"""Bucket timeline moments onto the frame that follows each one.
A moment is attached to the first frame at or after it happened, so the
note always precedes the image in which the change becomes visible.
"""
buckets: dict[int, list[str]] = {}
if not frame_times:
return buckets
for timestamp, phrase in timeline:
index = next(
(i for i, ft in enumerate(frame_times) if ft >= timestamp),
len(frame_times) - 1,
)
buckets.setdefault(index, []).append(phrase)
return buckets
def get_tracked_events(detection_ids: list[str]) -> list[dict[str, Any]]:
"""Load the tracked objects behind a review item's detections."""
if not detection_ids:
return []
rows = list(
Event.select(
Event.id,
Event.label,
Event.sub_label,
Event.start_time,
Event.end_time,
Event.data,
)
.where(Event.id << detection_ids)
.dicts()
.iterator()
)
return [
{
"id": row["id"],
"label": row["label"],
"sub_label": row["sub_label"],
"start_time": row["start_time"],
"end_time": row["end_time"],
"path_data": (row["data"] or {}).get("path_data") or [],
}
for row in rows
if row["start_time"] is not None
]
def get_state_changes(detection_ids: list[str]) -> list[dict[str, Any]]:
"""Stationary/active changes the timeline recorded for these objects."""
if not detection_ids:
return []
return list(
Timeline.select(Timeline.timestamp, Timeline.source_id, Timeline.class_type)
.where(
(Timeline.source_id << detection_ids)
& (Timeline.class_type << list(STATE_CHANGE_PHRASES))
)
.dicts()
.iterator()
)
def build_frame_captions(
detection_ids: list[str],
frame_times: list[float],
) -> list[str]:
"""A caption for each sampled frame, in frame order.
Every frame gets its index and elapsed time so the model can tell them
apart; frames where something changed also carry the tracker notes for
that moment. Returns an empty list when there is nothing to say, which
callers treat as a reason to fall back to sending plain frames.
"""
if not frame_times:
return []
events = get_tracked_events(detection_ids)
if not events:
logger.debug("No tracked events found for review item, skipping annotations")
return []
timeline = build_timeline(events, frame_times[-1], get_state_changes(detection_ids))
buckets = annotations_by_frame(timeline, frame_times)
if not buckets:
return []
total = len(frame_times)
origin = frame_times[0]
captions: list[str] = []
for index, timestamp in enumerate(frame_times):
lines = [f"Frame {index + 1} of {total} (+{timestamp - origin:.1f}s):"]
lines.extend(f"[tracker] {note}" for note in buckets.get(index, []))
captions.append("\n".join(lines))
return captions
@@ -8,7 +8,7 @@ import os
import shutil import shutil
import threading import threading
from pathlib import Path from pathlib import Path
from typing import Any from typing import Any, cast
import cv2 import cv2
from peewee import DoesNotExist from peewee import DoesNotExist
@@ -19,7 +19,11 @@ from frigate.comms.embeddings_updater import EmbeddingsRequestEnum
from frigate.comms.inter_process import InterProcessRequestor from frigate.comms.inter_process import InterProcessRequestor
from frigate.config import FrigateConfig from frigate.config import FrigateConfig
from frigate.config.camera import CameraConfig from frigate.config.camera import CameraConfig
from frigate.config.camera.review import GenAIReviewConfig, ImageSourceEnum from frigate.config.camera.review import (
GenAIReviewConfig,
ImageSourceEnum,
ReviewFrameModeEnum,
)
from frigate.const import ( from frigate.const import (
ATTRIBUTE_LABEL_DISPLAY_MAP, ATTRIBUTE_LABEL_DISPLAY_MAP,
CACHE_DIR, CACHE_DIR,
@@ -36,6 +40,7 @@ from frigate.util.image import get_image_from_recording
from ..post.api import PostProcessorApi from ..post.api import PostProcessorApi
from ..types import DataProcessorMetrics from ..types import DataProcessorMetrics
from .review_annotations import build_frame_captions
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -43,6 +48,7 @@ RECORDING_BUFFER_EXTENSION_PERCENT = 0.10
MIN_RECORDING_DURATION = 10 MIN_RECORDING_DURATION = 10
MAX_IMAGE_TOKENS = 24000 MAX_IMAGE_TOKENS = 24000
MAX_FRAMES_PER_SECOND = 1 MAX_FRAMES_PER_SECOND = 1
MAX_ANNOTATED_FRAMES = 28
class ReviewDescriptionProcessor(PostProcessorApi): class ReviewDescriptionProcessor(PostProcessorApi):
@@ -67,6 +73,7 @@ class ReviewDescriptionProcessor(PostProcessorApi):
duration: float, duration: float,
image_source: ImageSourceEnum = ImageSourceEnum.preview, image_source: ImageSourceEnum = ImageSourceEnum.preview,
height: int = 480, height: int = 480,
frame_mode: ReviewFrameModeEnum = ReviewFrameModeEnum.frames,
) -> int: ) -> int:
"""Calculate optimal number of frames based on event duration, context size, """Calculate optimal number of frames based on event duration, context size,
image source, and resolution. image source, and resolution.
@@ -80,6 +87,8 @@ class ReviewDescriptionProcessor(PostProcessorApi):
- MAX_FRAMES_PER_SECOND x duration, to avoid drowning short events in - MAX_FRAMES_PER_SECOND x duration, to avoid drowning short events in
near-duplicate frames where the model latches onto the redundant middle near-duplicate frames where the model latches onto the redundant middle
and skips the start/end action and skips the start/end action
- MAX_ANNOTATED_FRAMES in annotated mode, where the tracking notes
already carry the sequence
""" """
client = self.genai_manager.description_client client = self.genai_manager.description_client
@@ -125,6 +134,10 @@ class ReviewDescriptionProcessor(PostProcessorApi):
max_frames_by_tokens = int(image_token_budget / tokens_per_image) max_frames_by_tokens = int(image_token_budget / tokens_per_image)
max_frames_by_duration = int(duration * MAX_FRAMES_PER_SECOND) max_frames_by_duration = int(duration * MAX_FRAMES_PER_SECOND)
max_frames = min(max_frames_by_tokens, max_frames_by_duration) max_frames = min(max_frames_by_tokens, max_frames_by_duration)
if frame_mode == ReviewFrameModeEnum.annotated_frames:
max_frames = min(max_frames, MAX_ANNOTATED_FRAMES)
return max(max_frames, 3) return max(max_frames, 3)
def process_data( def process_data(
@@ -166,6 +179,7 @@ class ReviewDescriptionProcessor(PostProcessorApi):
return return
image_source = camera_config.review.genai.image_source image_source = camera_config.review.genai.image_source
frame_mode = camera_config.review.genai.frame_mode
if image_source == ImageSourceEnum.recordings: if image_source == ImageSourceEnum.recordings:
buffer_extension = get_recording_buffer_extension( buffer_extension = get_recording_buffer_extension(
@@ -174,40 +188,43 @@ class ReviewDescriptionProcessor(PostProcessorApi):
final_data["start_time"] -= buffer_extension final_data["start_time"] -= buffer_extension
final_data["end_time"] += buffer_extension final_data["end_time"] += buffer_extension
thumbs = self.get_recording_frames( frames = self.get_recording_frames(
camera, camera,
final_data["start_time"], final_data["start_time"],
final_data["end_time"], final_data["end_time"],
height=480, # Use 480p for good balance between quality and token usage height=480, # Use 480p for good balance between quality and token usage
frame_mode=frame_mode,
) )
if not thumbs: if not frames:
# Fallback to preview frames if no recordings available # Fallback to preview frames if no recordings available
logger.warning( logger.warning(
f"No recording frames found for {camera}, falling back to preview frames" f"No recording frames found for {camera}, falling back to preview frames"
) )
thumbs = self.get_preview_frames_as_bytes( frames = self.get_preview_frames_as_bytes(
camera, camera,
final_data["start_time"], final_data["start_time"],
final_data["end_time"], final_data["end_time"],
final_data["thumb_path"], final_data["thumb_path"],
id, id,
camera_config.review.genai.debug_save_thumbnails, camera_config.review.genai.debug_save_thumbnails,
frame_mode,
) )
elif camera_config.review.genai.debug_save_thumbnails: elif camera_config.review.genai.debug_save_thumbnails:
self.save_debug_recording_frames(id, thumbs) self.save_debug_recording_frames(id, frames)
else: else:
# Use preview frames # Use preview frames
thumbs = self.get_preview_frames_as_bytes( frames = self.get_preview_frames_as_bytes(
camera, camera,
final_data["start_time"], final_data["start_time"],
final_data["end_time"], final_data["end_time"],
final_data["thumb_path"], final_data["thumb_path"],
id, id,
camera_config.review.genai.debug_save_thumbnails, camera_config.review.genai.debug_save_thumbnails,
frame_mode,
) )
self.start_analysis(camera_config, final_data, thumbs) self.start_analysis(camera_config, final_data, frames)
def handle_request(self, topic: str, request_data: dict[str, Any]) -> str | None: def handle_request(self, topic: str, request_data: dict[str, Any]) -> str | None:
if topic == EmbeddingsRequestEnum.regenerate_review_description.value: if topic == EmbeddingsRequestEnum.regenerate_review_description.value:
@@ -386,31 +403,50 @@ class ReviewDescriptionProcessor(PostProcessorApi):
buffer_extension = get_recording_buffer_extension( buffer_extension = get_recording_buffer_extension(
final_data["end_time"] - final_data["start_time"] final_data["end_time"] - final_data["start_time"]
) )
thumbs = self.get_recording_frames( frames = self.get_recording_frames(
str(review.camera), str(review.camera),
final_data["start_time"] - buffer_extension, final_data["start_time"] - buffer_extension,
final_data["end_time"] + buffer_extension, final_data["end_time"] + buffer_extension,
height=480, height=480,
frame_mode=camera_config.review.genai.frame_mode,
) )
if not thumbs: if not frames:
logger.error( logger.error(
"No recording frames are available for review item %s", review_id "No recording frames are available for review item %s", review_id
) )
return return
if camera_config.review.genai.debug_save_thumbnails: if camera_config.review.genai.debug_save_thumbnails:
self.save_debug_recording_frames(review_id, thumbs) self.save_debug_recording_frames(review_id, frames)
self.start_analysis(camera_config, final_data, thumbs) self.start_analysis(camera_config, final_data, frames)
def start_analysis( def start_analysis(
self, self,
camera_config: CameraConfig, camera_config: CameraConfig,
final_data: dict[str, Any], final_data: dict[str, Any],
thumbs: list[bytes], frames: list[tuple[bytes, float]],
) -> None: ) -> None:
"""Kick off description generation for a review item in the background.""" """Kick off description generation for a review item in the background."""
thumbs = [frame for frame, _ in frames]
captions: list[str] = []
if (
camera_config.review.genai.frame_mode
== ReviewFrameModeEnum.annotated_frames
):
captions = build_frame_captions(
final_data["data"].get("detections") or [],
[timestamp for _, timestamp in frames],
)
if not captions:
logger.debug(
"No tracking annotations for review item %s, sending plain frames",
final_data["id"],
)
self.review_desc_dps.update() self.review_desc_dps.update()
threading.Thread( threading.Thread(
target=run_analysis, target=run_analysis,
@@ -421,19 +457,22 @@ class ReviewDescriptionProcessor(PostProcessorApi):
camera_config, camera_config,
final_data, final_data,
thumbs, thumbs,
captions,
camera_config.review.genai, camera_config.review.genai,
sorted(self.config.all_labels), sorted(self.config.all_labels),
self.config.all_attributes, self.config.all_attributes,
), ),
).start() ).start()
def save_debug_recording_frames(self, review_id: str, thumbs: list[bytes]) -> None: def save_debug_recording_frames(
self, review_id: str, frames: list[tuple[bytes, float]]
) -> None:
"""Write the recording frames sent to the provider out for debugging.""" """Write the recording frames sent to the provider out for debugging."""
Path(os.path.join(CLIPS_DIR, "genai-requests", review_id)).mkdir( Path(os.path.join(CLIPS_DIR, "genai-requests", review_id)).mkdir(
parents=True, exist_ok=True parents=True, exist_ok=True
) )
for idx, frame_bytes in enumerate(thumbs): for idx, (frame_bytes, _) in enumerate(frames):
with open( with open(
os.path.join(CLIPS_DIR, f"genai-requests/{review_id}/{idx}.jpg"), os.path.join(CLIPS_DIR, f"genai-requests/{review_id}/{idx}.jpg"),
"wb", "wb",
@@ -445,7 +484,9 @@ class ReviewDescriptionProcessor(PostProcessorApi):
camera: str, camera: str,
start_time: float, start_time: float,
end_time: float, end_time: float,
) -> list[str]: frame_mode: ReviewFrameModeEnum = ReviewFrameModeEnum.frames,
) -> list[tuple[str, float]]:
"""Preview frame paths paired with the time each one was captured."""
preview_dir = os.path.join(CACHE_DIR, "preview_frames") preview_dir = os.path.join(CACHE_DIR, "preview_frames")
file_start = f"preview_{camera}-" file_start = f"preview_{camera}-"
start_file = f"{file_start}{start_time}.webp" start_file = f"{file_start}{start_time}.webp"
@@ -477,18 +518,29 @@ class ReviewDescriptionProcessor(PostProcessorApi):
frame_count = len(all_frames) frame_count = len(all_frames)
desired_frame_count = self.calculate_frame_count( desired_frame_count = self.calculate_frame_count(
camera, duration=end_time - start_time camera,
duration=end_time - start_time,
frame_mode=frame_mode,
) )
def with_timestamp(path: str) -> tuple[str, float]:
# Preview frames are named preview_<camera>-<timestamp>.webp
stem = os.path.basename(path).removesuffix(".webp")
try:
return (path, float(stem.removeprefix(file_start)))
except ValueError:
return (path, start_time)
if frame_count <= desired_frame_count: if frame_count <= desired_frame_count:
return all_frames return [with_timestamp(f) for f in all_frames]
selected_frames = [] selected_frames = []
step_size = (frame_count - 1) / (desired_frame_count - 1) step_size = (frame_count - 1) / (desired_frame_count - 1)
for i in range(desired_frame_count): for i in range(desired_frame_count):
index = round(i * step_size) index = round(i * step_size)
selected_frames.append(all_frames[index]) selected_frames.append(with_timestamp(all_frames[index]))
return selected_frames return selected_frames
@@ -498,11 +550,12 @@ class ReviewDescriptionProcessor(PostProcessorApi):
start_time: float, start_time: float,
end_time: float, end_time: float,
height: int = 480, height: int = 480,
) -> list[bytes]: frame_mode: ReviewFrameModeEnum = ReviewFrameModeEnum.frames,
"""Get frames from recordings at specified timestamps.""" ) -> list[tuple[bytes, float]]:
"""Get frames from recordings paired with the time each was captured."""
duration = end_time - start_time duration = end_time - start_time
desired_frame_count = self.calculate_frame_count( desired_frame_count = self.calculate_frame_count(
camera, duration, ImageSourceEnum.recordings, height camera, duration, ImageSourceEnum.recordings, height, frame_mode
) )
# Calculate evenly spaced timestamps throughout the duration # Calculate evenly spaced timestamps throughout the duration
@@ -528,7 +581,8 @@ class ReviewDescriptionProcessor(PostProcessorApi):
.get() .get()
) )
time_in_segment = ts - recording.start_time # start_time is a DateTimeField holding a unix timestamp
time_in_segment = ts - cast(float, recording.start_time)
return get_image_from_recording( return get_image_from_recording(
self.config.ffmpeg, self.config.ffmpeg,
recording.path, recording.path,
@@ -539,7 +593,7 @@ class ReviewDescriptionProcessor(PostProcessorApi):
except DoesNotExist: except DoesNotExist:
return None return None
frames = [] frames: list[tuple[bytes, float]] = []
for timestamp in timestamps: for timestamp in timestamps:
try: try:
@@ -552,7 +606,7 @@ class ReviewDescriptionProcessor(PostProcessorApi):
image_data = extract_frame_from_recording(rounded_timestamp) image_data = extract_frame_from_recording(rounded_timestamp)
if image_data: if image_data:
frames.append(image_data) frames.append((image_data, timestamp))
else: else:
logger.warning( logger.warning(
f"No recording found for {camera} at timestamp {timestamp}" f"No recording found for {camera} at timestamp {timestamp}"
@@ -573,7 +627,8 @@ class ReviewDescriptionProcessor(PostProcessorApi):
thumb_path_fallback: str, thumb_path_fallback: str,
review_id: str, review_id: str,
save_debug: bool, save_debug: bool,
) -> list[bytes]: frame_mode: ReviewFrameModeEnum = ReviewFrameModeEnum.frames,
) -> list[tuple[bytes, float]]:
"""Get preview frames and convert them to JPEG bytes. """Get preview frames and convert them to JPEG bytes.
Args: Args:
@@ -585,14 +640,14 @@ class ReviewDescriptionProcessor(PostProcessorApi):
save_debug: Whether to save debug thumbnails save_debug: Whether to save debug thumbnails
Returns: Returns:
List of JPEG image bytes List of (JPEG image bytes, capture timestamp) pairs
""" """
frame_paths = self.get_cache_frames(camera, start_time, end_time) frame_paths = self.get_cache_frames(camera, start_time, end_time, frame_mode)
if not frame_paths: if not frame_paths:
frame_paths = [thumb_path_fallback] frame_paths = [(thumb_path_fallback, start_time)]
thumbs = [] thumbs: list[tuple[bytes, float]] = []
for idx, thumb_path in enumerate(frame_paths): for idx, (thumb_path, timestamp) in enumerate(frame_paths):
thumb_data = cv2.imread(thumb_path) thumb_data = cv2.imread(thumb_path)
if thumb_data is None: if thumb_data is None:
@@ -605,7 +660,7 @@ class ReviewDescriptionProcessor(PostProcessorApi):
".jpg", thumb_data, [int(cv2.IMWRITE_JPEG_QUALITY), 100] ".jpg", thumb_data, [int(cv2.IMWRITE_JPEG_QUALITY), 100]
) )
if ret: if ret:
thumbs.append(jpg.tobytes()) thumbs.append((jpg.tobytes(), timestamp))
if save_debug: if save_debug:
Path(os.path.join(CLIPS_DIR, "genai-requests", review_id)).mkdir( Path(os.path.join(CLIPS_DIR, "genai-requests", review_id)).mkdir(
@@ -640,6 +695,7 @@ def run_analysis(
camera_config: CameraConfig, camera_config: CameraConfig,
final_data: dict[str, Any], final_data: dict[str, Any],
thumbs: list[bytes], thumbs: list[bytes],
frame_captions: list[str],
genai_config: GenAIReviewConfig, genai_config: GenAIReviewConfig,
labelmap_objects: list[str], labelmap_objects: list[str],
attribute_labels: list[str], attribute_labels: list[str],
@@ -696,6 +752,7 @@ def run_analysis(
genai_config.debug_save_thumbnails, genai_config.debug_save_thumbnails,
genai_config.activity_context_prompt, genai_config.activity_context_prompt,
genai_config.response_style, genai_config.response_style,
frame_captions,
) )
review_inference_speed.update(datetime.datetime.now().timestamp() - start) review_inference_speed.update(datetime.datetime.now().timestamp() - start)
@@ -237,7 +237,7 @@ class SemanticTriggerProcessor(PostProcessorApi):
return return
# Skip the event if not an object # Skip the event if not an object
if event.data.get("type") != "object": # type: ignore[attr-defined] if event.data.get("type") != "object":
return return
thumbnail_bytes = get_event_thumbnail_bytes(event) thumbnail_bytes = get_event_thumbnail_bytes(event)
@@ -1,16 +1,19 @@
"""Handle processing audio for speech transcription using sherpa-onnx with FFmpeg pipe.""" """Handle processing audio for speech transcription using sherpa-onnx with FFmpeg pipe."""
import collections
import logging import logging
import os import os
import queue import queue
import threading import threading
from typing import Any import time
from typing import TYPE_CHECKING, Any
import numpy as np import numpy as np
from frigate.comms.inter_process import InterProcessRequestor from frigate.comms.inter_process import InterProcessRequestor
from frigate.config import CameraConfig, FrigateConfig from frigate.config import CameraConfig, FrigateConfig
from frigate.const import MODEL_CACHE_DIR from frigate.config.classification import AudioTranscriptionModelEnum
from frigate.const import AUDIO_DURATION, MODEL_CACHE_DIR
from frigate.data_processing.common.audio_transcription.model import ( from frigate.data_processing.common.audio_transcription.model import (
AudioTranscriptionModelRunner, AudioTranscriptionModelRunner,
) )
@@ -18,12 +21,38 @@ from frigate.data_processing.real_time.whisper_online import (
FasterWhisperASR, FasterWhisperASR,
OnlineASRProcessor, OnlineASRProcessor,
) )
from frigate.util.audio import (
clean_transcript,
pcm16_to_wav,
resolve_language,
stitch_transcripts,
)
from ..types import DataProcessorMetrics from ..types import DataProcessorMetrics
from .api import RealTimeProcessorApi from .api import RealTimeProcessorApi
if TYPE_CHECKING:
# importing frigate.genai eagerly would pull the provider SDKs into the
# audio process even when transcription runs on a local model
from frigate.genai.manager import GenAIClientManager
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# Number of ~0.975s audio detector chunks per GenAI request. The window advances
# one chunk at a time, so two chunks means a 50% overlap: every word lands whole
# in at least one window, which whisper-family models need to avoid hallucinating
# on a clipped clip. The cadence is fixed by the audio detector's frame size, so
# this is a constant rather than a config knob.
GENAI_WINDOW_CHUNKS = 2
# Bound the queue at ~30s of audio so a slow or hung provider cannot grow it
# without limit. The producer is the ffmpeg read thread and must never block.
AUDIO_QUEUE_MAXSIZE = int(30 / AUDIO_DURATION)
# A backed-up queue drops a chunk per cycle, so warning on each one would spam
# the log once a second per camera for as long as the provider stays slow.
AUDIO_DROP_WARN_INTERVAL = 10.0
class AudioTranscriptionRealTimeProcessor(RealTimeProcessorApi): class AudioTranscriptionRealTimeProcessor(RealTimeProcessorApi):
def __init__( def __init__(
@@ -31,9 +60,10 @@ class AudioTranscriptionRealTimeProcessor(RealTimeProcessorApi):
config: FrigateConfig, config: FrigateConfig,
camera_config: CameraConfig, camera_config: CameraConfig,
requestor: InterProcessRequestor, requestor: InterProcessRequestor,
model_runner: AudioTranscriptionModelRunner, model_runner: AudioTranscriptionModelRunner | None,
metrics: DataProcessorMetrics, metrics: DataProcessorMetrics,
stop_event: threading.Event, stop_event: threading.Event,
genai_manager: "GenAIClientManager | None" = None,
): ):
super().__init__(config, metrics) super().__init__(config, metrics)
self.config = config self.config = config
@@ -42,11 +72,31 @@ class AudioTranscriptionRealTimeProcessor(RealTimeProcessorApi):
self.stream: Any = None self.stream: Any = None
self.whisper_model: FasterWhisperASR | None = None self.whisper_model: FasterWhisperASR | None = None
self.model_runner = model_runner self.model_runner = model_runner
self.genai_manager = genai_manager
self.transcription_segments: list[str] = [] self.transcription_segments: list[str] = []
self.audio_queue: queue.Queue[tuple[dict[str, Any], np.ndarray]] = queue.Queue() self.audio_queue: queue.Queue[tuple[dict[str, Any], np.ndarray]] = queue.Queue(
maxsize=AUDIO_QUEUE_MAXSIZE
)
self.stop_event = stop_event self.stop_event = stop_event
self._use_genai = not isinstance(
config.audio_transcription.model, AudioTranscriptionModelEnum
)
# sliding window of raw int16 chunks; the deque's maxlen is what evicts
# the oldest chunk and so produces the overlap
self._genai_window: collections.deque[np.ndarray] = collections.deque(
maxlen=GENAI_WINDOW_CHUNKS
)
self._genai_committed = ""
# set by the producer when it discards a chunk, so the consumer knows the
# audio it is about to receive is not contiguous with what it buffered
self._audio_dropped = threading.Event()
self._last_drop_warning = 0.0
def __build_recognizer(self) -> None: def __build_recognizer(self) -> None:
if self._use_genai:
# nothing local to load; never import sherpa or FasterWhisperASR
return
try: try:
if self.config.audio_transcription.model_size == "large": if self.config.audio_transcription.model_size == "large":
# Whisper models need to be per-process and can only run one stream at a time # Whisper models need to be per-process and can only run one stream at a time
@@ -64,7 +114,7 @@ class AudioTranscriptionRealTimeProcessor(RealTimeProcessorApi):
self.stream = OnlineASRProcessor( self.stream = OnlineASRProcessor(
asr=self.whisper_model, asr=self.whisper_model,
) )
else: elif self.model_runner is not None:
logger.debug(f"Loading sherpa stream for {self.camera_config.name}") logger.debug(f"Loading sherpa stream for {self.camera_config.name}")
self.stream = self.model_runner.model.create_stream() self.stream = self.model_runner.model.create_stream()
logger.debug( logger.debug(
@@ -76,6 +126,15 @@ class AudioTranscriptionRealTimeProcessor(RealTimeProcessorApi):
) )
def __process_audio_stream(self, audio_data: np.ndarray) -> tuple[str, bool] | None: def __process_audio_stream(self, audio_data: np.ndarray) -> tuple[str, bool] | None:
# must precede both the model_runner guard (model_runner is None on this
# path) and the float32 normalization below (GenAI wants untouched int16)
if self._use_genai:
return self.__process_audio_genai(audio_data)
if self.model_runner is None:
logger.debug("Audio transcription (live) model runner not initialized")
return None
if ( if (
self.model_runner.model is None self.model_runner.model is None
and self.config.audio_transcription.model_size == "small" and self.config.audio_transcription.model_size == "small"
@@ -140,6 +199,82 @@ class AudioTranscriptionRealTimeProcessor(RealTimeProcessorApi):
logger.error(f"Error processing audio stream: {e}") logger.error(f"Error processing audio stream: {e}")
return None return None
def __process_audio_genai(self, audio_data: np.ndarray) -> tuple[str, bool] | None:
"""Transcribe a sliding overlapped window through the GenAI provider."""
client = self.genai_manager.transcribe_client if self.genai_manager else None
if not client:
logger.error(
"audio_transcription.model is '%s' (GenAI provider) but no transcribe "
"client is configured. Ensure the GenAI provider has 'transcribe' in its roles",
self.config.audio_transcription.model,
)
return None
if self._audio_dropped.is_set():
self._audio_dropped.clear()
# Chunks were discarded between what is buffered and this one, so
# concatenating them would splice non-adjacent audio into one window
# and destroy the overlap the stitcher depends on.
self._genai_window.clear()
if self._genai_committed:
# the transcript has a gap in it; close the utterance out rather
# than stitching across missing speech
return self.__end_genai_utterance()
self._genai_window.append(audio_data)
if len(self._genai_window) < GENAI_WINDOW_CHUNKS:
# wait for a full window so the first request is never a clipped clip
return None
window = np.concatenate(list(self._genai_window))
# Silence gate, using the same threshold audio detection uses. Gate the
# whole window rather than individual chunks; this is the primary cost
# and privacy brake and is what keeps a quiet camera near zero requests.
window_as_float = window.astype(np.float32)
rms = float(np.sqrt(np.mean(np.absolute(np.square(window_as_float)))))
if rms < self.camera_config.audio.min_volume:
logger.debug(
f"Window RMS {rms:.1f} below min_volume, skipping transcription"
)
return self.__end_genai_utterance()
text = client.transcribe(
pcm16_to_wav(window),
language=resolve_language(self.config.audio_transcription.language),
)
# cleaning has to come first: a silent window often comes back as the
# model's preamble alone, which is silence, not a word to commit
cleaned = clean_transcript(text)
if not cleaned:
return self.__end_genai_utterance()
self._genai_committed = stitch_transcripts(self._genai_committed, cleaned)
# no VAD on this path, so mirror the whisper branch's heuristic endpoint
is_endpoint = (
self._genai_committed.endswith((".", "!", "?"))
and len(self._genai_committed) > 300
)
logger.debug(f"GenAI transcription: '{self._genai_committed}'")
return self._genai_committed, is_endpoint
def __end_genai_utterance(self) -> tuple[str, bool] | None:
"""Close out the current utterance when a window carries no speech."""
if not self._genai_committed:
return None
return self._genai_committed, True
def process_frame(self, obj_data: dict[str, Any], frame: np.ndarray) -> None: def process_frame(self, obj_data: dict[str, Any], frame: np.ndarray) -> None:
pass pass
@@ -148,8 +283,38 @@ class AudioTranscriptionRealTimeProcessor(RealTimeProcessorApi):
logger.debug("No audio data provided for transcription") logger.debug("No audio data provided for transcription")
return None return None
# enqueue audio data for processing in the thread # enqueue audio data for processing in the thread. never block: the
self.audio_queue.put((obj_data, audio)) # producer is the ffmpeg read thread that audio detection depends on,
# so on a backlog drop the oldest chunk instead.
try:
self.audio_queue.put_nowait((obj_data, audio))
except queue.Full:
try:
self.audio_queue.get_nowait()
self.audio_queue.task_done()
except queue.Empty:
pass
# the stream now has a hole in it, which the consumer has to know
# about before it splices the next chunk onto what it already holds
self._audio_dropped.set()
now = time.monotonic()
if now - self._last_drop_warning >= AUDIO_DROP_WARN_INTERVAL:
self._last_drop_warning = now
logger.warning(
"Audio transcription queue for %s is full, dropping audio. The "
"provider is not keeping up with the %.2fs chunk rate",
self.camera_config.name,
AUDIO_DURATION,
)
try:
self.audio_queue.put_nowait((obj_data, audio))
except queue.Full:
pass
return None return None
def run(self) -> None: def run(self) -> None:
@@ -205,6 +370,14 @@ class AudioTranscriptionRealTimeProcessor(RealTimeProcessorApi):
break break
def reset(self) -> None: def reset(self) -> None:
if self._use_genai:
self._genai_committed = ""
# stale audio carried across an utterance boundary would be
# re-transcribed into the next one
self._genai_window.clear()
logger.debug("Stream reset")
return
if self.config.audio_transcription.model_size == "large": if self.config.audio_transcription.model_size == "large":
# get final output from whisper # get final output from whisper
output = self.stream.finish() output = self.stream.finish()
@@ -218,7 +391,7 @@ class AudioTranscriptionRealTimeProcessor(RealTimeProcessorApi):
# reset whisper # reset whisper
self.stream.init() self.stream.init()
self.transcription_segments = [] self.transcription_segments = []
else: elif self.model_runner is not None:
# reset sherpa # reset sherpa
self.model_runner.model.reset(self.stream) self.model_runner.model.reset(self.stream)
@@ -226,6 +399,24 @@ class AudioTranscriptionRealTimeProcessor(RealTimeProcessorApi):
def check_unload_model(self) -> None: def check_unload_model(self) -> None:
# regularly called in the loop in audio maintainer # regularly called in the loop in audio maintainer
if self._use_genai:
# no model to unload, but this is the hook that fires when
# live_enabled flips off. guard on emptiness: called ~1x/s per camera.
if self._genai_committed or self._genai_window:
logger.debug(
f"Clearing GenAI transcription state for {self.camera_config.name}"
)
self.clear_audio_queue()
self._genai_committed = ""
self._genai_window.clear()
self.requestor.send_data(
f"{self.camera_config.name}/audio/transcription",
"",
)
return
if ( if (
self.config.audio_transcription.model_size == "large" self.config.audio_transcription.model_size == "large"
and self.whisper_model is not None and self.whisper_model is not None
@@ -270,6 +461,10 @@ class AudioTranscriptionRealTimeProcessor(RealTimeProcessorApi):
self, topic: str, request_data: dict[str, Any] self, topic: str, request_data: dict[str, Any]
) -> dict[str, Any] | None: ) -> dict[str, Any] | None:
if topic == "clear_audio_recognizer": if topic == "clear_audio_recognizer":
if self._use_genai:
self.reset()
return {"message": "Audio transcription state cleared", "success": True}
self.stream = None self.stream = None
self.__build_recognizer() self.__build_recognizer()
return {"message": "Audio recognizer cleared and rebuilt", "success": True} return {"message": "Audio recognizer cleared and rebuilt", "success": True}
@@ -16,6 +16,7 @@ from frigate.config.classification import CustomClassificationConfig
from frigate.const import CLIPS_DIR, MODEL_CACHE_DIR from frigate.const import CLIPS_DIR, MODEL_CACHE_DIR
from frigate.log import suppress_stderr_during from frigate.log import suppress_stderr_during
from frigate.util.builtin import EventsPerSecond, InferenceSpeed, load_labels from frigate.util.builtin import EventsPerSecond, InferenceSpeed, load_labels
from frigate.util.file import trim_oldest_files
from frigate.util.image import calculate_region from frigate.util.image import calculate_region
from frigate.util.object import box_overlaps from frigate.util.object import box_overlaps
@@ -729,16 +730,4 @@ def write_classification_attempt(
file = os.path.join(folder, f"{event_id}-{timestamp}-{label}-{score}.webp") file = os.path.join(folder, f"{event_id}-{timestamp}-{label}-{score}.webp")
os.makedirs(folder, exist_ok=True) os.makedirs(folder, exist_ok=True)
cv2.imwrite(file, frame) cv2.imwrite(file, frame)
trim_oldest_files(folder, max_files)
# delete oldest face image if maximum is reached
try:
files = sorted(
filter(lambda f: f.endswith(".webp"), os.listdir(folder)),
key=lambda f: os.path.getctime(os.path.join(folder, f)),
reverse=True,
)
if len(files) > max_files:
os.unlink(os.path.join(folder, files[-1]))
except (FileNotFoundError, OSError):
pass
+2 -11
View File
@@ -6,7 +6,6 @@ import json
import logging import logging
import os import os
import shutil import shutil
from pathlib import Path
from typing import Any from typing import Any
import cv2 import cv2
@@ -28,6 +27,7 @@ from frigate.data_processing.common.face.recognizer import (
) )
from frigate.types import TrackedObjectUpdateTypesEnum from frigate.types import TrackedObjectUpdateTypesEnum
from frigate.util.builtin import EventsPerSecond, InferenceSpeed from frigate.util.builtin import EventsPerSecond, InferenceSpeed
from frigate.util.file import trim_oldest_files
from frigate.util.image import area from frigate.util.image import area
from frigate.util.path import safe_join, sanitize_path_component from frigate.util.path import safe_join, sanitize_path_component
@@ -489,13 +489,4 @@ class FaceRealTimeProcessor(RealTimeProcessorApi):
) )
os.makedirs(folder, exist_ok=True) os.makedirs(folder, exist_ok=True)
cv2.imwrite(file, frame) cv2.imwrite(file, frame)
trim_oldest_files(folder, self.config.face_recognition.save_attempts)
files = sorted(
filter(lambda f: f.endswith(".webp"), os.listdir(folder)),
key=lambda f: os.path.getctime(os.path.join(folder, f)),
reverse=True,
)
# delete oldest face image if maximum is reached
if len(files) > self.config.face_recognition.save_attempts:
Path(os.path.join(folder, files[-1])).unlink(missing_ok=True)
+37 -26
View File
@@ -247,15 +247,20 @@ class CudaGraphRunner(BaseModelRunner):
EnrichmentModelTypeEnum.yolov9_license_plate.value, EnrichmentModelTypeEnum.yolov9_license_plate.value,
] ]
# ORT performs two regular runs before it starts capturing, but on some
# driver / cuDNN combinations the arena still has to extend on the run that
# captures, and cudaMalloc is not allowed during capture. Running with
# capture disabled first keeps those allocations outside of the capture.
GRAPH_FREE_WARMUP_RUNS = 2
def __init__(self, session: ort.InferenceSession, cuda_device_id: int): def __init__(self, session: ort.InferenceSession, cuda_device_id: int):
self._session = session self._session = session
self._cuda_device_id = cuda_device_id self._cuda_device_id = cuda_device_id
self._captured = False self._prepared = False
self._io_binding: ort.IOBinding | None = None self._io_binding: ort.IOBinding | None = None
self._input_name: str | None = None self._input_name: str | None = None
self._output_names: list[str] | None = None self._output_names: list[str] | None = None
self._input_ortvalue: ort.OrtValue | None = None self._input_ortvalue: ort.OrtValue | None = None
self._output_ortvalues: ort.OrtValue | None = None
def get_input_names(self) -> list[str]: def get_input_names(self) -> list[str]:
"""Get input names for the model.""" """Get input names for the model."""
@@ -265,35 +270,41 @@ class CudaGraphRunner(BaseModelRunner):
"""Get the input width of the model.""" """Get the input width of the model."""
return self._session.get_inputs()[0].shape[3] return self._session.get_inputs()[0].shape[3]
def _prepare(self, input_name: str, tensor_input: np.ndarray) -> None:
"""Bind CUDA buffers and warm the session up with capture disabled."""
self._io_binding = self._session.io_binding()
self._input_name = input_name
self._output_names = [o.name for o in self._session.get_outputs()]
self._input_ortvalue = ort.OrtValue.ortvalue_from_numpy(
tensor_input, "cuda", self._cuda_device_id
)
self._io_binding.bind_ortvalue_input(self._input_name, self._input_ortvalue)
for name in self._output_names:
# Bind outputs to CUDA and allow ORT to allocate appropriately
self._io_binding.bind_output(name, "cuda", self._cuda_device_id)
# gpu_graph_id -1 disables capture and replay for the run
warmup_options = ort.RunOptions()
warmup_options.add_run_config_entry("gpu_graph_id", "-1")
for _ in range(self.GRAPH_FREE_WARMUP_RUNS):
self._session.run_with_iobinding(self._io_binding, warmup_options)
self._prepared = True
def run(self, input: dict[str, Any]): def run(self, input: dict[str, Any]):
# Extract the single tensor input (assuming one input) # Extract the single tensor input (assuming one input)
input_name = list(input.keys())[0] input_name = list(input.keys())[0]
tensor_input = input[input_name] tensor_input = np.ascontiguousarray(input[input_name])
tensor_input = np.ascontiguousarray(tensor_input)
if not self._captured: if not self._prepared:
# Prepare IOBinding with CUDA buffers and let ORT allocate outputs on device self._prepare(input_name, tensor_input)
self._io_binding = self._session.io_binding() else:
self._input_name = input_name # Replay using updated input
self._output_names = [o.name for o in self._session.get_outputs()] self._input_ortvalue.update_inplace(tensor_input)
self._input_ortvalue = ort.OrtValue.ortvalue_from_numpy(
tensor_input, "cuda", self._cuda_device_id
)
self._io_binding.bind_ortvalue_input(self._input_name, self._input_ortvalue)
for name in self._output_names:
# Bind outputs to CUDA and allow ORT to allocate appropriately
self._io_binding.bind_output(name, "cuda", self._cuda_device_id)
# First IOBinding run to allocate, execute, and capture CUDA Graph
ro = ort.RunOptions()
self._session.run_with_iobinding(self._io_binding, ro)
self._captured = True
return self._io_binding.copy_outputs_to_cpu()
# Replay using updated input, copy results to CPU
self._input_ortvalue.update_inplace(tensor_input)
ro = ort.RunOptions() ro = ort.RunOptions()
self._session.run_with_iobinding(self._io_binding, ro) self._session.run_with_iobinding(self._io_binding, ro)
return self._io_binding.copy_outputs_to_cpu() return self._io_binding.copy_outputs_to_cpu()
+8 -7
View File
@@ -3,14 +3,14 @@ import json
import logging import logging
import os import os
from enum import Enum from enum import Enum
from typing import Any, ClassVar from typing import ClassVar
import requests import requests
from pydantic import BaseModel, ConfigDict, Field from pydantic import BaseModel, ConfigDict, Field
from pydantic.fields import PrivateAttr from pydantic.fields import PrivateAttr
from frigate.const import DEFAULT_ATTRIBUTE_LABEL_MAP, MODEL_CACHE_DIR from frigate.const import DEFAULT_ATTRIBUTE_LABEL_MAP, MODEL_CACHE_DIR
from frigate.plus import PlusApi from frigate.plus import PlusApi, load_plus_model_info
from frigate.util.builtin import generate_color_palette, load_labels from frigate.util.builtin import generate_color_palette, load_labels
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -190,12 +190,13 @@ class ModelConfig(BaseModel):
# download the model info if it doesn't exist # download the model info if it doesn't exist
if not os.path.isfile(model_info_path): if not os.path.isfile(model_info_path):
model_info = plus_api.get_model_info(model_id)
with open(model_info_path, "w") as f: with open(model_info_path, "w") as f:
json.dump(model_info, f) json.dump(plus_api.get_model_info(model_id), f)
else:
with open(model_info_path) as f: model_info = load_plus_model_info(model_id)
model_info: dict[str, Any] = json.load(f)
if model_info is None:
raise ValueError(f"Unable to read the model info for {model_id}")
if detector and detector not in model_info["supportedDetectors"]: if detector and detector not in model_info["supportedDetectors"]:
raise ValueError(f"Model does not support detector type of {detector}") raise ValueError(f"Model does not support detector type of {detector}")
+13 -2
View File
@@ -259,8 +259,8 @@ def detect_hailo() -> DetectionHardware | None:
# the hailo runtime schedules across every attached device itself, so there # the hailo runtime schedules across every attached device itself, so there
# is nothing to address individually # is nothing to address individually
units = [HardwareUnit(device="hailo8l:PCIe", label=os.path.basename(nodes[0]))] units = [HardwareUnit(device="hailo:PCIe", label=os.path.basename(nodes[0]))]
return _hardware("hailo8l", "hailo8l", "Hailo", units) return _hardware("hailo", "hailo", "Hailo", units)
def detect_memryx() -> DetectionHardware | None: def detect_memryx() -> DetectionHardware | None:
@@ -273,6 +273,16 @@ def detect_memryx() -> DetectionHardware | None:
return _hardware("memryx", "memryx", "MemryX MX3", units) return _hardware("memryx", "memryx", "MemryX MX3", units)
def detect_deepx() -> DetectionHardware | None:
"""Find DEEPX NPUs by their device nodes."""
units = _dev_units("dxrt*", "deepx:PCIe:{index}", "PCIe")
if not units:
return None
return _hardware("deepx", "deepx", "DEEPX NPU", units)
def detect_rockchip() -> DetectionHardware | None: def detect_rockchip() -> DetectionHardware | None:
"""Find a Rockchip NPU by reading the SoC from the device tree.""" """Find a Rockchip NPU by reading the SoC from the device tree."""
compatible = _read(f"{PROC_ROOT}/device-tree/compatible") compatible = _read(f"{PROC_ROOT}/device-tree/compatible")
@@ -319,6 +329,7 @@ PROBES = (
detect_coral_usb, detect_coral_usb,
detect_hailo, detect_hailo,
detect_memryx, detect_memryx,
detect_deepx,
detect_intel_npu, detect_intel_npu,
detect_intel_gpu, detect_intel_gpu,
detect_nvidia_gpu, detect_nvidia_gpu,
-105
View File
@@ -1,105 +0,0 @@
import io
import logging
from typing import Literal
import numpy as np
import requests
from PIL import Image
from pydantic import ConfigDict, Field
from frigate.detectors.detection_api import DetectionApi
from frigate.detectors.detector_config import BaseDetectorConfig
logger = logging.getLogger(__name__)
DETECTOR_KEY = "deepstack"
class DeepstackDetectorConfig(BaseDetectorConfig):
"""DeepStack/CodeProject.AI detector that sends images to a remote DeepStack HTTP API for inference. Not recommended."""
model_config = ConfigDict(
title="DeepStack",
)
type: Literal[DETECTOR_KEY]
api_url: str = Field(
default="http://localhost:80/v1/vision/detection",
title="DeepStack API URL",
description="The URL of the DeepStack API.",
)
api_timeout: float = Field(
default=0.1,
title="DeepStack API timeout (in seconds)",
description="Maximum time allowed for a DeepStack API request.",
)
api_key: str = Field(
default="",
title="DeepStack API key (if required)",
description="Optional API key for authenticated DeepStack services.",
)
class DeepStack(DetectionApi):
type_key = DETECTOR_KEY
def __init__(self, detector_config: DeepstackDetectorConfig):
self.api_url = detector_config.api_url
self.api_timeout = detector_config.api_timeout
self.api_key = detector_config.api_key
self.labels = detector_config.model.merged_labelmap
self.session = requests.Session()
def get_label_index(self, label_value):
if label_value.lower() == "truck":
label_value = "car"
for index, value in self.labels.items():
if value == label_value.lower():
return index
return -1
def detect_raw(self, tensor_input):
image_data = np.squeeze(tensor_input).astype(np.uint8)
image = Image.fromarray(image_data)
self.w, self.h = image.size
with io.BytesIO() as output:
image.save(output, format="JPEG")
image_bytes = output.getvalue()
data = {"api_key": self.api_key}
try:
response = self.session.post(
self.api_url,
data=data,
files={"image": image_bytes},
timeout=self.api_timeout,
)
except requests.exceptions.RequestException as ex:
logger.error("Error calling deepstack API: %s", ex)
return np.zeros((20, 6), np.float32)
response_json = response.json()
detections = np.zeros((20, 6), np.float32)
if response_json.get("predictions") is None:
logger.debug(f"Error in parsing response json: {response_json}")
return detections
for i, detection in enumerate(response_json.get("predictions")):
logger.debug(f"Response: {detection}")
if detection["confidence"] < 0.4:
logger.debug("Break due to confidence < 0.4")
break
label = self.get_label_index(detection["label"])
if label < 0:
logger.debug("Break due to unknown label")
break
detections[i] = [
label,
float(detection["confidence"]),
detection["y_min"] / self.h,
detection["x_min"] / self.w,
detection["y_max"] / self.h,
detection["x_max"] / self.w,
]
return detections
File diff suppressed because it is too large Load Diff
@@ -53,7 +53,7 @@ def preprocess_tensor(image: np.ndarray, model_w: int, model_h: int) -> np.ndarr
# ----------------- Global Constants ----------------- # # ----------------- Global Constants ----------------- #
DETECTOR_KEY = "hailo8l" DETECTOR_KEY = "hailo"
ARCH = None ARCH = None
H8_DEFAULT_MODEL = "yolov6n.hef" H8_DEFAULT_MODEL = "yolov6n.hef"
H8L_DEFAULT_MODEL = "yolov6n.hef" H8L_DEFAULT_MODEL = "yolov6n.hef"
@@ -469,10 +469,10 @@ class HailoDetector(DetectionApi):
# ----------------- HailoDetectorConfig Class ----------------- # # ----------------- HailoDetectorConfig Class ----------------- #
class HailoDetectorConfig(BaseDetectorConfig): class HailoDetectorConfig(BaseDetectorConfig):
"""Hailo-8/Hailo-8L detector using HEF models and the HailoRT SDK for inference on Hailo hardware.""" """Hailo detector using HEF models and the HailoRT SDK for inference on Hailo hardware."""
model_config = ConfigDict( model_config = ConfigDict(
title="Hailo-8/Hailo-8L", title="Hailo",
) )
type: Literal[DETECTOR_KEY] type: Literal[DETECTOR_KEY]
+7 -3
View File
@@ -68,7 +68,7 @@ from frigate.events.types import (
RegenerateDescriptionEnum, RegenerateDescriptionEnum,
) )
from frigate.genai import GenAIClientManager from frigate.genai import GenAIClientManager
from frigate.models import Event, Recordings, ReviewSegment, Trigger from frigate.models import Event, Recordings, ReviewSegment, Timeline, Trigger
from frigate.types import TrackedObjectUpdateTypesEnum from frigate.types import TrackedObjectUpdateTypesEnum
from frigate.util.builtin import serialize from frigate.util.builtin import serialize
from frigate.util.file import get_event_thumbnail_bytes from frigate.util.file import get_event_thumbnail_bytes
@@ -139,7 +139,7 @@ class EmbeddingMaintainer(threading.Thread):
), ),
load_vec_extension=True, load_vec_extension=True,
) )
models = [Event, Recordings, ReviewSegment, Trigger] models = [Event, Recordings, ReviewSegment, Timeline, Trigger]
db.bind(models) db.bind(models)
self.genai_manager = GenAIClientManager(config) self.genai_manager = GenAIClientManager(config)
@@ -251,7 +251,11 @@ class EmbeddingMaintainer(threading.Thread):
): ):
self.post_processors.append( self.post_processors.append(
AudioTranscriptionPostProcessor( AudioTranscriptionPostProcessor(
self.config, self.requestor, self.embeddings, metrics self.config,
self.requestor,
self.embeddings,
metrics,
self.genai_manager,
) )
) )
+71 -38
View File
@@ -11,6 +11,7 @@ from typing import Any
import numpy as np import numpy as np
from frigate.camera import CameraMetrics
from frigate.comms.detections_updater import DetectionPublisher, DetectionTypeEnum from frigate.comms.detections_updater import DetectionPublisher, DetectionTypeEnum
from frigate.comms.inter_process import InterProcessRequestor from frigate.comms.inter_process import InterProcessRequestor
from frigate.config import CameraConfig, CameraInput, FrigateConfig from frigate.config import CameraConfig, CameraInput, FrigateConfig
@@ -19,6 +20,7 @@ from frigate.config.camera.updater import (
CameraConfigUpdateEnum, CameraConfigUpdateEnum,
CameraConfigUpdateSubscriber, CameraConfigUpdateSubscriber,
) )
from frigate.config.classification import AudioTranscriptionModelEnum
from frigate.const import ( from frigate.const import (
AUDIO_DURATION, AUDIO_DURATION,
AUDIO_FORMAT, AUDIO_FORMAT,
@@ -35,6 +37,7 @@ from frigate.data_processing.common.audio_transcription.model import (
from frigate.data_processing.real_time.audio_transcription import ( from frigate.data_processing.real_time.audio_transcription import (
AudioTranscriptionRealTimeProcessor, AudioTranscriptionRealTimeProcessor,
) )
from frigate.data_processing.types import DataProcessorMetrics
from frigate.ffmpeg_presets import parse_preset_input from frigate.ffmpeg_presets import parse_preset_input
from frigate.log import LogPipe, suppress_stderr_during from frigate.log import LogPipe, suppress_stderr_during
from frigate.util.builtin import get_ffmpeg_arg_list, load_labels from frigate.util.builtin import get_ffmpeg_arg_list, load_labels
@@ -85,6 +88,7 @@ class AudioProcessor(FrigateProcess):
self, self,
config: FrigateConfig, config: FrigateConfig,
camera_metrics: DictProxy, camera_metrics: DictProxy,
embeddings_metrics: DataProcessorMetrics,
stop_event: MpEvent, stop_event: MpEvent,
): ):
super().__init__( super().__init__(
@@ -92,8 +96,38 @@ class AudioProcessor(FrigateProcess):
) )
self.camera_metrics = camera_metrics self.camera_metrics = camera_metrics
self.embeddings_metrics = embeddings_metrics
self.config = config self.config = config
def spawn_if_needed(self, camera: CameraConfig) -> None:
"""Start an audio maintainer for the camera once everything it needs
has arrived. Returning early leaves the camera for the next poll."""
name = camera.name
if name is None or name in self.audio_threads:
return
if not camera.enabled or not camera.audio.enabled:
return
# ffmpeg update may not have arrived yet
if not any("audio" in i.roles for i in camera.ffmpeg.inputs):
return
# the camera maintainer creates metrics on its own poll of the same
# add update and may not have gotten there yet
metrics = self.camera_metrics.get(name)
if metrics is None:
return
thread = AudioEventMaintainer(
camera,
self.config,
metrics,
self.embeddings_metrics,
self.transcription_model_runner,
self.stop_event, # type: ignore[arg-type]
self.genai_manager,
)
self.audio_threads[name] = thread
thread.start()
self.logger.info(f"Audio maintainer started for {name}")
def __stop_audio_thread(self, camera: str) -> None: def __stop_audio_thread(self, camera: str) -> None:
thread = self.audio_threads.pop(camera, None) thread = self.audio_threads.pop(camera, None)
if thread is None: if thread is None:
@@ -112,18 +146,31 @@ class AudioProcessor(FrigateProcess):
threading.current_thread().name = "process:audio_manager" threading.current_thread().name = "process:audio_manager"
self.transcription_model_runner: AudioTranscriptionModelRunner | None = None
self.genai_manager: Any = None
if any( if any(
c.enabled_in_config and c.audio_transcription.enabled c.enabled_in_config and c.audio_transcription.enabled
for c in self.config.cameras.values() for c in self.config.cameras.values()
): ):
self.transcription_model_runner: AudioTranscriptionModelRunner | None = ( if isinstance(
AudioTranscriptionModelRunner( self.config.audio_transcription.model, AudioTranscriptionModelEnum
):
# AudioTranscriptionModelRunner.__init__ unconditionally fetches
# sherpa-onnx or whisper weights, so only build it on the local path
self.transcription_model_runner = AudioTranscriptionModelRunner(
self.config.audio_transcription.device or "AUTO", self.config.audio_transcription.device or "AUTO",
self.config.audio_transcription.model_size, self.config.audio_transcription.model_size,
) )
) else:
else: # imported here rather than at module scope: frigate.genai pulls in
self.transcription_model_runner = None # numpy, the provider SDKs, frigate.models, and the prompt builders,
# and this process runs at PROCESS_PRIORITY_HIGH. built after the
# fork because SDK clients hold sockets and TLS state that must not
# cross it; clients themselves stay lazy behind the role property.
from frigate.genai.manager import GenAIClientManager
self.genai_manager = GenAIClientManager(self.config)
config_subscriber = CameraConfigUpdateSubscriber( config_subscriber = CameraConfigUpdateSubscriber(
self.config, self.config,
@@ -136,28 +183,8 @@ class AudioProcessor(FrigateProcess):
], ],
) )
def spawn_if_needed(camera: CameraConfig) -> None:
name = camera.name
if name is None or name in self.audio_threads:
return
if not camera.enabled or not camera.audio.enabled:
return
# ffmpeg update may not have arrived yet; wait for next poll
if not any("audio" in i.roles for i in camera.ffmpeg.inputs):
return
thread = AudioEventMaintainer(
camera,
self.config,
self.camera_metrics,
self.transcription_model_runner,
self.stop_event, # type: ignore[arg-type]
)
self.audio_threads[name] = thread
thread.start()
self.logger.info(f"Audio maintainer started for {name}")
for camera in self.config.cameras.values(): for camera in self.config.cameras.values():
spawn_if_needed(camera) self.spawn_if_needed(camera)
self.logger.info(f"Audio processor started (pid: {self.pid})") self.logger.info(f"Audio processor started (pid: {self.pid})")
@@ -167,15 +194,14 @@ class AudioProcessor(FrigateProcess):
updated_topics = config_subscriber.check_for_updates() updated_topics = config_subscriber.check_for_updates()
# stop maintainers for removed cameras so their ffmpeg process is # stop maintainers for removed cameras so their ffmpeg process is
# torn down and they stop touching camera_metrics (which the camera # torn down
# maintainer has already popped for the removed camera)
for removed_camera in updated_topics.get( for removed_camera in updated_topics.get(
CameraConfigUpdateEnum.remove.name, [] CameraConfigUpdateEnum.remove.name, []
): ):
self.__stop_audio_thread(removed_camera) self.__stop_audio_thread(removed_camera)
for camera in self.config.cameras.values(): for camera in self.config.cameras.values():
spawn_if_needed(camera) self.spawn_if_needed(camera)
config_subscriber.stop() config_subscriber.stop()
@@ -197,15 +223,21 @@ class AudioEventMaintainer(threading.Thread):
self, self,
camera: CameraConfig, camera: CameraConfig,
config: FrigateConfig, config: FrigateConfig,
camera_metrics: DictProxy, metrics: CameraMetrics,
embeddings_metrics: DataProcessorMetrics,
audio_transcription_model_runner: AudioTranscriptionModelRunner | None, audio_transcription_model_runner: AudioTranscriptionModelRunner | None,
stop_event: threading.Event, stop_event: threading.Event,
genai_manager: Any = None,
) -> None: ) -> None:
super().__init__(name=f"{camera.name}_audio_event_processor") super().__init__(name=f"{camera.name}_audio_event_processor")
self.config = config self.config = config
self.camera_config = camera self.camera_config = camera
self.camera_metrics = camera_metrics # hold the metrics object rather than indexing the manager dict per
# chunk, which costs an IPC round trip and breaks once the camera
# maintainer pops the entry on removal
self.metrics = metrics
self.embeddings_metrics = embeddings_metrics
self.stop_event = stop_event self.stop_event = stop_event
# per-camera stop signal so a single maintainer can be torn down at # per-camera stop signal so a single maintainer can be torn down at
# runtime (e.g. on camera removal) without stopping the whole process # runtime (e.g. on camera removal) without stopping the whole process
@@ -222,6 +254,7 @@ class AudioEventMaintainer(threading.Thread):
self.logpipe = LogPipe(f"ffmpeg.{self.camera_config.name}.audio") self.logpipe = LogPipe(f"ffmpeg.{self.camera_config.name}.audio")
self.audio_listener: subprocess.Popen[Any] | None = None self.audio_listener: subprocess.Popen[Any] | None = None
self.audio_transcription_model_runner = audio_transcription_model_runner self.audio_transcription_model_runner = audio_transcription_model_runner
self.genai_manager = genai_manager
self.transcription_processor = None self.transcription_processor = None
self.transcription_thread = None self.transcription_thread = None
@@ -238,9 +271,9 @@ class AudioEventMaintainer(threading.Thread):
) )
self.detection_publisher = DetectionPublisher(DetectionTypeEnum.audio.value) self.detection_publisher = DetectionPublisher(DetectionTypeEnum.audio.value)
if ( if self.camera_config.audio_transcription.enabled and (
self.camera_config.audio_transcription.enabled self.audio_transcription_model_runner is not None
and self.audio_transcription_model_runner is not None or self.genai_manager is not None
): ):
# init the transcription processor for this camera # init the transcription processor for this camera
self.transcription_processor = AudioTranscriptionRealTimeProcessor( self.transcription_processor = AudioTranscriptionRealTimeProcessor(
@@ -248,8 +281,9 @@ class AudioEventMaintainer(threading.Thread):
camera_config=self.camera_config, camera_config=self.camera_config,
requestor=self.requestor, requestor=self.requestor,
model_runner=self.audio_transcription_model_runner, model_runner=self.audio_transcription_model_runner,
metrics=self.camera_metrics[self.camera_config.name], metrics=self.embeddings_metrics,
stop_event=self.stop_event, stop_event=self.stop_event,
genai_manager=self.genai_manager,
) )
self.transcription_thread = threading.Thread( self.transcription_thread = threading.Thread(
@@ -273,8 +307,8 @@ class AudioEventMaintainer(threading.Thread):
audio_as_float: np.ndarray = audio.astype(np.float32) audio_as_float: np.ndarray = audio.astype(np.float32)
rms, dBFS = self.calculate_audio_levels(audio_as_float) rms, dBFS = self.calculate_audio_levels(audio_as_float)
self.camera_metrics[self.camera_config.name].audio_rms.value = rms self.metrics.audio_rms.value = rms
self.camera_metrics[self.camera_config.name].audio_dBFS.value = dBFS self.metrics.audio_dBFS.value = dBFS
audio_detections: list[tuple[str, float]] = [] audio_detections: list[tuple[str, float]] = []
@@ -359,7 +393,6 @@ class AudioEventMaintainer(threading.Thread):
return return
time.sleep(self.camera_config.ffmpeg.retry_interval) time.sleep(self.camera_config.ffmpeg.retry_interval)
self.logpipe.dump()
self.start_or_restart_ffmpeg() self.start_or_restart_ffmpeg()
if self.audio_listener is None or self.audio_listener.stdout is None: if self.audio_listener is None or self.audio_listener.stdout is None:
+5 -5
View File
@@ -37,7 +37,7 @@ class EventCleanup(threading.Thread):
if self.removed_camera_labels is None: if self.removed_camera_labels is None:
self.removed_camera_labels = list( self.removed_camera_labels = list(
Event.select(Event.label) Event.select(Event.label)
.where(Event.camera.not_in(self.camera_keys)) # type: ignore[arg-type,call-arg,misc] .where(Event.camera.not_in(self.camera_keys))
.distinct() .distinct()
.execute() .execute()
) )
@@ -89,7 +89,7 @@ class EventCleanup(threading.Thread):
Event.thumbnail, Event.thumbnail,
) )
.where( .where(
Event.camera.not_in(self.camera_keys), # type: ignore[arg-type,call-arg,misc] Event.camera.not_in(self.camera_keys),
Event.start_time < expire_after, Event.start_time < expire_after,
Event.label == event.label, Event.label == event.label,
Event.retain_indefinitely == False, Event.retain_indefinitely == False,
@@ -111,7 +111,7 @@ class EventCleanup(threading.Thread):
# update the clips attribute for the db entry # update the clips attribute for the db entry
query = Event.select(Event.id).where( query = Event.select(Event.id).where(
Event.camera.not_in(self.camera_keys), # type: ignore[arg-type,call-arg,misc] Event.camera.not_in(self.camera_keys),
Event.start_time < expire_after, Event.start_time < expire_after,
Event.label == event.label, Event.label == event.label,
Event.retain_indefinitely == False, Event.retain_indefinitely == False,
@@ -218,7 +218,7 @@ class EventCleanup(threading.Thread):
Event.camera, Event.camera,
) )
.where( .where(
Event.camera.not_in(self.camera_keys), # type: ignore[arg-type,call-arg,misc] Event.camera.not_in(self.camera_keys),
Event.start_time < expire_after, Event.start_time < expire_after,
Event.retain_indefinitely == False, Event.retain_indefinitely == False,
) )
@@ -249,7 +249,7 @@ class EventCleanup(threading.Thread):
# update the clips attribute for the db entry # update the clips attribute for the db entry
query = Event.select(Event.id).where( query = Event.select(Event.id).where(
Event.camera.not_in(self.camera_keys), # type: ignore[arg-type,call-arg,misc] Event.camera.not_in(self.camera_keys),
Event.start_time < expire_after, Event.start_time < expire_after,
Event.retain_indefinitely == False, Event.retain_indefinitely == False,
) )
+89 -2
View File
@@ -105,8 +105,21 @@ class GenAIClient:
debug_save: bool, debug_save: bool,
activity_context_prompt: str, activity_context_prompt: str,
response_style: str = "default", response_style: str = "default",
frame_captions: list[str] | None = None,
) -> ReviewMetadata | None: ) -> ReviewMetadata | None:
"""Generate a description for the review item activity.""" """Generate a description for the review item activity.
`frame_captions` holds one caption per thumbnail for the annotated
frame mode; each is sent directly before its frame.
"""
if frame_captions and len(frame_captions) != len(thumbnails):
logger.warning(
"Got %d frame captions for %d thumbnails, sending plain frames",
len(frame_captions),
len(thumbnails),
)
frame_captions = None
context_prompt = build_review_description_prompt( context_prompt = build_review_description_prompt(
review_data, review_data,
thumbnails, thumbnails,
@@ -114,6 +127,7 @@ class GenAIClient:
preferred_language, preferred_language,
activity_context_prompt, activity_context_prompt,
response_style, response_style,
frame_captions,
) )
logger.debug( logger.debug(
@@ -129,9 +143,30 @@ class GenAIClient:
) as f: ) as f:
f.write(context_prompt) f.write(context_prompt)
if frame_captions:
# One file per frame, numbered to match the image it precedes
# (0.txt goes with 0.jpg), so the debug folder replays without
# having to re-derive the mapping.
for index, caption in enumerate(frame_captions):
with open(
os.path.join(
CLIPS_DIR,
"genai-requests",
review_data["id"],
f"{index}.txt",
),
"w",
) as f:
f.write(caption)
response_format = build_review_description_response_format(concerns) response_format = build_review_description_response_format(concerns)
response = self._send(context_prompt, thumbnails, response_format) response = self._send(
context_prompt,
thumbnails,
response_format,
image_captions=frame_captions,
)
if debug_save and response: if debug_save and response:
with open( with open(
@@ -269,6 +304,7 @@ class GenAIClient:
images: list[bytes], images: list[bytes],
response_format: dict | None = None, response_format: dict | None = None,
enable_thinking: bool = False, enable_thinking: bool = False,
image_captions: list[str] | None = None,
) -> str | None: ) -> str | None:
"""Submit a request to the provider. """Submit a request to the provider.
@@ -276,6 +312,10 @@ class GenAIClient:
``supports_toggleable_thinking``. Description-style callers leave it ``supports_toggleable_thinking``. Description-style callers leave it
at the default (off) since synthesis tasks don't benefit from at the default (off) since synthesis tasks don't benefit from
reasoning traces. reasoning traces.
``image_captions`` carries one caption per image, to be placed
immediately before its image so the model can tell the frames apart.
Providers build their request order with ``interleave_images``.
""" """
return None return None
@@ -298,6 +338,11 @@ class GenAIClient:
"""Whether the configured model can generate embeddings via embed().""" """Whether the configured model can generate embeddings via embed()."""
return False return False
@property
def supports_transcription(self) -> bool:
"""Whether the configured model can transcribe audio via transcribe()."""
return False
def list_models(self) -> list[str]: def list_models(self) -> list[str]:
"""Return the list of model names available from this provider. """Return the list of model names available from this provider.
@@ -305,6 +350,21 @@ class GenAIClient:
""" """
return [] return []
def list_model_capabilities(self) -> dict[str, dict[str, bool]]:
"""Return capability flags for each model the provider serves.
Only providers whose backend advertises capabilities per model can
populate this; llama.cpp reports input modalities for every model it
serves, so one request describes them all. An empty mapping means "no
per-model information available", and callers fall back to this
client's own capability properties, which describe only the configured
model. A model absent from a non-empty mapping means the same thing.
Returns:
Model name (including aliases) to its capability flags
"""
return {}
def get_context_size(self) -> int: def get_context_size(self) -> int:
"""Get the context window size for this provider in tokens.""" """Get the context window size for this provider in tokens."""
return 4096 return 4096
@@ -336,6 +396,33 @@ class GenAIClient:
) )
return [] return []
def transcribe(
self,
audio: bytes,
language: str | None = None,
mime_type: str = "audio/wav",
) -> str | None:
"""Transcribe speech audio to text.
Audio is passed as a self-describing blob rather than raw samples so
every provider receives a container it can declare, and WAV framing
lives in one place instead of in each plugin.
Args:
audio: The encoded audio payload (WAV bytes by default)
language: Optional ISO language hint for the provider
mime_type: Media type of ``audio``
Returns:
The transcript, or None when the provider cannot produce one
"""
logger.warning(
"%s does not support transcription. "
"This method should be overridden by the provider implementation.",
self.__class__.__name__,
)
return None
def chat_with_tools( def chat_with_tools(
self, self,
messages: list[dict[str, Any]], messages: list[dict[str, Any]],
+12
View File
@@ -110,6 +110,12 @@ class GenAIClientManager:
name = self._role_map.get(GenAIRoleEnum.embeddings) name = self._role_map.get(GenAIRoleEnum.embeddings)
return self._get_client(name) if name else None return self._get_client(name) if name else None
@property
def transcribe_client(self) -> "GenAIClient | None":
"""Client configured for the transcribe role."""
name = self._role_map.get(GenAIRoleEnum.transcribe)
return self._get_client(name) if name else None
def role_info(self) -> dict[str, dict[str, Any]]: def role_info(self) -> dict[str, dict[str, Any]]:
"""Return the model selected for each configured role and its context size. """Return the model selected for each configured role and its context size.
@@ -144,5 +150,11 @@ class GenAIClientManager:
"roles": [r.value for r in genai_cfg.roles], "roles": [r.value for r in genai_cfg.roles],
"supports_toggleable_thinking": client.supports_toggleable_thinking, "supports_toggleable_thinking": client.supports_toggleable_thinking,
"supports_embeddings": client.supports_embeddings, "supports_embeddings": client.supports_embeddings,
"supports_transcription": client.supports_transcription,
# Capabilities of the configured model are above; this maps every
# model the provider serves to its own, so the UI can react to a
# model selected but not yet saved. Empty when the provider
# cannot report capabilities without loading a model.
"model_capabilities": client.list_model_capabilities(),
} }
return result return result
+13
View File
@@ -13,6 +13,19 @@ overrides what is genuinely Azure-specific:
- Context size: Azure does not expose a per-model ``max_model_len`` field - Context size: Azure does not expose a per-model ``max_model_len`` field
reliably, so we keep the historical 128K default rather than the reliably, so we keep the historical 128K default rather than the
model-name heuristic used by OpenAI. model-name heuristic used by OpenAI.
Transcription is inherited too: :class:`openai.AzureOpenAI` exposes the same
``audio.transcriptions.create``. Two Azure-specific caveats apply when using
the ``transcribe`` role:
- ``model`` must be the Azure *deployment* name, not the underlying model name.
- The ``api-version`` parsed from ``base_url`` must be 2024-06-01 or later;
earlier versions have no transcriptions route and the 404 surfaces only as a
generic provider error.
- Because ``model`` is a deployment name, the inherited check that picks
``languages`` over ``language`` for gpt-transcribe cannot fire unless the
deployment happens to be named after the model. Name the deployment
``gpt-transcribe`` to get the right field, or leave the language on ``auto``.
""" """
import logging import logging

Some files were not shown because too many files have changed in this diff Show More