Compare commits

..

19 Commits

Author SHA1 Message Date
Hosted Weblate
84105be5e9
Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (128 of 128 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (119 of 119 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (40 of 40 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (72 of 72 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (639 of 639 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (52 of 52 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (116 of 116 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (55 of 55 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (128 of 128 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 100.0% (48 of 48 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/components-dialog/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-filter/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/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/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/nb_NO/
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-filter
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-search
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2025-12-04 06:08:22 +01:00
Hosted Weblate
27ed1ad4e1
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (130 of 130 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (55 of 55 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (40 of 40 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (128 of 128 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (128 of 128 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (92 of 92 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (119 of 119 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/components-dialog/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/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-explore/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/zh_Hans/
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-live
Translation: Frigate NVR/views-system
2025-12-04 06:08:21 +01:00
Hosted Weblate
d7200fec4c
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 92.3% (85 of 92 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 44.5% (53 of 119 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 44.5% (53 of 119 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (52 of 52 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% (48 of 48 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (2 of 2 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (214 of 214 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (40 of 40 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 15.7% (79 of 501 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (13 of 13 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 11.8% (76 of 639 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 92.1% (118 of 128 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 98.1% (54 of 55 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 85.3% (111 of 130 strings)

Co-authored-by: Ban <3637117+Ban921@users.noreply.github.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Yu Chun Huang <yujun@bo2.tw>
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-dialog/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-input/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-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-exports/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-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/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-auth
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-input
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-search
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2025-12-04 06:08:20 +01:00
Hosted Weblate
ace71505ca
Translated using Weblate (Slovak)
Currently translated at 100.0% (116 of 116 strings)

Translated using Weblate (Slovak)

Currently translated at 100.0% (55 of 55 strings)

Translated using Weblate (Slovak)

Currently translated at 100.0% (128 of 128 strings)

Translated using Weblate (Slovak)

Currently translated at 100.0% (501 of 501 strings)

Translated using Weblate (Slovak)

Currently translated at 100.0% (214 of 214 strings)

Translated using Weblate (Slovak)

Currently translated at 100.0% (52 of 52 strings)

Translated using Weblate (Slovak)

Currently translated at 100.0% (639 of 639 strings)

Translated using Weblate (Slovak)

Currently translated at 100.0% (128 of 128 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Jakub K <klacanjakub0@gmail.com>
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-dialog/sk/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/sk/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/sk/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/sk/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/sk/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/sk/
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-explore
Translation: Frigate NVR/views-facelibrary
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2025-12-04 06:08:18 +01:00
Hosted Weblate
52717b62de
Translated using Weblate (Swedish)
Currently translated at 100.0% (118 of 118 strings)

Translated using Weblate (Swedish)

Currently translated at 100.0% (40 of 40 strings)

Translated using Weblate (Swedish)

Currently translated at 100.0% (128 of 128 strings)

Translated using Weblate (Swedish)

Currently translated at 98.3% (117 of 119 strings)

Translated using Weblate (Swedish)

Currently translated at 100.0% (55 of 55 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/components-dialog/sv/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/sv/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/sv/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/sv/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/sv/
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
2025-12-04 06:08:17 +01:00
Hosted Weblate
3faefa5db2
Translated using Weblate (French)
Currently translated at 100.0% (130 of 130 strings)

Translated using Weblate (French)

Currently translated at 100.0% (119 of 119 strings)

Translated using Weblate (French)

Currently translated at 100.0% (40 of 40 strings)

Translated using Weblate (French)

Currently translated at 100.0% (55 of 55 strings)

Translated using Weblate (French)

Currently translated at 100.0% (128 of 128 strings)

Co-authored-by: Apocoloquintose <bertrand.moreux@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/fr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/fr/
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
2025-12-04 06:08:15 +01:00
Hosted Weblate
09b3f3cf66
Translated using Weblate (Spanish)
Currently translated at 90.2% (83 of 92 strings)

Co-authored-by: Hernán Rossetto <hmronline@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/es/
Translation: Frigate NVR/views-live
2025-12-04 06:08:14 +01:00
Hosted Weblate
06e72454bd
Translated using Weblate (Dutch)
Currently translated at 100.0% (130 of 130 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (40 of 40 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (119 of 119 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (55 of 55 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (128 of 128 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Marijn <168113859+Marijn0@users.noreply.github.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/nl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/nl/
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
2025-12-04 06:08:13 +01:00
Hosted Weblate
bde3b5d6db
Translated using Weblate (Italian)
Currently translated at 100.0% (128 of 128 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (40 of 40 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (119 of 119 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (55 of 55 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/components-dialog/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/it/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/it/
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
2025-12-04 06:08:12 +01:00
Hosted Weblate
eb9758583a
Translated using Weblate (Polish)
Currently translated at 89.2% (570 of 639 strings)

Translated using Weblate (Polish)

Currently translated at 92.9% (119 of 128 strings)

Translated using Weblate (Polish)

Currently translated at 98.1% (210 of 214 strings)

Translated using Weblate (Polish)

Currently translated at 85.4% (546 of 639 strings)

Translated using Weblate (Polish)

Currently translated at 95.0% (38 of 40 strings)

Translated using Weblate (Polish)

Currently translated at 83.5% (107 of 128 strings)

Translated using Weblate (Polish)

Currently translated at 98.0% (51 of 52 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (92 of 92 strings)

Translated using Weblate (Polish)

Currently translated at 37.8% (45 of 119 strings)

Co-authored-by: Bartlomiej Puls <bartlomiej.puls@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: piesu <dogiiee@proton.me>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/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-explore/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-settings/pl/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/pl/
Translation: Frigate NVR/common
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-settings
Translation: Frigate NVR/views-system
2025-12-04 06:08:11 +01:00
Hosted Weblate
364e1620b6
Translated using Weblate (Czech)
Currently translated at 63.2% (404 of 639 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Martin Brož <code@martin-broz.cz>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/cs/
Translation: Frigate NVR/views-settings
2025-12-04 06:08:09 +01:00
Hosted Weblate
c98d3a1aaf
Translated using Weblate (Catalan)
Currently translated at 100.0% (130 of 130 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (40 of 40 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (119 of 119 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (128 of 128 strings)

Translated using Weblate (Catalan)

Currently translated at 100.0% (55 of 55 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/components-dialog/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/ca/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/ca/
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
2025-12-04 06:08:08 +01:00
Hosted Weblate
0bcf171299
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (130 of 130 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (40 of 40 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (119 of 119 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (55 of 55 strings)

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (128 of 128 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Максим Горпиніч <gorpinicmaksim0@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/uk/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/uk/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/uk/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/uk/
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
2025-12-04 06:08:07 +01:00
Hosted Weblate
db886f85e7
Translated using Weblate (Bulgarian)
Currently translated at 100.0% (2 of 2 strings)

Translated using Weblate (Bulgarian)

Currently translated at 9.0% (5 of 55 strings)

Translated using Weblate (Bulgarian)

Currently translated at 0.7% (5 of 639 strings)

Translated using Weblate (Bulgarian)

Currently translated at 15.3% (2 of 13 strings)

Translated using Weblate (Bulgarian)

Currently translated at 31.5% (29 of 92 strings)

Translated using Weblate (Bulgarian)

Currently translated at 2.3% (3 of 128 strings)

Translated using Weblate (Bulgarian)

Currently translated at 20.0% (2 of 10 strings)

Translated using Weblate (Bulgarian)

Currently translated at 9.6% (5 of 52 strings)

Translated using Weblate (Bulgarian)

Currently translated at 22.5% (9 of 40 strings)

Translated using Weblate (Bulgarian)

Currently translated at 20.0% (2 of 10 strings)

Translated using Weblate (Bulgarian)

Currently translated at 6.2% (3 of 48 strings)

Translated using Weblate (Bulgarian)

Currently translated at 0.8% (1 of 119 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (2 of 2 strings)

Translated using Weblate (Bulgarian)

Currently translated at 2.3% (3 of 128 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Skye Fox <mardymcfly1985@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-auth/bg/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/bg/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-icons/bg/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-input/bg/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/bg/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-configeditor/bg/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/bg/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/bg/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-exports/bg/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/bg/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/bg/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-search/bg/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/bg/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/bg/
Translation: Frigate NVR/components-auth
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-icons
Translation: Frigate NVR/components-input
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-search
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
2025-12-04 06:08:06 +01:00
Hosted Weblate
76d2cc853f
Translated using Weblate (Romanian)
Currently translated at 100.0% (40 of 40 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (119 of 119 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (55 of 55 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (128 of 128 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/components-dialog/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/ro/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/ro/
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-explore
2025-12-04 06:08:04 +01:00
Hosted Weblate
5e38da8fb1
Translated using Weblate (Danish)
Currently translated at 85.5% (183 of 214 strings)

Translated using Weblate (Danish)

Currently translated at 36.1% (26 of 72 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: kklar <karred.larsen@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/da/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-filter/da/
Translation: Frigate NVR/common
Translation: Frigate NVR/components-filter
2025-12-04 06:08:03 +01:00
Hosted Weblate
672e91d24f
Translated using Weblate (German)
Currently translated at 100.0% (501 of 501 strings)

Translated using Weblate (German)

Currently translated at 100.0% (52 of 52 strings)

Translated using Weblate (German)

Currently translated at 99.8% (638 of 639 strings)

Translated using Weblate (German)

Currently translated at 99.8% (638 of 639 strings)

Translated using Weblate (German)

Currently translated at 100.0% (119 of 119 strings)

Translated using Weblate (German)

Currently translated at 100.0% (119 of 119 strings)

Translated using Weblate (German)

Currently translated at 100.0% (10 of 10 strings)

Translated using Weblate (German)

Currently translated at 100.0% (119 of 119 strings)

Translated using Weblate (German)

Currently translated at 100.0% (639 of 639 strings)

Translated using Weblate (German)

Currently translated at 100.0% (119 of 119 strings)

Translated using Weblate (German)

Currently translated at 100.0% (214 of 214 strings)

Translated using Weblate (German)

Currently translated at 100.0% (40 of 40 strings)

Translated using Weblate (German)

Currently translated at 100.0% (92 of 92 strings)

Translated using Weblate (German)

Currently translated at 100.0% (501 of 501 strings)

Translated using Weblate (German)

Currently translated at 100.0% (128 of 128 strings)

Translated using Weblate (German)

Currently translated at 100.0% (128 of 128 strings)

Translated using Weblate (German)

Currently translated at 99.5% (213 of 214 strings)

Translated using Weblate (German)

Currently translated at 99.5% (213 of 214 strings)

Translated using Weblate (German)

Currently translated at 83.5% (534 of 639 strings)

Translated using Weblate (German)

Currently translated at 93.8% (470 of 501 strings)

Translated using Weblate (German)

Currently translated at 98.9% (91 of 92 strings)

Translated using Weblate (German)

Currently translated at 100.0% (52 of 52 strings)

Translated using Weblate (German)

Currently translated at 100.0% (39 of 39 strings)

Translated using Weblate (German)

Currently translated at 100.0% (128 of 128 strings)

Translated using Weblate (German)

Currently translated at 100.0% (128 of 128 strings)

Translated using Weblate (German)

Currently translated at 100.0% (116 of 116 strings)

Translated using Weblate (German)

Currently translated at 100.0% (116 of 116 strings)

Translated using Weblate (German)

Currently translated at 34.4% (40 of 116 strings)

Translated using Weblate (German)

Currently translated at 94.8% (37 of 39 strings)

Translated using Weblate (German)

Currently translated at 100.0% (55 of 55 strings)

Translated using Weblate (German)

Currently translated at 78.0% (499 of 639 strings)

Translated using Weblate (German)

Currently translated at 98.4% (126 of 128 strings)

Translated using Weblate (German)

Currently translated at 29.3% (34 of 116 strings)

Translated using Weblate (German)

Currently translated at 96.0% (123 of 128 strings)

Translated using Weblate (German)

Currently translated at 78.0% (499 of 639 strings)

Co-authored-by: Fuxle <moritz.hofmann2005@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Sebastian Sie <sebastian.neuplanitz@googlemail.com>
Co-authored-by: jmtatsch <julian@tatsch.it>
Co-authored-by: mvdberge <micha.vordemberge@christmann.info>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-auth/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/de/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/de/
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-auth
Translation: Frigate NVR/components-dialog
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-settings
Translation: Frigate NVR/views-system
2025-12-04 06:08:02 +01:00
Hosted Weblate
ccefc79499
Translated using Weblate (Portuguese (Brazil))
Currently translated at 29.3% (34 of 116 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Jose Machado <machado.jm4@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/pt_BR/
Translation: Frigate NVR/views-classificationmodel
2025-12-04 06:08:01 +01:00
Hosted Weblate
00720f6b31
Translated using Weblate (Turkish)
Currently translated at 98.5% (211 of 214 strings)

Translated using Weblate (Turkish)

Currently translated at 66.3% (77 of 116 strings)

Translated using Weblate (Turkish)

Currently translated at 63.7% (74 of 116 strings)

Translated using Weblate (Turkish)

Currently translated at 97.6% (209 of 214 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (55 of 55 strings)

Translated using Weblate (Turkish)

Currently translated at 94.5% (121 of 128 strings)

Translated using Weblate (Turkish)

Currently translated at 93.7% (120 of 128 strings)

Translated using Weblate (Turkish)

Currently translated at 94.5% (87 of 92 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (39 of 39 strings)

Translated using Weblate (Turkish)

Currently translated at 58.9% (377 of 639 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (52 of 52 strings)

Co-authored-by: Emircanos <emircan368@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-explore/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-facelibrary/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-live/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/tr/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/tr/
Translation: Frigate NVR/common
Translation: Frigate NVR/components-dialog
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-settings
Translation: Frigate NVR/views-system
2025-12-04 06:08:00 +01:00
55 changed files with 695 additions and 996 deletions

View File

@ -111,9 +111,3 @@ review:
## Review Reports ## Review Reports
Along with individual review item summaries, Generative AI provides the ability to request a report of a given time period. For example, you can get a daily report while on a vacation of any suspicious activity or other concerns that may require review. Along with individual review item summaries, Generative AI provides the ability to request a report of a given time period. For example, you can get a daily report while on a vacation of any suspicious activity or other concerns that may require review.
### Requesting Reports Programmatically
Review reports can be requested via the [API](/integrations/api#review-summarization) by sending a POST request to `/api/review/summarize/start/{start_ts}/end/{end_ts}` with Unix timestamps.
For Home Assistant users, there is a built-in service (`frigate.generate_review_summary`) that makes it easy to request review reports as part of automations or scripts. This allows you to automatically generate daily summaries, vacation reports, or custom time period reports based on your specific needs.

View File

@ -107,7 +107,7 @@ Fine-tune the LPR feature using these optional parameters at the global level of
### Normalization Rules ### Normalization Rules
- **`replace_rules`**: List of regex replacement rules to normalize detected plates. These rules are applied sequentially and are applied _before_ the `format` regex, if specified. Each rule must have a `pattern` (which can be a string or a regex, prepended by `r`) and `replacement` (a string, which also supports [backrefs](https://docs.python.org/3/library/re.html#re.sub) like `\1`). These rules are useful for dealing with common OCR issues like noise characters, separators, or confusions (e.g., 'O'→'0'). - **`replace_rules`**: List of regex replacement rules to normalize detected plates. These rules are applied sequentially. Each rule must have a `pattern` (which can be a string or a regex, prepended by `r`) and `replacement` (a string, which also supports [backrefs](https://docs.python.org/3/library/re.html#re.sub) like `\1`). These rules are useful for dealing with common OCR issues like noise characters, separators, or confusions (e.g., 'O'→'0').
These rules must be defined at the global level of your `lpr` config. These rules must be defined at the global level of your `lpr` config.

View File

@ -164,6 +164,12 @@ A Tensorflow Lite is provided in the container at `/openvino-model/ssdlite_mobil
<details> <details>
<summary>YOLOv9 Setup & Config</summary> <summary>YOLOv9 Setup & Config</summary>
:::warning
If you are using a Frigate+ YOLOv9 model, you should not define any of the below `model` parameters in your config except for `path`. See [the Frigate+ model docs](/plus/first_model#step-3-set-your-model-id-in-the-config) for more information on setting up your model.
:::
After placing the downloaded files for the tflite model and labels in your config folder, you can use the following configuration: After placing the downloaded files for the tflite model and labels in your config folder, you can use the following configuration:
```yaml ```yaml
@ -402,7 +408,7 @@ The YOLO detector has been designed to support YOLOv3, YOLOv4, YOLOv7, and YOLOv
:::warning :::warning
If you are using a Frigate+ model, you should not define any of the below `model` parameters in your config except for `path`. See [the Frigate+ model docs](/plus/first_model#step-3-set-your-model-id-in-the-config) for more information on setting up your model. If you are using a Frigate+ YOLOv9 model, you should not define any of the below `model` parameters in your config except for `path`. See [the Frigate+ model docs](/plus/first_model#step-3-set-your-model-id-in-the-config) for more information on setting up your model.
::: :::
@ -742,7 +748,7 @@ The YOLO detector has been designed to support YOLOv3, YOLOv4, YOLOv7, and YOLOv
:::warning :::warning
If you are using a Frigate+ model, you should not define any of the below `model` parameters in your config except for `path`. See [the Frigate+ model docs](/plus/first_model#step-3-set-your-model-id-in-the-config) for more information on setting up your model. If you are using a Frigate+ YOLOv9 model, you should not define any of the below `model` parameters in your config except for `path`. See [the Frigate+ model docs](/plus/first_model#step-3-set-your-model-id-in-the-config) for more information on setting up your model.
::: :::

File diff suppressed because it is too large Load Diff

View File

@ -29,6 +29,7 @@ class EventsDescriptionBody(BaseModel):
class EventsCreateBody(BaseModel): class EventsCreateBody(BaseModel):
source_type: Optional[str] = "api"
sub_label: Optional[str] = None sub_label: Optional[str] = None
score: Optional[float] = 0 score: Optional[float] = 0
duration: Optional[int] = 30 duration: Optional[int] = 30

View File

@ -346,7 +346,7 @@ def events(
"/events/explore", "/events/explore",
response_model=list[EventResponse], response_model=list[EventResponse],
dependencies=[Depends(allow_any_authenticated())], dependencies=[Depends(allow_any_authenticated())],
summary="Get summary of objects", summary="Get summary of objects.",
description="""Gets a summary of objects from the database. description="""Gets a summary of objects from the database.
Returns a list of objects with a max of `limit` objects for each label. Returns a list of objects with a max of `limit` objects for each label.
""", """,
@ -439,7 +439,7 @@ def events_explore(
"/event_ids", "/event_ids",
response_model=list[EventResponse], response_model=list[EventResponse],
dependencies=[Depends(allow_any_authenticated())], dependencies=[Depends(allow_any_authenticated())],
summary="Get events by ids", summary="Get events by ids.",
description="""Gets events by a list of ids. description="""Gets events by a list of ids.
Returns a list of events. Returns a list of events.
""", """,
@ -473,7 +473,7 @@ async def event_ids(ids: str, request: Request):
@router.get( @router.get(
"/events/search", "/events/search",
dependencies=[Depends(allow_any_authenticated())], dependencies=[Depends(allow_any_authenticated())],
summary="Search events", summary="Search events.",
description="""Searches for events in the database. description="""Searches for events in the database.
Returns a list of events. Returns a list of events.
""", """,
@ -924,7 +924,7 @@ def events_summary(
"/events/{event_id}", "/events/{event_id}",
response_model=EventResponse, response_model=EventResponse,
dependencies=[Depends(allow_any_authenticated())], dependencies=[Depends(allow_any_authenticated())],
summary="Get event by id", summary="Get event by id.",
description="Gets an event by its id.", description="Gets an event by its id.",
) )
async def event(event_id: str, request: Request): async def event(event_id: str, request: Request):
@ -968,7 +968,7 @@ def set_retain(event_id: str):
"/events/{event_id}/plus", "/events/{event_id}/plus",
response_model=EventUploadPlusResponse, response_model=EventUploadPlusResponse,
dependencies=[Depends(require_role(["admin"]))], dependencies=[Depends(require_role(["admin"]))],
summary="Send event to Frigate+", summary="Send event to Frigate+.",
description="""Sends an event to Frigate+. description="""Sends an event to Frigate+.
Returns a success message or an error if the event is not found. Returns a success message or an error if the event is not found.
""", """,
@ -1207,7 +1207,7 @@ async def false_positive(request: Request, event_id: str):
"/events/{event_id}/retain", "/events/{event_id}/retain",
response_model=GenericResponse, response_model=GenericResponse,
dependencies=[Depends(require_role(["admin"]))], dependencies=[Depends(require_role(["admin"]))],
summary="Stop event from being retained indefinitely", summary="Stop event from being retained indefinitely.",
description="""Stops an event from being retained indefinitely. description="""Stops an event from being retained indefinitely.
Returns a success message or an error if the event is not found. Returns a success message or an error if the event is not found.
NOTE: This is a legacy endpoint and is not supported in the frontend. NOTE: This is a legacy endpoint and is not supported in the frontend.
@ -1236,7 +1236,7 @@ async def delete_retain(event_id: str, request: Request):
"/events/{event_id}/sub_label", "/events/{event_id}/sub_label",
response_model=GenericResponse, response_model=GenericResponse,
dependencies=[Depends(require_role(["admin"]))], dependencies=[Depends(require_role(["admin"]))],
summary="Set event sub label", summary="Set event sub label.",
description="""Sets an event's sub label. description="""Sets an event's sub label.
Returns a success message or an error if the event is not found. Returns a success message or an error if the event is not found.
""", """,
@ -1295,7 +1295,7 @@ async def set_sub_label(
"/events/{event_id}/recognized_license_plate", "/events/{event_id}/recognized_license_plate",
response_model=GenericResponse, response_model=GenericResponse,
dependencies=[Depends(require_role(["admin"]))], dependencies=[Depends(require_role(["admin"]))],
summary="Set event license plate", summary="Set event license plate.",
description="""Sets an event's license plate. description="""Sets an event's license plate.
Returns a success message or an error if the event is not found. Returns a success message or an error if the event is not found.
""", """,
@ -1355,7 +1355,7 @@ async def set_plate(
"/events/{event_id}/description", "/events/{event_id}/description",
response_model=GenericResponse, response_model=GenericResponse,
dependencies=[Depends(require_role(["admin"]))], dependencies=[Depends(require_role(["admin"]))],
summary="Set event description", summary="Set event description.",
description="""Sets an event's description. description="""Sets an event's description.
Returns a success message or an error if the event is not found. Returns a success message or an error if the event is not found.
""", """,
@ -1411,7 +1411,7 @@ async def set_description(
"/events/{event_id}/description/regenerate", "/events/{event_id}/description/regenerate",
response_model=GenericResponse, response_model=GenericResponse,
dependencies=[Depends(require_role(["admin"]))], dependencies=[Depends(require_role(["admin"]))],
summary="Regenerate event description", summary="Regenerate event description.",
description="""Regenerates an event's description. description="""Regenerates an event's description.
Returns a success message or an error if the event is not found. Returns a success message or an error if the event is not found.
""", """,
@ -1463,8 +1463,8 @@ async def regenerate_description(
@router.post( @router.post(
"/description/generate", "/description/generate",
response_model=GenericResponse, response_model=GenericResponse,
dependencies=[Depends(require_role(["admin"]))], # dependencies=[Depends(require_role(["admin"]))],
summary="Generate description embedding", summary="Generate description embedding.",
description="""Generates an embedding for an event's description. description="""Generates an embedding for an event's description.
Returns a success message or an error if the event is not found. Returns a success message or an error if the event is not found.
""", """,
@ -1529,7 +1529,7 @@ async def delete_single_event(event_id: str, request: Request) -> dict:
"/events/{event_id}", "/events/{event_id}",
response_model=GenericResponse, response_model=GenericResponse,
dependencies=[Depends(require_role(["admin"]))], dependencies=[Depends(require_role(["admin"]))],
summary="Delete event", summary="Delete event.",
description="""Deletes an event from the database. description="""Deletes an event from the database.
Returns a success message or an error if the event is not found. Returns a success message or an error if the event is not found.
""", """,
@ -1544,7 +1544,7 @@ async def delete_event(request: Request, event_id: str):
"/events/", "/events/",
response_model=EventMultiDeleteResponse, response_model=EventMultiDeleteResponse,
dependencies=[Depends(require_role(["admin"]))], dependencies=[Depends(require_role(["admin"]))],
summary="Delete events", summary="Delete events.",
description="""Deletes a list of events from the database. description="""Deletes a list of events from the database.
Returns a success message or an error if the events are not found. Returns a success message or an error if the events are not found.
""", """,
@ -1578,7 +1578,7 @@ async def delete_events(request: Request, body: EventsDeleteBody):
"/events/{camera_name}/{label}/create", "/events/{camera_name}/{label}/create",
response_model=EventCreateResponse, response_model=EventCreateResponse,
dependencies=[Depends(require_role(["admin"]))], dependencies=[Depends(require_role(["admin"]))],
summary="Create manual event", summary="Create manual event.",
description="""Creates a manual event in the database. description="""Creates a manual event in the database.
Returns a success message or an error if the event is not found. Returns a success message or an error if the event is not found.
NOTES: NOTES:
@ -1620,7 +1620,7 @@ def create_event(
body.score, body.score,
body.sub_label, body.sub_label,
body.duration, body.duration,
"api", body.source_type,
body.draw, body.draw,
), ),
EventMetadataTypeEnum.manual_event_create.value, EventMetadataTypeEnum.manual_event_create.value,
@ -1642,7 +1642,7 @@ def create_event(
"/events/{event_id}/end", "/events/{event_id}/end",
response_model=GenericResponse, response_model=GenericResponse,
dependencies=[Depends(require_role(["admin"]))], dependencies=[Depends(require_role(["admin"]))],
summary="End manual event", summary="End manual event.",
description="""Ends a manual event. description="""Ends a manual event.
Returns a success message or an error if the event is not found. Returns a success message or an error if the event is not found.
NOTE: This should only be used for manual events. NOTE: This should only be used for manual events.
@ -1652,27 +1652,10 @@ async def end_event(request: Request, event_id: str, body: EventsEndBody):
try: try:
event: Event = Event.get(Event.id == event_id) event: Event = Event.get(Event.id == event_id)
await require_camera_access(event.camera, request=request) await require_camera_access(event.camera, request=request)
if body.end_time is not None and body.end_time < event.start_time:
return JSONResponse(
content=(
{
"success": False,
"message": f"end_time ({body.end_time}) cannot be before start_time ({event.start_time}).",
}
),
status_code=400,
)
end_time = body.end_time or datetime.datetime.now().timestamp() end_time = body.end_time or datetime.datetime.now().timestamp()
request.app.event_metadata_updater.publish( request.app.event_metadata_updater.publish(
(event_id, end_time), EventMetadataTypeEnum.manual_event_end.value (event_id, end_time), EventMetadataTypeEnum.manual_event_end.value
) )
except DoesNotExist:
return JSONResponse(
content=({"success": False, "message": f"Event {event_id} not found."}),
status_code=404,
)
except Exception: except Exception:
return JSONResponse( return JSONResponse(
content=( content=(
@ -1691,7 +1674,7 @@ async def end_event(request: Request, event_id: str, body: EventsEndBody):
"/trigger/embedding", "/trigger/embedding",
response_model=dict, response_model=dict,
dependencies=[Depends(require_role(["admin"]))], dependencies=[Depends(require_role(["admin"]))],
summary="Create trigger embedding", summary="Create trigger embedding.",
description="""Creates a trigger embedding for a specific trigger. description="""Creates a trigger embedding for a specific trigger.
Returns a success message or an error if the trigger is not found. Returns a success message or an error if the trigger is not found.
""", """,
@ -1849,7 +1832,7 @@ def create_trigger_embedding(
"/trigger/embedding/{camera_name}/{name}", "/trigger/embedding/{camera_name}/{name}",
response_model=dict, response_model=dict,
dependencies=[Depends(require_role(["admin"]))], dependencies=[Depends(require_role(["admin"]))],
summary="Update trigger embedding", summary="Update trigger embedding.",
description="""Updates a trigger embedding for a specific trigger. description="""Updates a trigger embedding for a specific trigger.
Returns a success message or an error if the trigger is not found. Returns a success message or an error if the trigger is not found.
""", """,
@ -2014,7 +1997,7 @@ def update_trigger_embedding(
"/trigger/embedding/{camera_name}/{name}", "/trigger/embedding/{camera_name}/{name}",
response_model=dict, response_model=dict,
dependencies=[Depends(require_role(["admin"]))], dependencies=[Depends(require_role(["admin"]))],
summary="Delete trigger embedding", summary="Delete trigger embedding.",
description="""Deletes a trigger embedding for a specific trigger. description="""Deletes a trigger embedding for a specific trigger.
Returns a success message or an error if the trigger is not found. Returns a success message or an error if the trigger is not found.
""", """,
@ -2088,7 +2071,7 @@ def delete_trigger_embedding(
"/triggers/status/{camera_name}", "/triggers/status/{camera_name}",
response_model=dict, response_model=dict,
dependencies=[Depends(require_role(["admin"]))], dependencies=[Depends(require_role(["admin"]))],
summary="Get triggers status", summary="Get triggers status.",
description="""Gets the status of all triggers for a specific camera. description="""Gets the status of all triggers for a specific camera.
Returns a success message or an error if the camera is not found. Returns a success message or an error if the camera is not found.
""", """,

View File

@ -209,22 +209,10 @@ class ReviewDescriptionProcessor(PostProcessorApi):
logger.debug( logger.debug(
f"Found GenAI Review Summary request for {start_ts} to {end_ts}" f"Found GenAI Review Summary request for {start_ts} to {end_ts}"
) )
items: list[dict[str, Any]] = [
# Query all review segments with camera and time information r["data"]["metadata"]
segments: list[dict[str, Any]] = [
{
"camera": r["camera"].replace("_", " ").title(),
"start_time": r["start_time"],
"end_time": r["end_time"],
"metadata": r["data"]["metadata"],
}
for r in ( for r in (
ReviewSegment.select( ReviewSegment.select(ReviewSegment.data)
ReviewSegment.camera,
ReviewSegment.start_time,
ReviewSegment.end_time,
ReviewSegment.data,
)
.where( .where(
(ReviewSegment.data["metadata"].is_null(False)) (ReviewSegment.data["metadata"].is_null(False))
& (ReviewSegment.start_time < end_ts) & (ReviewSegment.start_time < end_ts)
@ -236,66 +224,21 @@ class ReviewDescriptionProcessor(PostProcessorApi):
) )
] ]
if len(segments) == 0: if len(items) == 0:
logger.debug("No review items with metadata found during time period") logger.debug("No review items with metadata found during time period")
return "No activity was found during this time period." return "No activity was found during this time."
# Identify primary items (important items that need review) important_items = list(
primary_segments = [ filter(
seg lambda item: item.get("potential_threat_level", 0) > 0
for seg in segments or item.get("other_concerns"),
if seg["metadata"].get("potential_threat_level", 0) > 0 items,
or seg["metadata"].get("other_concerns") )
]
if not primary_segments:
return "No concerns were found during this time period."
# For each primary segment, find overlapping contextual items from other cameras
all_items_for_summary = []
for primary_seg in primary_segments:
# Add the primary item with marker
primary_item = copy.deepcopy(primary_seg["metadata"])
primary_item["_is_primary"] = True
primary_item["_camera"] = primary_seg["camera"]
all_items_for_summary.append(primary_item)
# Find overlapping contextual items from other cameras
primary_start = primary_seg["start_time"]
primary_end = primary_seg["end_time"]
primary_camera = primary_seg["camera"]
for seg in segments:
seg_camera = seg["camera"]
if seg_camera == primary_camera:
continue
if seg in primary_segments:
continue
seg_start = seg["start_time"]
seg_end = seg["end_time"]
if seg_start < primary_end and primary_start < seg_end:
contextual_item = copy.deepcopy(seg["metadata"])
contextual_item["_is_primary"] = False
contextual_item["_camera"] = seg_camera
contextual_item["_related_to_camera"] = primary_camera
if not any(
item.get("_camera") == seg_camera
and item.get("time") == contextual_item.get("time")
for item in all_items_for_summary
):
all_items_for_summary.append(contextual_item)
logger.debug(
f"Summary includes {len(primary_segments)} primary items and "
f"{len(all_items_for_summary) - len(primary_segments)} contextual items"
) )
if not important_items:
return "No concerns were found during this time period."
if self.config.review.genai.debug_save_thumbnails: if self.config.review.genai.debug_save_thumbnails:
Path( Path(
os.path.join(CLIPS_DIR, "genai-requests", f"{start_ts}-{end_ts}") os.path.join(CLIPS_DIR, "genai-requests", f"{start_ts}-{end_ts}")
@ -304,7 +247,7 @@ class ReviewDescriptionProcessor(PostProcessorApi):
return self.genai_client.generate_review_summary( return self.genai_client.generate_review_summary(
start_ts, start_ts,
end_ts, end_ts,
all_items_for_summary, important_items,
self.config.review.genai.debug_save_thumbnails, self.config.review.genai.debug_save_thumbnails,
) )
else: else:

View File

@ -185,66 +185,44 @@ Each line represents a detection state, not necessarily unique individuals. Pare
timeline_summary_prompt = f""" timeline_summary_prompt = f"""
You are a security officer. You are a security officer.
Time range: {time_range}. Time range: {time_range}.
Input: JSON list with "title", "scene", "confidence", "potential_threat_level" (0-2), "other_concerns", "_is_primary", "_camera". Input: JSON list with "title", "scene", "confidence", "potential_threat_level" (1-2), "other_concerns".
Task: Write a concise, human-presentable security report in markdown format. Task: Write a concise, human-presentable security report in markdown format.
CRITICAL - Understanding Primary vs Contextual Items:
- Items with "_is_primary": true are events that REQUIRE REVIEW and MUST be included in the report
- Items with "_is_primary": false are additional context from other camera perspectives that overlap in time
- **DO NOT create separate bullet points or sections for contextual items**
- **ONLY use contextual items to enrich and inform the description of primary items**
- The "_camera" field indicates which camera captured each event
- **When a contextual item provides relevant background, you MUST incorporate it directly into the primary event's bullet point**
- Contextual information often explains or de-escalates seemingly suspicious primary events
Rules for the report: Rules for the report:
- Title & overview - Title & overview
- Start with: - Start with:
# Security Summary - {time_range} # Security Summary - {time_range}
- Write a 1-2 sentence situational overview capturing the general pattern of the period. - Write a 1-2 sentence situational overview capturing the general pattern of the period.
- Keep the overview high-level; specific details will be in the event bullets below.
- Event details - Event details
- **ONLY create bullet points for PRIMARY items (_is_primary: true)** - Present events in chronological order as a bullet list.
- **Do NOT create sections or bullets for events that don't exist** - **If multiple events occur within the same minute or overlapping time range, COMBINE them into a single bullet.**
- Do NOT create separate bullets for contextual items - Summarize the distinct activities as sub-points under the shared timestamp.
- Present primary events in chronological order as a bullet list. - If no timestamp is given, preserve order but label as Time not specified.
- **CRITICAL: When contextual items overlap with a primary event, you MUST weave that information directly into the same bullet point**
- Format: **[Timestamp]** - [Description incorporating any contextual information]. [Camera info]. (threat level: X)
- If contextual information provides an explanation (e.g., delivery truck person is likely delivery driver), reflect this understanding in your description and potentially adjust the perceived threat level
- If multiple PRIMARY events occur within the same minute, combine them into a single bullet with sub-points.
- Use bold timestamps for clarity. - Use bold timestamps for clarity.
- Camera format: "Camera: [camera name]" or mention contextual cameras inline when relevant - Group bullets under subheadings when multiple events fall into the same category (e.g., Vehicle Activity, Porch Activity, Unusual Behavior).
- Group bullets under subheadings ONLY when you have actual PRIMARY events to list (e.g., Porch Activity, Unusual Behavior).
- Threat levels - Threat levels
- Show the threat level for PRIMARY events using these labels: - Always show the threat level for each event using these labels:
- Threat level 0: "Normal" - Threat level 0: "Normal"
- Threat level 1: "Needs review" - Threat level 1: "Needs review"
- Threat level 2: "Security concern" - Threat level 2: "Security concern"
- Format as (threat level: Normal), (threat level: Needs review), or (threat level: Security concern). - Format as (threat level: Normal), (threat level: Needs review), or (threat level: Security concern).
- **When contextual items clearly explain a primary event (e.g., delivery truck explains person at door), you should describe it as normal activity and note the explanation** - If multiple events at the same time share the same threat level, only state it once.
- **Your description and tone should reflect the fuller understanding provided by contextual information**
- Example: Primary event says "unidentified person with face covering" but context shows delivery truck describe as "delivery person (truck visible on Front Driveway Cam)" rather than emphasizing suspicious elements
- The stored threat level remains as originally classified, but your narrative should reflect the contextual understanding
- If multiple PRIMARY events at the same time share the same threat level, only state it once.
- Final assessment - Final assessment
- End with a Final Assessment section. - End with a Final Assessment section.
- If all primary events are threat level 0 or explained by contextual items: - If all events are threat level 0:
Final assessment: Only normal residential activity observed during this period. Final assessment: Only normal residential activity observed during this period.
- If threat level 1 events are present: - If threat level 1 events are present:
Final assessment: Some activity requires review but no security concerns identified. Final assessment: Some activity requires review but no security concerns identified.
- If threat level 2 events are present, clearly summarize them as Security concerns requiring immediate attention. - If threat level 2 events are present, clearly summarize them as Security concerns requiring immediate attention.
- Keep this section brief - do not repeat details from the event descriptions above.
- Conciseness - Conciseness
- Do not repeat benign clothing/appearance details unless they distinguish individuals. - Do not repeat benign clothing/appearance details unless they distinguish individuals.
- Summarize similar routine events instead of restating full scene descriptions. - Summarize similar routine events instead of restating full scene descriptions.
- When incorporating contextual information, do so briefly and naturally within the primary event description.
- Avoid lengthy explanatory notes - integrate context seamlessly into the narrative.
""" """
for item in segments: for item in segments:

View File

@ -156,7 +156,7 @@
"modelCreated": "El model s'ha creat correctament. Utilitzeu la vista Classificacions recents per a afegir imatges per als estats que falten i, a continuació, entrenar el model.", "modelCreated": "El model s'ha creat correctament. Utilitzeu la vista Classificacions recents per a afegir imatges per als estats que falten i, a continuació, entrenar el model.",
"missingStatesWarning": { "missingStatesWarning": {
"title": "Falten exemples d'estat", "title": "Falten exemples d'estat",
"description": "Es recomana seleccionar exemples per a tots els estats per obtenir els millors resultats. Podeu continuar sense seleccionar tots els estats, però el model no serà entrenat fins que tots els estats tinguin imatges. Després de continuar, utilitzeu la vista Classificacions recents per classificar imatges per als estats que falten, i després entrenar el model." "description": "No heu seleccionat exemples per a tots els estats. El model no serà entrenat fins que tots els estats tinguin imatges. Després de continuar, utilitzeu la vista Classificacions recents per classificar imatges per als estats que falten, i després entrenar el model."
} }
} }
}, },

View File

@ -172,7 +172,7 @@
"name": { "name": {
"inputPlaceHolder": "Introduïu un nom…", "inputPlaceHolder": "Introduïu un nom…",
"title": "Nom", "title": "Nom",
"tips": "El nom ha de tenir almenys 2 caràcters, ha de tenir almenys una lletra, i no ha de ser el nom d'una càmera o una altra zona en aquesta càmera." "tips": "El nom ha de tenir almenys 2 caràcters, ha de tenir almenys una lletra, i no ha de ser el nom d'una càmera o una altra zona."
}, },
"label": "Zones", "label": "Zones",
"desc": { "desc": {

View File

@ -25,10 +25,7 @@
"deletedModel_one": "Úspešne odstranený {{count}} model", "deletedModel_one": "Úspešne odstranený {{count}} model",
"deletedModel_few": "Úspešne odstranené {{count}} modely", "deletedModel_few": "Úspešne odstranené {{count}} modely",
"deletedModel_other": "Úspěšne ostranených {{count}} modelov", "deletedModel_other": "Úspěšne ostranených {{count}} modelov",
"deletedCategory": "Zmazať triedu", "deletedCategory": "Zmazať triedu"
"categorizedImage": "Obrázek úspěšně klasifikován",
"trainedModel": "Úspěšně vytrénovaný model.",
"trainingModel": "Trénování modelu bylo úspěšně zahájeno."
} }
} }
} }

View File

@ -41,8 +41,6 @@
"zoomOut": "Oddálit", "zoomOut": "Oddálit",
"detail": { "detail": {
"label": "Detail", "label": "Detail",
"noDataFound": "Žádná detailní data k prohlédnutí", "noDataFound": "Žádná detailní data k prohlédnutí"
"aria": "Přepnout detailní zobrazení",
"trackedObject_other": "{{count}} objektů"
} }
} }

View File

@ -36,7 +36,7 @@
"desc": "Skutečně chcete vymazat kolekci {{name}}? Toto trvale vymaže všechny přiřazené obličeje." "desc": "Skutečně chcete vymazat kolekci {{name}}? Toto trvale vymaže všechny přiřazené obličeje."
}, },
"train": { "train": {
"title": "Nedávná rozpoznání", "title": "Trénovat",
"empty": "Nejsou zde žádné předchozí pokusy o rozpoznání obličeje", "empty": "Nejsou zde žádné předchozí pokusy o rozpoznání obličeje",
"aria": "Vybrat trénink" "aria": "Vybrat trénink"
}, },

View File

@ -307,9 +307,7 @@
"frigateplus": "Frigate+", "frigateplus": "Frigate+",
"enrichments": "Obohacení", "enrichments": "Obohacení",
"triggers": "Spouštěče", "triggers": "Spouštěče",
"cameraManagement": "Správa", "cameraManagement": "Správa"
"cameraReview": "Kontrola",
"roles": "Role"
}, },
"dialog": { "dialog": {
"unsavedChanges": { "unsavedChanges": {

View File

@ -177,7 +177,7 @@
"generateSuccess": "Successfully generated sample images", "generateSuccess": "Successfully generated sample images",
"missingStatesWarning": { "missingStatesWarning": {
"title": "Missing State Examples", "title": "Missing State Examples",
"description": "It's recommended to select examples for all states for best results. You can continue without selecting all states, but the model will not be trained until all states have images. After continuing, use the Recent Classifications view to classify images for the missing states, then train the model." "description": "You haven't selected examples for all states. The model will not be trained until all states have images. After continuing, use the Recent Classifications view to classify images for the missing states, then train the model."
} }
} }
} }

View File

@ -500,7 +500,7 @@
"name": { "name": {
"title": "Name", "title": "Name",
"inputPlaceHolder": "Enter a name…", "inputPlaceHolder": "Enter a name…",
"tips": "Name must be at least 2 characters, must have at least one letter, and must not be the name of a camera or another zone on this camera." "tips": "Name must be at least 2 characters, must have at least one letter, and must not be the name of a camera or another zone."
}, },
"inertia": { "inertia": {
"title": "Inertia", "title": "Inertia",

View File

@ -1 +0,0 @@
{}

View File

@ -1 +0,0 @@
{}

View File

@ -1 +0,0 @@
{}

View File

@ -1 +0,0 @@
{}

View File

@ -1 +0,0 @@
{}

View File

@ -1 +0,0 @@
{}

View File

@ -1 +0,0 @@
{}

View File

@ -1 +0,0 @@
{}

View File

@ -1 +0,0 @@
{}

View File

@ -1 +0,0 @@
{}

View File

@ -1 +0,0 @@
{}

View File

@ -1 +0,0 @@
{}

View File

@ -1 +0,0 @@
{}

View File

@ -1 +0,0 @@
{}

View File

@ -1 +0,0 @@
{}

View File

@ -1 +0,0 @@
{}

View File

@ -1 +0,0 @@
{}

View File

@ -1 +0,0 @@
{}

View File

@ -1 +0,0 @@
{}

View File

@ -1 +0,0 @@
{}

View File

@ -212,10 +212,6 @@
}, },
"hideObjectDetails": { "hideObjectDetails": {
"label": "Ascunde traseul obiectului" "label": "Ascunde traseul obiectului"
},
"downloadCleanSnapshot": {
"label": "Descarcă un snapshot curat",
"aria": "Descarcă snapshot curat"
} }
}, },
"dialog": { "dialog": {

View File

@ -121,8 +121,7 @@
"cancel": "İptal", "cancel": "İptal",
"twoWayTalk": "Çift Yönlü Ses", "twoWayTalk": "Çift Yönlü Ses",
"close": "Kapat", "close": "Kapat",
"delete": "Sil", "delete": "Sil"
"continue": "Devam Et"
}, },
"menu": { "menu": {
"systemLogs": "Sistem günlükleri", "systemLogs": "Sistem günlükleri",
@ -223,8 +222,7 @@
"help": "Yardım", "help": "Yardım",
"faceLibrary": "Yüz Veritabanı", "faceLibrary": "Yüz Veritabanı",
"systemMetrics": "Sistem metrikleri", "systemMetrics": "Sistem metrikleri",
"uiPlayground": "UI Deneme Alanı", "uiPlayground": "UI Deneme Alanı"
"classification": "Sınıflandırma"
}, },
"label": { "label": {
"back": "Geri", "back": "Geri",
@ -300,8 +298,5 @@
"field": { "field": {
"optional": "İsteğe bağlı", "optional": "İsteğe bağlı",
"internalID": "Frigateın yapılandırma ve veritabanında kullandığı Dahili Kimlik" "internalID": "Frigateın yapılandırma ve veritabanında kullandığı Dahili Kimlik"
},
"information": {
"pixels": "{{area}}px"
} }
} }

View File

@ -121,64 +121,7 @@
"objectLabel": "Nesne Etiketi", "objectLabel": "Nesne Etiketi",
"objectLabelPlaceholder": "Nesne türünü seçin...", "objectLabelPlaceholder": "Nesne türünü seçin...",
"classificationType": "Sınıflandırma Türü", "classificationType": "Sınıflandırma Türü",
"classificationTypeTip": "Sınıflandırma türleri hakkında bilgi edinin", "classificationTypeTip": "Sınıflandırma türleri hakkında bilgi edinin"
"classificationTypeDesc": "Alt etiketleri, nesne etiketine ek metin ekler (örneğin: “Person: UPS”). Öznitelikler (attributes) ise nesne meta verilerinde ayrı olarak saklanan ve aranabilir metadata bilgileridir.",
"classificationSubLabel": "Alt Etiket",
"classificationAttribute": "Özellik",
"classes": "Sınıflar",
"states": "Durumlar",
"classesTip": "Sınıflar hakkında bilgi edinin",
"classesStateDesc": "Kamera alanınızın içinde bulunabileceği farklı durumları tanımlayın. Örneğin: bir garaj kapısı için ık ve kapalı.",
"classesObjectDesc": "Algılanan nesneleri sınıflandırmak için farklı kategorileri tanımlayın. Örneğin: Bir kişi sınıflandırması için teslimat_görevlisi, sakin, yabancı.",
"classPlaceholder": "Sınıf adını girin...",
"errors": {
"nameRequired": "Model adı gerekli",
"nameLength": "Model adı 64 karakter veya daha az olmalıdır",
"nameOnlyNumbers": "Model adı yalnızca rakamlardan oluşamaz",
"classRequired": "En az 1 sınıf gereklidir",
"classesUnique": "Sınıf adları benzersiz olmalıdır",
"stateRequiresTwoClasses": "Durum modelleri en az 2 sınıf gerektirir",
"objectLabelRequired": "Lütfen bir nesne etiketi seçin",
"objectTypeRequired": "Lütfen bir sınıflandırma türü seçin"
}
},
"step2": {
"description": "İzlenecek alanı her kamera için seçin ve tanımlayın. Model bu alanların durumunu sınıflandıracaktır.",
"cameras": "Kameralar",
"selectCamera": "Kamera Seç",
"noCameras": "Kameraları eklemek için + simgesine tıklayın",
"selectCameraPrompt": "Listedeki bir kamerayı seçerek izlenecek alanı tanımlayın"
},
"step3": {
"selectImagesPrompt": "{{className}} etiketli tüm görselleri seç",
"selectImagesDescription": "Görselleri seçmek için üzerlerine tıklayın. Bu sınıfla işiniz bittiğinde Devam Ete tıklayın.",
"allImagesRequired_one": "Lütfen tüm görselleri sınıflandırın. {{count}} görsel kaldı.",
"allImagesRequired_other": "Lütfen tüm görselleri sınıflandırın. {{count}} görsel kaldı.",
"generating": {
"title": "Örnek Görseller Oluşturuluyor",
"description": "Frigate kayıtlarınızdan temsilî görüntüler çekiliyor. Bu işlem biraz zaman alabilir…"
},
"training": {
"title": "Model Eğitiliyor",
"description": "Modeliniz arka planda eğitiliyor. Bu pencereyi kapatabilirsiniz; eğitim tamamlandığında model otomatik olarak çalışmaya başlayacaktır."
},
"retryGenerate": "Oluşturmayı Yeniden Dene",
"noImages": "Örnek görsel oluşturulamadı",
"classifying": "Sınıflandırılıyor ve Eğitiliyor...",
"trainingStarted": "Eğitim başarıyla başlatıldı",
"modelCreated": "Model başarıyla oluşturuldu. Eksik durumlar için görseller eklemek üzere Son Sınıflandırmalar görünümünü kullanın ve ardından modeli eğitin.",
"errors": {
"noCameras": "Hiç kamera yapılandırılmadı",
"noObjectLabel": "Nesne etiketi seçilmedi",
"generateFailed": "Örnekler oluşturulamadı: {{error}}",
"generationFailed": "Oluşturma başarısız oldu. Lütfen tekrar deneyin.",
"classifyFailed": "Görseller sınıflandırılamadı: {{error}}"
},
"generateSuccess": "Örnek görseller başarıyla oluşturuldu",
"missingStatesWarning": {
"title": "Eksik Durum Örnekleri",
"description": "En iyi sonuçlar için tavsiye edilir: Tüm durumlar (state) için örnekler seçin. Tüm durumlar için örnek seçmeden devam edebilirsiniz, ancak model, tüm durumlara ait görüntüler eklenene kadar eğitilmeyecektir. Devam ettikten sonra, eksik durumlar için görüntüleri sınıflandırmak ve ardından modeli eğitmek için Son Sınıflandırmalar (Recent Classifications) görünümünü kullanın."
}
} }
} }
} }

View File

@ -55,8 +55,5 @@
"objectTrack": { "objectTrack": {
"trackedPoint": "Takip edilen nokta", "trackedPoint": "Takip edilen nokta",
"clickToSeek": "Bu zamana gitmek için tıklayın" "clickToSeek": "Bu zamana gitmek için tıklayın"
}, }
"normalActivity": "Normal",
"needsReview": "İnceleme Gerekiyor",
"securityConcern": "Güvenlik endişesi"
} }

View File

@ -197,20 +197,6 @@
"audioTranscription": { "audioTranscription": {
"label": "Çözümle", "label": "Çözümle",
"aria": "Ses çözümlemesi iste" "aria": "Ses çözümlemesi iste"
},
"downloadCleanSnapshot": {
"label": "Temiz anlık görüntüyü indir",
"aria": "Temiz anlık görüntüyü indir"
},
"viewTrackingDetails": {
"label": "İzleme ayrıntılarını görüntüle",
"aria": "Takip ayrıntılarını göster"
},
"showObjectDetails": {
"label": "Nesne yolunu göster"
},
"hideObjectDetails": {
"label": "Nesne yolunu gizle"
} }
}, },
"noTrackedObjects": "Takip Edilen Nesne Bulunamadı", "noTrackedObjects": "Takip Edilen Nesne Bulunamadı",
@ -222,13 +208,11 @@
"success": "Takip edilen nesne başarıyla silindi." "success": "Takip edilen nesne başarıyla silindi."
} }
}, },
"tooltip": "Eşleşme: {{type}} (%{{confidence}})", "tooltip": "Eşleşme: {{type}} (%{{confidence}})"
"previousTrackedObject": "Önceki izlenen nesne",
"nextTrackedObject": "Sonraki izlenen nesne"
}, },
"dialog": { "dialog": {
"confirmDelete": { "confirmDelete": {
"desc": "Bu takip edilen nesneyi silmek anlık görüntüyü, kaydedilmiş gömü verilerini ve ilişkili yaşam döngüsü kayıtlarını siler. Geçmiş görünümündeki bu izlenen nesneye ait kayıtlı video görüntüleri <em>SİLİNMEYECEKTİR.</em> <br /><br />Devam etmek istediğinizden emin misiniz?", "desc": "Bu takip edilen nesneyi silmek nesne fotoğrafını, ilişkili gömüyü ve ilişkili yaşam döngüsü kayıtlarını siler. Video kayıt görüntüleri geçmiş görünümünden <em>SİLİNMEYECEKTİR.</em> <br /><br />Devam etmek istediğinize emin misiniz?",
"title": "Silmeyi onayla" "title": "Silmeyi onayla"
} }
}, },
@ -286,8 +270,5 @@
"previous": "Önceki slayt", "previous": "Önceki slayt",
"next": "Sonraki slayt" "next": "Sonraki slayt"
} }
},
"concerns": {
"label": "Endişeler"
} }
} }

View File

@ -49,7 +49,7 @@
"validation": { "validation": {
"selectImage": "Lütfen bir resim dosyası seçin." "selectImage": "Lütfen bir resim dosyası seçin."
}, },
"dropInstructions": "Bir görseli buraya sürükleyip bırakın, yapıştırın ya da seçmek için tıklayın" "dropInstructions": "Bir görseli buraya sürükleyip bırakın, yapıştırın ya da seçmek için tıklayın."
}, },
"trainFaceAs": "Yüzü şu olarak eğit:", "trainFaceAs": "Yüzü şu olarak eğit:",
"toast": { "toast": {

View File

@ -176,14 +176,5 @@
"noVideoSource": "Anlık görüntü için kullanılabilir bir video kaynağı bulunamadı.", "noVideoSource": "Anlık görüntü için kullanılabilir bir video kaynağı bulunamadı.",
"captureFailed": "Anlık görüntü yakalanamadı.", "captureFailed": "Anlık görüntü yakalanamadı.",
"downloadStarted": "Anlık görüntü indirme işlemi başlatıldı." "downloadStarted": "Anlık görüntü indirme işlemi başlatıldı."
},
"noCameras": {
"title": "Hiç Kamera Yapılandırılmamış",
"description": "Frigatee bir kamera bağlayarak başlayın.",
"buttonText": "Kamera Ekle",
"restricted": {
"title": "Kullanılabilir Kamera Yok",
"description": "Bu gruptaki kameraları görüntüleme izniniz yok."
}
} }
} }

View File

@ -839,53 +839,5 @@
"deleteTriggerFailed": "Tetik silinemedi: {{errorMessage}}" "deleteTriggerFailed": "Tetik silinemedi: {{errorMessage}}"
} }
} }
},
"cameraWizard": {
"title": "Kamera Ekle",
"description": "Aşağıdaki adımları izleyerek Frigate kurulumunuza yeni bir kamera ekleyin.",
"steps": {
"nameAndConnection": "Ad & Bağlantı",
"probeOrSnapshot": "Probe veya Anlık Görüntü",
"streamConfiguration": "Akış Yapılandırması",
"validationAndTesting": "Doğrulama ve Test"
},
"save": {
"success": "Yeni kamera {{cameraName}} başarıyla kaydedildi.",
"failure": "{{cameraName}} kaydedilirken hata oluştu."
},
"testResultLabels": {
"resolution": "Çözünürlük",
"video": "Video",
"audio": "Ses",
"fps": "FPS"
},
"commonErrors": {
"noUrl": "Lütfen geçerli bir akış URL'si sağlayın",
"testFailed": "Akış testi başarısız oldu: {{error}}"
},
"step1": {
"description": "Kamera bilgilerinizi girin ve kamerayı taramayı (probe) ya da markayı manuel olarak seçmeyi tercih edin.",
"cameraName": "Kamera Adı",
"cameraNamePlaceholder": "ör. front_door veya Arka Bahçe Genel Görünümü",
"host": "Ana Makine / IP Adresi",
"port": "Port",
"username": "Kullanıcı adı",
"usernamePlaceholder": "İsteğe bağlı",
"password": "Şifre",
"passwordPlaceholder": "İsteğe bağlı",
"selectTransport": "İletişim protokolünü seçin",
"cameraBrand": "Kamera Markası",
"selectBrand": "URL şablonu için kamera markasını seçin",
"customUrl": "Özel Akış URLsi",
"brandInformation": "Marka Bilgileri",
"brandUrlFormat": "RTSP URL formatı şu şekilde olan kameralar için: {{exampleUrl}}",
"customUrlPlaceholder": "rtsp://kullanıcıadı:şifre@host:port/path",
"connectionSettings": "Bağlantı Ayarları",
"detectionMethod": "Akış Algılama Yöntemi",
"onvifPort": "ONVIF Portu",
"probeMode": "Kamerayı tara",
"manualMode": "Manuel seçim",
"detectionMethodDescription": "Kamera akış URLlerini bulmak için kamerayı ONVIF ile tarayın (destekleniyorsa) veya ön tanımlı URLleri kullanmak için kamera markasını manuel olarak seçin. Özel bir RTSP URLsi girmek için manuel yöntemi seçin ve “Diğer”i işaretleyin."
}
} }
} }

View File

@ -159,17 +159,10 @@
"plate_recognition": "Plaka Tanıma", "plate_recognition": "Plaka Tanıma",
"face_recognition_speed": "Yüz Tanıma Hızı", "face_recognition_speed": "Yüz Tanıma Hızı",
"yolov9_plate_detection_speed": "YOLOv9 Plaka Tanıma Hızı", "yolov9_plate_detection_speed": "YOLOv9 Plaka Tanıma Hızı",
"yolov9_plate_detection": "YOLOv9 Plaka Tanıma", "yolov9_plate_detection": "YOLOv9 Plaka Tanıma"
"review_description": "İnceleme Açıklaması",
"review_description_speed": "İnceleme Açıklama Hızı",
"review_description_events_per_second": "İnceleme Açıklaması",
"object_description": "Nesne Açıklaması",
"object_description_speed": "Nesne Açıklama Hızı",
"object_description_events_per_second": "Nesne Açıklaması"
}, },
"infPerSecond": "Saniye Başına Çıkarım", "infPerSecond": "Saniye Başına Çıkarım",
"title": "Zenginleştirmeler", "title": "Zenginleştirmeler"
"averageInf": "Ortalama Çıkarım Süresi"
}, },
"logs": { "logs": {
"download": { "download": {

View File

@ -156,7 +156,7 @@
"modelCreated": "Модель успішно створено. Використовуйте режим перегляду «Нещодавні класифікації», щоб додати зображення для відсутніх станів, а потім навчіть модель.", "modelCreated": "Модель успішно створено. Використовуйте режим перегляду «Нещодавні класифікації», щоб додати зображення для відсутніх станів, а потім навчіть модель.",
"missingStatesWarning": { "missingStatesWarning": {
"title": "Приклади відсутніх станів", "title": "Приклади відсутніх станів",
"description": "Для найкращих результатів рекомендується вибрати приклади для всіх станів. Ви можете продовжити, не вибираючи всі стани, але модель не буде навчена, доки всі стани не матимуть зображень. Після продовження скористайтеся поданням «Нещодавні класифікації», щоб класифікувати зображення для відсутніх станів, а потім навчіть модель." "description": "Ви не вибрали приклади для всіх станів. Модель не буде навчена, доки всі стани не матимуть зображень. Після продовження скористайтеся поданням «Нещодавні класифікації», щоб класифікувати зображення для відсутніх станів, а потім навчіть модель."
} }
} }
}, },

View File

@ -161,7 +161,7 @@
"name": { "name": {
"inputPlaceHolder": "Введіть назву…", "inputPlaceHolder": "Введіть назву…",
"title": "Ім'я", "title": "Ім'я",
"tips": "Назва має містити щонайменше 2 символи, принаймні одну літеру та не повинна бути назвою камери чи іншої зони на цій камері." "tips": "Назва має містити щонайменше 2 символи, принаймні одну літеру та не повинна бути назвою камери чи іншої зони."
}, },
"desc": { "desc": {
"title": "Зони дозволяють визначити певну область кадру, щоб ви могли визначити, чи знаходиться об'єкт у певній області.", "title": "Зони дозволяють визначити певну область кадру, щоб ви могли визначити, чи знаходиться об'єкт у певній області.",

View File

@ -1,12 +0,0 @@
// Module-level flag to prevent multiple simultaneous redirects
// (eg, when multiple SWR queries fail with 401 at once, or when
// both ApiProvider and ProtectedRoute try to redirect)
let _isRedirectingToLogin = false;
export function isRedirectingToLogin(): boolean {
return _isRedirectingToLogin;
}
export function setRedirectingToLogin(value: boolean): void {
_isRedirectingToLogin = value;
}

View File

@ -3,7 +3,6 @@ import { SWRConfig } from "swr";
import { WsProvider } from "./ws"; import { WsProvider } from "./ws";
import axios from "axios"; import axios from "axios";
import { ReactNode } from "react"; import { ReactNode } from "react";
import { isRedirectingToLogin, setRedirectingToLogin } from "./auth-redirect";
axios.defaults.baseURL = `${baseUrl}api/`; axios.defaults.baseURL = `${baseUrl}api/`;
@ -32,8 +31,7 @@ export function ApiProvider({ children, options }: ApiProviderType) {
) { ) {
// redirect to the login page if not already there // redirect to the login page if not already there
const loginPage = error.response.headers.get("location") ?? "login"; const loginPage = error.response.headers.get("location") ?? "login";
if (window.location.href !== loginPage && !isRedirectingToLogin()) { if (window.location.href !== loginPage) {
setRedirectingToLogin(true);
window.location.href = loginPage; window.location.href = loginPage;
} }
} }

View File

@ -1,11 +1,7 @@
import { useContext, useEffect } from "react"; import { useContext } from "react";
import { Navigate, Outlet } from "react-router-dom"; import { Navigate, Outlet } from "react-router-dom";
import { AuthContext } from "@/context/auth-context"; import { AuthContext } from "@/context/auth-context";
import ActivityIndicator from "../indicators/activity-indicator"; import ActivityIndicator from "../indicators/activity-indicator";
import {
isRedirectingToLogin,
setRedirectingToLogin,
} from "@/api/auth-redirect";
export default function ProtectedRoute({ export default function ProtectedRoute({
requiredRoles, requiredRoles,
@ -14,20 +10,6 @@ export default function ProtectedRoute({
}) { }) {
const { auth } = useContext(AuthContext); const { auth } = useContext(AuthContext);
// Redirect to login page when not authenticated
// don't use <Navigate> because we need a full page load to reset state
useEffect(() => {
if (
!auth.isLoading &&
auth.isAuthenticated &&
!auth.user &&
!isRedirectingToLogin()
) {
setRedirectingToLogin(true);
window.location.href = "/login";
}
}, [auth.isLoading, auth.isAuthenticated, auth.user]);
if (auth.isLoading) { if (auth.isLoading) {
return ( return (
<ActivityIndicator className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2" /> <ActivityIndicator className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2" />
@ -41,9 +23,7 @@ export default function ProtectedRoute({
// Authenticated mode (8971): require login // Authenticated mode (8971): require login
if (!auth.user) { if (!auth.user) {
return ( return <Navigate to="/login" replace />;
<ActivityIndicator className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2" />
);
} }
// If role is null (shouldnt happen if isAuthenticated, but type safety), fallback // If role is null (shouldnt happen if isAuthenticated, but type safety), fallback

View File

@ -23,7 +23,6 @@ import { useTranslation } from "react-i18next";
import { ImageShadowOverlay } from "../overlay/ImageShadowOverlay"; import { ImageShadowOverlay } from "../overlay/ImageShadowOverlay";
import BlurredIconButton from "../button/BlurredIconButton"; import BlurredIconButton from "../button/BlurredIconButton";
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip"; import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip";
import { useIsAdmin } from "@/hooks/use-is-admin";
type ExportProps = { type ExportProps = {
className: string; className: string;
@ -41,7 +40,6 @@ export default function ExportCard({
onDelete, onDelete,
}: ExportProps) { }: ExportProps) {
const { t } = useTranslation(["views/exports"]); const { t } = useTranslation(["views/exports"]);
const isAdmin = useIsAdmin();
const [hovered, setHovered] = useState(false); const [hovered, setHovered] = useState(false);
const [loading, setLoading] = useState( const [loading, setLoading] = useState(
exportedRecording.thumb_path.length > 0, exportedRecording.thumb_path.length > 0,
@ -197,7 +195,7 @@ export default function ExportCard({
</Tooltip> </Tooltip>
</a> </a>
)} )}
{isAdmin && !exportedRecording.in_progress && ( {!exportedRecording.in_progress && (
<Tooltip> <Tooltip>
<TooltipTrigger asChild> <TooltipTrigger asChild>
<BlurredIconButton <BlurredIconButton
@ -214,23 +212,21 @@ export default function ExportCard({
<TooltipContent>{t("tooltip.editName")}</TooltipContent> <TooltipContent>{t("tooltip.editName")}</TooltipContent>
</Tooltip> </Tooltip>
)} )}
{isAdmin && ( <Tooltip>
<Tooltip> <TooltipTrigger asChild>
<TooltipTrigger asChild> <BlurredIconButton
<BlurredIconButton onClick={() =>
onClick={() => onDelete({
onDelete({ file: exportedRecording.id,
file: exportedRecording.id, exportName: exportedRecording.name,
exportName: exportedRecording.name, })
}) }
} >
> <LuTrash className="size-4 fill-destructive text-destructive hover:text-white" />
<LuTrash className="size-4 fill-destructive text-destructive hover:text-white" /> </BlurredIconButton>
</BlurredIconButton> </TooltipTrigger>
</TooltipTrigger> <TooltipContent>{t("tooltip.deleteExport")}</TooltipContent>
<TooltipContent>{t("tooltip.deleteExport")}</TooltipContent> </Tooltip>
</Tooltip>
)}
</div> </div>
</div> </div>

View File

@ -407,6 +407,30 @@ export default function Step3ChooseExamples({
return allClasses.every((className) => statesWithExamples.has(className)); return allClasses.every((className) => statesWithExamples.has(className));
}, [step1Data.modelType, allClasses, statesWithExamples]); }, [step1Data.modelType, allClasses, statesWithExamples]);
// For state models on the last class, require all images to be classified
// But allow proceeding even if not all states have examples (with warning)
const canProceed = useMemo(() => {
if (step1Data.modelType === "state" && isLastClass) {
// Check if all 24 images will be classified after current selections are applied
const totalImages = unknownImages.slice(0, 24).length;
// Count images that will be classified (either already classified or currently selected)
const allImages = unknownImages.slice(0, 24);
const willBeClassified = allImages.filter((img) => {
return imageClassifications[img] || selectedImages.has(img);
}).length;
return willBeClassified >= totalImages;
}
return true;
}, [
step1Data.modelType,
isLastClass,
unknownImages,
imageClassifications,
selectedImages,
]);
const hasUnclassifiedImages = useMemo(() => { const hasUnclassifiedImages = useMemo(() => {
if (!unknownImages) return false; if (!unknownImages) return false;
const allImages = unknownImages.slice(0, 24); const allImages = unknownImages.slice(0, 24);
@ -570,7 +594,9 @@ export default function Step3ChooseExamples({
} }
variant="select" variant="select"
className="flex items-center justify-center gap-2 sm:flex-1" className="flex items-center justify-center gap-2 sm:flex-1"
disabled={!hasGenerated || isGenerating || isProcessing} disabled={
!hasGenerated || isGenerating || isProcessing || !canProceed
}
> >
{isProcessing && <ActivityIndicator className="size-4" />} {isProcessing && <ActivityIndicator className="size-4" />}
{t("button.continue", { ns: "common" })} {t("button.continue", { ns: "common" })}

View File

@ -559,7 +559,6 @@ export function TrackingDetails({
isDetailMode={true} isDetailMode={true}
camera={event.camera} camera={event.camera}
currentTimeOverride={currentTime} currentTimeOverride={currentTime}
enableGapControllerRecovery={true}
/> />
{isVideoLoading && ( {isVideoLoading && (
<ActivityIndicator className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2" /> <ActivityIndicator className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2" />

View File

@ -5,7 +5,7 @@ import {
useRef, useRef,
useState, useState,
} from "react"; } from "react";
import Hls, { HlsConfig } from "hls.js"; import Hls from "hls.js";
import { isDesktop, isMobile } from "react-device-detect"; import { isDesktop, isMobile } from "react-device-detect";
import { TransformComponent, TransformWrapper } from "react-zoom-pan-pinch"; import { TransformComponent, TransformWrapper } from "react-zoom-pan-pinch";
import VideoControls from "./VideoControls"; import VideoControls from "./VideoControls";
@ -57,7 +57,6 @@ type HlsVideoPlayerProps = {
isDetailMode?: boolean; isDetailMode?: boolean;
camera?: string; camera?: string;
currentTimeOverride?: number; currentTimeOverride?: number;
enableGapControllerRecovery?: boolean;
}; };
export default function HlsVideoPlayer({ export default function HlsVideoPlayer({
@ -82,7 +81,6 @@ export default function HlsVideoPlayer({
isDetailMode = false, isDetailMode = false,
camera, camera,
currentTimeOverride, currentTimeOverride,
enableGapControllerRecovery = false,
}: HlsVideoPlayerProps) { }: HlsVideoPlayerProps) {
const { t } = useTranslation("components/player"); const { t } = useTranslation("components/player");
const { data: config } = useSWR<FrigateConfig>("config"); const { data: config } = useSWR<FrigateConfig>("config");
@ -172,23 +170,11 @@ export default function HlsVideoPlayer({
return; return;
} }
// Base HLS configuration hlsRef.current = new Hls({
const baseConfig: Partial<HlsConfig> = {
maxBufferLength: 10, maxBufferLength: 10,
maxBufferSize: 20 * 1000 * 1000, maxBufferSize: 20 * 1000 * 1000,
startPosition: currentSource.startPosition, startPosition: currentSource.startPosition,
}; });
const hlsConfig = { ...baseConfig };
if (enableGapControllerRecovery) {
hlsConfig.highBufferWatchdogPeriod = 1; // Check for stalls every 1 second (default: 3)
hlsConfig.nudgeOffset = 0.2; // Nudge playhead forward 0.2s when stalled (default: 0.1)
hlsConfig.nudgeMaxRetry = 5; // Try up to 5 nudges before giving up (default: 3)
hlsConfig.maxBufferHole = 0.5; // Tolerate up to 0.5s gaps between fragments (default: 0.1)
}
hlsRef.current = new Hls(hlsConfig);
hlsRef.current.attachMedia(videoRef.current); hlsRef.current.attachMedia(videoRef.current);
hlsRef.current.loadSource(currentSource.playlist); hlsRef.current.loadSource(currentSource.playlist);
videoRef.current.playbackRate = currentPlaybackRate; videoRef.current.playbackRate = currentPlaybackRate;
@ -201,13 +187,7 @@ export default function HlsVideoPlayer({
hlsRef.current.destroy(); hlsRef.current.destroy();
} }
}; };
}, [ }, [videoRef, hlsRef, useHlsCompat, currentSource]);
videoRef,
hlsRef,
useHlsCompat,
currentSource,
enableGapControllerRecovery,
]);
// state handling // state handling