mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-01-22 20:18:30 +03:00
Compare commits
13 Commits
702c9a5f16
...
7ddf88f823
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ddf88f823 | ||
|
|
c9719d32d2 | ||
|
|
4e71d88e53 | ||
|
|
c3e9be2b0e | ||
|
|
035376f04f | ||
|
|
891f8e21f0 | ||
|
|
f67f09dbec | ||
|
|
2c0dddba1d | ||
|
|
203fe7c871 | ||
|
|
b1d8ffdffc | ||
|
|
e1bbb9ed21 | ||
|
|
c90ece33cd | ||
|
|
0a8f499640 |
5
.github/copilot-instructions.md
vendored
5
.github/copilot-instructions.md
vendored
@ -1,2 +1,3 @@
|
||||
Never write strings in the frontend directly, always write to and reference the relevant translations file.
|
||||
Always conform new and refactored code to the existing coding style in the project.
|
||||
- For Frigate NVR, never write strings in the frontend directly. Since the project uses `react-i18next`, use `t()` and write the English string in the relevant translations file in `web/public/locales/en`.
|
||||
- Always conform new and refactored code to the existing coding style in the project.
|
||||
- Always have a way to test your work and confirm your changes. When running backend tests, use `python3 -u -m unittest`.
|
||||
|
||||
@ -66,8 +66,6 @@ Some models are labeled as **hybrid** (capable of both thinking and instruct tas
|
||||
**Recommendation:**
|
||||
Always select the `-instruct` or documented instruct/tagged variant of any model you use in your Frigate configuration. If in doubt, refer to your model provider’s documentation or model library for guidance on the correct model variant to use.
|
||||
|
||||
|
||||
|
||||
### Supported Models
|
||||
|
||||
You must use a vision capable model with Frigate. Current model variants can be found [in their model library](https://ollama.com/search?c=vision). Note that Frigate will not automatically download the model you specify in your config, you must download the model to your local instance of Ollama first i.e. by running `ollama pull qwen3-vl:2b-instruct` on your Ollama server/Docker container. Note that the model specified in Frigate's config must match the downloaded model tag.
|
||||
@ -93,7 +91,7 @@ genai:
|
||||
|
||||
## Google Gemini
|
||||
|
||||
Google Gemini has a free tier allowing [15 queries per minute](https://ai.google.dev/pricing) to the API, which is more than sufficient for standard Frigate usage.
|
||||
Google Gemini has a [free tier](https://ai.google.dev/pricing) for the API, however the limits may not be sufficient for standard Frigate usage. Choose a plan appropriate for your installation.
|
||||
|
||||
### Supported Models
|
||||
|
||||
@ -114,7 +112,7 @@ To start using Gemini, you must first get an API key from [Google AI Studio](htt
|
||||
genai:
|
||||
provider: gemini
|
||||
api_key: "{FRIGATE_GEMINI_API_KEY}"
|
||||
model: gemini-2.0-flash
|
||||
model: gemini-2.5-flash
|
||||
```
|
||||
|
||||
:::note
|
||||
|
||||
@ -68,8 +68,8 @@ Fine-tune the LPR feature using these optional parameters at the global level of
|
||||
- Default: `1000` pixels. Note: this is intentionally set very low as it is an _area_ measurement (length x width). For reference, 1000 pixels represents a ~32x32 pixel square in your camera image.
|
||||
- Depending on the resolution of your camera's `detect` stream, you can increase this value to ignore small or distant plates.
|
||||
- **`device`**: Device to use to run license plate detection _and_ recognition models.
|
||||
- Default: `CPU`
|
||||
- This can be `CPU`, `GPU`, or the GPU's device number. For users without a model that detects license plates natively, using a GPU may increase performance of the YOLOv9 license plate detector model. See the [Hardware Accelerated Enrichments](/configuration/hardware_acceleration_enrichments.md) documentation. However, for users who run a model that detects `license_plate` natively, there is little to no performance gain reported with running LPR on GPU compared to the CPU.
|
||||
- Default: `None`
|
||||
- This is auto-selected by Frigate and can be `CPU`, `GPU`, or the GPU's device number. For users without a model that detects license plates natively, using a GPU may increase performance of the YOLOv9 license plate detector model. See the [Hardware Accelerated Enrichments](/configuration/hardware_acceleration_enrichments.md) documentation. However, for users who run a model that detects `license_plate` natively, there is little to no performance gain reported with running LPR on GPU compared to the CPU.
|
||||
- **`model_size`**: The size of the model used to identify regions of text on plates.
|
||||
- Default: `small`
|
||||
- This can be `small` or `large`.
|
||||
@ -432,6 +432,6 @@ If you are using a model that natively detects `license_plate`, add an _object m
|
||||
|
||||
If you are not using a model that natively detects `license_plate` or you are using dedicated LPR camera mode, only a _motion mask_ over your text is required.
|
||||
|
||||
### I see "Error running ... model" in my logs. How can I fix this?
|
||||
### I see "Error running ... model" in my logs, or my inference time is very high. How can I fix this?
|
||||
|
||||
This usually happens when your GPU is unable to compile or use one of the LPR models. Set your `device` to `CPU` and try again. GPU acceleration only provides a slight performance increase, and the models are lightweight enough to run without issue on most CPUs.
|
||||
|
||||
@ -23,7 +23,12 @@ from markupsafe import escape
|
||||
from peewee import SQL, fn, operator
|
||||
from pydantic import ValidationError
|
||||
|
||||
from frigate.api.auth import allow_any_authenticated, allow_public, require_role
|
||||
from frigate.api.auth import (
|
||||
allow_any_authenticated,
|
||||
allow_public,
|
||||
get_allowed_cameras_for_filter,
|
||||
require_role,
|
||||
)
|
||||
from frigate.api.defs.query.app_query_parameters import AppTimelineHourlyQueryParameters
|
||||
from frigate.api.defs.request.app_body import AppConfigSetBody
|
||||
from frigate.api.defs.tags import Tags
|
||||
@ -687,13 +692,19 @@ def plusModels(request: Request, filterByCurrentModelDetector: bool = False):
|
||||
@router.get(
|
||||
"/recognized_license_plates", dependencies=[Depends(allow_any_authenticated())]
|
||||
)
|
||||
def get_recognized_license_plates(split_joined: Optional[int] = None):
|
||||
def get_recognized_license_plates(
|
||||
split_joined: Optional[int] = None,
|
||||
allowed_cameras: List[str] = Depends(get_allowed_cameras_for_filter),
|
||||
):
|
||||
try:
|
||||
query = (
|
||||
Event.select(
|
||||
SQL("json_extract(data, '$.recognized_license_plate') AS plate")
|
||||
)
|
||||
.where(SQL("json_extract(data, '$.recognized_license_plate') IS NOT NULL"))
|
||||
.where(
|
||||
(SQL("json_extract(data, '$.recognized_license_plate') IS NOT NULL"))
|
||||
& (Event.camera << allowed_cameras)
|
||||
)
|
||||
.distinct()
|
||||
)
|
||||
recognized_license_plates = [row[0] for row in query.tuples()]
|
||||
|
||||
@ -662,6 +662,13 @@ class FrigateConfig(FrigateBaseModel):
|
||||
# generate zone contours
|
||||
if len(camera_config.zones) > 0:
|
||||
for zone in camera_config.zones.values():
|
||||
if zone.filters:
|
||||
for object_name, filter_config in zone.filters.items():
|
||||
zone.filters[object_name] = RuntimeFilterConfig(
|
||||
frame_shape=camera_config.frame_shape,
|
||||
**filter_config.model_dump(exclude_unset=True),
|
||||
)
|
||||
|
||||
zone.generate_contour(camera_config.frame_shape)
|
||||
|
||||
# Set live view stream if none is set
|
||||
|
||||
@ -24,6 +24,14 @@ class GeminiClient(GenAIClient):
|
||||
http_options_dict = {
|
||||
"api_version": "v1",
|
||||
"timeout": int(self.timeout * 1000), # requires milliseconds
|
||||
"retry_options": types.HttpRetryOptions(
|
||||
attempts=3,
|
||||
initial_delay=1.0,
|
||||
max_delay=60.0,
|
||||
exp_base=2.0,
|
||||
jitter=1.0,
|
||||
http_status_codes=[429, 500, 502, 503, 504],
|
||||
),
|
||||
}
|
||||
|
||||
if isinstance(self.genai_config.provider_options, dict):
|
||||
|
||||
@ -632,6 +632,49 @@ class TestConfig(unittest.TestCase):
|
||||
)
|
||||
assert frigate_config.cameras["back"].zones["test"].color != (0, 0, 0)
|
||||
|
||||
def test_zone_filter_area_percent_converts_to_pixels(self):
|
||||
config = {
|
||||
"mqtt": {"host": "mqtt"},
|
||||
"record": {
|
||||
"alerts": {
|
||||
"retain": {
|
||||
"days": 20,
|
||||
}
|
||||
}
|
||||
},
|
||||
"cameras": {
|
||||
"back": {
|
||||
"ffmpeg": {
|
||||
"inputs": [
|
||||
{"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}
|
||||
]
|
||||
},
|
||||
"detect": {
|
||||
"height": 1080,
|
||||
"width": 1920,
|
||||
"fps": 5,
|
||||
},
|
||||
"zones": {
|
||||
"notification": {
|
||||
"coordinates": "0.03,1,0.025,0,0.626,0,0.643,1",
|
||||
"objects": ["person"],
|
||||
"filters": {"person": {"min_area": 0.1}},
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
frigate_config = FrigateConfig(**config)
|
||||
expected_min_area = int(1080 * 1920 * 0.1)
|
||||
assert (
|
||||
frigate_config.cameras["back"]
|
||||
.zones["notification"]
|
||||
.filters["person"]
|
||||
.min_area
|
||||
== expected_min_area
|
||||
)
|
||||
|
||||
def test_zone_relative_matches_explicit(self):
|
||||
config = {
|
||||
"mqtt": {"host": "mqtt"},
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
"untilForTime": "Until {{time}}",
|
||||
"untilForRestart": "Until Frigate restarts.",
|
||||
"untilRestart": "Until restart",
|
||||
"never": "Never",
|
||||
"ago": "{{timeAgo}} ago",
|
||||
"justNow": "Just now",
|
||||
"today": "Today",
|
||||
|
||||
@ -116,7 +116,8 @@
|
||||
"show": "Pokaż {{item}}",
|
||||
"ID": "ID",
|
||||
"none": "Brak",
|
||||
"all": "Wszystko"
|
||||
"all": "Wszystko",
|
||||
"other": "Inne"
|
||||
},
|
||||
"button": {
|
||||
"apply": "Zastosuj",
|
||||
|
||||
@ -50,5 +50,18 @@
|
||||
"biting": "Угриз",
|
||||
"gargling": "Гргорење",
|
||||
"stomach_rumble": "Крчање стомака",
|
||||
"camera": "Камера"
|
||||
"camera": "Камера",
|
||||
"burping": "Подригивање",
|
||||
"skateboard": "Скејтборд",
|
||||
"hiccup": "Штуцање",
|
||||
"fart": "Прдеж",
|
||||
"hands": "Руке",
|
||||
"finger_snapping": "Пуцање прстима",
|
||||
"clapping": "Пљескање",
|
||||
"heartbeat": "Откуцаји срца",
|
||||
"cheering": "Навијање",
|
||||
"applause": "Аплауз",
|
||||
"chatter": "Жамор",
|
||||
"crowd": "Маса",
|
||||
"children_playing": "Деца се играју"
|
||||
}
|
||||
|
||||
@ -23,9 +23,9 @@
|
||||
"pm": "pm",
|
||||
"am": "am",
|
||||
"yr": "{{time}}god",
|
||||
"year_one": "1,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21...",
|
||||
"year_few": "2,3,4,22,23,24,32,33,34,42,...",
|
||||
"year_other": "",
|
||||
"year_one": "{{time}} година",
|
||||
"year_few": "{{time}} године",
|
||||
"year_other": "{{time}} година",
|
||||
"mo": "{{time}}mes",
|
||||
"month_one": "{{time}} месец",
|
||||
"month_few": "{{time}} месеца",
|
||||
@ -45,7 +45,35 @@
|
||||
"s": "{{time}}s",
|
||||
"second_one": "{{time}} секунда",
|
||||
"second_few": "{{time}} секунде",
|
||||
"second_other": "{{time}} секунди"
|
||||
"second_other": "{{time}} секунди",
|
||||
"formattedTimestampHourMinute": {
|
||||
"24hour": "HH:mm"
|
||||
},
|
||||
"formattedTimestampHourMinuteSecond": {
|
||||
"12hour": "h:mm:ss aaa",
|
||||
"24hour": "HH:mm:ss"
|
||||
},
|
||||
"formattedTimestampMonthDayHourMinute": {
|
||||
"12hour": "MMM d, h:mm aaa",
|
||||
"24hour": "MMM d, HH:mm"
|
||||
},
|
||||
"formattedTimestampMonthDayYear": {
|
||||
"12hour": "MMM d, yyyy",
|
||||
"24hour": "MMM d, yyyy"
|
||||
},
|
||||
"formattedTimestampMonthDayYearHourMinute": {
|
||||
"12hour": "MMM d yyyy, h:mm aaa",
|
||||
"24hour": "MMM d yyyy, HH:mm"
|
||||
},
|
||||
"formattedTimestamp": {
|
||||
"12hour": "MMM d, h:mm:ss aaa",
|
||||
"24hour": "MMM d, HH:mm:ss"
|
||||
},
|
||||
"formattedTimestampMonthDay": "MMM d",
|
||||
"formattedTimestampFilename": {
|
||||
"12hour": "MM-dd-yy-h-mm-ss-a",
|
||||
"24hour": "MM-dd-yy-HH-mm-ss"
|
||||
}
|
||||
},
|
||||
"readTheDocumentation": "Прочитајте документацију"
|
||||
}
|
||||
|
||||
@ -73,7 +73,14 @@
|
||||
"options": {
|
||||
"label": "Подешавања",
|
||||
"title": "Опције",
|
||||
"showOptions": "Приказ опција"
|
||||
}
|
||||
"showOptions": "Приказ опција",
|
||||
"hideOptions": "Скривање опција"
|
||||
},
|
||||
"boundingBox": "Оквир",
|
||||
"timestamp": "Временски тренутак",
|
||||
"zones": "Зоне",
|
||||
"mask": "Маска",
|
||||
"motion": "Покрет",
|
||||
"regions": "Региони"
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,7 +83,36 @@
|
||||
"search": {
|
||||
"saveSearch": {
|
||||
"label": "Сачувати претрагу",
|
||||
"desc": "Обезбедите назив за ову сачувану претрагу."
|
||||
"desc": "Обезбедите назив за ову сачувану претрагу.",
|
||||
"placeholder": "Унесите име за вашу претрагу",
|
||||
"overwrite": "{{searchName}} већ постоји. Чување ће преписати постојећу вредност.",
|
||||
"success": "Претрага ({{searchName}}) је сачувана.",
|
||||
"button": {
|
||||
"save": {
|
||||
"label": "Чување ове претраге"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"recording": {
|
||||
"confirmDelete": {
|
||||
"title": "Потврдите брисање",
|
||||
"desc": {
|
||||
"selected": "Да ли сте сигурни да желите да обришете све видео снимке повезане са овом ставком? <br /><br /> Држите притиснут <em>Shift</em> тастер да прескочите овај дијалог у будућности."
|
||||
},
|
||||
"toast": {
|
||||
"success": "Видео снимак повезан са изабраним ставкама за преглед успешно је обрисан.",
|
||||
"error": "Неуспешно брисање: {{error}}"
|
||||
}
|
||||
},
|
||||
"button": {
|
||||
"export": "Извоз",
|
||||
"markAsReviewed": "Означити као прегледано",
|
||||
"markAsUnreviewed": "Означити као непрегледано",
|
||||
"deleteNow": "Обрисати сада"
|
||||
}
|
||||
},
|
||||
"imagePicker": {
|
||||
"selectImage": "Избор сличице за праћени објекат"
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,5 +36,19 @@
|
||||
"snowboard": "Сноуборд",
|
||||
"sports_ball": "Спортска лопта",
|
||||
"baseball_bat": "Палица за бејзбол",
|
||||
"baseball_glove": "Рукавица за бејзбол"
|
||||
"baseball_glove": "Рукавица за бејзбол",
|
||||
"kite": "Змај",
|
||||
"skateboard": "Скејтборд",
|
||||
"surfboard": "Даска за сурфовање",
|
||||
"tennis_racket": "Тениски рекет",
|
||||
"bottle": "Боца",
|
||||
"plate": "Тањир",
|
||||
"wine_glass": "Чаша за вино",
|
||||
"cup": "Шоља",
|
||||
"fork": "Виљушка",
|
||||
"knife": "Нож",
|
||||
"spoon": "Кашика",
|
||||
"bowl": "Посуда",
|
||||
"banana": "Банана",
|
||||
"apple": "Јабука"
|
||||
}
|
||||
|
||||
@ -46,7 +46,8 @@
|
||||
}
|
||||
},
|
||||
"train": {
|
||||
"titleShort": "Скорашње"
|
||||
"titleShort": "Скорашње",
|
||||
"title": "Скорашње класификације"
|
||||
},
|
||||
"deleteCategory": {
|
||||
"title": "Брисање класе",
|
||||
@ -56,6 +57,34 @@
|
||||
},
|
||||
"deleteModel": {
|
||||
"title": "Брисање класификационог модела",
|
||||
"single": "Да ли сте сигурни да желите да обришете {{name}}? Ово ће трајно обрисати све повезане податке, укључујући слике и податке за тренирање. Ова акција се не може накнадно опозвати."
|
||||
"single": "Да ли сте сигурни да желите да обришете {{name}}? Ово ће трајно обрисати све повезане податке, укључујући слике и податке за тренирање. Ова акција се не може накнадно опозвати.",
|
||||
"desc_one": "Да ли сте сигурни да желите да обришете {{count}} модел? Ово ће трајно обрисати све повезане податке, укључујући и слике и податке за тренирање. Ова акција не може бити опозвана накнадно.",
|
||||
"desc_few": "Да ли сте сигурни да желите да обришете {{count}} модела? Ово ће трајно обрисати све повезане податке, укључујући и слике и податке за тренирање. Ова акција не може бити опозвана накнадно.",
|
||||
"desc_other": "Да ли сте сигурни да желите да обришете {{count}} модела? Ово ће трајно обрисати све повезане податке, укључујући и слике и податке за тренирање. Ова акција не може бити опозвана накнадно."
|
||||
},
|
||||
"edit": {
|
||||
"title": "Уређивање класификационог модела",
|
||||
"descriptionState": "Уређивање класа за класификациони модел овог стања. Измене ће захтевати поновно тренирање модела.",
|
||||
"descriptionObject": "Уређивање типа објекта и типа касификације за овај објекат класификационог модела.",
|
||||
"stateClassesInfo": "Напомена: Измена класа стања захтева поновно тренирање модела са ажурираним класама."
|
||||
},
|
||||
"deleteDatasetImages": {
|
||||
"title": "Брисање слика датасета",
|
||||
"desc_one": "Да ли сте сигурни да желите да обришете {{count}} слику из {{dataset}}? Ова акција се не може накнадно опозвати и захтева поновно тренирање модела.",
|
||||
"desc_few": "Да ли сте сигурни да желите да обришете {{count}} слике из {{dataset}}? Ова акција се не може накнадно опозвати и захтева поновно тренирање модела.",
|
||||
"desc_other": "Да ли сте сигурни да желите да обришете {{count}} слика из {{dataset}}? Ова акција се не може накнадно опозвати и захтева поновно тренирање модела."
|
||||
},
|
||||
"deleteTrainImages": {
|
||||
"title": "Брисање слика за тренирање",
|
||||
"desc_one": "Да ли сте сигурни да желите да избришете {{count}} слику? Ова акција не може бити накнадно опозвана.",
|
||||
"desc_few": "Да ли сте сигурни да желите да избришете {{count}} слике? Ова акција не може бити накнадно опозвана.",
|
||||
"desc_other": "Да ли сте сигурни да желите да избришете {{count}} слика? Ова акција не може бити накнадно опозвана."
|
||||
},
|
||||
"renameCategory": {
|
||||
"title": "Преименовање класе",
|
||||
"desc": "Унесите ново име за {{name}}. Мораћете поново да тренирате модел да би промена имала ефекта."
|
||||
},
|
||||
"description": {
|
||||
"invalidName": "Неисправно име. Имена могу да садрже само слова, цифре, размаке, апострофе, доње црте и повлаке."
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,5 +57,9 @@
|
||||
"selected_one": "{{count}} изабрано",
|
||||
"selected_other": "{{count}} изабрано",
|
||||
"select_all": "Све",
|
||||
"camera": "Камера"
|
||||
"camera": "Камера",
|
||||
"detected": "детектовано",
|
||||
"normalActivity": "Нормално",
|
||||
"needsReview": "Потребан је преглед",
|
||||
"securityConcern": "Безбедносно питање"
|
||||
}
|
||||
|
||||
@ -57,6 +57,22 @@
|
||||
"attribute": {
|
||||
"faceOrLicense_plate": "{{attribute}} детектован за {{label}}",
|
||||
"other": "{{label}} је препознат као {{attribute}}"
|
||||
},
|
||||
"gone": "{{label}} преостало",
|
||||
"heard": "{{label}} се чуло",
|
||||
"external": "{{label}} детектован",
|
||||
"header": {
|
||||
"zones": "Зоне",
|
||||
"ratio": "Однос",
|
||||
"area": "Подручје",
|
||||
"score": "Резултат"
|
||||
}
|
||||
},
|
||||
"annotationSettings": {
|
||||
"title": "Подешавања анотације",
|
||||
"showAllZones": {
|
||||
"title": "Приказ свих зона",
|
||||
"desc": "Увек приказати зоне на фрејмовима у којима су објекти ушли у зону."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
{
|
||||
"description": {
|
||||
"addFace": "Prođite kroz dodavanje nove kolekcije u biblioteku lica.",
|
||||
"addFace": "Додавање нове колекције у библиотеку лица отпремањем прве слике.",
|
||||
"placeholder": "Unesite ime za ovu kolekciju",
|
||||
"invalidName": "Nevažeće ime. Imena mogu da sadrže samo slova, brojeve, razmake, apostrofe, donje crte i crtice."
|
||||
"invalidName": "Неисправно име. Имена могу да садрже само слова, цифре, размаке, апострофе, доње црте и повлаке."
|
||||
},
|
||||
"details": {
|
||||
"person": "Osoba",
|
||||
@ -69,5 +69,28 @@
|
||||
},
|
||||
"nofaces": "Нема доступних лица",
|
||||
"trainFaceAs": "Тренирање лица као:",
|
||||
"trainFace": "Тренирање лица"
|
||||
"trainFace": "Тренирање лица",
|
||||
"toast": {
|
||||
"success": {
|
||||
"uploadedImage": "Слика је успешно отпремљена.",
|
||||
"addFaceLibrary": "{{name}} је успешно додат у библиотеку лица!",
|
||||
"deletedFace_one": "Успешно је обрисано {{count}} лице.",
|
||||
"deletedFace_few": "Успешно је обрисано {{count}} лица.",
|
||||
"deletedFace_other": "Успешно је обрисано {{count}} лица.",
|
||||
"deletedName_one": "{{count}} лице је успешно обрисано.",
|
||||
"deletedName_few": "{{count}} лица су успешно обрисана.",
|
||||
"deletedName_other": "{{count}} лица је успешно обрисано.",
|
||||
"renamedFace": "Лице је успешно преименовано у {{name}}",
|
||||
"trainedFace": "Лице је успешно истренирано.",
|
||||
"updatedFaceScore": "Успешно је ажуриран резултат лица за {{name}} ({{score}})."
|
||||
},
|
||||
"error": {
|
||||
"uploadingImageFailed": "Неуспешно отпремање слике: {{errorMessage}}",
|
||||
"addFaceLibraryFailed": "Неуспешно постављање имена лица: {{errorMessage}}",
|
||||
"deleteFaceFailed": "Неуспешно брисање: {{errorMessage}}",
|
||||
"deleteNameFailed": "Неуспешно брисање имена: {{errorMessage}}",
|
||||
"renameFaceFailed": "Неуспешна промена назива лица: {{errorMessage}}",
|
||||
"trainFailed": "Неуспешно тренирање: {{errorMessage}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,6 +88,26 @@
|
||||
"disable": "Искључивање транскрибовања звука уживо"
|
||||
},
|
||||
"autotracking": {
|
||||
"enable": "Омогућавање аутоматског праћења"
|
||||
"enable": "Омогућавање аутоматског праћења",
|
||||
"disable": "Онемогућити аутоматско праћење"
|
||||
},
|
||||
"streamStats": {
|
||||
"enable": "Приказ статистике стримовања",
|
||||
"disable": "Скривање статистике стримовања"
|
||||
},
|
||||
"manualRecording": {
|
||||
"title": "На захтев",
|
||||
"tips": "Преузимање тренутног снепшота или ручно покретање догађаја засновано на подешавањима задржавања снимања ове камере.",
|
||||
"playInBackground": {
|
||||
"label": "Пустити у позадини",
|
||||
"desc": "Укључите ову опцију да наставите стримовање када је плејер скривен."
|
||||
},
|
||||
"showStats": {
|
||||
"label": "Приказ статистике"
|
||||
},
|
||||
"debugView": "Приказ за дебаговање",
|
||||
"start": "Почетак снимања на захтев",
|
||||
"started": "Ручно снимање на захтев је започето.",
|
||||
"failedToStart": "Неуспешно покретање ручног снимања на захтев."
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
"searchFor": "Pretraži {{inputValue}}",
|
||||
"button": {
|
||||
"clear": "Obriši pretragu",
|
||||
"save": "Sačuvaj pretragu",
|
||||
"save": "Чување претраге",
|
||||
"delete": "Izbrišite sačuvanu pretragu",
|
||||
"filterInformation": "Filtriraj informacije",
|
||||
"filterActive": "Aktivni filteri"
|
||||
@ -50,8 +50,24 @@
|
||||
"step1": "Откуцајте назив кључа филтера а затим две тачке (нпр. \"cameras:\").",
|
||||
"step2": "Изаберите предложену или сопствену вредност.",
|
||||
"step3": "Примените више филтера тако што ћете их додати један за другим са размаком између.",
|
||||
"step4": "Филтери за датум (пре: и касније:) користе {{DateFormat}} формат."
|
||||
"step4": "Филтери за датум (пре: и касније:) користе {{DateFormat}} формат.",
|
||||
"step5": "Филтер за временски распон користи {{exampleTime}} формат.",
|
||||
"step6": "Уклоните филтере кликом на 'x' поред њих.",
|
||||
"exampleLabel": "Пример:"
|
||||
}
|
||||
},
|
||||
"header": {
|
||||
"currentFilterType": "Филтрирање вредности",
|
||||
"noFilters": "Филтери",
|
||||
"activeFilters": "Активни филтери"
|
||||
}
|
||||
},
|
||||
"similaritySearch": {
|
||||
"title": "Претрага сличности",
|
||||
"active": "Претрага по сличности је активна",
|
||||
"clear": "Почистити претрагу сличности"
|
||||
},
|
||||
"placeholder": {
|
||||
"search": "Претрага…"
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
"enrichments": "Podešavanja obogaćivanja - Frigate",
|
||||
"masksAndZones": "Uređivač maski i zona - Frigate",
|
||||
"motionTuner": "Tjuner pokreta - Frigate",
|
||||
"general": "Generalna podešavanja - Frigate",
|
||||
"general": "Подењавања UI - Фригејт",
|
||||
"cameraManagement": "Управљање камерама - Фригејт",
|
||||
"cameraReview": "Преглед подешавања камере - Фригејт",
|
||||
"object": "Дебаговање - Фригејт",
|
||||
@ -58,7 +58,30 @@
|
||||
}
|
||||
},
|
||||
"storedLayouts": {
|
||||
"title": "Сачувани распореди"
|
||||
"title": "Сачувани распореди",
|
||||
"desc": "Распоред камера у групи може бити превлачен и може му се променити величина. Позиције су складиштене у локалном Веб браузеру.",
|
||||
"clearAll": "Чишћење свих распореда"
|
||||
},
|
||||
"cameraGroupStreaming": {
|
||||
"title": "Подешавање стримовања за групу камера",
|
||||
"desc": "Подешавања стримовања за сваку групу камера чувају се у локалном браузеру.",
|
||||
"clearAll": "Чишћење свих подешавања стримовања"
|
||||
},
|
||||
"recordingsViewer": {
|
||||
"title": "Преглед снимака",
|
||||
"defaultPlaybackRate": {
|
||||
"label": "Подразумевана брзина репродукције",
|
||||
"desc": "Подразумевана брзина репродукције за снимке."
|
||||
}
|
||||
},
|
||||
"calendar": {
|
||||
"title": "Календар",
|
||||
"firstWeekday": {
|
||||
"label": "Први дан у недељи",
|
||||
"desc": "Дан којим недеље у календару прегледа почињу.",
|
||||
"sunday": "Недеља",
|
||||
"monday": "Понедељак"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
"documentTitle": {
|
||||
"cameras": "Statusi kamera - Frigate",
|
||||
"storage": "Statistika skladištenja - Frigate",
|
||||
"general": "Opšta statistika - Frigate",
|
||||
"general": "Општа статистика - Фригејт",
|
||||
"enrichments": "Statistika obogaćivanja - Frigate",
|
||||
"logs": {
|
||||
"frigate": "Frigate logovi - Frigate",
|
||||
@ -60,9 +60,33 @@
|
||||
},
|
||||
"nvidiaSMIOutput": {
|
||||
"title": "Nvidia SMI излаз",
|
||||
"name": "Назив: {{name}}"
|
||||
"name": "Назив: {{name}}",
|
||||
"driver": "Драјвер: {{driver}}",
|
||||
"cudaComputerCapability": "Способност CUDA рачунања: {{cuda_compute}}",
|
||||
"vbios": "VBios Info: {{vbios}}"
|
||||
},
|
||||
"closeInfo": {
|
||||
"label": "Затварање GPU информација"
|
||||
},
|
||||
"copyInfo": {
|
||||
"label": "Копирање GPU ифнормација"
|
||||
},
|
||||
"toast": {
|
||||
"success": "Копиране су GPU информације у клипборд"
|
||||
}
|
||||
},
|
||||
"npuUsage": "Употреба NPU",
|
||||
"npuMemory": "NPU меморија",
|
||||
"intelGpuWarning": {
|
||||
"title": "Упозорење за Intel GPU статистику",
|
||||
"message": "GPU статистика није доступна",
|
||||
"description": "Ово је познати баг у алатима за извештавање статистике код Intel GPU (intel_gpu_top) где се јавља пуцање и враћа 0% као GPU искоришћење, чак и у случајевима када хардверска акцелерација и детектовање објекта регуларно раде на (i)GPU. Ово није баг у Фригејту. Можете рестартовати хост да привремено поправите проблем и потврдите да GPU ради исправно. Ово не утиче на перформансе."
|
||||
}
|
||||
},
|
||||
"otherProcesses": {
|
||||
"title": "Остали процеси",
|
||||
"processCpuUsage": "Процесна употреба CPU",
|
||||
"processMemoryUsage": "Процесна употреба меморије"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -268,7 +268,7 @@ export default function CreateTriggerDialog({
|
||||
<FormItem className="flex flex-row items-center justify-between">
|
||||
<div className="space-y-0.5">
|
||||
<FormLabel className="text-base">
|
||||
{t("enabled", { ns: "common" })}
|
||||
{t("button.enabled", { ns: "common" })}
|
||||
</FormLabel>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
{t("triggers.dialog.form.enabled.description")}
|
||||
@ -394,7 +394,10 @@ export default function CreateTriggerDialog({
|
||||
</FormLabel>
|
||||
<div className="space-y-2">
|
||||
{availableActions.map((action) => (
|
||||
<div key={action} className="flex items-center space-x-2">
|
||||
<label
|
||||
key={action}
|
||||
className="flex cursor-pointer items-center space-x-2"
|
||||
>
|
||||
<FormControl>
|
||||
<Checkbox
|
||||
checked={form
|
||||
@ -416,10 +419,10 @@ export default function CreateTriggerDialog({
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormLabel className="text-sm font-normal">
|
||||
<span className="text-sm font-normal">
|
||||
{t(`triggers.actions.${action}`)}
|
||||
</FormLabel>
|
||||
</div>
|
||||
</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
<FormDescription>
|
||||
|
||||
@ -142,7 +142,10 @@ export default function Step3ThresholdAndActions({
|
||||
<FormLabel>{t("triggers.dialog.form.actions.title")}</FormLabel>
|
||||
<div className="space-y-2">
|
||||
{availableActions.map((action) => (
|
||||
<div key={action} className="flex items-center space-x-2">
|
||||
<label
|
||||
key={action}
|
||||
className="flex cursor-pointer items-center space-x-2"
|
||||
>
|
||||
<FormControl>
|
||||
<Checkbox
|
||||
checked={form
|
||||
@ -164,10 +167,10 @@ export default function Step3ThresholdAndActions({
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormLabel className="text-sm font-normal">
|
||||
<span className="text-sm font-normal">
|
||||
{t(`triggers.actions.${action}`)}
|
||||
</FormLabel>
|
||||
</div>
|
||||
</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
<FormDescription>
|
||||
@ -197,9 +200,7 @@ export default function Step3ThresholdAndActions({
|
||||
{isLoading && <ActivityIndicator className="mr-2 size-5" />}
|
||||
{isLoading
|
||||
? t("button.saving", { ns: "common" })
|
||||
: t("triggers.dialog.form.save", {
|
||||
defaultValue: "Save Trigger",
|
||||
})}
|
||||
: t("button.save", { ns: "common" })}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@ -206,7 +206,7 @@ function Exports() {
|
||||
>
|
||||
{Object.values(exports).map((item) => (
|
||||
<ExportCard
|
||||
key={item.name}
|
||||
key={item.id}
|
||||
className={
|
||||
search == "" || filteredExports.includes(item) ? "" : "hidden"
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
import { Toaster, toast } from "sonner";
|
||||
import { toast } from "sonner";
|
||||
import { Toaster } from "@/components/ui/sonner";
|
||||
import useSWR from "swr";
|
||||
import axios from "axios";
|
||||
import { Button } from "@/components/ui/button";
|
||||
@ -598,7 +599,7 @@ export default function TriggerView({
|
||||
date_style: "medium",
|
||||
},
|
||||
)
|
||||
: "Never"}
|
||||
: t("never", { ns: "common" })}
|
||||
</span>
|
||||
{trigger_status?.triggers[trigger.name]
|
||||
?.triggering_event_id && (
|
||||
@ -663,7 +664,9 @@ export default function TriggerView({
|
||||
<TableHeader className="sticky top-0 bg-muted/50">
|
||||
<TableRow>
|
||||
<TableHead className="w-4"></TableHead>
|
||||
<TableHead>{t("name", { ns: "common" })}</TableHead>
|
||||
<TableHead>
|
||||
{t("name", { ns: "triggers.table.name" })}
|
||||
</TableHead>
|
||||
<TableHead>{t("triggers.table.type")}</TableHead>
|
||||
<TableHead>
|
||||
{t("triggers.table.lastTriggered")}
|
||||
@ -759,7 +762,7 @@ export default function TriggerView({
|
||||
date_style: "medium",
|
||||
},
|
||||
)
|
||||
: "Never"}
|
||||
: t("time.never", { ns: "common" })}
|
||||
</span>
|
||||
{trigger_status?.triggers[trigger.name]
|
||||
?.triggering_event_id && (
|
||||
|
||||
Loading…
Reference in New Issue
Block a user