mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-07-27 06:09:01 +03:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ede06d794d |
@@ -82,7 +82,6 @@ frontdoor
|
||||
fstype
|
||||
fullchain
|
||||
fullscreen
|
||||
gatekeep
|
||||
genai
|
||||
generativeai
|
||||
genpts
|
||||
|
||||
@@ -10,11 +10,8 @@ body:
|
||||
|
||||
Before submitting, read the [beta documentation][docs].
|
||||
|
||||
By posting here you agree to follow our [AI policy][ai-policy]. Posts that appear to be written by an AI on your behalf may be closed without a response.
|
||||
|
||||
[docs]: https://docs-dev.frigate.video/
|
||||
[discussions]: https://github.com/blakeblackshear/frigate/discussions
|
||||
[ai-policy]: https://github.com/blakeblackshear/frigate/blob/dev/AI_POLICY.md
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
|
||||
@@ -8,12 +8,9 @@ body:
|
||||
|
||||
Before submitting your support request, please [search the discussions][discussions], read the [official Frigate documentation][docs], and read the [Frigate FAQ][faq] pinned at the Discussion page to see if your question has already been answered by the community.
|
||||
|
||||
By posting here you agree to follow our [AI policy][ai-policy]. Posts that appear to be written by an AI on your behalf may be closed without a response.
|
||||
|
||||
[discussions]: https://www.github.com/blakeblackshear/frigate/discussions
|
||||
[docs]: https://docs.frigate.video
|
||||
[faq]: https://github.com/blakeblackshear/frigate/discussions/12724
|
||||
[ai-policy]: https://github.com/blakeblackshear/frigate/blob/dev/AI_POLICY.md
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
|
||||
@@ -8,12 +8,9 @@ body:
|
||||
|
||||
Before submitting your support request, please [search the discussions][discussions], read the [official Frigate documentation][docs], and read the [Frigate FAQ][faq] pinned at the Discussion page to see if your question has already been answered by the community.
|
||||
|
||||
By posting here you agree to follow our [AI policy][ai-policy]. Posts that appear to be written by an AI on your behalf may be closed without a response.
|
||||
|
||||
[discussions]: https://www.github.com/blakeblackshear/frigate/discussions
|
||||
[docs]: https://docs.frigate.video
|
||||
[faq]: https://github.com/blakeblackshear/frigate/discussions/12724
|
||||
[ai-policy]: https://github.com/blakeblackshear/frigate/blob/dev/AI_POLICY.md
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
|
||||
@@ -8,12 +8,9 @@ body:
|
||||
|
||||
Before submitting your support request, please [search the discussions][discussions], read the [official Frigate documentation][docs], and read the [Frigate FAQ][faq] pinned at the Discussion page to see if your question has already been answered by the community.
|
||||
|
||||
By posting here you agree to follow our [AI policy][ai-policy]. Posts that appear to be written by an AI on your behalf may be closed without a response.
|
||||
|
||||
[discussions]: https://www.github.com/blakeblackshear/frigate/discussions
|
||||
[docs]: https://docs.frigate.video
|
||||
[faq]: https://github.com/blakeblackshear/frigate/discussions/12724
|
||||
[ai-policy]: https://github.com/blakeblackshear/frigate/blob/dev/AI_POLICY.md
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
|
||||
@@ -8,12 +8,9 @@ body:
|
||||
|
||||
Before submitting your support request, please [search the discussions][discussions], read the [official Frigate documentation][docs], and read the [Frigate FAQ][faq] pinned at the Discussion page to see if your question has already been answered by the community.
|
||||
|
||||
By posting here you agree to follow our [AI policy][ai-policy]. Posts that appear to be written by an AI on your behalf may be closed without a response.
|
||||
|
||||
[discussions]: https://www.github.com/blakeblackshear/frigate/discussions
|
||||
[docs]: https://docs.frigate.video
|
||||
[faq]: https://github.com/blakeblackshear/frigate/discussions/12724
|
||||
[ai-policy]: https://github.com/blakeblackshear/frigate/blob/dev/AI_POLICY.md
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
|
||||
@@ -8,12 +8,9 @@ body:
|
||||
|
||||
Before submitting your support request, please [search the discussions][discussions], read the [official Frigate documentation][docs], and read the [Frigate FAQ][faq] pinned at the Discussion page to see if your question has already been answered by the community.
|
||||
|
||||
By posting here you agree to follow our [AI policy][ai-policy]. Posts that appear to be written by an AI on your behalf may be closed without a response.
|
||||
|
||||
[discussions]: https://www.github.com/blakeblackshear/frigate/discussions
|
||||
[docs]: https://docs.frigate.video
|
||||
[faq]: https://github.com/blakeblackshear/frigate/discussions/12724
|
||||
[ai-policy]: https://github.com/blakeblackshear/frigate/blob/dev/AI_POLICY.md
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
|
||||
@@ -10,12 +10,9 @@ body:
|
||||
|
||||
**If you are looking for support, start a new discussion and use a support category.**
|
||||
|
||||
By posting here you agree to follow our [AI policy][ai-policy]. Posts that appear to be written by an AI on your behalf may be closed without a response.
|
||||
|
||||
[discussions]: https://www.github.com/blakeblackshear/frigate/discussions
|
||||
[docs]: https://docs.frigate.video
|
||||
[faq]: https://github.com/blakeblackshear/frigate/discussions/12724
|
||||
[ai-policy]: https://github.com/blakeblackshear/frigate/blob/dev/AI_POLICY.md
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
|
||||
@@ -12,14 +12,11 @@ body:
|
||||
|
||||
**If you are unsure if your issue is actually a bug or not, please submit a support request first.**
|
||||
|
||||
By posting here you agree to follow our [AI policy][ai-policy]. Posts that appear to be written by an AI on your behalf may be closed without a response.
|
||||
|
||||
[discussions]: https://www.github.com/blakeblackshear/frigate/discussions
|
||||
[prs]: https://www.github.com/blakeblackshear/frigate/pulls
|
||||
[docs]: https://docs.frigate.video
|
||||
[faq]: https://github.com/blakeblackshear/frigate/discussions/12724
|
||||
[ai]: https://docs.frigate.video
|
||||
[ai-policy]: https://github.com/blakeblackshear/frigate/blob/dev/AI_POLICY.md
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Checklist
|
||||
|
||||
@@ -7,13 +7,6 @@ assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
By posting here you agree to follow our AI policy:
|
||||
https://github.com/blakeblackshear/frigate/blob/dev/AI_POLICY.md
|
||||
|
||||
Requests that appear to be written by an AI on your behalf may be closed without a response.
|
||||
-->
|
||||
|
||||
**Describe what you are trying to accomplish and why in non technical terms**
|
||||
I want to be able to ... so that I can ...
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
_Please read the [contributing guidelines](https://github.com/blakeblackshear/frigate/blob/dev/CONTRIBUTING.md) and the [AI policy](https://github.com/blakeblackshear/frigate/blob/dev/AI_POLICY.md) before submitting a PR. Every PR must be read and submitted by a person, and PRs that appear to be unreviewed AI output will be closed without review._
|
||||
_Please read the [contributing guidelines](https://github.com/blakeblackshear/frigate/blob/dev/CONTRIBUTING.md) before submitting a PR._
|
||||
|
||||
## Proposed change
|
||||
|
||||
|
||||
-126
@@ -1,126 +0,0 @@
|
||||
# Frigate AI Policy
|
||||
|
||||
## TL;DR
|
||||
|
||||
- **Use AI tools if they help you.** We do too. This is about what you post, not which tools you use to write it.
|
||||
- **A person has to read it and send it.** Don't wire a bot or an agent up to post on your behalf.
|
||||
- **Write your posts yourself.** Your own words, the template filled in, and you answering maintainers rather than your assistant.
|
||||
- **Don't paste an AI's guess at the cause as though it were a diagnosis.** Tell us what you actually observed.
|
||||
- **Read your code before you submit it.** Disclose that AI was used, and be ready to explain every line.
|
||||
- **If we misjudge something you wrote, just say so.** We'll take you at your word.
|
||||
|
||||
The rest of this document explains each of these, and why.
|
||||
|
||||
## Scope
|
||||
|
||||
AI tools are a reality of modern development and we're not opposed to their use. You are responsible for anything you submit, however it was produced, and we are responsible for anything we merge and release. We hold a high bar for both.
|
||||
|
||||
This policy applies everywhere this project is discussed: issues, discussions, pull requests, code reviews, and commit comments.
|
||||
|
||||
## Why this exists
|
||||
|
||||
Frigate is built and supported by a small group of maintainers and a community of volunteers who read every post and review every pull request. Nobody here is paid to do it, and time spent reading a post is time not spent fixing bugs or building features.
|
||||
|
||||
We're not opposed to AI tools. We use them too. But content generated by an AI and submitted without review costs a real person real time, and usually gives them less to work with than a few honest sentences would have. That is the problem this policy addresses.
|
||||
|
||||
## A person has to be in the loop
|
||||
|
||||
Every issue, discussion, comment, and pull request here must be read and submitted by a person. Using an AI tool to help you write is fine. Wiring one up to post on your behalf is not.
|
||||
|
||||
Specifically, do not:
|
||||
|
||||
- Connect a bot or agent to GitHub that opens issues, discussions, or pull requests without you reading them first
|
||||
- Post output from a tool you have not read
|
||||
- Use tooling to file bulk or drive-by contributions across the repository
|
||||
|
||||
We will close anything we believe was posted without a person reading it, and we may mark it as spam. Posts that skip the templates are the most common sign of this.
|
||||
|
||||
## Issues, discussions, and comments
|
||||
|
||||
We do not mind if you use AI tools to help you write. Do not have tools post unreviewed content on your behalf. We may hide any comment we believe to be unreviewed AI output.
|
||||
|
||||
Keep posts to what is needed to communicate your point. A long, confidently written, AI-padded post is harder to help with than a short direct one, not easier, and it is usually obvious.
|
||||
|
||||
**Describe your actual problem in your own words.** Tell us what you did, what you expected, and what actually happened. That is the information we need, and only you have it.
|
||||
|
||||
**Do not paste an AI's guess at the cause as though it were a diagnosis.** It is frequently wrong in ways that send everyone down the wrong path, and it buries the details that would have led to the real answer. We would rather see what you observed than what a model inferred.
|
||||
|
||||
**Fill in the template completely.** The templates ask for logs, config, version, and hardware because those are the things needed to help you. An AI cannot supply them for you, and a post missing them cannot be acted on.
|
||||
|
||||
**Answer maintainers yourself.** If we ask you a question, we are asking _you_, not your AI assistant. These are the spaces where we build trust and understanding with the community, and that only works if we're talking to each other. Using AI to fix your grammar or clarity is fine, but the substance has to be yours.
|
||||
|
||||
This applies to pull request descriptions and review replies as much as it does to bug reports and discussions.
|
||||
|
||||
### Quoting AI output
|
||||
|
||||
If you want to include something an AI told you, it must be:
|
||||
|
||||
- In a quote block, using `>`
|
||||
- Disclosed as AI output, saying which tool it came from
|
||||
- Accompanied by your own comment explaining why you think it is relevant
|
||||
|
||||
Keep the excerpt short. Do not paste long transcripts.
|
||||
|
||||
### Non-native English speakers
|
||||
|
||||
AI is genuinely useful for participating in a project that operates in English, and we would rather hear from you through a translation tool than not hear from you at all. Using AI to improve the grammar or clarity of something you wrote yourself is fine.
|
||||
|
||||
If you are translating your posts, make sure the translation says what you meant. Including your original text in a `<details>` block helps us verify the translation if something reads oddly, and keeps the thread readable.
|
||||
|
||||
## Code contributions
|
||||
|
||||
We need to understand your relationship with the code you're submitting. The more AI was involved, the more important it is that you've genuinely reviewed, tested, and understood what it produced.
|
||||
|
||||
Because of the long-term maintenance burden every merged change creates, we require a human in the loop who understands the work the AI produced. Pull requests that appear to be unreviewed AI output will be closed without review.
|
||||
|
||||
### Requirements when AI is used
|
||||
|
||||
If AI is used to generate any portion of the code, contributors must adhere to the following requirements:
|
||||
|
||||
1. **Explicitly disclose the manner in which AI was employed.** The PR template asks for this. Be honest, this won't automatically disqualify your PR. We'd rather have an honest disclosure than find out later. Trust matters more than method.
|
||||
2. **Perform a comprehensive manual review prior to submitting the pull request.** Don't submit code you haven't read carefully and tested locally.
|
||||
3. **Be prepared to explain every line of code you submitted when asked about it by a maintainer.** If you can't explain why something works the way it does, you're not ready to submit it.
|
||||
4. **Check for an existing pull request addressing the same change.** If one exists, comment there and work with its author instead of opening a duplicate.
|
||||
5. **It is strictly prohibited to use AI to write your posts for you** (bug reports, feature requests, pull request descriptions, GitHub discussions, responding to humans, etc.). We need to hear from _you_, not your AI assistant. These are the spaces where we build trust and understanding with contributors, and that only works if we're talking to each other.
|
||||
|
||||
### Established contributors
|
||||
|
||||
Contributors with a long history of thoughtful, quality contributions to Frigate have earned trust through that track record. The level of scrutiny we apply to AI usage naturally reflects that trust. This isn't a formal exemption, it's just how trust works. If you've been around, we know how you think and how you work. If you're new, we're still getting to know you, and clear disclosure helps build that relationship.
|
||||
|
||||
### What this means in practice
|
||||
|
||||
We're not trying to gatekeep how you write code. Use whatever tools make you productive. But there's a difference between using AI as a tool to implement something you understand and handing a feature request to an AI and submitting whatever comes back. The former is fine. The latter creates maintenance risk for the project.
|
||||
|
||||
Some honest context: when we review a PR, we're not just evaluating whether the code works today. We're evaluating whether we can maintain it, debug it, and extend it long-term, often without the original author's involvement. Code that the author doesn't deeply understand is code that nobody understands, and that's a liability.
|
||||
|
||||
One more thing worth saying directly: most maintainers already have access to the same AI tools you do. A PR that's entirely AI-generated, where the author can't explain the design, debug issues independently, or engage substantively in design discussions, doesn't offer something we couldn't produce ourselves. What makes a contribution genuinely valuable is the human judgment and domain understanding behind it, as well as the engagement during review that shapes it into something we can confidently take on long-term.
|
||||
|
||||
## Our use of AI
|
||||
|
||||
The Frigate documentation site has an "Ask AI" search that answers questions from the docs, and we may use AI tooling to help with triage and project management. Like any automated tooling, it is not always right.
|
||||
|
||||
If an AI tool leaves a comment on your contribution, treat it the way you would any other comment. If you think it is wrong, say so, and a brief explanation is enough. Maintainers always have the final say.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Contributions and posts that do not follow this policy will be closed. Depending on the situation, maintainers may also:
|
||||
|
||||
- Hide or delete comments that appear to be unreviewed AI output
|
||||
- Mark automated content as spam
|
||||
- Close an issue, discussion, or pull request without further review
|
||||
- Lock a conversation
|
||||
- Temporarily or permanently block an account from participating in the project
|
||||
|
||||
Repeated violations may result in being blocked from contributing to Frigate.
|
||||
|
||||
### When we get it wrong
|
||||
|
||||
There is no reliable way to detect this, and we're not going to pretend otherwise. Whether something reads as unreviewed AI output is a judgment call, usually made quickly, by a volunteer with limited time and no way to know for certain. These calls are subjective and we won't always get them right.
|
||||
|
||||
If it happens to you, just say so. A short reply telling us you wrote it yourself is enough, and we'll take you at your word and pick the conversation back up. We would much rather occasionally reopen something we misjudged than treat everyone who posts here as a suspect.
|
||||
|
||||
We'd ask for some understanding in return. These calls get made quickly because the volume is real, and time spent second-guessing them is time not spent helping the person in the next thread.
|
||||
|
||||
## Attribution
|
||||
|
||||
Portions of this policy are adapted from the [Open Home Foundation AI Policy](https://developers.home-assistant.io/docs/ai_policy/).
|
||||
+19
-9
@@ -2,8 +2,6 @@
|
||||
|
||||
Thank you for your interest in contributing to Frigate. This document covers the expectations and guidelines for contributions. Please read it before submitting a pull request.
|
||||
|
||||
All participation in this project, including pull requests, issues, and discussions, is covered by our [AI policy](AI_POLICY.md).
|
||||
|
||||
## Before you start
|
||||
|
||||
### Bugfixes
|
||||
@@ -23,16 +21,28 @@ Before writing code for a new feature:
|
||||
|
||||
## AI usage policy
|
||||
|
||||
AI tools are a reality of modern development and we're not opposed to their use. But we need to understand your relationship with the code you're submitting, and we need to hear from you rather than from your AI assistant.
|
||||
AI tools are a reality of modern development and we're not opposed to their use. But we need to understand your relationship with the code you're submitting. The more AI was involved, the more important it is that you've genuinely reviewed, tested, and understood what it produced.
|
||||
|
||||
**Read the [AI policy](AI_POLICY.md) before you open a pull request.** It is short, and it applies to everything you post here. The parts that most often catch people out:
|
||||
### Requirements when AI is used
|
||||
|
||||
- A person has to be in the loop. Don't wire a bot or agent up to open pull requests, issues, or discussions on your behalf.
|
||||
- Disclose how AI was used. The PR template asks for this. Be honest, it won't automatically disqualify your PR.
|
||||
- Review and test everything you submit, and be prepared to explain every line when asked.
|
||||
- Don't use AI to write your PR description or your replies to maintainers.
|
||||
If AI is used to generate any portion of the code, contributors must adhere to the following requirements:
|
||||
|
||||
Pull requests that appear to be unreviewed AI output will be closed without review.
|
||||
1. **Explicitly disclose the manner in which AI was employed.** The PR template asks for this. Be honest — this won't automatically disqualify your PR. We'd rather have an honest disclosure than find out later. Trust matters more than method.
|
||||
2. **Perform a comprehensive manual review prior to submitting the pull request.** Don't submit code you haven't read carefully and tested locally.
|
||||
3. **Be prepared to explain every line of code they submitted when asked about it by a maintainer.** If you can't explain why something works the way it does, you're not ready to submit it.
|
||||
4. **It is strictly prohibited to use AI to write your posts for you** (bug reports, feature requests, pull request descriptions, GitHub discussions, responding to humans, etc.). We need to hear from _you_, not your AI assistant. These are the spaces where we build trust and understanding with contributors, and that only works if we're talking to each other.
|
||||
|
||||
### Established contributors
|
||||
|
||||
Contributors with a long history of thoughtful, quality contributions to Frigate have earned trust through that track record. The level of scrutiny we apply to AI usage naturally reflects that trust. This isn't a formal exemption — it's just how trust works. If you've been around, we know how you think and how you work. If you're new, we're still getting to know you, and clear disclosure helps build that relationship.
|
||||
|
||||
### What this means in practice
|
||||
|
||||
We're not trying to gatekeep how you write code. Use whatever tools make you productive. But there's a difference between using AI as a tool to implement something you understand and handing a feature request to an AI and submitting whatever comes back. The former is fine. The latter creates maintenance risk for the project.
|
||||
|
||||
Some honest context: when we review a PR, we're not just evaluating whether the code works today. We're evaluating whether we can maintain it, debug it, and extend it long-term — often without the original author's involvement. Code that the author doesn't deeply understand is code that nobody understands, and that's a liability.
|
||||
|
||||
One more thing worth saying directly: most maintainers already have access to the same AI tools you do. A PR that's entirely AI-generated — where the author can't explain the design, debug issues independently, or engage substantively in design discussions — doesn't offer something we couldn't produce ourselves. What makes a contribution genuinely valuable is the human judgment and domain understanding behind it, as well as the engagement during review that shapes it into something we can confidently take on long-term.
|
||||
|
||||
## Pull request guidelines
|
||||
|
||||
|
||||
@@ -34,12 +34,13 @@ edgeTPU:
|
||||
type: edgetpu
|
||||
device: usb
|
||||
|
||||
model:
|
||||
model_type: yolo-generic
|
||||
width: 320 # <--- should match the imgsize of the model, typically 320
|
||||
height: 320 # <--- should match the imgsize of the model, typically 320
|
||||
path: /config/model_cache/yolov9-s-relu6-best_320_int8_edgetpu.tflite
|
||||
labelmap_path: /config/labels-coco17.txt
|
||||
models:
|
||||
default:
|
||||
model_type: yolo-generic
|
||||
width: 320 # <--- should match the imgsize of the model, typically 320
|
||||
height: 320 # <--- should match the imgsize of the model, typically 320
|
||||
path: /config/model_cache/yolov9-s-relu6-best_320_int8_edgetpu.tflite
|
||||
labelmap_path: /config/labels-coco17.txt
|
||||
hailo8l:
|
||||
title: Hailo-8/Hailo-8L
|
||||
models:
|
||||
@@ -67,27 +68,28 @@ hailo8l:
|
||||
type: hailo8l
|
||||
device: PCIe
|
||||
|
||||
model:
|
||||
width: 320
|
||||
height: 320
|
||||
input_tensor: nhwc
|
||||
input_pixel_format: rgb
|
||||
input_dtype: int
|
||||
model_type: yolo-generic
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
models:
|
||||
default:
|
||||
width: 320
|
||||
height: 320
|
||||
input_tensor: nhwc
|
||||
input_pixel_format: rgb
|
||||
input_dtype: int
|
||||
model_type: yolo-generic
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
|
||||
# The detector automatically selects the default model based on your hardware:
|
||||
# - For Hailo-8 hardware: YOLOv6n (default: yolov6n.hef)
|
||||
# - For Hailo-8L hardware: YOLOv6n (default: yolov6n.hef)
|
||||
#
|
||||
# Optionally, you can specify a local model path to override the default.
|
||||
# If a local path is provided and the file exists, it will be used instead of downloading.
|
||||
# Example:
|
||||
# path: /config/model_cache/hailo/yolov6n.hef
|
||||
#
|
||||
# You can also override using a custom URL:
|
||||
# path: https://hailo-model-zoo.s3.eu-west-2.amazonaws.com/ModelZoo/Compiled/v2.14.0/hailo8/yolov6n.hef
|
||||
# just make sure to give it the write configuration based on the model
|
||||
# The detector automatically selects the default model based on your hardware:
|
||||
# - For Hailo-8 hardware: YOLOv6n (default: yolov6n.hef)
|
||||
# - For Hailo-8L hardware: YOLOv6n (default: yolov6n.hef)
|
||||
#
|
||||
# Optionally, you can specify a local model path to override the default.
|
||||
# If a local path is provided and the file exists, it will be used instead of downloading.
|
||||
# Example:
|
||||
# path: /config/model_cache/hailo/yolov6n.hef
|
||||
#
|
||||
# You can also override using a custom URL:
|
||||
# path: https://hailo-model-zoo.s3.eu-west-2.amazonaws.com/ModelZoo/Compiled/v2.14.0/hailo8/yolov6n.hef
|
||||
# just make sure to give it the write configuration based on the model
|
||||
- key: ssd
|
||||
label: SSD MobileNet v1
|
||||
recommended: false
|
||||
@@ -111,18 +113,19 @@ hailo8l:
|
||||
type: hailo8l
|
||||
device: PCIe
|
||||
|
||||
model:
|
||||
width: 300
|
||||
height: 300
|
||||
input_tensor: nhwc
|
||||
input_pixel_format: rgb
|
||||
model_type: ssd
|
||||
# Specify the local model path (if available) or URL for SSD MobileNet v1.
|
||||
# Example with a local path:
|
||||
# path: /config/model_cache/h8l_cache/ssd_mobilenet_v1.hef
|
||||
#
|
||||
# Or override using a custom URL:
|
||||
# path: https://hailo-model-zoo.s3.eu-west-2.amazonaws.com/ModelZoo/Compiled/v2.14.0/hailo8l/ssd_mobilenet_v1.hef
|
||||
models:
|
||||
default:
|
||||
width: 300
|
||||
height: 300
|
||||
input_tensor: nhwc
|
||||
input_pixel_format: rgb
|
||||
model_type: ssd
|
||||
# Specify the local model path (if available) or URL for SSD MobileNet v1.
|
||||
# Example with a local path:
|
||||
# path: /config/model_cache/h8l_cache/ssd_mobilenet_v1.hef
|
||||
#
|
||||
# Or override using a custom URL:
|
||||
# path: https://hailo-model-zoo.s3.eu-west-2.amazonaws.com/ModelZoo/Compiled/v2.14.0/hailo8l/ssd_mobilenet_v1.hef
|
||||
openvino:
|
||||
title: OpenVINO
|
||||
models:
|
||||
@@ -171,14 +174,15 @@ openvino:
|
||||
type: openvino
|
||||
device: GPU # or NPU
|
||||
|
||||
model:
|
||||
model_type: yolo-generic
|
||||
width: 320 # <--- should match the imgsize set during model export
|
||||
height: 320 # <--- should match the imgsize set during model export
|
||||
input_tensor: nchw
|
||||
input_dtype: float
|
||||
path: /config/model_cache/yolo.onnx # use the filename you generated above
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
models:
|
||||
default:
|
||||
model_type: yolo-generic
|
||||
width: 320 # <--- should match the imgsize set during model export
|
||||
height: 320 # <--- should match the imgsize set during model export
|
||||
input_tensor: nchw
|
||||
input_dtype: float
|
||||
path: /config/model_cache/yolo.onnx # use the filename you generated above
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
- key: ssd
|
||||
label: SSDLite MobileNet v2
|
||||
recommended: false
|
||||
@@ -202,13 +206,14 @@ openvino:
|
||||
type: openvino
|
||||
device: GPU # Or NPU
|
||||
|
||||
model:
|
||||
width: 300
|
||||
height: 300
|
||||
input_tensor: nhwc
|
||||
input_pixel_format: bgr
|
||||
path: /openvino-model/ssdlite_mobilenet_v2.xml
|
||||
labelmap_path: /openvino-model/coco_91cl_bkgr.txt
|
||||
models:
|
||||
default:
|
||||
width: 300
|
||||
height: 300
|
||||
input_tensor: nhwc
|
||||
input_pixel_format: bgr
|
||||
path: /openvino-model/ssdlite_mobilenet_v2.xml
|
||||
labelmap_path: /openvino-model/coco_91cl_bkgr.txt
|
||||
- key: yolo-legacy
|
||||
label: YOLO (v3, v4, v7)
|
||||
recommended: false
|
||||
@@ -240,14 +245,15 @@ openvino:
|
||||
type: openvino
|
||||
device: GPU # or NPU
|
||||
|
||||
model:
|
||||
model_type: yolo-generic
|
||||
width: 320 # <--- should match the imgsize set during model export
|
||||
height: 320 # <--- should match the imgsize set during model export
|
||||
input_tensor: nchw
|
||||
input_dtype: float
|
||||
path: /config/model_cache/yolo.onnx # use the filename you generated above
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
models:
|
||||
default:
|
||||
model_type: yolo-generic
|
||||
width: 320 # <--- should match the imgsize set during model export
|
||||
height: 320 # <--- should match the imgsize set during model export
|
||||
input_tensor: nchw
|
||||
input_dtype: float
|
||||
path: /config/model_cache/yolo.onnx # use the filename you generated above
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
- key: yolonas
|
||||
label: YOLO-NAS
|
||||
recommended: false
|
||||
@@ -280,14 +286,15 @@ openvino:
|
||||
type: openvino
|
||||
device: GPU
|
||||
|
||||
model:
|
||||
model_type: yolonas
|
||||
width: 320 # <--- should match whatever was set in notebook
|
||||
height: 320 # <--- should match whatever was set in notebook
|
||||
input_tensor: nchw
|
||||
input_pixel_format: bgr
|
||||
path: /config/yolo_nas_s.onnx
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
models:
|
||||
default:
|
||||
model_type: yolonas
|
||||
width: 320 # <--- should match whatever was set in notebook
|
||||
height: 320 # <--- should match whatever was set in notebook
|
||||
input_tensor: nchw
|
||||
input_pixel_format: bgr
|
||||
path: /config/yolo_nas_s.onnx
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
- key: yolox
|
||||
label: YOLOX
|
||||
recommended: false
|
||||
@@ -308,10 +315,11 @@ openvino:
|
||||
type: openvino
|
||||
device: GPU
|
||||
|
||||
model:
|
||||
model_type: yolox
|
||||
path: /config/model_cache/yolox.onnx # use the filename you generated above
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
models:
|
||||
default:
|
||||
model_type: yolox
|
||||
path: /config/model_cache/yolox.onnx # use the filename you generated above
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
- key: rfdetr
|
||||
label: RF-DETR
|
||||
recommended: false
|
||||
@@ -350,13 +358,14 @@ openvino:
|
||||
type: openvino
|
||||
device: GPU
|
||||
|
||||
model:
|
||||
model_type: rfdetr
|
||||
width: 320
|
||||
height: 320
|
||||
input_tensor: nchw
|
||||
input_dtype: float
|
||||
path: /config/model_cache/rfdetr.onnx # use the filename you generated above
|
||||
models:
|
||||
default:
|
||||
model_type: rfdetr
|
||||
width: 320
|
||||
height: 320
|
||||
input_tensor: nchw
|
||||
input_dtype: float
|
||||
path: /config/model_cache/rfdetr.onnx # use the filename you generated above
|
||||
- key: dfine
|
||||
label: D-FINE / DEIMv2
|
||||
recommended: false
|
||||
@@ -448,14 +457,15 @@ openvino:
|
||||
type: openvino
|
||||
device: CPU
|
||||
|
||||
model:
|
||||
model_type: dfine
|
||||
width: 640
|
||||
height: 640
|
||||
input_tensor: nchw
|
||||
input_dtype: float
|
||||
path: /config/model_cache/dfine-s.onnx # use the filename you generated above
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
models:
|
||||
default:
|
||||
model_type: dfine
|
||||
width: 640
|
||||
height: 640
|
||||
input_tensor: nchw
|
||||
input_dtype: float
|
||||
path: /config/model_cache/dfine-s.onnx # use the filename you generated above
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
appleSilicon:
|
||||
title: Apple Silicon
|
||||
models:
|
||||
@@ -504,14 +514,15 @@ appleSilicon:
|
||||
type: zmq
|
||||
endpoint: tcp://host.docker.internal:5555
|
||||
|
||||
model:
|
||||
model_type: yolo-generic
|
||||
width: 320 # <--- should match the imgsize set during model export
|
||||
height: 320 # <--- should match the imgsize set during model export
|
||||
input_tensor: nchw
|
||||
input_dtype: float
|
||||
path: /config/model_cache/yolo.onnx # use the filename you generated above
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
models:
|
||||
default:
|
||||
model_type: yolo-generic
|
||||
width: 320 # <--- should match the imgsize set during model export
|
||||
height: 320 # <--- should match the imgsize set during model export
|
||||
input_tensor: nchw
|
||||
input_dtype: float
|
||||
path: /config/model_cache/yolo.onnx # use the filename you generated above
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
- key: yolo-legacy
|
||||
label: YOLO (v3, v4, v7)
|
||||
recommended: false
|
||||
@@ -543,14 +554,15 @@ appleSilicon:
|
||||
type: zmq
|
||||
endpoint: tcp://host.docker.internal:5555
|
||||
|
||||
model:
|
||||
model_type: yolo-generic
|
||||
width: 320 # <--- should match the imgsize set during model export
|
||||
height: 320 # <--- should match the imgsize set during model export
|
||||
input_tensor: nchw
|
||||
input_dtype: float
|
||||
path: /config/model_cache/yolo.onnx # use the filename you generated above
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
models:
|
||||
default:
|
||||
model_type: yolo-generic
|
||||
width: 320 # <--- should match the imgsize set during model export
|
||||
height: 320 # <--- should match the imgsize set during model export
|
||||
input_tensor: nchw
|
||||
input_dtype: float
|
||||
path: /config/model_cache/yolo.onnx # use the filename you generated above
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
onnx:
|
||||
title: ONNX
|
||||
models:
|
||||
@@ -598,14 +610,15 @@ onnx:
|
||||
onnx:
|
||||
type: onnx
|
||||
|
||||
model:
|
||||
model_type: yolo-generic
|
||||
width: 320 # <--- should match the imgsize set during model export
|
||||
height: 320 # <--- should match the imgsize set during model export
|
||||
input_tensor: nchw
|
||||
input_dtype: float
|
||||
path: /config/model_cache/yolo.onnx # use the filename you generated above
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
models:
|
||||
default:
|
||||
model_type: yolo-generic
|
||||
width: 320 # <--- should match the imgsize set during model export
|
||||
height: 320 # <--- should match the imgsize set during model export
|
||||
input_tensor: nchw
|
||||
input_dtype: float
|
||||
path: /config/model_cache/yolo.onnx # use the filename you generated above
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
- key: rfdetr
|
||||
label: RF-DETR
|
||||
recommended: false
|
||||
@@ -643,13 +656,14 @@ onnx:
|
||||
onnx:
|
||||
type: onnx
|
||||
|
||||
model:
|
||||
model_type: rfdetr
|
||||
width: 320
|
||||
height: 320
|
||||
input_tensor: nchw
|
||||
input_dtype: float
|
||||
path: /config/model_cache/rfdetr.onnx # use the filename you generated above
|
||||
models:
|
||||
default:
|
||||
model_type: rfdetr
|
||||
width: 320
|
||||
height: 320
|
||||
input_tensor: nchw
|
||||
input_dtype: float
|
||||
path: /config/model_cache/rfdetr.onnx # use the filename you generated above
|
||||
- key: yolonas
|
||||
label: YOLO-NAS
|
||||
recommended: false
|
||||
@@ -681,14 +695,15 @@ onnx:
|
||||
onnx:
|
||||
type: onnx
|
||||
|
||||
model:
|
||||
model_type: yolonas
|
||||
width: 320 # <--- should match whatever was set in notebook
|
||||
height: 320 # <--- should match whatever was set in notebook
|
||||
input_pixel_format: bgr
|
||||
input_tensor: nchw
|
||||
path: /config/yolo_nas_s.onnx
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
models:
|
||||
default:
|
||||
model_type: yolonas
|
||||
width: 320 # <--- should match whatever was set in notebook
|
||||
height: 320 # <--- should match whatever was set in notebook
|
||||
input_pixel_format: bgr
|
||||
input_tensor: nchw
|
||||
path: /config/yolo_nas_s.onnx
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
- key: yolox
|
||||
label: YOLOX
|
||||
recommended: false
|
||||
@@ -711,14 +726,15 @@ onnx:
|
||||
onnx:
|
||||
type: onnx
|
||||
|
||||
model:
|
||||
model_type: yolox
|
||||
width: 416 # <--- should match the imgsize set during model export
|
||||
height: 416 # <--- should match the imgsize set during model export
|
||||
input_tensor: nchw
|
||||
input_dtype: float_denorm
|
||||
path: /config/model_cache/yolox_tiny.onnx # use the filename you generated above
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
models:
|
||||
default:
|
||||
model_type: yolox
|
||||
width: 416 # <--- should match the imgsize set during model export
|
||||
height: 416 # <--- should match the imgsize set during model export
|
||||
input_tensor: nchw
|
||||
input_dtype: float_denorm
|
||||
path: /config/model_cache/yolox_tiny.onnx # use the filename you generated above
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
- key: dfine
|
||||
label: D-FINE / DEIMv2
|
||||
recommended: false
|
||||
@@ -809,14 +825,15 @@ onnx:
|
||||
onnx:
|
||||
type: onnx
|
||||
|
||||
model:
|
||||
model_type: dfine
|
||||
width: 640
|
||||
height: 640
|
||||
input_tensor: nchw
|
||||
input_dtype: float
|
||||
path: /config/model_cache/dfine_m_obj2coco.onnx # use the filename you generated above
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
models:
|
||||
default:
|
||||
model_type: dfine
|
||||
width: 640
|
||||
height: 640
|
||||
input_tensor: nchw
|
||||
input_dtype: float
|
||||
path: /config/model_cache/dfine_m_obj2coco.onnx # use the filename you generated above
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
- key: yolo-legacy
|
||||
label: YOLO (v3, v4, v7)
|
||||
recommended: false
|
||||
@@ -847,14 +864,15 @@ onnx:
|
||||
onnx:
|
||||
type: onnx
|
||||
|
||||
model:
|
||||
model_type: yolo-generic
|
||||
width: 320 # <--- should match the imgsize set during model export
|
||||
height: 320 # <--- should match the imgsize set during model export
|
||||
input_tensor: nchw
|
||||
input_dtype: float
|
||||
path: /config/model_cache/yolo.onnx # use the filename you generated above
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
models:
|
||||
default:
|
||||
model_type: yolo-generic
|
||||
width: 320 # <--- should match the imgsize set during model export
|
||||
height: 320 # <--- should match the imgsize set during model export
|
||||
input_tensor: nchw
|
||||
input_dtype: float
|
||||
path: /config/model_cache/yolo.onnx # use the filename you generated above
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
cpu:
|
||||
title: CPU
|
||||
models:
|
||||
@@ -928,18 +946,19 @@ memryx:
|
||||
type: memryx
|
||||
device: PCIe:0
|
||||
|
||||
model:
|
||||
model_type: yolonas
|
||||
width: 320 # (Can be set to 640 for higher resolution)
|
||||
height: 320 # (Can be set to 640 for higher resolution)
|
||||
input_tensor: nchw
|
||||
input_dtype: float
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
# Optional: The model is normally fetched through the runtime, so 'path' can be omitted unless you want to use a custom or local model.
|
||||
# path: /config/yolonas.zip
|
||||
# The .zip file must contain:
|
||||
# ├── yolonas.dfp (a file ending with .dfp)
|
||||
# └── yolonas_post.onnx (optional; only if the model includes a cropped post-processing network)
|
||||
models:
|
||||
default:
|
||||
model_type: yolonas
|
||||
width: 320 # (Can be set to 640 for higher resolution)
|
||||
height: 320 # (Can be set to 640 for higher resolution)
|
||||
input_tensor: nchw
|
||||
input_dtype: float
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
# Optional: The model is normally fetched through the runtime, so 'path' can be omitted unless you want to use a custom or local model.
|
||||
# path: /config/yolonas.zip
|
||||
# The .zip file must contain:
|
||||
# ├── yolonas.dfp (a file ending with .dfp)
|
||||
# └── yolonas_post.onnx (optional; only if the model includes a cropped post-processing network)
|
||||
- key: yolov9
|
||||
label: YOLOv9
|
||||
recommended: false
|
||||
@@ -965,17 +984,18 @@ memryx:
|
||||
type: memryx
|
||||
device: PCIe:0
|
||||
|
||||
model:
|
||||
model_type: yolo-generic
|
||||
width: 320 # (Can be set to 640 for higher resolution)
|
||||
height: 320 # (Can be set to 640 for higher resolution)
|
||||
input_tensor: nchw
|
||||
input_dtype: float
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
# Optional: The model is normally fetched through the runtime, so 'path' can be omitted unless you want to use a custom or local model.
|
||||
# path: /config/yolov9.zip
|
||||
# The .zip file must contain:
|
||||
# ├── yolov9.dfp (a file ending with .dfp)
|
||||
models:
|
||||
default:
|
||||
model_type: yolo-generic
|
||||
width: 320 # (Can be set to 640 for higher resolution)
|
||||
height: 320 # (Can be set to 640 for higher resolution)
|
||||
input_tensor: nchw
|
||||
input_dtype: float
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
# Optional: The model is normally fetched through the runtime, so 'path' can be omitted unless you want to use a custom or local model.
|
||||
# path: /config/yolov9.zip
|
||||
# The .zip file must contain:
|
||||
# ├── yolov9.dfp (a file ending with .dfp)
|
||||
- key: yolox
|
||||
label: YOLOX
|
||||
recommended: false
|
||||
@@ -1001,17 +1021,18 @@ memryx:
|
||||
type: memryx
|
||||
device: PCIe:0
|
||||
|
||||
model:
|
||||
model_type: yolox
|
||||
width: 640
|
||||
height: 640
|
||||
input_tensor: nchw
|
||||
input_dtype: float_denorm
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
# Optional: The model is normally fetched through the runtime, so 'path' can be omitted unless you want to use a custom or local model.
|
||||
# path: /config/yolox.zip
|
||||
# The .zip file must contain:
|
||||
# ├── yolox.dfp (a file ending with .dfp)
|
||||
models:
|
||||
default:
|
||||
model_type: yolox
|
||||
width: 640
|
||||
height: 640
|
||||
input_tensor: nchw
|
||||
input_dtype: float_denorm
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
# Optional: The model is normally fetched through the runtime, so 'path' can be omitted unless you want to use a custom or local model.
|
||||
# path: /config/yolox.zip
|
||||
# The .zip file must contain:
|
||||
# ├── yolox.dfp (a file ending with .dfp)
|
||||
- key: ssd
|
||||
label: SSDLite MobileNet v2
|
||||
recommended: false
|
||||
@@ -1037,18 +1058,19 @@ memryx:
|
||||
type: memryx
|
||||
device: PCIe:0
|
||||
|
||||
model:
|
||||
model_type: ssd
|
||||
width: 320
|
||||
height: 320
|
||||
input_tensor: nchw
|
||||
input_dtype: float
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
# Optional: The model is normally fetched through the runtime, so 'path' can be omitted unless you want to use a custom or local model.
|
||||
# path: /config/ssdlite_mobilenet.zip
|
||||
# The .zip file must contain:
|
||||
# ├── ssdlite_mobilenet.dfp (a file ending with .dfp)
|
||||
# └── ssdlite_mobilenet_post.onnx (optional; only if the model includes a cropped post-processing network)
|
||||
models:
|
||||
default:
|
||||
model_type: ssd
|
||||
width: 320
|
||||
height: 320
|
||||
input_tensor: nchw
|
||||
input_dtype: float
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
# Optional: The model is normally fetched through the runtime, so 'path' can be omitted unless you want to use a custom or local model.
|
||||
# path: /config/ssdlite_mobilenet.zip
|
||||
# The .zip file must contain:
|
||||
# ├── ssdlite_mobilenet.dfp (a file ending with .dfp)
|
||||
# └── ssdlite_mobilenet_post.onnx (optional; only if the model includes a cropped post-processing network)
|
||||
tensorrt:
|
||||
title: TensorRT
|
||||
models:
|
||||
@@ -1087,13 +1109,14 @@ tensorrt:
|
||||
type: tensorrt
|
||||
device: 0 #This is the default, select the first GPU
|
||||
|
||||
model:
|
||||
path: /config/model_cache/tensorrt/yolov7-320.trt # use the filename you generated above
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
input_tensor: nchw
|
||||
input_pixel_format: rgb
|
||||
width: 320 # MUST match the chosen model i.e yolov7-320 -> 320, yolov4-416 -> 416
|
||||
height: 320 # MUST match the chosen model i.e yolov7-320 -> 320 yolov4-416 -> 416
|
||||
models:
|
||||
default:
|
||||
path: /config/model_cache/tensorrt/yolov7-320.trt # use the filename you generated above
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
input_tensor: nchw
|
||||
input_pixel_format: rgb
|
||||
width: 320 # MUST match the chosen model i.e yolov7-320 -> 320, yolov4-416 -> 416
|
||||
height: 320 # MUST match the chosen model i.e yolov7-320 -> 320 yolov4-416 -> 416
|
||||
synaptics:
|
||||
title: Synaptics
|
||||
models:
|
||||
@@ -1261,14 +1284,15 @@ axengine:
|
||||
axengine:
|
||||
type: axengine
|
||||
|
||||
model:
|
||||
path: frigate-yolov9-tiny
|
||||
model_type: yolo-generic
|
||||
width: 320
|
||||
height: 320
|
||||
input_dtype: int
|
||||
input_pixel_format: bgr
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
models:
|
||||
default:
|
||||
path: frigate-yolov9-tiny
|
||||
model_type: yolo-generic
|
||||
width: 320
|
||||
height: 320
|
||||
input_dtype: int
|
||||
input_pixel_format: bgr
|
||||
labelmap_path: /labelmap/coco-80.txt
|
||||
degirumAiServer:
|
||||
title: DeGirum AI Server
|
||||
models:
|
||||
|
||||
@@ -157,44 +157,51 @@ auth:
|
||||
- front_door
|
||||
- back_yard
|
||||
|
||||
# Optional: model modifications
|
||||
# Optional: named object detection models (default: a single model named "default")
|
||||
# Each entry defines a model; cameras choose which model to use with detect.model.
|
||||
# Detectors that support multiple models (openvino, onnx, tensorrt, cpu, rknn) run
|
||||
# one instance per model in use. Detectors that only support a single model
|
||||
# (edgetpu, hailo8l, memryx, and others) are assigned to models round robin, so at
|
||||
# least as many of those detectors as models are required when no multi-model
|
||||
# capable detector is configured.
|
||||
# NOTE: The default values are for the EdgeTPU detector.
|
||||
# Other detectors will require the model config to be set.
|
||||
model:
|
||||
# Required: path to the model. Frigate+ models use plus://<model_id> (default: automatic based on detector)
|
||||
path: /edgetpu_model.tflite
|
||||
# Required: path to the labelmap (default: shown below)
|
||||
labelmap_path: /labelmap.txt
|
||||
# Required: Object detection model input width (default: shown below)
|
||||
width: 320
|
||||
# Required: Object detection model input height (default: shown below)
|
||||
height: 320
|
||||
# Required: Object detection model input colorspace
|
||||
# Valid values are rgb, bgr, or yuv. (default: shown below)
|
||||
input_pixel_format: rgb
|
||||
# Required: Object detection model input tensor format
|
||||
# Valid values are nhwc, nchw, hwnc, or hwcn (default: shown below)
|
||||
input_tensor: nhwc
|
||||
# Optional: Data type of the model input tensor
|
||||
# Valid values are float, float_denorm, or int (default: shown below)
|
||||
input_dtype: int
|
||||
# Required: Object detection model architecture, used by detectors that support more
|
||||
# than one model type (openvino, onnx, rknn, memryx, axengine, synaptics, and others)
|
||||
# Valid values are ssd, yolox, yolonas, yolo-generic, rfdetr, dfine (default: shown below)
|
||||
model_type: ssd
|
||||
# Required: Label name modifications. These are merged into the standard labelmap.
|
||||
labelmap:
|
||||
2: vehicle
|
||||
# Optional: Map of object labels to their attribute labels (default: depends on model)
|
||||
attributes_map:
|
||||
person:
|
||||
- amazon
|
||||
- face
|
||||
car:
|
||||
- amazon
|
||||
- fedex
|
||||
- license_plate
|
||||
- ups
|
||||
models:
|
||||
default:
|
||||
# Required: path to the model. Frigate+ models use plus://<model_id> (default: automatic based on detector)
|
||||
path: /edgetpu_model.tflite
|
||||
# Required: path to the labelmap (default: shown below)
|
||||
labelmap_path: /labelmap.txt
|
||||
# Required: Object detection model input width (default: shown below)
|
||||
width: 320
|
||||
# Required: Object detection model input height (default: shown below)
|
||||
height: 320
|
||||
# Required: Object detection model input colorspace
|
||||
# Valid values are rgb, bgr, or yuv. (default: shown below)
|
||||
input_pixel_format: rgb
|
||||
# Required: Object detection model input tensor format
|
||||
# Valid values are nhwc, nchw, hwnc, or hwcn (default: shown below)
|
||||
input_tensor: nhwc
|
||||
# Optional: Data type of the model input tensor
|
||||
# Valid values are float, float_denorm, or int (default: shown below)
|
||||
input_dtype: int
|
||||
# Required: Object detection model architecture, used by detectors that support more
|
||||
# than one model type (openvino, onnx, rknn, memryx, axengine, synaptics, and others)
|
||||
# Valid values are ssd, yolox, yolonas, yolo-generic, rfdetr, dfine (default: shown below)
|
||||
model_type: ssd
|
||||
# Required: Label name modifications. These are merged into the standard labelmap.
|
||||
labelmap:
|
||||
2: vehicle
|
||||
# Optional: Map of object labels to their attribute labels (default: depends on model)
|
||||
attributes_map:
|
||||
person:
|
||||
- amazon
|
||||
- face
|
||||
car:
|
||||
- amazon
|
||||
- fedex
|
||||
- license_plate
|
||||
- ups
|
||||
|
||||
# Optional: Audio Events Configuration
|
||||
# NOTE: Can be overridden at the camera level
|
||||
@@ -302,6 +309,9 @@ ffmpeg:
|
||||
detect:
|
||||
# Optional: enables detection for the camera (default: shown below)
|
||||
enabled: False
|
||||
# Optional: name of the model (key under models) used by this camera
|
||||
# (default: the only defined model, or the model named "default")
|
||||
model: default
|
||||
# Optional: width of the frame for the input with the detect role (default: use native stream resolution)
|
||||
width: 1280
|
||||
# Optional: height of the frame for the input with the detect role (default: use native stream resolution)
|
||||
|
||||
@@ -192,12 +192,13 @@ Navigate to <NavPath path="Settings > System > Detectors and model" /> and open
|
||||
|
||||
```yaml
|
||||
# Optional: model config
|
||||
model:
|
||||
path: /path/to/model
|
||||
width: 320
|
||||
height: 320
|
||||
input_tensor: "nhwc"
|
||||
input_pixel_format: "bgr"
|
||||
models:
|
||||
default:
|
||||
path: /path/to/model
|
||||
width: 320
|
||||
height: 320
|
||||
input_tensor: "nhwc"
|
||||
input_pixel_format: "bgr"
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@@ -214,15 +215,16 @@ If the labelmap is customized then the labels used for alerts will need to be ad
|
||||
The labelmap can be customized to your needs. A common reason to do this is to combine multiple object types that are easily confused when you don't need to be as granular such as car/truck. By default, truck is renamed to car because they are often confused. You cannot add new object types, but you can change the names of existing objects in the model.
|
||||
|
||||
```yaml
|
||||
model:
|
||||
labelmap:
|
||||
2: vehicle
|
||||
3: vehicle
|
||||
5: vehicle
|
||||
7: vehicle
|
||||
15: animal
|
||||
16: animal
|
||||
17: animal
|
||||
models:
|
||||
default:
|
||||
labelmap:
|
||||
2: vehicle
|
||||
3: vehicle
|
||||
5: vehicle
|
||||
7: vehicle
|
||||
15: animal
|
||||
16: animal
|
||||
17: animal
|
||||
```
|
||||
|
||||
Note that if you rename objects in the labelmap, you will also need to update your `objects -> track` list as well.
|
||||
|
||||
@@ -165,7 +165,7 @@ If available, recommended settings are:
|
||||
|
||||
#### Setup via the Add Camera Wizard
|
||||
|
||||
The [Add Camera Wizard](cameras.md#adding-a-camera-with-the-add-camera-wizard) is the recommended way to add a standard Reolink camera. Before starting, make sure [HTTP is enabled](https://support.reolink.com/articles/360003452893-How-to-Access-Reolink-Cameras-NVRs-Home-Hub-Locally-via-Web-Browsers/) in the camera's advanced network settings. The wizard uses the camera's HTTP API to determine its resolution and choose the recommended stream type from the table above.
|
||||
The Add Camera Wizard is the recommended way to add a standard Reolink camera. Before starting, make sure [HTTP is enabled](https://support.reolink.com/articles/360003452893-How-to-Access-Reolink-Cameras-NVRs-Home-Hub-Locally-via-Web-Browsers/) in the camera's advanced network settings. The wizard uses the camera's HTTP API to determine its resolution and choose the recommended stream type from the table above.
|
||||
|
||||
1. Click **Add Camera** in <NavPath path="Settings > Global configuration > Camera management" />.
|
||||
2. Choose **Manual selection** as the stream detection method and select **Reolink** as the camera brand.
|
||||
|
||||
@@ -7,49 +7,6 @@ import ConfigTabs from "@site/src/components/ConfigTabs";
|
||||
import TabItem from "@theme/TabItem";
|
||||
import NavPath from "@site/src/components/NavPath";
|
||||
|
||||
## Adding a camera with the Add Camera Wizard
|
||||
|
||||
The Add Camera Wizard is the recommended way to add a camera. Click **Add Camera** in <NavPath path="Settings > Global configuration > Camera management" />. The wizard connects to your camera, tests each stream, and writes the camera's configuration for you, including the [go2rtc](go2rtc.md) restream and the live view stream mapping, so a standard setup needs no hand-written YAML.
|
||||
|
||||
### Step 1: Name and connection
|
||||
|
||||
Enter a name for the camera along with its host or IP address and credentials, then choose how the wizard should find the camera's streams:
|
||||
|
||||
- **Probe camera** queries the camera over ONVIF (the ONVIF port is usually 80 or 8080) and asks it for its stream URLs. Some cameras use a separate ONVIF/service account rather than the device admin user, and some require **Use digest authentication** to be enabled.
|
||||
- **Manual selection** builds a stream URL from a template for the camera brand you pick (Dahua/Amcrest/EmpireTech, Hikvision/Uniview/Annke, Ubiquiti, Reolink, Axis, TP-Link, or Foscam). Choose **Other** to enter a custom RTSP URL directly. Non-RTSP stream types must be [configured manually](#setting-up-camera-inputs).
|
||||
|
||||
The name you enter is lowercased and spaces become underscores. If the result still isn't a valid config key, the wizard generates a safe name and stores what you typed as `friendly_name`.
|
||||
|
||||
### Step 2: Probe or snapshot
|
||||
|
||||
In probe mode, the wizard reports what the camera returned (manufacturer, model, firmware, profile count, and whether PTZ, presets, and [autotracking](autotracking.md) are supported) along with the RTSP URLs it discovered. Test each candidate to see its resolution, frame rate, and codecs together with a snapshot, then select the one you want to use.
|
||||
|
||||
In manual mode, the wizard tests the templated URL and shows the same metadata and snapshot.
|
||||
|
||||
If no RTSP URLs are found, the credentials may be wrong or the camera may not support ONVIF. Go back and use manual selection instead.
|
||||
|
||||
### Step 3: Stream configuration
|
||||
|
||||
Assign [roles](#setting-up-camera-inputs) to the stream, and use **Add Another Stream** to add the camera's other streams, for example a substream for `detect` alongside the main stream for `record`. At least one stream must have the `detect` role before you can continue.
|
||||
|
||||
**Reduce connections to camera** routes that input through the go2rtc restream so Frigate and the live view share a single connection to the camera instead of each opening their own. See [restream](restream.md) for more detail.
|
||||
|
||||
### Step 4: Validation and testing
|
||||
|
||||
Connect each stream to get a live preview, an estimated bandwidth figure, and a list of validation results. The wizard checks for the most common misconfigurations, including:
|
||||
|
||||
- A detect resolution that is too high (increased resource usage) or too low for reliable detection, or one it could not probe at all
|
||||
- A stream marked `record` whose audio codec is not AAC, or that has no audio at all
|
||||
- A stream marked `audio` that carries no audio stream
|
||||
- Using a restreamed input for the `record` role
|
||||
- Brand-specific issues, such as an RTSP stream on a Reolink camera that should use http-flv, or a Dahua/Hikvision substream selected for `detect`
|
||||
|
||||
**Use stream compatibility mode** passes the stream through go2rtc's ffmpeg module. Enable it if a stream fails to load after several attempts. Note that this also prevents [two way talk](/configuration/live#two-way-talk) from being detected for that stream.
|
||||
|
||||
**Save New Camera** writes the configuration and starts the camera right away. No restart is required.
|
||||
|
||||
Other features, including [hardware acceleration](hardware_acceleration_video.md), [two way talk](/configuration/live#two-way-talk), and audio transcoding, is configured after the camera has been added. For camera model specific quirks, see the [camera specific](camera_specific.md) docs.
|
||||
|
||||
## Setting Up Camera Inputs
|
||||
|
||||
Several inputs can be configured for each camera and the role of each input can be mixed and matched based on your needs. This allows you to use a lower resolution stream for object detection, but create recordings from a higher resolution stream, or vice versa.
|
||||
@@ -112,7 +69,7 @@ Additional cameras are simply added under the camera configuration section.
|
||||
<ConfigTabs>
|
||||
<TabItem value="ui">
|
||||
|
||||
Navigate to <NavPath path="Settings > Global configuration > Camera management" /> and use the [Add Camera Wizard](#adding-a-camera-with-the-add-camera-wizard) to configure each additional camera.
|
||||
Navigate to <NavPath path="Settings > Global configuration > Camera management" /> and use the add camera button to configure each additional camera.
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="yaml">
|
||||
|
||||
@@ -334,13 +334,14 @@ detectors:
|
||||
type: openvino
|
||||
device: AUTO
|
||||
|
||||
model:
|
||||
width: 300
|
||||
height: 300
|
||||
input_tensor: nhwc
|
||||
input_pixel_format: bgr
|
||||
path: /openvino-model/ssdlite_mobilenet_v2.xml
|
||||
labelmap_path: /openvino-model/coco_91cl_bkgr.txt
|
||||
models:
|
||||
default:
|
||||
width: 300
|
||||
height: 300
|
||||
input_tensor: nhwc
|
||||
input_pixel_format: bgr
|
||||
path: /openvino-model/ssdlite_mobilenet_v2.xml
|
||||
labelmap_path: /openvino-model/coco_91cl_bkgr.txt
|
||||
|
||||
record:
|
||||
enabled: True
|
||||
|
||||
@@ -15,7 +15,7 @@ Frigate uses the bundled go2rtc to power a number of key features:
|
||||
|
||||
:::tip[Most users no longer need to configure go2rtc by hand]
|
||||
|
||||
The [**camera setup wizard**](cameras.md#adding-a-camera-with-the-add-camera-wizard) is the recommended way to add cameras. Click **Add Camera** in <NavPath path="Settings > Global configuration > Camera management" />, and the wizard probes your camera and writes its configuration for you, including the go2rtc restream and the live stream mapping, so go2rtc is set up automatically.
|
||||
The **camera setup wizard** is the recommended way to add cameras. Click **Add Camera** in <NavPath path="Settings > Global configuration > Camera management" />, and the wizard probes your camera and writes its configuration for you, including the go2rtc restream and the live stream mapping, so go2rtc is set up automatically.
|
||||
|
||||
This guide is mainly useful if you are **upgrading from an older version and have existing cameras that don't yet use go2rtc**, or if you want to fine-tune a stream by hand (for example, to transcode a codec your browser can't play). The [go2rtc troubleshooting guide](/troubleshooting/go2rtc) applies regardless of how your cameras were added.
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ If you are using go2rtc, you should adjust the following settings in your camera
|
||||
|
||||
- Video codec: **H.264** - provides the most compatible video codec with all Live view technologies and browsers. Avoid any kind of "smart codec" or "+" codec like _H.264+_ or _H.265+_. as these non-standard codecs remove keyframes (see below).
|
||||
- Audio codec: **AAC** - provides the most compatible audio codec with all Live view technologies and browsers that support audio.
|
||||
- I-frame interval (sometimes called the keyframe interval, the interframe space, or the GOP length): match your camera's frame rate, or choose "1x" (for interframe space on Reolink cameras). For example, if your stream outputs 20fps, your i-frame interval should be 20 (or 1x on Reolink). Values higher than the frame rate will cause the stream to take longer to begin playback. See [this page](https://web.archive.org/web/20251213190836/https://gardinal.net/understanding-the-keyframe-interval/) for more on keyframes. For many users this may not be an issue, but it should be noted that a 1x i-frame interval will cause more storage utilization if you are using the stream for the `record` role as well.
|
||||
- I-frame interval (sometimes called the keyframe interval, the interframe space, or the GOP length): match your camera's frame rate, or choose "1x" (for interframe space on Reolink cameras). For example, if your stream outputs 20fps, your i-frame interval should be 20 (or 1x on Reolink). Values higher than the frame rate will cause the stream to take longer to begin playback. See [this page](https://gardinal.net/understanding-the-keyframe-interval/) for more on keyframes. For many users this may not be an issue, but it should be noted that a 1x i-frame interval will cause more storage utilization if you are using the stream for the `record` role as well.
|
||||
|
||||
The default video and audio codec on your camera may not always be compatible with your browser, which is why setting them to H.264 and AAC is recommended. See the [go2rtc docs](https://github.com/AlexxIT/go2rtc?tab=readme-ov-file#codecs-madness) for codec support information.
|
||||
|
||||
|
||||
@@ -91,6 +91,41 @@ The best detection accuracy comes from a model trained on images that look like
|
||||
|
||||
:::
|
||||
|
||||
### Running multiple models
|
||||
|
||||
Models are defined as named entries under `models`, and each camera selects the model it uses with `detect.model`. This makes it possible to run different models for different groups of cameras, for example a dedicated model for indoor cameras, outdoor cameras, or thermal cameras.
|
||||
|
||||
```yaml
|
||||
detectors:
|
||||
ov:
|
||||
type: openvino
|
||||
device: GPU
|
||||
|
||||
models:
|
||||
indoor:
|
||||
path: /config/model_cache/indoor-model.xml
|
||||
model_type: yolo-generic
|
||||
width: 320
|
||||
height: 320
|
||||
outdoor:
|
||||
path: plus://<your_model_id>
|
||||
|
||||
cameras:
|
||||
living_room:
|
||||
detect:
|
||||
model: indoor
|
||||
driveway:
|
||||
detect:
|
||||
model: outdoor
|
||||
```
|
||||
|
||||
When only one model is defined, all cameras use it automatically. With multiple models, cameras use the model named `default` unless `detect.model` selects another one; `detect.model` can also be set globally and overridden per camera.
|
||||
|
||||
How detectors handle multiple models depends on the hardware:
|
||||
|
||||
- **Detectors that support multiple models** (`openvino`, `onnx`, `tensorrt`, `cpu`, `rknn`): a single detector entry is automatically expanded into one instance per model in use. For example, detector `ov` with models `indoor` and `outdoor` runs as `ov_indoor` and `ov_outdoor`, and each instance appears separately in the System Metrics page. Keep in mind that each instance loads its own copy of the model, which increases GPU memory usage.
|
||||
- **Detectors that only support a single model** (`edgetpu`, `hailo8l`, `memryx`, and other single-session hardware): each detector entry serves exactly one model. Detector entries are assigned to models round robin, so running two models on Coral hardware requires two Corals. If these are the only detectors configured and there are fewer of them than models in use, Frigate will fail to start with an error explaining the options.
|
||||
|
||||
# Officially Supported Detectors
|
||||
|
||||
Frigate provides a number of builtin detector types. By default, Frigate will use a single CPU detector. Other detectors may require additional configuration as described below. When using multiple detectors they will run in dedicated processes, but pull from a common queue of detection requests from across all cameras.
|
||||
@@ -789,11 +824,12 @@ You can set it to:
|
||||
- A path to some model.json.
|
||||
|
||||
```yaml
|
||||
model:
|
||||
path: ./mobilenet_v2_ssd_coco--300x300_quant_n2x_orca1_1 # directory to model .json and file
|
||||
width: 300 # width is in the model name as the first number in the "int"x"int" section
|
||||
height: 300 # height is in the model name as the second number in the "int"x"int" section
|
||||
input_pixel_format: rgb/bgr # look at the model.json to figure out which to put here
|
||||
models:
|
||||
default:
|
||||
path: ./mobilenet_v2_ssd_coco--300x300_quant_n2x_orca1_1 # directory to model .json and file
|
||||
width: 300 # width is in the model name as the first number in the "int"x"int" section
|
||||
height: 300 # height is in the model name as the second number in the "int"x"int" section
|
||||
input_pixel_format: rgb/bgr # look at the model.json to figure out which to put here
|
||||
```
|
||||
|
||||
#### Local Inference
|
||||
@@ -809,11 +845,12 @@ It is also possible to eliminate the need for an AI server and run the hardware
|
||||
Once `degirum_detector` is setup, you can choose a model through 'model' section in the `config.yml` file.
|
||||
|
||||
```yaml
|
||||
model:
|
||||
path: mobilenet_v2_ssd_coco--300x300_quant_n2x_orca1_1
|
||||
width: 300 # width is in the model name as the first number in the "int"x"int" section
|
||||
height: 300 # height is in the model name as the second number in the "int"x"int" section
|
||||
input_pixel_format: rgb/bgr # look at the model.json to figure out which to put here
|
||||
models:
|
||||
default:
|
||||
path: mobilenet_v2_ssd_coco--300x300_quant_n2x_orca1_1
|
||||
width: 300 # width is in the model name as the first number in the "int"x"int" section
|
||||
height: 300 # height is in the model name as the second number in the "int"x"int" section
|
||||
input_pixel_format: rgb/bgr # look at the model.json to figure out which to put here
|
||||
```
|
||||
|
||||
#### AI Hub Cloud Inference
|
||||
@@ -829,11 +866,12 @@ If you do not possess whatever hardware you want to run, there's also the option
|
||||
Once `degirum_detector` is setup, you can choose a model through 'model' section in the `config.yml` file.
|
||||
|
||||
```yaml
|
||||
model:
|
||||
path: mobilenet_v2_ssd_coco--300x300_quant_n2x_orca1_1
|
||||
width: 300 # width is in the model name as the first number in the "int"x"int" section
|
||||
height: 300 # height is in the model name as the second number in the "int"x"int" section
|
||||
input_pixel_format: rgb/bgr # look at the model.json to figure out which to put here
|
||||
models:
|
||||
default:
|
||||
path: mobilenet_v2_ssd_coco--300x300_quant_n2x_orca1_1
|
||||
width: 300 # width is in the model name as the first number in the "int"x"int" section
|
||||
height: 300 # height is in the model name as the second number in the "int"x"int" section
|
||||
input_pixel_format: rgb/bgr # look at the model.json to figure out which to put here
|
||||
```
|
||||
|
||||
## AXERA
|
||||
|
||||
@@ -144,7 +144,7 @@ At this point you should be able to start Frigate and a basic config will be cre
|
||||
|
||||
### Step 2: Add a camera
|
||||
|
||||
Click the **Add Camera** button in <NavPath path="Settings > Global configuration > Camera management" /> to use the camera setup wizard to get your first camera added into Frigate. See [Adding a camera with the Add Camera Wizard](../configuration/cameras.md#adding-a-camera-with-the-add-camera-wizard) for a walkthrough of each step.
|
||||
Click the **Add Camera** button in <NavPath path="Settings > Global configuration > Camera management" /> to use the camera setup wizard to get your first camera added into Frigate.
|
||||
|
||||
### Step 3: Configure hardware acceleration (recommended)
|
||||
|
||||
@@ -228,13 +228,14 @@ detectors: # <---- add detectors
|
||||
device: GPU
|
||||
|
||||
# We will use the default MobileNet_v2 model from OpenVINO.
|
||||
model:
|
||||
width: 300
|
||||
height: 300
|
||||
input_tensor: nhwc
|
||||
input_pixel_format: bgr
|
||||
path: /openvino-model/ssdlite_mobilenet_v2.xml
|
||||
labelmap_path: /openvino-model/coco_91cl_bkgr.txt
|
||||
models:
|
||||
default:
|
||||
width: 300
|
||||
height: 300
|
||||
input_tensor: nhwc
|
||||
input_pixel_format: bgr
|
||||
path: /openvino-model/ssdlite_mobilenet_v2.xml
|
||||
labelmap_path: /openvino-model/coco_91cl_bkgr.txt
|
||||
|
||||
cameras:
|
||||
name_of_your_camera:
|
||||
|
||||
@@ -64,8 +64,9 @@ You can either choose the new model from the <NavPath path="Settings > System >
|
||||
```yaml
|
||||
detectors: ...
|
||||
|
||||
model:
|
||||
path: plus://<your_model_id>
|
||||
models:
|
||||
default:
|
||||
path: plus://<your_model_id>
|
||||
```
|
||||
|
||||
:::note
|
||||
@@ -79,10 +80,11 @@ Models are downloaded into the `/config/model_cache` folder and only downloaded
|
||||
If needed, you can override the labelmap for Frigate+ models. This is not recommended as renaming labels will break the Submit to Frigate+ feature if the labels are not available in Frigate+.
|
||||
|
||||
```yaml
|
||||
model:
|
||||
path: plus://<your_model_id>
|
||||
labelmap:
|
||||
3: animal
|
||||
4: animal
|
||||
5: animal
|
||||
models:
|
||||
default:
|
||||
path: plus://<your_model_id>
|
||||
labelmap:
|
||||
3: animal
|
||||
4: animal
|
||||
5: animal
|
||||
```
|
||||
|
||||
@@ -38,8 +38,9 @@ Navigate to <NavPath path="Settings > System > Detectors and model" />. In the *
|
||||
```yaml
|
||||
detectors: ...
|
||||
|
||||
model:
|
||||
path: plus://<your_model_id>
|
||||
models:
|
||||
default:
|
||||
path: plus://<your_model_id>
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
+37
-25
@@ -372,31 +372,40 @@ def config(request: Request):
|
||||
config["go2rtc"]["streams"][stream_name] = cleaned
|
||||
|
||||
config["plus"] = {"enabled": request.app.frigate_config.plus_api.is_active()}
|
||||
config["model"]["colormap"] = config_obj.model.colormap
|
||||
config["model"]["all_attributes"] = config_obj.model.all_attributes
|
||||
config["model"]["non_logo_attributes"] = config_obj.model.non_logo_attributes
|
||||
|
||||
# Add model plus data if plus is enabled
|
||||
if config["plus"]["enabled"]:
|
||||
model_path = config.get("model", {}).get("path")
|
||||
if model_path:
|
||||
model_json_path = FilePath(model_path).with_suffix(".json")
|
||||
try:
|
||||
with open(model_json_path) as f:
|
||||
model_plus_data = json.load(f)
|
||||
config["model"]["plus"] = model_plus_data
|
||||
except FileNotFoundError:
|
||||
config["model"]["plus"] = None
|
||||
except json.JSONDecodeError:
|
||||
config["model"]["plus"] = None
|
||||
else:
|
||||
config["model"]["plus"] = None
|
||||
for model_key, model in config_obj.models.items():
|
||||
model_dict = config["models"][model_key]
|
||||
model_dict["colormap"] = model.colormap
|
||||
model_dict["all_attributes"] = model.all_attributes
|
||||
model_dict["non_logo_attributes"] = model.non_logo_attributes
|
||||
|
||||
# use merged labelamp
|
||||
for detector_config in config["detectors"].values():
|
||||
detector_config["model"]["labelmap"] = (
|
||||
request.app.frigate_config.model.merged_labelmap
|
||||
)
|
||||
# Add model plus data if plus is enabled
|
||||
if config["plus"]["enabled"]:
|
||||
model_plus_data = None
|
||||
|
||||
if model.path:
|
||||
model_json_path = FilePath(model.path).with_suffix(".json")
|
||||
try:
|
||||
with open(model_json_path) as f:
|
||||
model_plus_data = json.load(f)
|
||||
except (FileNotFoundError, json.JSONDecodeError):
|
||||
model_plus_data = None
|
||||
|
||||
model_dict["plus"] = model_plus_data
|
||||
|
||||
# legacy single-model block kept for frontend compatibility, remove
|
||||
# once the UI is fully multi-model aware
|
||||
default_model_key = (
|
||||
"default" if "default" in config_obj.models else next(iter(config_obj.models))
|
||||
)
|
||||
config["model"] = config["models"][default_model_key]
|
||||
|
||||
# use each detector's assigned merged labelmap
|
||||
for key, detector_config in config["detectors"].items():
|
||||
if config_obj.detectors[key].model:
|
||||
detector_config["model"]["labelmap"] = config_obj.detectors[
|
||||
key
|
||||
].model.merged_labelmap
|
||||
|
||||
return JSONResponse(content=config)
|
||||
|
||||
@@ -1323,8 +1332,11 @@ def plusModels(request: Request, filterByCurrentModelDetector: bool = False):
|
||||
|
||||
modelList = models["list"]
|
||||
|
||||
# current model type
|
||||
modelType = request.app.frigate_config.model.model_type
|
||||
# current model type, based on the default model until the UI is
|
||||
# fully multi-model aware
|
||||
config_models = request.app.frigate_config.models
|
||||
default_model = config_models.get("default") or next(iter(config_models.values()))
|
||||
modelType = default_model.model_type
|
||||
|
||||
# current detectorType for comparing to supportedDetectors
|
||||
detectorType = list(request.app.frigate_config.detectors.values())[0].type
|
||||
|
||||
@@ -813,7 +813,7 @@ async def event_snapshot(
|
||||
timestamp_style=request.app.frigate_config.cameras[
|
||||
event.camera
|
||||
].timestamp_style,
|
||||
colormap=request.app.frigate_config.model.colormap,
|
||||
colormap=request.app.frigate_config.model_for_camera(event.camera).colormap,
|
||||
)
|
||||
except DoesNotExist:
|
||||
# see if the object is currently being tracked
|
||||
|
||||
+19
-17
@@ -97,7 +97,9 @@ class FrigateApp:
|
||||
self.metrics_manager = manager
|
||||
self.audio_process: mp.Process | None = None
|
||||
self.stop_event = stop_event
|
||||
self.detection_queue: Queue = mp.Queue()
|
||||
self.detection_queues: dict[str, Queue] = {
|
||||
model_key: mp.Queue() for model_key in config.models
|
||||
}
|
||||
self.detectors: dict[str, ObjectDetectProcess] = {}
|
||||
self.detection_shms: list[mp.shared_memory.SharedMemory] = []
|
||||
self.log_queue: Queue = mp.Queue()
|
||||
@@ -363,20 +365,14 @@ class FrigateApp:
|
||||
)
|
||||
|
||||
def start_detectors(self) -> None:
|
||||
for name in self.config.cameras.keys():
|
||||
for name, camera_config in self.config.cameras.items():
|
||||
camera_model = self.config.models[camera_config.detect.model]
|
||||
|
||||
try:
|
||||
largest_frame = max(
|
||||
[
|
||||
det.model.height * det.model.width * 3
|
||||
if det.model is not None
|
||||
else 320
|
||||
for det in self.config.detectors.values()
|
||||
]
|
||||
)
|
||||
shm_in = UntrackedSharedMemory(
|
||||
name=name,
|
||||
create=True,
|
||||
size=largest_frame,
|
||||
size=camera_model.height * camera_model.width * 3,
|
||||
)
|
||||
except FileExistsError:
|
||||
shm_in = UntrackedSharedMemory(name=name)
|
||||
@@ -391,11 +387,16 @@ class FrigateApp:
|
||||
self.detection_shms.append(shm_in)
|
||||
self.detection_shms.append(shm_out)
|
||||
|
||||
for name, detector_config in self.config.detectors.items():
|
||||
for name, detector_config in self.config.detector_instances.items():
|
||||
cameras_using_model = [
|
||||
camera_name
|
||||
for camera_name, camera_config in self.config.cameras.items()
|
||||
if camera_config.detect.model == detector_config.model_key
|
||||
]
|
||||
self.detectors[name] = ObjectDetectProcess(
|
||||
name,
|
||||
self.detection_queue,
|
||||
list(self.config.cameras.keys()),
|
||||
self.detection_queues[detector_config.model_key],
|
||||
cameras_using_model,
|
||||
self.config,
|
||||
detector_config,
|
||||
self.stop_event,
|
||||
@@ -430,7 +431,7 @@ class FrigateApp:
|
||||
def start_camera_processor(self) -> None:
|
||||
self.camera_maintainer = CameraMaintainer(
|
||||
self.config,
|
||||
self.detection_queue,
|
||||
self.detection_queues,
|
||||
self.detected_frames_queue,
|
||||
self.camera_metrics,
|
||||
self.ptz_metrics,
|
||||
@@ -685,8 +686,9 @@ class FrigateApp:
|
||||
for detector in self.detectors.values():
|
||||
detector.stop()
|
||||
|
||||
empty_and_close_queue(self.detection_queue)
|
||||
logger.info("Detection queue closed")
|
||||
for detection_queue in self.detection_queues.values():
|
||||
empty_and_close_queue(detection_queue)
|
||||
logger.info("Detection queues closed")
|
||||
|
||||
self.detected_frames_processor.join()
|
||||
empty_and_close_queue(self.detected_frames_queue)
|
||||
|
||||
@@ -178,7 +178,7 @@ class CameraActivityManager:
|
||||
return
|
||||
|
||||
for label in camera_config.objects.track:
|
||||
if label in self.config.model.non_logo_attributes:
|
||||
if label in self.config.model_for_camera(camera).non_logo_attributes:
|
||||
continue
|
||||
|
||||
new_count = all_objects[label]
|
||||
|
||||
@@ -29,7 +29,7 @@ class CameraMaintainer(threading.Thread):
|
||||
def __init__(
|
||||
self,
|
||||
config: FrigateConfig,
|
||||
detection_queue: Queue,
|
||||
detection_queues: dict[str, Queue],
|
||||
detected_frames_queue: Queue,
|
||||
camera_metrics: DictProxy,
|
||||
ptz_metrics: dict[str, PTZMetrics],
|
||||
@@ -38,7 +38,7 @@ class CameraMaintainer(threading.Thread):
|
||||
):
|
||||
super().__init__(name="camera_processor")
|
||||
self.config = config
|
||||
self.detection_queue = detection_queue
|
||||
self.detection_queues = detection_queues
|
||||
self.detected_frames_queue = detected_frames_queue
|
||||
self.stop_event = stop_event
|
||||
self.camera_metrics = camera_metrics
|
||||
@@ -79,10 +79,11 @@ class CameraMaintainer(threading.Thread):
|
||||
# create or update region grids for each camera
|
||||
for camera in self.config.cameras.values():
|
||||
assert camera.name is not None
|
||||
camera_model = self.config.models[camera.detect.model]
|
||||
self.region_grids[camera.name] = get_camera_regions_grid(
|
||||
camera.name,
|
||||
camera.detect,
|
||||
max(self.config.model.width, self.config.model.height),
|
||||
max(camera_model.width, camera_model.height),
|
||||
)
|
||||
|
||||
def __calculate_shm_frame_count(self) -> int:
|
||||
@@ -115,6 +116,8 @@ class CameraMaintainer(threading.Thread):
|
||||
|
||||
camera_stop_event = self.__ensure_camera_stop_event(name)
|
||||
|
||||
camera_model = self.config.models[config.detect.model]
|
||||
|
||||
if runtime:
|
||||
self.camera_metrics[name] = CameraMetrics(self.metrics_manager)
|
||||
self.ptz_metrics[name] = PTZMetrics(
|
||||
@@ -123,32 +126,24 @@ class CameraMaintainer(threading.Thread):
|
||||
self.region_grids[name] = get_camera_regions_grid(
|
||||
name,
|
||||
config.detect,
|
||||
max(self.config.model.width, self.config.model.height),
|
||||
max(camera_model.width, camera_model.height),
|
||||
)
|
||||
|
||||
try:
|
||||
largest_frame = max(
|
||||
[
|
||||
det.model.height * det.model.width * 3
|
||||
if det.model is not None
|
||||
else 320
|
||||
for det in self.config.detectors.values()
|
||||
]
|
||||
)
|
||||
UntrackedSharedMemory(name=f"out-{name}", create=True, size=20 * 6 * 4)
|
||||
UntrackedSharedMemory(
|
||||
name=name,
|
||||
create=True,
|
||||
size=largest_frame,
|
||||
size=camera_model.height * camera_model.width * 3,
|
||||
)
|
||||
except FileExistsError:
|
||||
pass
|
||||
|
||||
camera_process = CameraTracker(
|
||||
config,
|
||||
self.config.model,
|
||||
self.config.model.merged_labelmap,
|
||||
self.detection_queue,
|
||||
camera_model,
|
||||
camera_model.merged_labelmap,
|
||||
self.detection_queues[config.detect.model],
|
||||
self.detected_frames_queue,
|
||||
self.camera_metrics[name],
|
||||
self.ptz_metrics[name],
|
||||
|
||||
@@ -40,6 +40,7 @@ class CameraState:
|
||||
self.name = name
|
||||
self.config = config
|
||||
self.camera_config = config.cameras[name]
|
||||
self.model_config = config.model_for_camera(name)
|
||||
self.frame_manager = frame_manager
|
||||
self.best_objects: dict[str, TrackedObject] = {}
|
||||
self.tracked_objects: dict[str, TrackedObject] = {}
|
||||
@@ -101,7 +102,7 @@ class CameraState:
|
||||
thickness = 1
|
||||
else:
|
||||
thickness = 2
|
||||
color = self.config.model.colormap.get(
|
||||
color = self.model_config.colormap.get(
|
||||
obj["label"], (255, 255, 255)
|
||||
)
|
||||
else:
|
||||
@@ -125,7 +126,7 @@ class CameraState:
|
||||
and obj["frame_time"] == frame_time
|
||||
):
|
||||
thickness = 5
|
||||
color = self.config.model.colormap.get(
|
||||
color = self.model_config.colormap.get(
|
||||
obj["label"], (255, 255, 255)
|
||||
)
|
||||
|
||||
@@ -261,7 +262,7 @@ class CameraState:
|
||||
if draw_options.get("paths"):
|
||||
for obj in tracked_objects.values():
|
||||
if obj["frame_time"] == frame_time and obj["path_data"]:
|
||||
color = self.config.model.colormap.get(
|
||||
color = self.model_config.colormap.get(
|
||||
obj["label"], (255, 255, 255)
|
||||
)
|
||||
|
||||
@@ -366,7 +367,7 @@ class CameraState:
|
||||
for id in new_ids:
|
||||
logger.debug(f"{self.name}: New tracked object ID: {id}")
|
||||
new_obj = tracked_objects[id] = TrackedObject(
|
||||
self.config.model,
|
||||
self.model_config,
|
||||
self.camera_config,
|
||||
self.config.ui,
|
||||
self.frame_cache,
|
||||
@@ -510,7 +511,7 @@ class CameraState:
|
||||
sub_label = None
|
||||
|
||||
if obj.obj_data.get("sub_label"):
|
||||
if obj.obj_data["sub_label"][0] in self.config.model.all_attributes:
|
||||
if obj.obj_data["sub_label"][0] in self.model_config.all_attributes:
|
||||
label = obj.obj_data["sub_label"][0]
|
||||
else:
|
||||
label = f"{object_type}-verified"
|
||||
|
||||
@@ -156,10 +156,11 @@ class Dispatcher:
|
||||
if camera not in self.config.cameras:
|
||||
return None
|
||||
|
||||
camera_model = self.config.model_for_camera(camera)
|
||||
grid = get_camera_regions_grid(
|
||||
camera,
|
||||
self.config.cameras[camera].detect,
|
||||
max(self.config.model.width, self.config.model.height),
|
||||
max(camera_model.width, camera_model.height),
|
||||
)
|
||||
return grid
|
||||
|
||||
|
||||
@@ -50,6 +50,11 @@ class DetectConfig(FrigateBaseModel):
|
||||
title="Enable object detection",
|
||||
description="Enable or disable object detection for all cameras; can be overridden per-camera.",
|
||||
)
|
||||
model: str | None = Field(
|
||||
default=None,
|
||||
title="Detection model name",
|
||||
description="Name of the model (key under `models`) used by this camera. Defaults to the only defined model, or the model named 'default'.",
|
||||
)
|
||||
height: int | None = Field(
|
||||
default=None,
|
||||
title="Detect height",
|
||||
|
||||
+154
-32
@@ -4,6 +4,7 @@ import io
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
from typing import Any, Self
|
||||
|
||||
import numpy as np
|
||||
@@ -11,6 +12,7 @@ from pydantic import (
|
||||
BaseModel,
|
||||
ConfigDict,
|
||||
Field,
|
||||
PrivateAttr,
|
||||
TypeAdapter,
|
||||
ValidationInfo,
|
||||
field_validator,
|
||||
@@ -19,7 +21,11 @@ from pydantic import (
|
||||
from ruamel.yaml import YAML
|
||||
|
||||
from frigate.const import REGEX_JSON
|
||||
from frigate.detectors import DetectorConfig, ModelConfig
|
||||
from frigate.detectors import (
|
||||
DetectorConfig,
|
||||
ModelConfig,
|
||||
assign_detector_instances,
|
||||
)
|
||||
from frigate.detectors.detector_config import BaseDetectorConfig
|
||||
from frigate.plus import PlusApi
|
||||
from frigate.util.builtin import (
|
||||
@@ -109,7 +115,7 @@ DEFAULT_CONFIG = f"""
|
||||
mqtt:
|
||||
enabled: False
|
||||
|
||||
{_render_default_yaml({"detectors": NEW_CONFIG_DETECTORS, "model": DEFAULT_MODEL})}
|
||||
{_render_default_yaml({"detectors": NEW_CONFIG_DETECTORS, "models": {"default": DEFAULT_MODEL}})}
|
||||
cameras: {{}} # No cameras defined, UI wizard should be used
|
||||
version: {CURRENT_CONFIG_VERSION}
|
||||
"""
|
||||
@@ -503,10 +509,10 @@ class FrigateConfig(FrigateBaseModel):
|
||||
title="Detector hardware",
|
||||
description="Configuration for object detectors (CPU, GPU, ONNX backends) and any detector-specific model settings.",
|
||||
)
|
||||
model: ModelConfig = Field(
|
||||
default_factory=ModelConfig,
|
||||
title="Detection model",
|
||||
description="Settings to configure a custom object detection model and its input shape.",
|
||||
models: dict[str, ModelConfig] = Field(
|
||||
default_factory=lambda: {"default": ModelConfig()},
|
||||
title="Detection models",
|
||||
description="Named object detection models. Cameras select a model with detect.model; detectors are assigned to models automatically.",
|
||||
)
|
||||
|
||||
# GenAI config (named provider configs: name -> GenAIConfig)
|
||||
@@ -621,11 +627,37 @@ class FrigateConfig(FrigateBaseModel):
|
||||
)
|
||||
|
||||
_plus_api: PlusApi
|
||||
_detector_instances: dict[str, BaseDetectorConfig] = PrivateAttr(
|
||||
default_factory=dict
|
||||
)
|
||||
|
||||
@property
|
||||
def plus_api(self) -> PlusApi:
|
||||
return self._plus_api
|
||||
|
||||
@property
|
||||
def detector_instances(self) -> dict[str, BaseDetectorConfig]:
|
||||
"""Runtime detector instances expanded per assigned model."""
|
||||
return self._detector_instances
|
||||
|
||||
def model_for_camera(self, camera_name: str) -> ModelConfig:
|
||||
"""Return the detection model config used by the given camera."""
|
||||
return self.models[self.cameras[camera_name].detect.model]
|
||||
|
||||
@field_validator("models")
|
||||
@classmethod
|
||||
def validate_model_names(cls, v: dict[str, ModelConfig]):
|
||||
if not v:
|
||||
raise ValueError("At least one model must be defined under models")
|
||||
|
||||
for name in v.keys():
|
||||
if not re.match(r"^[a-zA-Z0-9_-]+$", name):
|
||||
raise ValueError(
|
||||
f"Invalid model name '{name}'. Model names can only contain letters, numbers, underscores, and hyphens"
|
||||
)
|
||||
|
||||
return v
|
||||
|
||||
@model_validator(mode="after")
|
||||
def post_validation(self, info: ValidationInfo) -> Self:
|
||||
# Load plus api from context, if possible.
|
||||
@@ -671,7 +703,12 @@ class FrigateConfig(FrigateBaseModel):
|
||||
)
|
||||
|
||||
# set default min_score for object attributes
|
||||
for attribute in self.model.all_attributes:
|
||||
all_model_attributes = {
|
||||
attribute
|
||||
for model in self.models.values()
|
||||
for attribute in model.all_attributes
|
||||
}
|
||||
for attribute in sorted(all_model_attributes):
|
||||
existing = self.objects.filters.get(attribute)
|
||||
if existing is None:
|
||||
self.objects.filters[attribute] = FilterConfig(min_score=0.7)
|
||||
@@ -721,8 +758,18 @@ class FrigateConfig(FrigateBaseModel):
|
||||
exclude_unset=True,
|
||||
)
|
||||
|
||||
# capture raw model dumps before plus models are loaded so detector
|
||||
# instances can run their own detector-specific plus validation
|
||||
raw_model_dumps = {
|
||||
name: model.model_dump(exclude_unset=True, warnings="none")
|
||||
for name, model in self.models.items()
|
||||
}
|
||||
|
||||
for model in self.models.values():
|
||||
model.check_and_load_plus_model(self.plus_api)
|
||||
|
||||
adapter = TypeAdapter(DetectorConfig)
|
||||
for key, detector in self.detectors.items():
|
||||
adapter = TypeAdapter(DetectorConfig)
|
||||
model_dict = (
|
||||
detector
|
||||
if isinstance(detector, dict)
|
||||
@@ -737,27 +784,6 @@ class FrigateConfig(FrigateBaseModel):
|
||||
)
|
||||
detector_config.model = None
|
||||
|
||||
model_config = self.model.model_dump(exclude_unset=True, warnings="none")
|
||||
|
||||
if detector_config.model_path:
|
||||
model_config["path"] = detector_config.model_path
|
||||
|
||||
if "path" not in model_config:
|
||||
if detector_config.type == "cpu" or detector_config.type.endswith(
|
||||
"_tfl"
|
||||
):
|
||||
model_config["path"] = "/cpu_model.tflite"
|
||||
elif detector_config.type == "edgetpu":
|
||||
model_config["path"] = "/edgetpu_model.tflite"
|
||||
elif detector_config.type == "openvino":
|
||||
for default_key, default_value in DEFAULT_MODEL.items():
|
||||
model_config.setdefault(default_key, default_value)
|
||||
|
||||
model = ModelConfig.model_validate(model_config)
|
||||
model.check_and_load_plus_model(self.plus_api, detector_config.type)
|
||||
model.compute_model_hash()
|
||||
labelmap_objects = model.merged_labelmap.values()
|
||||
detector_config.model = model
|
||||
self.detectors[key] = detector_config
|
||||
|
||||
for name, camera in self.cameras.items():
|
||||
@@ -785,6 +811,21 @@ class FrigateConfig(FrigateBaseModel):
|
||||
{"name": name, **merged_config}
|
||||
)
|
||||
|
||||
# resolve which named model this camera uses
|
||||
if camera_config.detect.model is not None:
|
||||
if camera_config.detect.model not in self.models:
|
||||
raise ValueError(
|
||||
f"Camera {name} references model '{camera_config.detect.model}' which is not defined under models. Defined models: {', '.join(self.models.keys())}"
|
||||
)
|
||||
elif len(self.models) == 1:
|
||||
camera_config.detect.model = next(iter(self.models))
|
||||
elif "default" in self.models:
|
||||
camera_config.detect.model = "default"
|
||||
else:
|
||||
raise ValueError(
|
||||
f"Camera {name} does not specify detect.model and multiple models are defined. Set detect.model on the camera or globally, or name one of the models 'default'."
|
||||
)
|
||||
|
||||
if camera_config.ffmpeg.hwaccel_args == "auto":
|
||||
camera_config.ffmpeg.hwaccel_args = self.ffmpeg.hwaccel_args
|
||||
|
||||
@@ -1005,7 +1046,10 @@ class FrigateConfig(FrigateBaseModel):
|
||||
verify_profile_overrides_match_base(camera_config)
|
||||
verify_autotrack_zones(camera_config)
|
||||
verify_motion_and_detect(camera_config)
|
||||
verify_objects_track(camera_config, labelmap_objects)
|
||||
verify_objects_track(
|
||||
camera_config,
|
||||
self.models[camera_config.detect.model].merged_labelmap.values(),
|
||||
)
|
||||
verify_lpr_and_face(self, camera_config)
|
||||
|
||||
# Validate camera profiles reference top-level profile definitions
|
||||
@@ -1022,8 +1066,11 @@ class FrigateConfig(FrigateBaseModel):
|
||||
config.name = name
|
||||
|
||||
self.objects.parse_all_objects(self.cameras)
|
||||
self.model.create_colormap(sorted(self.objects.all_objects))
|
||||
self.model.check_and_load_plus_model(self.plus_api)
|
||||
for model in self.models.values():
|
||||
model.create_colormap(sorted(self.objects.all_objects))
|
||||
|
||||
# expand detectors into per-model runtime instances
|
||||
self.__build_detector_instances(raw_model_dumps)
|
||||
|
||||
# Check audio transcription and audio detection requirements
|
||||
if self.audio_transcription.enabled:
|
||||
@@ -1054,6 +1101,81 @@ class FrigateConfig(FrigateBaseModel):
|
||||
|
||||
return self
|
||||
|
||||
def __build_detector_instances(
|
||||
self, raw_model_dumps: dict[str, dict[str, Any]]
|
||||
) -> None:
|
||||
"""Expand detector entries into runtime instances, one per assigned model."""
|
||||
used_models = list(
|
||||
dict.fromkeys(camera.detect.model for camera in self.cameras.values())
|
||||
) or list(self.models.keys())
|
||||
|
||||
unused_models = set(self.models.keys()) - set(used_models)
|
||||
if unused_models:
|
||||
logger.warning(
|
||||
f"Models {', '.join(sorted(unused_models))} are defined but not used by any camera, no detector instances will be created for them"
|
||||
)
|
||||
|
||||
assignments = assign_detector_instances(
|
||||
{key: detector.type for key, detector in self.detectors.items()},
|
||||
used_models,
|
||||
)
|
||||
|
||||
models_per_detector: dict[str, int] = {}
|
||||
for _, detector_key, _ in assignments:
|
||||
models_per_detector[detector_key] = (
|
||||
models_per_detector.get(detector_key, 0) + 1
|
||||
)
|
||||
|
||||
instances: dict[str, BaseDetectorConfig] = {}
|
||||
|
||||
for instance_name, detector_key, model_key in assignments:
|
||||
instance = self.detectors[detector_key].model_copy(deep=True)
|
||||
instance.model_key = model_key
|
||||
|
||||
model_dict = raw_model_dumps[model_key].copy()
|
||||
|
||||
if instance.model_path:
|
||||
if models_per_detector[detector_key] > 1:
|
||||
logger.warning(
|
||||
f"Detector {detector_key} runs multiple models, its model_path will be ignored"
|
||||
)
|
||||
else:
|
||||
model_dict["path"] = instance.model_path
|
||||
|
||||
if "path" not in model_dict:
|
||||
if instance.type == "cpu" or instance.type.endswith("_tfl"):
|
||||
model_dict["path"] = "/cpu_model.tflite"
|
||||
elif instance.type == "edgetpu":
|
||||
model_dict["path"] = "/edgetpu_model.tflite"
|
||||
elif instance.type == "openvino":
|
||||
for default_key, default_value in DEFAULT_MODEL.items():
|
||||
model_dict.setdefault(default_key, default_value)
|
||||
|
||||
model = ModelConfig.model_validate(model_dict)
|
||||
|
||||
try:
|
||||
model.check_and_load_plus_model(self.plus_api, instance.type)
|
||||
except ValueError as e:
|
||||
raise ValueError(f"Model '{model_key}': {e}") from e
|
||||
|
||||
model.compute_model_hash()
|
||||
instance.model = model
|
||||
instances[instance_name] = instance
|
||||
logger.log(
|
||||
logging.INFO if len(used_models) > 1 else logging.DEBUG,
|
||||
f"Detector instance {instance_name} ({instance.type}) will run model '{model_key}'",
|
||||
)
|
||||
|
||||
# populate user-facing detector entries with their first assigned
|
||||
# model for display purposes
|
||||
for instance_name, detector_key, model_key in assignments:
|
||||
detector = self.detectors[detector_key]
|
||||
if detector.model is None:
|
||||
detector.model = instances[instance_name].model
|
||||
detector.model_key = model_key
|
||||
|
||||
self._detector_instances = instances
|
||||
|
||||
@field_validator("cameras")
|
||||
@classmethod
|
||||
def ensure_zones_and_cameras_have_different_names(cls, v: dict[str, CameraConfig]):
|
||||
|
||||
@@ -72,9 +72,10 @@ class LicensePlateProcessingMixin:
|
||||
# Object config
|
||||
self.lp_objects: list[str] = []
|
||||
|
||||
for obj, attributes in self.config.model.attributes_map.items():
|
||||
if "license_plate" in attributes:
|
||||
self.lp_objects.append(obj)
|
||||
for model in self.config.models.values():
|
||||
for obj, attributes in model.attributes_map.items():
|
||||
if "license_plate" in attributes and obj not in self.lp_objects:
|
||||
self.lp_objects.append(obj)
|
||||
|
||||
# Detection specific parameters
|
||||
self.min_size = 8
|
||||
|
||||
@@ -231,8 +231,12 @@ class ReviewDescriptionProcessor(PostProcessorApi):
|
||||
final_data,
|
||||
thumbs,
|
||||
camera_config.review.genai,
|
||||
list(self.config.model.merged_labelmap.values()),
|
||||
self.config.model.all_attributes,
|
||||
list(
|
||||
self.config.model_for_camera(
|
||||
camera_config.name
|
||||
).merged_labelmap.values()
|
||||
),
|
||||
self.config.model_for_camera(camera_config.name).all_attributes,
|
||||
),
|
||||
).start()
|
||||
|
||||
|
||||
@@ -1,11 +1,69 @@
|
||||
import logging
|
||||
|
||||
from .detector_config import InputTensorEnum, ModelConfig, PixelFormatEnum # noqa: F401
|
||||
from .detector_types import DetectorConfig, DetectorTypeEnum, api_types # noqa: F401
|
||||
from .detector_types import ( # noqa: F401
|
||||
DetectorConfig,
|
||||
DetectorTypeEnum,
|
||||
api_types,
|
||||
detector_supports_multiple_models,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def assign_detector_instances(
|
||||
detector_types: dict[str, str],
|
||||
used_models: list[str],
|
||||
) -> list[tuple[str, str, str]]:
|
||||
"""Assign detector entries to models.
|
||||
|
||||
Detector types that support multiple models get one instance per model.
|
||||
Single-model detector entries are round-robin assigned across the models,
|
||||
wrapping around so that every detector entry is assigned.
|
||||
|
||||
Args:
|
||||
detector_types: Detector key to detector type, in config order
|
||||
used_models: Ordered model keys in use by cameras
|
||||
|
||||
Returns:
|
||||
List of (instance_name, detector_key, model_key) assignments
|
||||
"""
|
||||
multi = [
|
||||
key
|
||||
for key, type_key in detector_types.items()
|
||||
if detector_supports_multiple_models(type_key)
|
||||
]
|
||||
single = [key for key in detector_types if key not in multi]
|
||||
|
||||
if not multi and len(single) < len(used_models):
|
||||
single_types = sorted({detector_types[key] for key in single})
|
||||
raise ValueError(
|
||||
f"Detectors {', '.join(single)} (types: {', '.join(single_types)}) can each only run a single model, "
|
||||
f"but {len(used_models)} models are in use ({', '.join(used_models)}). "
|
||||
"Add more detectors, use a detector type that supports multiple models, or reduce the number of models assigned to cameras."
|
||||
)
|
||||
|
||||
assignments: list[tuple[str, str, str]] = []
|
||||
|
||||
for key in multi:
|
||||
for model_key in used_models:
|
||||
instance_name = key if len(used_models) == 1 else f"{key}_{model_key}"
|
||||
assignments.append((instance_name, key, model_key))
|
||||
|
||||
for i, key in enumerate(single):
|
||||
assignments.append((key, key, used_models[i % len(used_models)]))
|
||||
|
||||
instance_names = [name for name, _, _ in assignments]
|
||||
duplicates = {name for name in instance_names if instance_names.count(name) > 1}
|
||||
if duplicates:
|
||||
raise ValueError(
|
||||
f"Detector instance names collide: {', '.join(sorted(duplicates))}. "
|
||||
"Rename the conflicting detectors or models so that expanded instance names (detector_model) are unique."
|
||||
)
|
||||
|
||||
return assignments
|
||||
|
||||
|
||||
def create_detector(detector_config):
|
||||
if detector_config.type == DetectorTypeEnum.cpu:
|
||||
logger.warning(
|
||||
|
||||
@@ -11,6 +11,10 @@ logger = logging.getLogger(__name__)
|
||||
class DetectionApi(ABC):
|
||||
type_key: str
|
||||
supported_models: list[ModelTypeEnum]
|
||||
# whether this detector type can run multiple model instances concurrently
|
||||
# on the same hardware (one detector config entry can be expanded to an
|
||||
# instance per model); single-model detectors serve exactly one model each
|
||||
supports_multiple_models: bool = False
|
||||
|
||||
@abstractmethod
|
||||
def __init__(self, detector_config: BaseDetectorConfig):
|
||||
|
||||
@@ -250,6 +250,11 @@ class BaseDetectorConfig(BaseModel):
|
||||
title="Detector specific model path",
|
||||
description="File path to the detector model binary if required by the chosen detector.",
|
||||
)
|
||||
model_key: str | None = Field(
|
||||
default=None,
|
||||
title="Assigned model name",
|
||||
description="Name of the model (key under `models`) this detector instance serves. Set automatically at runtime, users should not set this.",
|
||||
)
|
||||
model_config = ConfigDict(
|
||||
extra="allow", arbitrary_types_allowed=True, protected_namespaces=()
|
||||
)
|
||||
|
||||
@@ -29,6 +29,12 @@ for _, name, _ in _included_modules:
|
||||
api_types = {det.type_key: det for det in DetectionApi.__subclasses__()}
|
||||
|
||||
|
||||
def detector_supports_multiple_models(type_key: str) -> bool:
|
||||
"""Return whether the given detector type can run multiple model instances."""
|
||||
detector = api_types.get(type_key)
|
||||
return bool(detector and getattr(detector, "supports_multiple_models", False))
|
||||
|
||||
|
||||
class StrEnum(str, Enum):
|
||||
pass
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ class CpuDetectorConfig(BaseDetectorConfig):
|
||||
|
||||
class CpuTfl(DetectionApi):
|
||||
type_key = DETECTOR_KEY
|
||||
supports_multiple_models = True
|
||||
|
||||
def __init__(self, detector_config: CpuDetectorConfig):
|
||||
# Suppress TFLite delegate creation messages that bypass Python logging
|
||||
|
||||
@@ -41,6 +41,7 @@ class ONNXDetectorConfig(BaseDetectorConfig):
|
||||
|
||||
class ONNXDetector(DetectionApi):
|
||||
type_key = DETECTOR_KEY
|
||||
supports_multiple_models = True
|
||||
|
||||
def __init__(self, detector_config: ONNXDetectorConfig):
|
||||
super().__init__(detector_config)
|
||||
|
||||
@@ -36,6 +36,7 @@ class OvDetectorConfig(BaseDetectorConfig):
|
||||
|
||||
class OvDetector(DetectionApi):
|
||||
type_key = DETECTOR_KEY
|
||||
supports_multiple_models = True
|
||||
supported_models = [
|
||||
ModelTypeEnum.dfine,
|
||||
ModelTypeEnum.rfdetr,
|
||||
|
||||
@@ -47,6 +47,7 @@ class RknnDetectorConfig(BaseDetectorConfig):
|
||||
|
||||
class Rknn(DetectionApi):
|
||||
type_key = DETECTOR_KEY
|
||||
supports_multiple_models = True
|
||||
|
||||
def __init__(self, config: RknnDetectorConfig):
|
||||
super().__init__(config)
|
||||
|
||||
@@ -30,6 +30,7 @@ class TeflonDetectorConfig(BaseDetectorConfig):
|
||||
|
||||
class TeflonTfl(DetectionApi):
|
||||
type_key = DETECTOR_KEY
|
||||
supports_multiple_models = True
|
||||
|
||||
def __init__(self, detector_config: TeflonDetectorConfig):
|
||||
# Location in Debian's mesa-teflon-delegate
|
||||
|
||||
@@ -82,6 +82,7 @@ class HostDeviceMem:
|
||||
|
||||
class TensorRtDetector(DetectionApi):
|
||||
type_key = DETECTOR_KEY
|
||||
supports_multiple_models = True
|
||||
|
||||
def _load_engine(self, model_path):
|
||||
try:
|
||||
|
||||
@@ -159,7 +159,16 @@ class EventProcessor(threading.Thread):
|
||||
if width is None or height is None:
|
||||
return
|
||||
|
||||
first_detector = list(self.config.detectors.values())[0]
|
||||
# find a detector instance running this camera's model so the
|
||||
# event records the model that produced it
|
||||
camera_detector = next(
|
||||
(
|
||||
detector
|
||||
for detector in self.config.detector_instances.values()
|
||||
if detector.model_key == camera_config.detect.model
|
||||
),
|
||||
list(self.config.detectors.values())[0],
|
||||
)
|
||||
|
||||
start_time = event_data["start_time"]
|
||||
end_time = (
|
||||
@@ -229,13 +238,13 @@ class EventProcessor(threading.Thread):
|
||||
Event.thumbnail: event_data.get("thumbnail"),
|
||||
Event.has_clip: event_data["has_clip"],
|
||||
Event.has_snapshot: event_data["has_snapshot"],
|
||||
Event.model_hash: first_detector.model.model_hash
|
||||
if first_detector.model
|
||||
Event.model_hash: camera_detector.model.model_hash
|
||||
if camera_detector.model
|
||||
else None,
|
||||
Event.model_type: first_detector.model.model_type
|
||||
if first_detector.model
|
||||
Event.model_type: camera_detector.model.model_type
|
||||
if camera_detector.model
|
||||
else None,
|
||||
Event.detector_type: first_detector.type,
|
||||
Event.detector_type: camera_detector.type,
|
||||
Event.data: {
|
||||
"box": box,
|
||||
"region": region,
|
||||
|
||||
@@ -115,11 +115,9 @@ class PendingReviewSegment:
|
||||
if self._frame is not None:
|
||||
self.thumb_time = datetime.datetime.now().timestamp()
|
||||
self.has_frame = True
|
||||
Path(self.frame_path).parent.mkdir(parents=True, exist_ok=True)
|
||||
if not cv2.imwrite(
|
||||
cv2.imwrite(
|
||||
self.frame_path, self._frame, [int(cv2.IMWRITE_WEBP_QUALITY), 60]
|
||||
):
|
||||
logger.error("Failed to write review thumbnail to %s", self.frame_path)
|
||||
)
|
||||
|
||||
def save_full_frame(self, camera_config: CameraConfig, frame: np.ndarray) -> None:
|
||||
color_frame = cv2.cvtColor(frame, cv2.COLOR_YUV2BGR_I420)
|
||||
@@ -130,11 +128,9 @@ class PendingReviewSegment:
|
||||
|
||||
if self._frame is not None:
|
||||
self.has_frame = True
|
||||
Path(self.frame_path).parent.mkdir(parents=True, exist_ok=True)
|
||||
if not cv2.imwrite(
|
||||
cv2.imwrite(
|
||||
self.frame_path, self._frame, [int(cv2.IMWRITE_WEBP_QUALITY), 60]
|
||||
):
|
||||
logger.error("Failed to write review thumbnail to %s", self.frame_path)
|
||||
)
|
||||
|
||||
def get_data(self, ended: bool) -> dict:
|
||||
end_time = None
|
||||
@@ -378,16 +374,6 @@ class ReviewSegmentMaintainer(threading.Thread):
|
||||
"""Forcibly end the pending segment for a camera."""
|
||||
segment = self.active_review_segments.get(camera)
|
||||
if segment:
|
||||
if self.indefinite_events.get(camera):
|
||||
self.indefinite_events[camera] = {}
|
||||
now = datetime.datetime.now().timestamp()
|
||||
|
||||
if segment.last_alert_time == sys.maxsize:
|
||||
segment.last_alert_time = now
|
||||
|
||||
if segment.last_detection_time == sys.maxsize:
|
||||
segment.last_detection_time = now
|
||||
|
||||
prev_data = segment.get_data(False)
|
||||
return self._publish_segment_end(segment, prev_data)
|
||||
return None
|
||||
@@ -450,7 +436,10 @@ class ReviewSegmentMaintainer(threading.Thread):
|
||||
|
||||
if not object["sub_label"]:
|
||||
segment.detections[object["id"]] = object["label"]
|
||||
elif object["sub_label"][0] in self.config.model.all_attributes:
|
||||
elif (
|
||||
object["sub_label"][0]
|
||||
in self.config.model_for_camera(segment.camera).all_attributes
|
||||
):
|
||||
segment.detections[object["id"]] = object["sub_label"][0]
|
||||
else:
|
||||
segment.detections[object["id"]] = f"{object['label']}-verified"
|
||||
@@ -588,7 +577,10 @@ class ReviewSegmentMaintainer(threading.Thread):
|
||||
for object in activity.get_all_objects():
|
||||
if not object["sub_label"]:
|
||||
detections[object["id"]] = object["label"]
|
||||
elif object["sub_label"][0] in self.config.model.all_attributes:
|
||||
elif (
|
||||
object["sub_label"][0]
|
||||
in self.config.model_for_camera(camera).all_attributes
|
||||
):
|
||||
detections[object["id"]] = object["sub_label"][0]
|
||||
else:
|
||||
detections[object["id"]] = f"{object['label']}-verified"
|
||||
|
||||
+181
-9
@@ -86,7 +86,7 @@ class TestConfig(unittest.TestCase):
|
||||
},
|
||||
},
|
||||
# needs to be a file that will exist, doesn't matter what
|
||||
"model": {"path": "/etc/hosts", "width": 512},
|
||||
"models": {"default": {"path": "/etc/hosts", "width": 512}},
|
||||
}
|
||||
|
||||
frigate_config = FrigateConfig(**(deep_merge(config, self.minimal)))
|
||||
@@ -103,7 +103,7 @@ class TestConfig(unittest.TestCase):
|
||||
assert frigate_config.detectors["edgetpu"].device is None
|
||||
assert frigate_config.detectors["openvino"].device is None
|
||||
|
||||
assert frigate_config.model.path == "/etc/hosts"
|
||||
assert frigate_config.models["default"].path == "/etc/hosts"
|
||||
assert frigate_config.detectors["cpu"].model.path == "/cpu_model.tflite"
|
||||
assert frigate_config.detectors["edgetpu"].model.path == "/edgetpu_model.tflite"
|
||||
assert frigate_config.detectors["openvino"].model.path == "/etc/hosts"
|
||||
@@ -956,7 +956,7 @@ class TestConfig(unittest.TestCase):
|
||||
def test_merge_labelmap(self):
|
||||
config = {
|
||||
"mqtt": {"host": "mqtt"},
|
||||
"model": {"labelmap": {7: "truck"}},
|
||||
"models": {"default": {"labelmap": {7: "truck"}}},
|
||||
"cameras": {
|
||||
"back": {
|
||||
"ffmpeg": {
|
||||
@@ -977,7 +977,7 @@ class TestConfig(unittest.TestCase):
|
||||
}
|
||||
|
||||
frigate_config = FrigateConfig(**config)
|
||||
assert frigate_config.model.merged_labelmap[7] == "truck"
|
||||
assert frigate_config.models["default"].merged_labelmap[7] == "truck"
|
||||
|
||||
def test_default_labelmap_empty(self):
|
||||
config = {
|
||||
@@ -1002,12 +1002,12 @@ class TestConfig(unittest.TestCase):
|
||||
}
|
||||
|
||||
frigate_config = FrigateConfig(**config)
|
||||
assert frigate_config.model.merged_labelmap[0] == "person"
|
||||
assert frigate_config.models["default"].merged_labelmap[0] == "person"
|
||||
|
||||
def test_default_labelmap(self):
|
||||
config = {
|
||||
"mqtt": {"host": "mqtt"},
|
||||
"model": {"width": 320, "height": 320},
|
||||
"models": {"default": {"width": 320, "height": 320}},
|
||||
"cameras": {
|
||||
"back": {
|
||||
"ffmpeg": {
|
||||
@@ -1028,7 +1028,7 @@ class TestConfig(unittest.TestCase):
|
||||
}
|
||||
|
||||
frigate_config = FrigateConfig(**config)
|
||||
assert frigate_config.model.merged_labelmap[0] == "person"
|
||||
assert frigate_config.models["default"].merged_labelmap[0] == "person"
|
||||
|
||||
def test_plus_labelmap(self):
|
||||
with open(os.path.join(MODEL_CACHE_DIR, "test"), "w") as f:
|
||||
@@ -1039,7 +1039,7 @@ class TestConfig(unittest.TestCase):
|
||||
config = {
|
||||
"mqtt": {"host": "mqtt"},
|
||||
"detectors": {"cpu": {"type": "cpu"}},
|
||||
"model": {"path": "plus://test"},
|
||||
"models": {"default": {"path": "plus://test"}},
|
||||
"cameras": {
|
||||
"back": {
|
||||
"ffmpeg": {
|
||||
@@ -1060,7 +1060,7 @@ class TestConfig(unittest.TestCase):
|
||||
}
|
||||
|
||||
frigate_config = FrigateConfig(**config)
|
||||
assert frigate_config.model.merged_labelmap[0] == "amazon"
|
||||
assert frigate_config.models["default"].merged_labelmap[0] == "amazon"
|
||||
|
||||
def test_fails_on_invalid_role(self):
|
||||
config = {
|
||||
@@ -1765,5 +1765,177 @@ class TestAttributeFilterDefaults(unittest.TestCase):
|
||||
self.assertEqual(face_filter.min_score, 0.3)
|
||||
|
||||
|
||||
class TestMultiModelConfig(unittest.TestCase):
|
||||
"""Tests for named models and detector instance assignment."""
|
||||
|
||||
def setUp(self):
|
||||
self.base = {
|
||||
"mqtt": {"host": "mqtt"},
|
||||
"models": {
|
||||
"indoor": {"width": 320, "height": 320},
|
||||
"outdoor": {"width": 640, "height": 640},
|
||||
},
|
||||
"cameras": {
|
||||
"living_room": self._camera("indoor"),
|
||||
"driveway": self._camera("outdoor"),
|
||||
},
|
||||
}
|
||||
|
||||
def _camera(self, model=None):
|
||||
camera = {
|
||||
"ffmpeg": {
|
||||
"inputs": [{"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}]
|
||||
},
|
||||
"detect": {"height": 1080, "width": 1920, "fps": 5},
|
||||
}
|
||||
|
||||
if model:
|
||||
camera["detect"]["model"] = model
|
||||
|
||||
return camera
|
||||
|
||||
def test_single_model_resolves_implicitly(self):
|
||||
config = FrigateConfig(
|
||||
mqtt={"host": "mqtt"},
|
||||
models={"custom": {"width": 320, "height": 320}},
|
||||
cameras={"back": self._camera()},
|
||||
)
|
||||
assert config.cameras["back"].detect.model == "custom"
|
||||
|
||||
def test_multiple_models_resolve_to_default(self):
|
||||
config = FrigateConfig(
|
||||
mqtt={"host": "mqtt"},
|
||||
models={
|
||||
"default": {"width": 320, "height": 320},
|
||||
"outdoor": {"width": 640, "height": 640},
|
||||
},
|
||||
cameras={"back": self._camera()},
|
||||
)
|
||||
assert config.cameras["back"].detect.model == "default"
|
||||
|
||||
def test_multiple_models_without_default_requires_selection(self):
|
||||
config = self.base.copy()
|
||||
config["cameras"] = {"back": self._camera()}
|
||||
self.assertRaises(ValidationError, lambda: FrigateConfig(**config))
|
||||
|
||||
def test_camera_references_missing_model(self):
|
||||
config = self.base.copy()
|
||||
config["cameras"] = {"back": self._camera("thermal")}
|
||||
self.assertRaises(ValidationError, lambda: FrigateConfig(**config))
|
||||
|
||||
def test_global_detect_model_inherited_and_overridden(self):
|
||||
config = self.base.copy()
|
||||
config["detect"] = {"model": "indoor"}
|
||||
config["cameras"] = {
|
||||
"living_room": self._camera(),
|
||||
"driveway": self._camera("outdoor"),
|
||||
}
|
||||
frigate_config = FrigateConfig(**config)
|
||||
assert frigate_config.cameras["living_room"].detect.model == "indoor"
|
||||
assert frigate_config.cameras["driveway"].detect.model == "outdoor"
|
||||
|
||||
def test_invalid_model_name(self):
|
||||
config = self.base.copy()
|
||||
config["models"] = {"bad name!": {"width": 320, "height": 320}}
|
||||
self.assertRaises(ValidationError, lambda: FrigateConfig(**config))
|
||||
|
||||
def test_multi_model_detector_expands_instances(self):
|
||||
config = self.base.copy()
|
||||
config["detectors"] = {
|
||||
"ov0": {"type": "openvino", "device": "GPU"},
|
||||
"ov1": {"type": "openvino", "device": "GPU.1"},
|
||||
}
|
||||
frigate_config = FrigateConfig(**config)
|
||||
assert sorted(frigate_config.detector_instances.keys()) == [
|
||||
"ov0_indoor",
|
||||
"ov0_outdoor",
|
||||
"ov1_indoor",
|
||||
"ov1_outdoor",
|
||||
]
|
||||
assert frigate_config.detector_instances["ov0_indoor"].model_key == "indoor"
|
||||
assert frigate_config.detector_instances["ov0_indoor"].model.width == 320
|
||||
assert frigate_config.detector_instances["ov0_outdoor"].model.width == 640
|
||||
|
||||
def test_multi_model_detector_single_model_keeps_name(self):
|
||||
config = self.base.copy()
|
||||
config["models"] = {"default": {"width": 320, "height": 320}}
|
||||
config["cameras"] = {"back": self._camera()}
|
||||
config["detectors"] = {"ov": {"type": "openvino", "device": "GPU"}}
|
||||
frigate_config = FrigateConfig(**config)
|
||||
assert list(frigate_config.detector_instances.keys()) == ["ov"]
|
||||
assert frigate_config.detector_instances["ov"].model_key == "default"
|
||||
|
||||
def test_single_model_detectors_round_robin(self):
|
||||
config = self.base.copy()
|
||||
config["detectors"] = {
|
||||
"coral0": {"type": "edgetpu", "device": "usb:0"},
|
||||
"coral1": {"type": "edgetpu", "device": "usb:1"},
|
||||
"coral2": {"type": "edgetpu", "device": "usb:2"},
|
||||
}
|
||||
frigate_config = FrigateConfig(**config)
|
||||
assignments = {
|
||||
key: instance.model_key
|
||||
for key, instance in frigate_config.detector_instances.items()
|
||||
}
|
||||
assert assignments == {
|
||||
"coral0": "indoor",
|
||||
"coral1": "outdoor",
|
||||
"coral2": "indoor",
|
||||
}
|
||||
|
||||
def test_single_model_detectors_insufficient_coverage(self):
|
||||
config = self.base.copy()
|
||||
config["detectors"] = {"coral": {"type": "edgetpu", "device": "usb"}}
|
||||
self.assertRaises(ValidationError, lambda: FrigateConfig(**config))
|
||||
|
||||
def test_single_model_detector_with_multi_model_detector(self):
|
||||
config = self.base.copy()
|
||||
config["detectors"] = {
|
||||
"coral": {"type": "edgetpu", "device": "usb"},
|
||||
"ov": {"type": "openvino", "device": "GPU"},
|
||||
}
|
||||
frigate_config = FrigateConfig(**config)
|
||||
assert frigate_config.detector_instances["coral"].model_key == "indoor"
|
||||
assert frigate_config.detector_instances["ov_indoor"].model_key == "indoor"
|
||||
assert frigate_config.detector_instances["ov_outdoor"].model_key == "outdoor"
|
||||
|
||||
def test_unused_model_gets_no_instances(self):
|
||||
config = self.base.copy()
|
||||
config["models"] = {
|
||||
**config["models"],
|
||||
"thermal": {"width": 320, "height": 320},
|
||||
}
|
||||
frigate_config = FrigateConfig(**config)
|
||||
model_keys = {
|
||||
instance.model_key
|
||||
for instance in frigate_config.detector_instances.values()
|
||||
}
|
||||
assert "thermal" not in model_keys
|
||||
|
||||
def test_model_path_ignored_when_detector_runs_multiple_models(self):
|
||||
config = self.base.copy()
|
||||
config["detectors"] = {
|
||||
"cpu": {"type": "cpu", "model_path": "/custom_model.tflite"}
|
||||
}
|
||||
frigate_config = FrigateConfig(**config)
|
||||
assert (
|
||||
frigate_config.detector_instances["cpu_indoor"].model.path
|
||||
== "/cpu_model.tflite"
|
||||
)
|
||||
|
||||
def test_model_path_applied_when_detector_runs_one_model(self):
|
||||
config = self.base.copy()
|
||||
config["models"] = {"default": {"width": 320, "height": 320}}
|
||||
config["cameras"] = {"back": self._camera()}
|
||||
config["detectors"] = {
|
||||
"cpu": {"type": "cpu", "model_path": "/custom_model.tflite"}
|
||||
}
|
||||
frigate_config = FrigateConfig(**config)
|
||||
assert (
|
||||
frigate_config.detector_instances["cpu"].model.path
|
||||
== "/custom_model.tflite"
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(verbosity=2)
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
"""Tests for config file migration functions."""
|
||||
|
||||
import unittest
|
||||
|
||||
from frigate.util.config import migrate_019_0
|
||||
|
||||
|
||||
class TestMigrate019(unittest.TestCase):
|
||||
def test_migrates_model_to_named_models(self):
|
||||
config = {
|
||||
"version": "0.18-0",
|
||||
"mqtt": {"host": "mqtt"},
|
||||
"model": {"path": "/config/model.tflite", "width": 320, "height": 320},
|
||||
}
|
||||
new_config = migrate_019_0(config)
|
||||
assert "model" not in new_config
|
||||
assert new_config["models"] == {
|
||||
"default": {"path": "/config/model.tflite", "width": 320, "height": 320}
|
||||
}
|
||||
assert new_config["version"] == "0.19-0"
|
||||
|
||||
def test_no_model_defined(self):
|
||||
config = {"version": "0.18-0", "mqtt": {"host": "mqtt"}}
|
||||
new_config = migrate_019_0(config)
|
||||
assert "model" not in new_config
|
||||
assert "models" not in new_config
|
||||
assert new_config["version"] == "0.19-0"
|
||||
|
||||
def test_existing_models_not_overwritten(self):
|
||||
config = {
|
||||
"version": "0.18-0",
|
||||
"model": {"width": 320},
|
||||
"models": {"custom": {"width": 640}},
|
||||
}
|
||||
new_config = migrate_019_0(config)
|
||||
assert "model" not in new_config
|
||||
assert new_config["models"] == {"custom": {"width": 640}}
|
||||
assert new_config["version"] == "0.19-0"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(verbosity=2)
|
||||
@@ -209,7 +209,10 @@ class TrackedObjectProcessor(threading.Thread):
|
||||
if obj.obj_data.get("sub_label"):
|
||||
sub_label = obj.obj_data["sub_label"][0]
|
||||
|
||||
if sub_label in self.config.model.all_attribute_logos:
|
||||
if (
|
||||
sub_label
|
||||
in self.config.model_for_camera(camera).all_attribute_logos
|
||||
):
|
||||
self.dispatcher.publish(
|
||||
f"{camera}/{sub_label}/snapshot",
|
||||
jpg_bytes,
|
||||
|
||||
+29
-1
@@ -20,7 +20,7 @@ from frigate.util.services import get_video_properties
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
CURRENT_CONFIG_VERSION = "0.18-0"
|
||||
CURRENT_CONFIG_VERSION = "0.19-0"
|
||||
DEFAULT_CONFIG_FILE = os.path.join(CONFIG_DIR, "config.yml")
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@ def migrate_frigate_config(config_file: str):
|
||||
new_config = migrate_014(config)
|
||||
with open(config_file, "w") as f:
|
||||
yaml.dump(new_config, f)
|
||||
config = new_config
|
||||
previous_version = "0.14"
|
||||
|
||||
logger.info("Migrating export file names...")
|
||||
@@ -117,6 +118,7 @@ def migrate_frigate_config(config_file: str):
|
||||
new_config = migrate_015_0(config)
|
||||
with open(config_file, "w") as f:
|
||||
yaml.dump(new_config, f)
|
||||
config = new_config
|
||||
previous_version = "0.15-0"
|
||||
|
||||
if previous_version < "0.15-1":
|
||||
@@ -124,6 +126,7 @@ def migrate_frigate_config(config_file: str):
|
||||
new_config = migrate_015_1(config)
|
||||
with open(config_file, "w") as f:
|
||||
yaml.dump(new_config, f)
|
||||
config = new_config
|
||||
previous_version = "0.15-1"
|
||||
|
||||
if previous_version < "0.16-0":
|
||||
@@ -131,6 +134,7 @@ def migrate_frigate_config(config_file: str):
|
||||
new_config = migrate_016_0(config)
|
||||
with open(config_file, "w") as f:
|
||||
yaml.dump(new_config, f)
|
||||
config = new_config
|
||||
previous_version = "0.16-0"
|
||||
|
||||
if previous_version < "0.17-0":
|
||||
@@ -138,6 +142,7 @@ def migrate_frigate_config(config_file: str):
|
||||
new_config = migrate_017_0(config)
|
||||
with open(config_file, "w") as f:
|
||||
yaml.dump(new_config, f)
|
||||
config = new_config
|
||||
previous_version = "0.17-0"
|
||||
|
||||
if previous_version < "0.18-0":
|
||||
@@ -145,8 +150,17 @@ def migrate_frigate_config(config_file: str):
|
||||
new_config = migrate_018_0(config)
|
||||
with open(config_file, "w") as f:
|
||||
yaml.dump(new_config, f)
|
||||
config = new_config
|
||||
previous_version = "0.18-0"
|
||||
|
||||
if previous_version < "0.19-0":
|
||||
logger.info(f"Migrating frigate config from {previous_version} to 0.19-0...")
|
||||
new_config = migrate_019_0(config)
|
||||
with open(config_file, "w") as f:
|
||||
yaml.dump(new_config, f)
|
||||
config = new_config
|
||||
previous_version = "0.19-0"
|
||||
|
||||
logger.info("Finished frigate config migration...")
|
||||
|
||||
|
||||
@@ -658,6 +672,20 @@ def migrate_018_0(config: dict[str, dict[str, Any]]) -> dict[str, dict[str, Any]
|
||||
return new_config
|
||||
|
||||
|
||||
def migrate_019_0(config: dict[str, dict[str, Any]]) -> dict[str, dict[str, Any]]:
|
||||
"""Handle migrating frigate config to 0.19-0"""
|
||||
new_config = config.copy()
|
||||
|
||||
# Migrate the single model config to named models
|
||||
model = new_config.pop("model", None)
|
||||
|
||||
if model is not None and "models" not in new_config:
|
||||
new_config["models"] = {"default": model}
|
||||
|
||||
new_config["version"] = "0.19-0"
|
||||
return new_config
|
||||
|
||||
|
||||
def get_relative_coordinates(
|
||||
mask: str | list | None,
|
||||
frame_shape: tuple[int, int],
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"id": "case-001", "name": "Package Theft Investigation", "description": "Review of suspicious activity near the front porch", "created_at": 1780597809.365581, "updated_at": 1780673409.365581}]
|
||||
[{"id": "case-001", "name": "Package Theft Investigation", "description": "Review of suspicious activity near the front porch", "created_at": 1784761296.1184616, "updated_at": 1784836896.1184616}]
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
[{"id": "event-person-001", "label": "person", "sub_label": null, "camera": "front_door", "start_time": 1780677009.365581, "end_time": 1780677039.365581, "false_positive": false, "zones": ["front_yard"], "thumbnail": null, "has_clip": true, "has_snapshot": true, "retain_indefinitely": false, "plus_id": null, "model_hash": "abc123", "detector_type": "cpu", "model_type": "ssd", "data": {"top_score": 0.92, "score": 0.92, "region": [0.1, 0.1, 0.5, 0.8], "box": [0.2, 0.15, 0.45, 0.75], "area": 0.18, "ratio": 0.6, "type": "object", "description": "A person walking toward the front door", "average_estimated_speed": 1.2, "velocity_angle": 45.0, "path_data": [[[0.2, 0.5], 0.0], [[0.3, 0.5], 1.0]]}}, {"id": "event-car-001", "label": "car", "sub_label": null, "camera": "backyard", "start_time": 1780673409.365581, "end_time": 1780673454.365581, "false_positive": false, "zones": ["driveway"], "thumbnail": null, "has_clip": true, "has_snapshot": true, "retain_indefinitely": false, "plus_id": null, "model_hash": "def456", "detector_type": "cpu", "model_type": "ssd", "data": {"top_score": 0.87, "score": 0.87, "region": [0.3, 0.2, 0.9, 0.7], "box": [0.35, 0.25, 0.85, 0.65], "area": 0.2, "ratio": 1.25, "type": "object", "description": "A car parked in the driveway", "average_estimated_speed": 0.0, "velocity_angle": 0.0, "path_data": []}}, {"id": "event-person-002", "label": "person", "sub_label": null, "camera": "garage", "start_time": 1780669809.365581, "end_time": 1780669829.365581, "false_positive": false, "zones": [], "thumbnail": null, "has_clip": false, "has_snapshot": true, "retain_indefinitely": false, "plus_id": null, "model_hash": "ghi789", "detector_type": "cpu", "model_type": "ssd", "data": {"top_score": 0.78, "score": 0.78, "region": [0.0, 0.0, 0.6, 0.9], "box": [0.1, 0.05, 0.5, 0.85], "area": 0.32, "ratio": 0.5, "type": "object", "description": null, "average_estimated_speed": 0.5, "velocity_angle": 90.0, "path_data": [[[0.1, 0.4], 0.0]]}}]
|
||||
[{"id": "event-person-001", "label": "person", "sub_label": null, "camera": "front_door", "start_time": 1784840496.1184616, "end_time": 1784840526.1184616, "false_positive": false, "zones": ["front_yard"], "thumbnail": null, "has_clip": true, "has_snapshot": true, "retain_indefinitely": false, "plus_id": null, "model_hash": "abc123", "detector_type": "cpu", "model_type": "ssd", "data": {"top_score": 0.92, "score": 0.92, "region": [0.1, 0.1, 0.5, 0.8], "box": [0.2, 0.15, 0.45, 0.75], "area": 0.18, "ratio": 0.6, "type": "object", "description": "A person walking toward the front door", "average_estimated_speed": 1.2, "velocity_angle": 45.0, "path_data": [[[0.2, 0.5], 0.0], [[0.3, 0.5], 1.0]]}}, {"id": "event-car-001", "label": "car", "sub_label": null, "camera": "backyard", "start_time": 1784836896.1184616, "end_time": 1784836941.1184616, "false_positive": false, "zones": ["driveway"], "thumbnail": null, "has_clip": true, "has_snapshot": true, "retain_indefinitely": false, "plus_id": null, "model_hash": "def456", "detector_type": "cpu", "model_type": "ssd", "data": {"top_score": 0.87, "score": 0.87, "region": [0.3, 0.2, 0.9, 0.7], "box": [0.35, 0.25, 0.85, 0.65], "area": 0.2, "ratio": 1.25, "type": "object", "description": "A car parked in the driveway", "average_estimated_speed": 0.0, "velocity_angle": 0.0, "path_data": []}}, {"id": "event-person-002", "label": "person", "sub_label": null, "camera": "garage", "start_time": 1784833296.1184616, "end_time": 1784833316.1184616, "false_positive": false, "zones": [], "thumbnail": null, "has_clip": false, "has_snapshot": true, "retain_indefinitely": false, "plus_id": null, "model_hash": "ghi789", "detector_type": "cpu", "model_type": "ssd", "data": {"top_score": 0.78, "score": 0.78, "region": [0.0, 0.0, 0.6, 0.9], "box": [0.1, 0.05, 0.5, 0.85], "area": 0.32, "ratio": 0.5, "type": "object", "description": null, "average_estimated_speed": 0.5, "velocity_angle": 90.0, "path_data": [[[0.1, 0.4], 0.0]]}}]
|
||||
@@ -1 +1 @@
|
||||
[{"id": "export-001", "camera": "front_door", "name": "Front Door - Person Alert", "date": 1780680609.365581, "video_path": "/exports/export-001.mp4", "thumb_path": "/exports/export-001-thumb.jpg", "in_progress": false, "export_case_id": null}, {"id": "export-002", "camera": "backyard", "name": "Backyard - Car Detection", "date": 1780673409.365581, "video_path": "/exports/export-002.mp4", "thumb_path": "/exports/export-002-thumb.jpg", "in_progress": false, "export_case_id": "case-001"}, {"id": "export-003", "camera": "garage", "name": "Garage - In Progress", "date": 1780682409.365581, "video_path": "/exports/export-003.mp4", "thumb_path": "/exports/export-003-thumb.jpg", "in_progress": true, "export_case_id": null}]
|
||||
[{"id": "export-001", "camera": "front_door", "name": "Front Door - Person Alert", "date": 1784844096.1184616, "video_path": "/exports/export-001.mp4", "thumb_path": "/exports/export-001-thumb.jpg", "in_progress": false, "export_case_id": null}, {"id": "export-002", "camera": "backyard", "name": "Backyard - Car Detection", "date": 1784836896.1184616, "video_path": "/exports/export-002.mp4", "thumb_path": "/exports/export-002-thumb.jpg", "in_progress": false, "export_case_id": "case-001"}, {"id": "export-003", "camera": "garage", "name": "Garage - In Progress", "date": 1784845896.1184616, "video_path": "/exports/export-003.mp4", "thumb_path": "/exports/export-003-thumb.jpg", "in_progress": true, "export_case_id": null}]
|
||||
@@ -102,11 +102,17 @@ def generate_config():
|
||||
snapshot = config.model_dump()
|
||||
|
||||
# Runtime-computed fields not in the Pydantic dump
|
||||
all_attrs = set()
|
||||
for attrs in snapshot.get("model", {}).get("attributes_map", {}).values():
|
||||
all_attrs.update(attrs)
|
||||
snapshot["model"]["all_attributes"] = sorted(all_attrs)
|
||||
snapshot["model"]["colormap"] = {}
|
||||
for model_dict in snapshot.get("models", {}).values():
|
||||
all_attrs = set()
|
||||
for attrs in model_dict.get("attributes_map", {}).values():
|
||||
all_attrs.update(attrs)
|
||||
model_dict["all_attributes"] = sorted(all_attrs)
|
||||
model_dict["colormap"] = {}
|
||||
|
||||
# legacy single-model block mirrors the default model, matching /api/config
|
||||
models = snapshot.get("models", {})
|
||||
default_key = "default" if "default" in models else next(iter(models))
|
||||
snapshot["model"] = models[default_key]
|
||||
|
||||
return snapshot
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"2026-06-05": {"day": "2026-06-05", "reviewed_alert": 1, "reviewed_detection": 0, "total_alert": 2, "total_detection": 2}, "2026-06-04": {"day": "2026-06-04", "reviewed_alert": 3, "reviewed_detection": 2, "total_alert": 3, "total_detection": 4}}
|
||||
{"2026-07-23": {"day": "2026-07-23", "reviewed_alert": 1, "reviewed_detection": 0, "total_alert": 2, "total_detection": 2}, "2026-07-22": {"day": "2026-07-22", "reviewed_alert": 3, "reviewed_detection": 2, "total_alert": 3, "total_detection": 4}}
|
||||
@@ -1 +1 @@
|
||||
[{"id": "review-alert-001", "camera": "front_door", "start_time": "2026-06-05T11:30:09.365581", "end_time": "2026-06-05T11:30:39.365581", "has_been_reviewed": false, "severity": "alert", "thumb_path": "/clips/front_door/review-alert-001-thumb.jpg", "data": {"audio": [], "detections": ["person-abc123"], "objects": ["person"], "sub_labels": [], "significant_motion_areas": [], "zones": ["front_yard"]}}, {"id": "review-alert-002", "camera": "backyard", "start_time": "2026-06-05T10:30:09.365581", "end_time": "2026-06-05T10:30:54.365581", "has_been_reviewed": true, "severity": "alert", "thumb_path": "/clips/backyard/review-alert-002-thumb.jpg", "data": {"audio": [], "detections": ["car-def456"], "objects": ["car"], "sub_labels": [], "significant_motion_areas": [], "zones": ["driveway"]}}, {"id": "review-detect-001", "camera": "garage", "start_time": "2026-06-05T09:30:09.365581", "end_time": "2026-06-05T09:30:29.365581", "has_been_reviewed": false, "severity": "detection", "thumb_path": "/clips/garage/review-detect-001-thumb.jpg", "data": {"audio": [], "detections": ["person-ghi789"], "objects": ["person"], "sub_labels": [], "significant_motion_areas": [], "zones": []}}, {"id": "review-detect-002", "camera": "front_door", "start_time": "2026-06-05T08:30:09.365581", "end_time": "2026-06-05T08:30:24.365581", "has_been_reviewed": false, "severity": "detection", "thumb_path": "/clips/front_door/review-detect-002-thumb.jpg", "data": {"audio": [], "detections": ["car-jkl012"], "objects": ["car"], "sub_labels": [], "significant_motion_areas": [], "zones": ["front_yard"]}}]
|
||||
[{"id": "review-alert-001", "camera": "front_door", "start_time": "2026-07-23T21:01:36.118462", "end_time": "2026-07-23T21:02:06.118462", "has_been_reviewed": false, "severity": "alert", "thumb_path": "/clips/front_door/review-alert-001-thumb.jpg", "data": {"audio": [], "detections": ["person-abc123"], "objects": ["person"], "sub_labels": [], "significant_motion_areas": [], "zones": ["front_yard"]}}, {"id": "review-alert-002", "camera": "backyard", "start_time": "2026-07-23T20:01:36.118462", "end_time": "2026-07-23T20:02:21.118462", "has_been_reviewed": true, "severity": "alert", "thumb_path": "/clips/backyard/review-alert-002-thumb.jpg", "data": {"audio": [], "detections": ["car-def456"], "objects": ["car"], "sub_labels": [], "significant_motion_areas": [], "zones": ["driveway"]}}, {"id": "review-detect-001", "camera": "garage", "start_time": "2026-07-23T19:01:36.118462", "end_time": "2026-07-23T19:01:56.118462", "has_been_reviewed": false, "severity": "detection", "thumb_path": "/clips/garage/review-detect-001-thumb.jpg", "data": {"audio": [], "detections": ["person-ghi789"], "objects": ["person"], "sub_labels": [], "significant_motion_areas": [], "zones": []}}, {"id": "review-detect-002", "camera": "front_door", "start_time": "2026-07-23T18:01:36.118462", "end_time": "2026-07-23T18:01:51.118462", "has_been_reviewed": false, "severity": "detection", "thumb_path": "/clips/front_door/review-detect-002-thumb.jpg", "data": {"audio": [], "detections": ["car-jkl012"], "objects": ["car"], "sub_labels": [], "significant_motion_areas": [], "zones": ["front_yard"]}}]
|
||||
Generated
+4
-4
@@ -73,7 +73,7 @@
|
||||
"react-markdown": "^9.0.1",
|
||||
"react-router-dom": "^6.30.3",
|
||||
"react-swipeable": "^7.0.2",
|
||||
"react-zoom-pan-pinch": "3.4.4",
|
||||
"react-zoom-pan-pinch": "^3.7.0",
|
||||
"remark-gfm": "^4.0.0",
|
||||
"scroll-into-view-if-needed": "^3.1.0",
|
||||
"sonner": "^2.0.7",
|
||||
@@ -12354,9 +12354,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-zoom-pan-pinch": {
|
||||
"version": "3.4.4",
|
||||
"resolved": "https://registry.npmjs.org/react-zoom-pan-pinch/-/react-zoom-pan-pinch-3.4.4.tgz",
|
||||
"integrity": "sha512-lGTu7D9lQpYEQ6sH+NSlLA7gicgKRW8j+D/4HO1AbSV2POvKRFzdWQ8eI0r3xmOsl4dYQcY+teV6MhULeg1xBw==",
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/react-zoom-pan-pinch/-/react-zoom-pan-pinch-3.7.0.tgz",
|
||||
"integrity": "sha512-UmReVZ0TxlKzxSbYiAj+LeGRW8s8LraAFTXRAxzMYnNRgGPsxCudwZKVkjvGmjtx7SW/hZamt69NUmGf4xrkXA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8",
|
||||
|
||||
+1
-1
@@ -87,7 +87,7 @@
|
||||
"react-markdown": "^9.0.1",
|
||||
"react-router-dom": "^6.30.3",
|
||||
"react-swipeable": "^7.0.2",
|
||||
"react-zoom-pan-pinch": "3.4.4",
|
||||
"react-zoom-pan-pinch": "^3.7.0",
|
||||
"remark-gfm": "^4.0.0",
|
||||
"scroll-into-view-if-needed": "^3.1.0",
|
||||
"sonner": "^2.0.7",
|
||||
|
||||
@@ -61,8 +61,7 @@
|
||||
"error": {
|
||||
"endTimeMustAfterStartTime": "L'hora de finalització ha de ser posterior a l'hora d'inici",
|
||||
"noVaildTimeSelected": "No s'ha seleccionat un rang de temps vàlid",
|
||||
"failed": "No s'ha pogut inciar l'exportació: {{error}}",
|
||||
"noValidTimeSelected": "No s'ha seleccionat cap interval de temps vàlid"
|
||||
"failed": "No s'ha pogut inciar l'exportació: {{error}}"
|
||||
},
|
||||
"view": "Vista",
|
||||
"queued": "Exporta a la cua. Mostra el progrés a la pàgina d'exportacions.",
|
||||
|
||||
@@ -493,9 +493,6 @@
|
||||
"max_concurrent": {
|
||||
"label": "Màxim d'exportacions concurrents",
|
||||
"description": "Nombre màxim de treballs d'exportació a processar al mateix temps."
|
||||
},
|
||||
"chapters": {
|
||||
"label": "Metadades de capítol per incrustar en els enregistraments exportats"
|
||||
}
|
||||
},
|
||||
"preview": {
|
||||
|
||||
@@ -380,9 +380,6 @@
|
||||
"max_concurrent": {
|
||||
"label": "Màxim d'exportacions concurrents",
|
||||
"description": "Nombre màxim de treballs d'exportació a processar al mateix temps."
|
||||
},
|
||||
"chapters": {
|
||||
"label": "Metadades de capítol per incrustar en els enregistraments exportats"
|
||||
}
|
||||
},
|
||||
"preview": {
|
||||
@@ -1920,7 +1917,7 @@
|
||||
},
|
||||
"model_type": {
|
||||
"label": "Tipus de Model de detecció d'objecte",
|
||||
"description": "Tipus d'arquitectura del model de detector (ssd, yolox, yolonas, yolo-generic, rfdetr, dfine) utilitzat per alguns detectors per a l'optimització"
|
||||
"description": "Tipus d'arquitectura del model de detector (ssd, yolox, yolonas) usat per l'optimització d'alguns detectors."
|
||||
}
|
||||
},
|
||||
"model_path": {
|
||||
@@ -1969,7 +1966,7 @@
|
||||
},
|
||||
"model_type": {
|
||||
"label": "Tipus de model de detecció d'objectes",
|
||||
"description": "Tipus d'arquitectura del model de detector (ssd, yolox, yolonas, yolo-generic, rfdetr, dfine) utilitzat per alguns detectors per a l'optimització."
|
||||
"description": "Tipus d'arquitectura del model de detector (ssd, yolox, yolonas) utilitzat per alguns detectors per a l'optimització."
|
||||
}
|
||||
},
|
||||
"genai": {
|
||||
|
||||
@@ -192,20 +192,7 @@
|
||||
"title": "Edita el model de classificació",
|
||||
"descriptionState": "Edita les classes per a aquest model de classificació d'estats. Els canvis requeriran tornar a entrenar el model.",
|
||||
"descriptionObject": "Edita el tipus d'objecte i el tipus de classificació per a aquest model de classificació d'objectes.",
|
||||
"stateClassesInfo": "S'ha actualitzat el model. Restringeix el model perquè els canvis de classe tinguin efecte.",
|
||||
"enabled": "Habilitat",
|
||||
"enabledDesc": "Executa aquest model. Quan està desactivat, deixa d'executar-se i ja no classifica.",
|
||||
"saveAttempts": "Desa els intents",
|
||||
"saveAttemptsDesc": "Nombre d'imatges de classificació que s'intenten mantenir per a les classificacions recents UI.",
|
||||
"motion": "Executa en moviment",
|
||||
"motionDesc": "Executa la classificació quan es detecta el moviment dins de l'escapçat configurat.",
|
||||
"interval": "Interval",
|
||||
"intervalDesc": "Segons entre les classificacions periòdiques. Deixeu-ho buit per a executar-se només en moviment.",
|
||||
"intervalPlaceholder": "Sense interval",
|
||||
"errors": {
|
||||
"saveAttemptsInvalid": "Els intents de desar han de ser un nombre sencer de 0 o més",
|
||||
"intervalInvalid": "L'interval ha de ser un nombre sencer més gran que 0"
|
||||
}
|
||||
"stateClassesInfo": "Nota: Canviar les classes d'estat requereix tornar a entrenar el model amb les classes actualitzades."
|
||||
},
|
||||
"tooltip": {
|
||||
"trainingInProgress": "El model s'està entrenant actualment",
|
||||
@@ -215,6 +202,5 @@
|
||||
},
|
||||
"none": "Cap",
|
||||
"reclassifyImageAs": "Reclassifica la imatge com a:",
|
||||
"reclassifyImage": "Reclassifica la imatge",
|
||||
"disabled": "Desactivat"
|
||||
"reclassifyImage": "Reclassifica la imatge"
|
||||
}
|
||||
|
||||
@@ -303,7 +303,7 @@
|
||||
},
|
||||
"offset": {
|
||||
"label": "Òfset d'Anotació",
|
||||
"desc": "Aquestes dades provenen del canal de detecció de la càmera, però estan sobreposades a les imatges del canal de registre. És poc probable que els dos corrents estiguin perfectament sincronitzats. Com a resultat, la caixa contenidora i les imatges no s'alinearan perfectament. Podeu utilitzar aquest paràmetre per a compensar les anotacions cap endavant o cap enrere en el temps per a alinear-les millor amb el metratge gravat.",
|
||||
"desc": "Aquestes dades provenen del flux de detecció de la càmera, però se superposen a les imatges del flux de gravació. És poc probable que els dos fluxos estiguin perfectament sincronitzats. Com a resultat, el quadre delimitador i les imatges no s'alinearan perfectament. Tanmateix, es pot utilitzar el camp <code>annotation_offset</code> per ajustar-ho.",
|
||||
"millisecondsToOffset": "Millisegons per l'òfset de detecció d'anotacions per. <em>Per defecte: 0</em>",
|
||||
"tips": "Reduïu el valor si la reproducció del vídeo es troba per davant dels quadres i els punts de ruta, i augmenteu-lo si es troba per darrere. Aquest valor pot ser negatiu.",
|
||||
"toast": {
|
||||
|
||||
@@ -698,7 +698,7 @@
|
||||
"title": "Crear un nou usuari",
|
||||
"confirmPassword": "Siusplau, confirma la contrasenya",
|
||||
"usernameOnlyInclude": "El nom d'usuari només pot contenir lletres, números, . o _",
|
||||
"desc": "Afegeix un compte d'usuari nou i especifica un rol per a l'accés a les àrees de la interfície d'usuari de Frigate."
|
||||
"desc": "Afegeix un nou compte d'usuari i especifica un rol per accedir a àrees de la interfície de Frigate."
|
||||
}
|
||||
},
|
||||
"title": "Usuaris",
|
||||
@@ -1323,7 +1323,7 @@
|
||||
"details": {
|
||||
"edit": "Edita els detalls de la càmera",
|
||||
"title": "Edita els detalls de la càmera",
|
||||
"description": "Actualitza el nom de visualització, l'URL extern i la visibilitat utilitzada per a aquesta càmera a tota la interfície d'usuari de Frigate.",
|
||||
"description": "Actualitza el nom de visualització, l'URL extern i la visibilitat utilitzada per a aquesta càmera a tota la interfície d'usuari de la Fragata.",
|
||||
"friendlyNameLabel": "Nom a mostrar",
|
||||
"friendlyNameHelp": "Nom amistós que es mostra per a aquesta càmera a tota la interfície d'usuari de Frigate. Deixeu-ho en blanc per utilitzar l'ID de la càmera.",
|
||||
"webuiUrlLabel": "URL de la interfície web de la càmera",
|
||||
@@ -1484,7 +1484,7 @@
|
||||
"successMulti_other": "Configuració copiada a {{count}} càmeres",
|
||||
"successMultiWithRestart_one": "Configuració copiada a la càmera {{count}}. Reinicia Frigate per aplicar tots els canvis.",
|
||||
"successMultiWithRestart_many": "Configuració copiada a {{count}} càmeres. Reinicia Frigate per aplicar tots els canvis.",
|
||||
"successMultiWithRestart_other": "Configuració copiada a {{count}} càmeres. Reinicia Frigate per aplicar tots els canvis.",
|
||||
"successMultiWithRestart_other": "Configuració copiada a {{count}} càmeres. Reinicia la fragata per aplicar tots els canvis.",
|
||||
"partialFailure": "{{successCount}} seccions aplicades; «{{failedSection}}» ha fallat: {{errorMessage}}",
|
||||
"partialFailureMulti": "S'ha copiat a {{successCount}} càmera(es); ha fallat {{failed}}: {{errorMessage}}",
|
||||
"newCameraPartialFailure": "S'ha creat la càmera {{cameraName}} però no s'han pogut copiar alguns paràmetres: {{errorMessage}}",
|
||||
@@ -1641,14 +1641,7 @@
|
||||
"keyLabel": "Clau",
|
||||
"valueLabel": "Valor",
|
||||
"keyPlaceholder": "Nou valor",
|
||||
"remove": "Elimina",
|
||||
"providerNameLabel": "Nom del proveïdor",
|
||||
"providerNamePlaceholder": "p. ex., openai",
|
||||
"variableNameLabel": "Nom de la variable",
|
||||
"variableNamePlaceholder": ". ex., La_Meva_Variable",
|
||||
"loggerNameLabel": "Nom del registrador",
|
||||
"loggerNamePlaceholder": "p. ex., friagte.registre",
|
||||
"keyPatternError": "Utilitza només lletres, números, guions i guions baixos (sense espais)"
|
||||
"remove": "Elimina"
|
||||
},
|
||||
"timezone": {
|
||||
"defaultOption": "Utilitza la zona horària del navegador"
|
||||
@@ -2103,8 +2096,7 @@
|
||||
"autotrackingNoZones": "Autotraquejar requereix al menys una zona. Defineix una zona per aquesta cámera a Mascares/Zones, després usa'l com a requerit a la part inferior."
|
||||
},
|
||||
"ffmpeg": {
|
||||
"hwaccelManualNotRecommended": "No es recomanen arguments manuals d'acceleració de maquinari. Tret que existeixi un requisit específic, seleccioneu el predefinit que coincideixi amb el vostre maquinari.",
|
||||
"inputsMissingGo2rtcStream": "Una entrada a sota apunta a un restream go2rtc que ja no existeix. Seleccioneu un restream existent o introduïu manualment l'URL de la càmera, en cas contrari aquesta càmera no es connectarà."
|
||||
"hwaccelManualNotRecommended": "No es recomanen arguments manuals d'acceleració de maquinari. Tret que existeixi un requisit específic, seleccioneu el predefinit que coincideixi amb el vostre maquinari."
|
||||
},
|
||||
"model": {
|
||||
"optimizedFor320": "Frigate està optimitzada per a un model 320x320, que és la millor opció per a la majoria de configuracions. Un model 640x640 és més lent i només ajuda en escenaris específics.",
|
||||
|
||||
@@ -425,23 +425,5 @@
|
||||
"chop": "Sekání",
|
||||
"crack": "Prasknutí",
|
||||
"chink": "Cinknutí",
|
||||
"field_recording": "Nahrávka z terénu",
|
||||
"change_ringing": "Změnit vyzvánění",
|
||||
"liquid": "Tekutina",
|
||||
"splash": "Šplouchnutí",
|
||||
"squish": "Zmáčknout",
|
||||
"drip": "Kapat",
|
||||
"pour": "Lít",
|
||||
"trickle": "Stékat",
|
||||
"fill": "Naplnit",
|
||||
"stir": "Míchat",
|
||||
"boiling": "Vařící",
|
||||
"sonar": "Sonar",
|
||||
"arrow": "Šíp",
|
||||
"electronic_tuner": "Elektronický Ladič",
|
||||
"bang": "Rána",
|
||||
"slap": "Plácnout",
|
||||
"smash": "Rozmlátit",
|
||||
"bouncing": "Odrážející",
|
||||
"scratch": "Škrábat"
|
||||
"field_recording": "Nahrávka z terénu"
|
||||
}
|
||||
|
||||
@@ -86,6 +86,10 @@
|
||||
"label": "Enable object detection",
|
||||
"description": "Enable or disable object detection for this camera."
|
||||
},
|
||||
"model": {
|
||||
"label": "Detection model name",
|
||||
"description": "Name of the model (key under `models`) used by this camera. Defaults to the only defined model, or the model named 'default'."
|
||||
},
|
||||
"height": {
|
||||
"label": "Detect height",
|
||||
"description": "Height (pixels) of frames used for the detect stream; leave empty to use the native stream resolution."
|
||||
|
||||
@@ -329,6 +329,10 @@
|
||||
"label": "Detector specific model path",
|
||||
"description": "File path to the detector model binary if required by the chosen detector."
|
||||
},
|
||||
"model_key": {
|
||||
"label": "Assigned model name",
|
||||
"description": "Name of the model (key under `models`) this detector instance serves. Set automatically at runtime, users should not set this."
|
||||
},
|
||||
"axengine": {
|
||||
"label": "AXEngine NPU",
|
||||
"description": "AXERA AX650N/AX8850N NPU detector running compiled .axmodel files via the AXEngine runtime."
|
||||
@@ -454,9 +458,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"model": {
|
||||
"label": "Detection model",
|
||||
"description": "Settings to configure a custom object detection model and its input shape.",
|
||||
"models": {
|
||||
"label": "Detection models",
|
||||
"description": "Named object detection models. Cameras select a model with detect.model; detectors are assigned to models automatically.",
|
||||
"path": {
|
||||
"label": "Custom object detector model path",
|
||||
"description": "Path to a custom detection model file (or plus://<model_id> for Frigate+ models)."
|
||||
@@ -625,6 +629,10 @@
|
||||
"label": "Enable object detection",
|
||||
"description": "Enable or disable object detection for all cameras; can be overridden per-camera."
|
||||
},
|
||||
"model": {
|
||||
"label": "Detection model name",
|
||||
"description": "Name of the model (key under `models`) used by this camera. Defaults to the only defined model, or the model named 'default'."
|
||||
},
|
||||
"height": {
|
||||
"label": "Detect height",
|
||||
"description": "Height (pixels) of frames used for the detect stream; leave empty to use the native stream resolution."
|
||||
|
||||
@@ -125,7 +125,5 @@
|
||||
"baby": "Baby",
|
||||
"baby_stroller": "Baby Stroller",
|
||||
"rickshaw": "Rickshaw",
|
||||
"rodent": "Rodent",
|
||||
"possum": "Possum",
|
||||
"garbage_truck": "Garbage Truck"
|
||||
"rodent": "Rodent"
|
||||
}
|
||||
|
||||
@@ -36,9 +36,6 @@
|
||||
"ask_a": "¿Es este objeto un <code>{{label}}</code>?",
|
||||
"ask_an": "¿Es este objeto un <code>{{label}}</code>?",
|
||||
"ask_full": "¿Es este objeto un <code>{{untranslatedLabel}}</code> ({{translatedLabel}})?"
|
||||
},
|
||||
"toast": {
|
||||
"error": "Error al enviarlo a Frigate+. Por favor, comprueba tu conexión a internet y prueba de nuevo."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -71,8 +68,7 @@
|
||||
"error": {
|
||||
"failed": "No se pudo iniciar la exportación: {{error}}",
|
||||
"noVaildTimeSelected": "No se seleccionó un rango de tiempo válido",
|
||||
"endTimeMustAfterStartTime": "La hora de finalización debe ser posterior a la hora de inicio",
|
||||
"noValidTimeSelected": "Rango de tiempo seleccionado no valido"
|
||||
"endTimeMustAfterStartTime": "La hora de finalización debe ser posterior a la hora de inicio"
|
||||
},
|
||||
"success": "Exportación iniciada con éxito. Ver el archivo en la página exportaciones.",
|
||||
"view": "Vista",
|
||||
|
||||
@@ -273,69 +273,5 @@
|
||||
"sailboat": "Purjekas",
|
||||
"soundtrack_music": "Filmimuusika",
|
||||
"jingle": "Kõlisemine/tilisemine",
|
||||
"theme_music": "Tunnusmuusika",
|
||||
"steel_guitar": "Steel Kitarr",
|
||||
"tapping": "Koputamine",
|
||||
"strum": "Klimberdus",
|
||||
"drum_machine": "Trummimasin",
|
||||
"drum": "Trumm",
|
||||
"maraca": "Marakas",
|
||||
"bowed_string_instrument": "Poogenkeelpill",
|
||||
"singing_bowl": "Helikauss",
|
||||
"wind_noise": "Tuulemüra",
|
||||
"rustling_leaves": "Sahisevad lehed",
|
||||
"waves": "Lained",
|
||||
"steam": "Aur",
|
||||
"ship": "Laev",
|
||||
"motor_vehicle": "Mootorsõiduk",
|
||||
"rowboat": "Sõudepaat",
|
||||
"motorboat": "Mootorpaat",
|
||||
"waterfall": "Kosk",
|
||||
"ocean": "Ookean",
|
||||
"rain_on_surface": "Vihm pinnal",
|
||||
"stream": "Oja",
|
||||
"fire": "Tuli",
|
||||
"crackle": "Praksumine",
|
||||
"car_alarm": "Auto alarm",
|
||||
"truck": "Veoauto",
|
||||
"police_car": "Politseiauto",
|
||||
"ambulance": "Kiirabi",
|
||||
"fire_engine": "Tuletõrjeauto",
|
||||
"aircraft": "Lennuk",
|
||||
"aircraft_engine": "Lennukimootor",
|
||||
"jet_engine": "Reaktiivmootor",
|
||||
"propeller": "Propeller",
|
||||
"helicopter": "Helikopter",
|
||||
"fixed-wing_aircraft": "Fikseeritud tiivaga õhusõiduk",
|
||||
"train_horn": "Rongisignaal",
|
||||
"railroad_car": "Kaubavagun",
|
||||
"lawn_mower": "Muruniiduk",
|
||||
"chainsaw": "mootorsaag",
|
||||
"engine": "Mootor",
|
||||
"knock": "Koputus",
|
||||
"alarm": "Häire",
|
||||
"siren": "Sireen",
|
||||
"fire_alarm": "Tulekahjuhäire",
|
||||
"telephone": "Telefon",
|
||||
"telephone_bell_ringing": "Helisev telefon",
|
||||
"ringtone": "Telefonihelin",
|
||||
"smoke_detector": "Suitsuandur",
|
||||
"foghorn": "Udupasun",
|
||||
"whistle": "Vile",
|
||||
"printer": "Printer",
|
||||
"drill": "Puur",
|
||||
"explosion": "Plahvatus",
|
||||
"hammer": "Haamer",
|
||||
"air_conditioning": "Õhukonditsioneer",
|
||||
"gunshot": "Püssilask",
|
||||
"glass": "Klaas",
|
||||
"boom": "Pauk",
|
||||
"fireworks": "Ilutulestik",
|
||||
"static": "Staatiline",
|
||||
"white_noise": "Valge müra",
|
||||
"radio": "Raadio",
|
||||
"television": "Televiisor",
|
||||
"scream": "Karjumine",
|
||||
"pour": "Valamine",
|
||||
"drip": "Tilkumine"
|
||||
"theme_music": "Tunnusmuusika"
|
||||
}
|
||||
|
||||
@@ -37,9 +37,6 @@
|
||||
"ask_an": "Kas see objekt on <code>{{label}}</code>?",
|
||||
"ask_full": "Kas see objekt on <code>{{untranslatedLabel}}</code> ({{translatedLabel}})?",
|
||||
"label": "Kinnita see silt Frigate+ teenuse jaoks"
|
||||
},
|
||||
"toast": {
|
||||
"error": "Frigate+ teenusesse saatmine ebaõnnestus. Palun kontrolli oma võrguühendust ja proovi uuesti."
|
||||
}
|
||||
},
|
||||
"submitToPlus": {
|
||||
@@ -73,79 +70,18 @@
|
||||
"success": "Eksportimise käivitamine õnnestus. Faili leiad eksportimise lehelt.",
|
||||
"view": "Vaata",
|
||||
"error": {
|
||||
"failed": "Eksportimise järjekorda lisamine ei õnnestunud: {{error}}",
|
||||
"failed": "Eksportimise käivitamine ei õnnestunud: {{error}}",
|
||||
"endTimeMustAfterStartTime": "Ajavahemiku lõpp peab olema peale algust",
|
||||
"noVaildTimeSelected": "Ühtegi kehtivat ajavahemikku pole valitud",
|
||||
"noValidTimeSelected": "Ühtegi korrektset ajavahemikku pole valitud"
|
||||
},
|
||||
"queued": "Eksport on järjekorda lisatud. Vaata progressi eksportide lehelt.",
|
||||
"batchSuccess_one": "Alustasin 1 ekspordiga. Avan juhtumi kohe.",
|
||||
"batchSuccess_other": "Alustasin {{count}} ekspordiga. Avan juhtumi kohe.",
|
||||
"batchPartial": "Alustasin {{successful}}/{{total}} ekspordiga. Ebaõnnestunud kaamerad: {{failedCameras}}",
|
||||
"batchFailed": "{{total}} eksporti ebaõnnestus algatada. Ebaõnnestunud kaamerad: {{failedCameras}}",
|
||||
"batchQueuedSuccess_one": "1 eksport järjekorda lisatud. Avan juhtumi kohe.",
|
||||
"batchQueuedSuccess_other": "{{count}} eksporti järjekorda lisatud. Avan juhtumi kohe.",
|
||||
"batchQueuedPartial": "{{successful}}/{{total}} ekspordist on järjekorda lisatud. Ebaõnnestunud kaamerad: {{failedCameras}}",
|
||||
"batchQueueFailed": "{{total}} eksporti ebaõnnestus järjekorda lisada. Ebaõnnestunud kaamerad: {{failedCameras}}"
|
||||
"noVaildTimeSelected": "Ühtegi kehtivat ajavahemikku pole valitud"
|
||||
}
|
||||
},
|
||||
"fromTimeline": {
|
||||
"saveExport": "Salvesta eksporditud sisu",
|
||||
"previewExport": "Eksporditud sisu eelvaade",
|
||||
"queueingExport": "Ekspordi järjekorda lisamine...",
|
||||
"useThisRange": "Kasuta seda vahemikku"
|
||||
"previewExport": "Eksporditud sisu eelvaade"
|
||||
},
|
||||
"case": {
|
||||
"label": "Juhtum",
|
||||
"placeholder": "Vali juhtum",
|
||||
"newCaseOption": "Ava uus juhtum",
|
||||
"newCaseNamePlaceholder": "Uue juhtumi nimi",
|
||||
"newCaseDescriptionPlaceholder": "Juhtumi kirjeldus",
|
||||
"nonAdminHelp": "Uus juhtum avatakse järnevatele eksportidele."
|
||||
},
|
||||
"queueing": "Ekspordi järjekorda lisamine...",
|
||||
"tabs": {
|
||||
"export": "Üksik kaamera",
|
||||
"multiCamera": "Mitu kaamerat"
|
||||
},
|
||||
"multiCamera": {
|
||||
"timeRange": "Ajavahemik",
|
||||
"selectFromTimeline": "Vali ajajoonelt",
|
||||
"cameraSelection": "Kaamerad",
|
||||
"cameraSelectionHelp": "Selles ajavahemikus tuvastatud objektidega kaamerad on eelvalitud",
|
||||
"searchOrSelectGroup": "Otsi või vali kaamera grupp...",
|
||||
"selectAll": "Vali kõik kaamerad",
|
||||
"clearSelection": "Tühista valik",
|
||||
"selectWithActivity": "Jälgitud objektidega kaamerad",
|
||||
"selectGroup": "Vali grupp",
|
||||
"noMatchingCameras": "Ükski kaamera ei sobitunud otsinguga",
|
||||
"selectedCount": "{{selected}} / {{total}} valitud",
|
||||
"checkingActivity": "Kaamera aktiivsuse kontrollimine...",
|
||||
"noCameras": "Ühtegi kaamerat pole saadaval",
|
||||
"detectionCount_one": "1 jälgitav objekt",
|
||||
"detectionCount_other": "{{count}} jälgitavat objekti",
|
||||
"nameLabel": "Ekspordi nimi",
|
||||
"namePlaceholder": "Valikuline baasnimi nendele eksportidele",
|
||||
"queueingButton": "Ekspordi järjekorda lisamine...",
|
||||
"exportButton_one": "Ekspordi 1 kaamera",
|
||||
"exportButton_other": "Ekspordi {{count}} kaamerat"
|
||||
},
|
||||
"multi": {
|
||||
"title_one": "Ekspordi 1 ülevaade",
|
||||
"title_other": "Espordi {{count}} ülevaadet",
|
||||
"description": "Ekspordi valitud ülevaated. Kõik ekspordid on grupeeritud ühte juhtumisse.",
|
||||
"descriptionNoCase": "Ekspordi kõik valitud juhtumid.",
|
||||
"caseNamePlaceholder": "Ülevaate eksport - {{date}}",
|
||||
"exportButton_one": "Ekspordi 1 ülevaade",
|
||||
"exportButton_other": "Ekspordi {{count}} ülevaadet",
|
||||
"exportingButton": "Ekspordin...",
|
||||
"toast": {
|
||||
"started_one": "Alustasin 1 eksporti. Avan juhtumi kohe.",
|
||||
"started_other": "Alustasin {{count}} ekspordiga. Avan juhtumi kohe.",
|
||||
"startedNoCase_one": "Alustasin 1 ekspordiga.",
|
||||
"startedNoCase_other": "Alustasin {{count}} ekspordiga.",
|
||||
"partial": "Alustasin {{successful}}/{{total}} ekspordiga. Ebaõnnestusid: {{failedItems}}",
|
||||
"failed": "{{total}} ekspordi algatamine ebaõnnestus. Ebaõnnestunud: {{failedItems}}"
|
||||
}
|
||||
"placeholder": "Vali juhtum"
|
||||
}
|
||||
},
|
||||
"streaming": {
|
||||
@@ -178,14 +114,6 @@
|
||||
"success": "Selle ülevaadatava objektiga seotud videosisu on kustutatud.",
|
||||
"error": "Kustutamine ei õnnestunud: {{error}}"
|
||||
}
|
||||
},
|
||||
"shareTimestamp": {
|
||||
"label": "Jaotise ajatempel",
|
||||
"title": "Jaotise ajatempel",
|
||||
"description": "Jaga praeguse esituskoha ajatempliga URL-i või vali kohandatud ajatempel. Arvesta, et see ei ole avalik jagamislink ja on kättesaadav ainult kasutajatele, kellel on ligipääs Frigate'ile ja sellele kaamerale.",
|
||||
"custom": "Kohandatud ajatempel",
|
||||
"button": "Jaga ajatempliga linki",
|
||||
"shareTitle": "Frigate ülevaate ajatempel: {{camera}}"
|
||||
}
|
||||
},
|
||||
"imagePicker": {
|
||||
|
||||
@@ -12,20 +12,11 @@
|
||||
"description": "Kasutusel"
|
||||
},
|
||||
"audio": {
|
||||
"label": "Heli tuvastus",
|
||||
"min_volume": {
|
||||
"label": "Minimaalne helitase"
|
||||
},
|
||||
"filters": {
|
||||
"label": "Audio filtrid"
|
||||
}
|
||||
"label": "Helisündmused"
|
||||
},
|
||||
"birdseye": {
|
||||
"mode": {
|
||||
"label": "Jälgimisrežiim"
|
||||
},
|
||||
"order": {
|
||||
"label": "Positsioon"
|
||||
}
|
||||
},
|
||||
"label": "Kaameraseadistus",
|
||||
@@ -34,8 +25,7 @@
|
||||
"threshold": {
|
||||
"description": "Minimaalne sarnasuse punktiskoor (0-1), mis on vajalik selle päästiku käivitamiseks."
|
||||
}
|
||||
},
|
||||
"label": "Semantiline otsing"
|
||||
}
|
||||
},
|
||||
"lpr": {
|
||||
"label": "Sõidukite numbrimärkide tuvastus",
|
||||
@@ -44,171 +34,6 @@
|
||||
"review": {
|
||||
"genai": {
|
||||
"description": "Kontrollib generatiivse tehisaru kasutamist kirjelduste ja kokkuvõtete koostamiseks ülevaatamisele kuuluvate objektide jaoks."
|
||||
},
|
||||
"alerts": {
|
||||
"enabled": {
|
||||
"label": "Luba häired"
|
||||
}
|
||||
}
|
||||
},
|
||||
"audio_transcription": {
|
||||
"label": "Audio transkriptsioon",
|
||||
"live_enabled": {
|
||||
"label": "Reaalajas transkriptsioon"
|
||||
},
|
||||
"enabled": {
|
||||
"label": "Luba heli üleskirjutamine tekstina"
|
||||
}
|
||||
},
|
||||
"detect": {
|
||||
"label": "Objekti tuvastus",
|
||||
"enabled": {
|
||||
"label": "Luba objektituvastus"
|
||||
},
|
||||
"height": {
|
||||
"label": "Tuvastamise kõrgus"
|
||||
},
|
||||
"width": {
|
||||
"label": "Tuvastamise laius"
|
||||
},
|
||||
"fps": {
|
||||
"label": "Tuvastamise kaadrisagedus"
|
||||
},
|
||||
"stationary": {
|
||||
"label": "Püsivate objektide sätted"
|
||||
}
|
||||
},
|
||||
"face_recognition": {
|
||||
"label": "Näotuvastus"
|
||||
},
|
||||
"ffmpeg": {
|
||||
"path": {
|
||||
"label": "FFmpeg asukoht"
|
||||
},
|
||||
"gpu": {
|
||||
"label": "GPU indeks"
|
||||
},
|
||||
"inputs": {
|
||||
"global_args": {
|
||||
"label": "FFmpeg globaalsed argumendid"
|
||||
}
|
||||
}
|
||||
},
|
||||
"live": {
|
||||
"label": "Reaalajas mahamängimine",
|
||||
"height": {
|
||||
"label": "Otseülekande kõrgus"
|
||||
},
|
||||
"quality": {
|
||||
"label": "Otseülekande kvaliteet"
|
||||
},
|
||||
"streams": {
|
||||
"label": "Otseülekande voo nimed"
|
||||
}
|
||||
},
|
||||
"motion": {
|
||||
"label": "Liikumistuvastus",
|
||||
"frame_height": {
|
||||
"label": "Kaadri kõrgus"
|
||||
},
|
||||
"enabled": {
|
||||
"label": "Luba liikumistuvastus"
|
||||
}
|
||||
},
|
||||
"objects": {
|
||||
"label": "Objektid",
|
||||
"filters": {
|
||||
"min_area": {
|
||||
"label": "Minimaalne objekti ala"
|
||||
},
|
||||
"max_area": {
|
||||
"label": "Maksimaalne objekti ala"
|
||||
}
|
||||
},
|
||||
"genai": {
|
||||
"label": "GenAI objekti konfiguratsioon",
|
||||
"required_zones": {
|
||||
"label": "Nõutud tsoonid"
|
||||
},
|
||||
"debug_save_thumbnails": {
|
||||
"label": "Salvesta pisipildid"
|
||||
},
|
||||
"enabled": {
|
||||
"label": "Luba GenAI"
|
||||
},
|
||||
"use_snapshot": {
|
||||
"label": "Kasuta hetktõmmiseid"
|
||||
}
|
||||
}
|
||||
},
|
||||
"mqtt": {
|
||||
"label": "MQTT"
|
||||
},
|
||||
"notifications": {
|
||||
"enabled": {
|
||||
"label": "Luba teavitused"
|
||||
},
|
||||
"email": {
|
||||
"label": "Teavituste email"
|
||||
},
|
||||
"label": "Teavitused"
|
||||
},
|
||||
"ui": {
|
||||
"label": "Kaamera kasutajaliides"
|
||||
},
|
||||
"record": {
|
||||
"label": "Salvestus",
|
||||
"enabled": {
|
||||
"label": "Luba salvestamine"
|
||||
}
|
||||
},
|
||||
"snapshots": {
|
||||
"enabled": {
|
||||
"label": "Luba hetktõmmised"
|
||||
}
|
||||
},
|
||||
"timestamp_style": {
|
||||
"color": {
|
||||
"red": {
|
||||
"label": "Punane",
|
||||
"description": "Punase komponent (0–255) ajatempli värvi jaoks."
|
||||
},
|
||||
"green": {
|
||||
"label": "Roheline",
|
||||
"description": "Rohelise komponent (0–255) ajatempli värvi jaoks."
|
||||
},
|
||||
"blue": {
|
||||
"label": "Sinine",
|
||||
"description": "Sinise komponent (0–255) ajatempli värvi jaoks."
|
||||
},
|
||||
"label": "Ajatempli värv",
|
||||
"description": "Ajatempli teksti RGB värviväärtused (kõik väärtused 0–255)."
|
||||
},
|
||||
"thickness": {
|
||||
"label": "Ajatempli paksus",
|
||||
"description": "Ajatempli teksti joone paksus."
|
||||
},
|
||||
"effect": {
|
||||
"label": "Ajatempli efekt",
|
||||
"description": "Ajatempli teksti visuaalne efekt (puudub, ühtlane, vari)."
|
||||
}
|
||||
},
|
||||
"onvif": {
|
||||
"user": {
|
||||
"label": "ONVIF kasutajanimi"
|
||||
},
|
||||
"password": {
|
||||
"label": "ONVIF parool"
|
||||
},
|
||||
"port": {
|
||||
"label": "ONVIF port"
|
||||
},
|
||||
"label": "ONVIF",
|
||||
"host": {
|
||||
"label": "ONVIF host"
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"label": "Profiilid"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,31 +1,10 @@
|
||||
{
|
||||
"audio": {
|
||||
"label": "Heli tuvastus",
|
||||
"min_volume": {
|
||||
"label": "Minimaalne helitase"
|
||||
},
|
||||
"filters": {
|
||||
"label": "Audio filtrid"
|
||||
}
|
||||
"label": "Helisündmused"
|
||||
},
|
||||
"birdseye": {
|
||||
"mode": {
|
||||
"label": "Jälgimisrežiim"
|
||||
},
|
||||
"order": {
|
||||
"label": "Positsioon"
|
||||
},
|
||||
"height": {
|
||||
"label": "Kõrgus"
|
||||
},
|
||||
"width": {
|
||||
"label": "Laius"
|
||||
},
|
||||
"layout": {
|
||||
"label": "Paigutus",
|
||||
"scaling_factor": {
|
||||
"label": "Skaleerimistegur"
|
||||
}
|
||||
}
|
||||
},
|
||||
"version": {
|
||||
@@ -43,15 +22,6 @@
|
||||
"threshold": {
|
||||
"label": "Punktiskoori lävend",
|
||||
"description": "Punktiskoori lävend, mida kasutatakse klassifitseerimise oleku muutmiseks."
|
||||
},
|
||||
"enabled": {
|
||||
"label": "Luba mudel"
|
||||
},
|
||||
"name": {
|
||||
"label": "Mudeli nimi"
|
||||
},
|
||||
"save_attempts": {
|
||||
"label": "Salvestamiskatsed"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -60,25 +30,11 @@
|
||||
"threshold": {
|
||||
"description": "Minimaalne sarnasuse punktiskoor (0-1), mis on vajalik selle päästiku käivitamiseks."
|
||||
}
|
||||
},
|
||||
"label": "Semantiline otsing",
|
||||
"model_size": {
|
||||
"label": "Mudeli suurus"
|
||||
},
|
||||
"device": {
|
||||
"label": "Seade"
|
||||
}
|
||||
},
|
||||
"face_recognition": {
|
||||
"unknown_score": {
|
||||
"label": "Tundmatu punktiskoori lävend"
|
||||
},
|
||||
"label": "Näotuvastus",
|
||||
"model_size": {
|
||||
"label": "Mudeli suurus"
|
||||
},
|
||||
"device": {
|
||||
"label": "Seade"
|
||||
}
|
||||
},
|
||||
"lpr": {
|
||||
@@ -86,393 +42,15 @@
|
||||
"description": "Sõidukite numbrimärkide tuvastuse seadistus sisaldab tuvastuse lävendeid, vormindust ja teadaolevaid numbrimärke.",
|
||||
"enabled": {
|
||||
"description": "Lülita sõidukite numbrimärkide tuvastus kõikide kaamerate jaoks sisse; seda saad kaamerakohaselt ka sürjutada."
|
||||
},
|
||||
"model_size": {
|
||||
"label": "Mudeli suurus"
|
||||
},
|
||||
"device": {
|
||||
"label": "Seade"
|
||||
}
|
||||
},
|
||||
"genai": {
|
||||
"label": "Generatiivse tehisaru seadistus",
|
||||
"description": "Seadistsued generatiivse tehisaru teenusepakkujate kasutamisel kirjelduste ja kokkuvõtete loomiseks ülevaatamisele kuuluvate objektide jaoks.",
|
||||
"model": {
|
||||
"label": "Mudel"
|
||||
},
|
||||
"roles": {
|
||||
"label": "Rollid"
|
||||
},
|
||||
"api_key": {
|
||||
"label": "API võti"
|
||||
},
|
||||
"base_url": {
|
||||
"label": "Baas-URL"
|
||||
}
|
||||
"description": "Seadistsued generatiivse tehisaru teenusepakkujate kasutamisel kirjelduste ja kokkuvõtete loomiseks ülevaatamisele kuuluvate objektide jaoks."
|
||||
},
|
||||
"review": {
|
||||
"genai": {
|
||||
"description": "Kontrollib generatiivse tehisaru kasutamist kirjelduste ja kokkuvõtete koostamiseks ülevaatamisele kuuluvate objektide jaoks."
|
||||
},
|
||||
"alerts": {
|
||||
"enabled": {
|
||||
"label": "Luba häired",
|
||||
"description": "Luba või keela kõigi kaamerate häirete genereerimine; seda saab kaamerati eraldi muuta."
|
||||
}
|
||||
}
|
||||
},
|
||||
"audio_transcription": {
|
||||
"label": "Audio transkriptsioon",
|
||||
"live_enabled": {
|
||||
"label": "Reaalajas transkriptsioon"
|
||||
},
|
||||
"enabled": {
|
||||
"label": "Luba heli üleskirjutamine tekstina",
|
||||
"description": "Luba või keela automaatne heli üleskirjutamine tektina kõigi kaamerate jaoks; seda saad kaamerati eraldi muuta."
|
||||
},
|
||||
"language": {
|
||||
"label": "Üleskirjutuse keel",
|
||||
"description": "Üleskirjutuse/tõlkimise jaoks kasutatav keelekood (näiteks „en” inglise keele puhul). Toetatud keelekoodid leiad lehelt https://whisper-api.com/docs/languages/."
|
||||
},
|
||||
"device": {
|
||||
"label": "Üleskirjutusseade"
|
||||
},
|
||||
"model_size": {
|
||||
"label": "Mudeli suurus"
|
||||
}
|
||||
},
|
||||
"detect": {
|
||||
"label": "Objekti tuvastus",
|
||||
"enabled": {
|
||||
"label": "Luba objektituvastus"
|
||||
},
|
||||
"height": {
|
||||
"label": "Tuvastamise kõrgus"
|
||||
},
|
||||
"width": {
|
||||
"label": "Tuvastamise laius"
|
||||
},
|
||||
"fps": {
|
||||
"label": "Tuvastamise kaadrisagedus"
|
||||
},
|
||||
"stationary": {
|
||||
"label": "Püsivate objektide sätted"
|
||||
}
|
||||
},
|
||||
"ffmpeg": {
|
||||
"path": {
|
||||
"label": "FFmpeg asukoht"
|
||||
},
|
||||
"gpu": {
|
||||
"label": "GPU indeks"
|
||||
},
|
||||
"inputs": {
|
||||
"global_args": {
|
||||
"label": "FFmpeg globaalsed argumendid"
|
||||
}
|
||||
},
|
||||
"label": "FFmpeg"
|
||||
},
|
||||
"live": {
|
||||
"label": "Reaalajas mahamängimine",
|
||||
"height": {
|
||||
"label": "Otseülekande kõrgus"
|
||||
},
|
||||
"quality": {
|
||||
"label": "Otseülekande kvaliteet"
|
||||
},
|
||||
"streams": {
|
||||
"label": "Otseülekande voo nimed"
|
||||
}
|
||||
},
|
||||
"motion": {
|
||||
"label": "Liikumistuvastus",
|
||||
"frame_height": {
|
||||
"label": "Kaadri kõrgus"
|
||||
},
|
||||
"enabled": {
|
||||
"label": "Luba liikumistuvastus"
|
||||
}
|
||||
},
|
||||
"objects": {
|
||||
"label": "Objektid",
|
||||
"filters": {
|
||||
"min_area": {
|
||||
"label": "Minimaalne objekti ala"
|
||||
},
|
||||
"max_area": {
|
||||
"label": "Maksimaalne objekti ala"
|
||||
}
|
||||
},
|
||||
"genai": {
|
||||
"label": "GenAI objekti konfiguratsioon",
|
||||
"required_zones": {
|
||||
"label": "Nõutud tsoonid"
|
||||
},
|
||||
"debug_save_thumbnails": {
|
||||
"label": "Salvesta pisipildid"
|
||||
},
|
||||
"enabled": {
|
||||
"label": "Luba GenAI"
|
||||
},
|
||||
"use_snapshot": {
|
||||
"label": "Kasuta hetktõmmiseid"
|
||||
}
|
||||
}
|
||||
},
|
||||
"auth": {
|
||||
"reset_admin_password": {
|
||||
"label": "Lähtesta administraatori parool"
|
||||
},
|
||||
"cookie_name": {
|
||||
"label": "JWT küpsise nimi"
|
||||
},
|
||||
"enabled": {
|
||||
"label": "Luba autentimine"
|
||||
},
|
||||
"label": "Autentimine",
|
||||
"session_length": {
|
||||
"label": "Sessiooni pikkus"
|
||||
}
|
||||
},
|
||||
"database": {
|
||||
"label": "Andmebaas"
|
||||
},
|
||||
"mqtt": {
|
||||
"label": "MQTT",
|
||||
"enabled": {
|
||||
"label": "Luba MQTT"
|
||||
},
|
||||
"user": {
|
||||
"label": "MQTT kasutajanimi"
|
||||
},
|
||||
"tls_ca_certs": {
|
||||
"label": "TLS CA sertifikaat"
|
||||
},
|
||||
"tls_client_cert": {
|
||||
"label": "Kliendi sertifikaat"
|
||||
},
|
||||
"host": {
|
||||
"label": "MQTT host",
|
||||
"description": "MQTT maakleri hostinimi või IP-aadress."
|
||||
},
|
||||
"port": {
|
||||
"label": "MQTT port"
|
||||
},
|
||||
"client_id": {
|
||||
"label": "Kliendi ID"
|
||||
},
|
||||
"stats_interval": {
|
||||
"label": "Statistika intervall"
|
||||
},
|
||||
"tls_client_key": {
|
||||
"label": "Kliendi võti"
|
||||
},
|
||||
"qos": {
|
||||
"label": "MQTT QoS"
|
||||
}
|
||||
},
|
||||
"go2rtc": {
|
||||
"label": "go2rtc"
|
||||
},
|
||||
"notifications": {
|
||||
"enabled": {
|
||||
"label": "Luba teavitused"
|
||||
},
|
||||
"email": {
|
||||
"label": "Teavituste email"
|
||||
},
|
||||
"label": "Teavitused"
|
||||
},
|
||||
"networking": {
|
||||
"ipv6": {
|
||||
"label": "IPv6 sätted",
|
||||
"enabled": {
|
||||
"label": "Luba IPv6"
|
||||
}
|
||||
},
|
||||
"label": "Võrguühendus",
|
||||
"listen": {
|
||||
"internal": {
|
||||
"label": "Sisemine port"
|
||||
},
|
||||
"external": {
|
||||
"label": "Välimine port"
|
||||
}
|
||||
}
|
||||
},
|
||||
"proxy": {
|
||||
"label": "Vaheserver",
|
||||
"logout_url": {
|
||||
"label": "Väljalogimise url"
|
||||
},
|
||||
"default_role": {
|
||||
"label": "Vaikimisi roll"
|
||||
}
|
||||
},
|
||||
"telemetry": {
|
||||
"stats": {
|
||||
"label": "Süsteemi statistika",
|
||||
"amd_gpu_stats": {
|
||||
"label": "AMD GPU statistika"
|
||||
},
|
||||
"intel_gpu_stats": {
|
||||
"label": "Intel GPU statistika"
|
||||
},
|
||||
"intel_gpu_device": {
|
||||
"label": "Intel GPU seade"
|
||||
},
|
||||
"network_bandwidth": {
|
||||
"label": "Võrgu ribalaius"
|
||||
}
|
||||
},
|
||||
"label": "Telemeetria",
|
||||
"network_interfaces": {
|
||||
"label": "Võrguliides"
|
||||
},
|
||||
"version_check": {
|
||||
"label": "Versiooni kontroll",
|
||||
"description": "Luba väljaminev ühendus, et kontrollida uuema Frigate versooni olemasolu."
|
||||
}
|
||||
},
|
||||
"tls": {
|
||||
"label": "TLS",
|
||||
"enabled": {
|
||||
"label": "Luba TLS"
|
||||
}
|
||||
},
|
||||
"ui": {
|
||||
"timezone": {
|
||||
"label": "ajavöönd"
|
||||
},
|
||||
"label": "Kasutajaliides",
|
||||
"description": "Kasutajaliidese eelistused nagu ajavöönd, aja ja kuupäeva formaat ning ühikud.",
|
||||
"unit_system": {
|
||||
"label": "Ühikute süsteem"
|
||||
}
|
||||
},
|
||||
"detectors": {
|
||||
"label": "Detektori riistvara",
|
||||
"cpu": {
|
||||
"label": "CPU"
|
||||
},
|
||||
"deepstack": {
|
||||
"label": "DeepStack"
|
||||
},
|
||||
"edgetpu": {
|
||||
"label": "EdgeTPU"
|
||||
},
|
||||
"onnx": {
|
||||
"label": "ONNX",
|
||||
"device": {
|
||||
"label": "Seadme tüüp"
|
||||
}
|
||||
},
|
||||
"rknn": {
|
||||
"label": "RKNN"
|
||||
},
|
||||
"openvino": {
|
||||
"label": "OpenVINO"
|
||||
},
|
||||
"tensorrt": {
|
||||
"label": "TensorRT"
|
||||
},
|
||||
"teflon_tfl": {
|
||||
"label": "Teflon"
|
||||
},
|
||||
"synaptics": {
|
||||
"label": "Synaptics"
|
||||
},
|
||||
"memryx": {
|
||||
"device": {
|
||||
"label": "Seadme asukoht"
|
||||
},
|
||||
"label": "MemryX"
|
||||
},
|
||||
"hailo8l": {
|
||||
"label": "Hailo-8/Hailo-8L"
|
||||
},
|
||||
"zmq": {
|
||||
"label": "ZMQ IPC"
|
||||
},
|
||||
"axengine": {
|
||||
"label": "AXEngine NPU"
|
||||
},
|
||||
"degirum": {
|
||||
"label": "DeGirum"
|
||||
}
|
||||
},
|
||||
"logger": {
|
||||
"label": "Logimine"
|
||||
},
|
||||
"model": {
|
||||
"label": "Tuvastusmudel"
|
||||
},
|
||||
"record": {
|
||||
"label": "Salvestus",
|
||||
"enabled": {
|
||||
"label": "Luba salvestamine",
|
||||
"description": "Luba või keela salvestamine kõigi kaamerate jaoks; seda saab kaamerati eraldi muuta."
|
||||
}
|
||||
},
|
||||
"snapshots": {
|
||||
"enabled": {
|
||||
"label": "Luba hetktõmmised",
|
||||
"description": "Luba või keela kõigi kaamerate hetktõmmiste salvestamine; seda saab kaamerati eraldi muuta."
|
||||
}
|
||||
},
|
||||
"timestamp_style": {
|
||||
"color": {
|
||||
"red": {
|
||||
"label": "Punane",
|
||||
"description": "Punase komponent (0–255) ajatempli värvi jaoks."
|
||||
},
|
||||
"green": {
|
||||
"label": "Roheline",
|
||||
"description": "Rohelise komponent (0–255) ajatempli värvi jaoks."
|
||||
},
|
||||
"blue": {
|
||||
"label": "Sinine",
|
||||
"description": "Sinise komponent (0–255) ajatempli värvi jaoks."
|
||||
},
|
||||
"label": "Ajatempli värv",
|
||||
"description": "Ajatempli teksti RGB värviväärtused (kõik väärtused 0–255)."
|
||||
},
|
||||
"thickness": {
|
||||
"label": "Ajatempli paksus",
|
||||
"description": "Ajatempli teksti joone paksus."
|
||||
},
|
||||
"effect": {
|
||||
"label": "Ajatempli efekt",
|
||||
"description": "Ajatempli teksti visuaalne efekt (puudub, ühtlane, vari)."
|
||||
}
|
||||
},
|
||||
"onvif": {
|
||||
"user": {
|
||||
"label": "ONVIF kasutajanimi"
|
||||
},
|
||||
"password": {
|
||||
"label": "ONVIF parool"
|
||||
},
|
||||
"port": {
|
||||
"label": "ONVIF port"
|
||||
},
|
||||
"label": "ONVIF",
|
||||
"host": {
|
||||
"label": "ONVIF host"
|
||||
}
|
||||
},
|
||||
"camera_mqtt": {
|
||||
"quality": {
|
||||
"label": "JPEG kvaliteet",
|
||||
"description": "MQTT-sse saadetud piltide JPEG-kvaliteet (0–100)."
|
||||
},
|
||||
"enabled": {
|
||||
"label": "Saada pilt"
|
||||
},
|
||||
"label": "MQTT"
|
||||
},
|
||||
"profiles": {
|
||||
"label": "Profiilid"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,67 +6,5 @@
|
||||
"error": "Midagi läks valesti. Palun proovi uuesti.",
|
||||
"processing": "Töötlen…",
|
||||
"toolsUsed": "Kasutatud: {{tools}}",
|
||||
"similarity_score": "Sarnasus",
|
||||
"showTools": "Näita tööriistu ({{count}})",
|
||||
"hideTools": "Peida tööriistad",
|
||||
"call": "Kutse",
|
||||
"result": "Tulemus",
|
||||
"arguments": "Argumendid:",
|
||||
"response": "Vastus:",
|
||||
"send": "Saada",
|
||||
"new_chat": "Uus vestlus",
|
||||
"settings": {
|
||||
"title": "Vestluse sätted",
|
||||
"show_stats": {
|
||||
"title": "Näita statistikat",
|
||||
"always": "Alati",
|
||||
"desc": "Kuva vastuste genereerimise kiirus ja konteksti suurus.",
|
||||
"while_generating": "Genereerimise ajal"
|
||||
},
|
||||
"auto_scroll": {
|
||||
"title": "Automaatne kerimine",
|
||||
"desc": "Jälgi uusi sõnumeid kohe, kui need saabuvad."
|
||||
}
|
||||
},
|
||||
"stats": {
|
||||
"context": "{{tokens}} tokenit",
|
||||
"tokens_per_second": "{{rate}} t/s"
|
||||
},
|
||||
"starting_requests_prompts": {
|
||||
"recap": "Mis juhtus kui ma olin ära?",
|
||||
"watch_camera": "Jälgi ust ja anna mulle teada kui keegi tuleb",
|
||||
"show_camera_status": "Milline on minu kaamerate praegune seis?",
|
||||
"show_recent_events": "Näita mulle viimase tunni viimaseid sündmusi"
|
||||
},
|
||||
"starting_requests": {
|
||||
"show_camera_status": "Näita kaamera olekut",
|
||||
"show_recent_events": "Kuva hiljutised sündmused",
|
||||
"recap": "Mis juhtus kui ma olin ära?",
|
||||
"watch_camera": "Jälgi kaamerat aktiivsuse osas"
|
||||
},
|
||||
"suggested_requests": "Proovi küsida:",
|
||||
"semantic_search_required": "Sarnaste objektide leidmiseks peab olema lubatud semantiline otsing.",
|
||||
"no_similar_objects_found": "Sarnaseid objekte ei leitud.",
|
||||
"quick_reply_when_else": "Millal seda veel nähti?",
|
||||
"quick_reply_find_similar_text": "Leia sarnaseid vaatepilte.",
|
||||
"quick_reply_tell_me_more_text": "Räägi mulle sellest lähemalt.",
|
||||
"quick_reply_when_else_text": "Millal seda veel nähtud on?",
|
||||
"attach_event_aria": "Lisa sündmus {{eventId}}",
|
||||
"attachment_picker_paste_label": "Või kleebi sündmuse ID",
|
||||
"attachment_picker_attach": "Lisa",
|
||||
"attachment_picker_placeholder": "Lisa sündmus",
|
||||
"quick_reply_find_similar": "Leia sarnaseid vaatlusi",
|
||||
"quick_reply_tell_me_more": "Räägi mulle sellest lähemalt",
|
||||
"attachment_chip_remove": "Eemalda manus",
|
||||
"attachment_chip_label": "{{label}} kaameras {{camera}}",
|
||||
"open_in_explore": "Ava uurimisvaates",
|
||||
"anchor": "Viide",
|
||||
"reasoning": {
|
||||
"active": "Otsin põhjendust…",
|
||||
"show": "Näita põhjendust",
|
||||
"hide": "Peida põhjendus"
|
||||
},
|
||||
"thinking": {
|
||||
"toggle": "Näita mõtlemise olekut või peida see"
|
||||
}
|
||||
"similarity_score": "Sarnasus"
|
||||
}
|
||||
|
||||
@@ -43,8 +43,5 @@
|
||||
},
|
||||
"tooltip": {
|
||||
"trainingInProgress": "Mudel on parasjagu õppimas"
|
||||
},
|
||||
"train": {
|
||||
"titleShort": "Hiljutised"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
"noTrackedObjects": "Ühtegi jälgitavat objekti ei leidunud",
|
||||
"itemMenu": {
|
||||
"findSimilar": {
|
||||
"aria": "Otsi sarnaseid jälgitavaid objekte",
|
||||
"label": "Leia sarnane"
|
||||
"aria": "Otsi sarnaseid jälgitavaid objekte"
|
||||
},
|
||||
"downloadSnapshot": {
|
||||
"label": "Laadi hetkvõte alla",
|
||||
@@ -15,14 +14,6 @@
|
||||
"downloadCleanSnapshot": {
|
||||
"label": "Laadi puhas hetkvõte alla",
|
||||
"aria": "Laadi puhas hetkvõte alla"
|
||||
},
|
||||
"viewTrackingDetails": {
|
||||
"label": "Vaata jälgimise üksikasju",
|
||||
"aria": "Näita jälgimise üksikasju"
|
||||
},
|
||||
"downloadVideo": {
|
||||
"label": "Laadi video alla",
|
||||
"aria": "Laadi video alla"
|
||||
}
|
||||
},
|
||||
"trackingDetails": {
|
||||
@@ -30,22 +21,11 @@
|
||||
"showAllZones": {
|
||||
"title": "Näita kõiki tsoone",
|
||||
"desc": "Kui objekt on sisenenud tsooni, siis alati näida tsooni märgistust."
|
||||
},
|
||||
"title": "Annotatsioonide seaded",
|
||||
"offset": {
|
||||
"desc": "Need andmed pärinevad teie kaamera tuvastusvoost, kuid on salvestusvoo piltide peal. On ebatõenäoline, et need kaks voogu on ideaalselt sünkroonis. Seetõttu ei joondu piirav kast ja kaader ideaalselt. Selle säte abil saad annotatsioone ajas edasi või tagasi nihutada, et need salvestatud kaadriga paremini joonduks.",
|
||||
"millisecondsToOffset": "Millisekundid annotatsioonide tuvastuse nihutamiseks. <em>Vaikimisi: 0</em>",
|
||||
"tips": "Vähendage väärtust, kui video taasesitus on kastidest ja teekonnapunktidest ees, ning suurendage väärtust, kui video taasesitus on neist maas. See väärtus võib olla negatiivne.",
|
||||
"toast": {
|
||||
"success": "Kaamera '{{camera}}' annotatsiooni nihe on konfiguratsioonifaili salvestatud."
|
||||
},
|
||||
"label": "Annotatsiooni nihe"
|
||||
}
|
||||
},
|
||||
"lifecycleItemDesc": {
|
||||
"attribute": {
|
||||
"other": "{{label}} on tuvastatud kui {{attribute}}",
|
||||
"faceOrLicense_plate": "{{attribute}} tuvastatud objektil {{label}}"
|
||||
"other": "{{label}} on tuvastatud kui {{attribute}}"
|
||||
},
|
||||
"stationary": "{{label}} jäi paigale",
|
||||
"active": "{{label}} muutus aktiivseks",
|
||||
@@ -57,8 +37,7 @@
|
||||
"area": "Ala",
|
||||
"score": "Punktiskoor",
|
||||
"computedScore": "Arvutatud punktiskoor",
|
||||
"topScore": "Suuremad punktiskoorid",
|
||||
"toggleAdvancedScores": "Täpsemate tulemuste sisse-/väljalülitamine"
|
||||
"topScore": "Suuremad punktiskoorid"
|
||||
},
|
||||
"external": "{{label}} on tuvastatud",
|
||||
"heard": "{{label}} on kuuldud",
|
||||
@@ -71,11 +50,7 @@
|
||||
"previous": "Eelmine slaid",
|
||||
"next": "Järgmine slaid"
|
||||
},
|
||||
"count": "{{first}} / {{second}}",
|
||||
"adjustAnnotationSettings": "Korrigeeri annotatsioonide seadeid",
|
||||
"scrollViewTips": "Klõpsake selle objekti elutsükli oluliste hetkede vaatamiseks.",
|
||||
"autoTrackingTips": "Piirdekastide asukohad on automaatselt jälgivate kaamerate puhul ebatäpsed.",
|
||||
"trackedPoint": "Jälgitav punkt"
|
||||
"count": "{{first}} / {{second}}"
|
||||
},
|
||||
"documentTitle": "Avasta - Frigate",
|
||||
"generativeAI": "Generatiivne tehisaru",
|
||||
@@ -89,22 +64,7 @@
|
||||
},
|
||||
"startingUp": "Käivitun…",
|
||||
"estimatedTime": "Hinnanguliselt jäänud aega:",
|
||||
"finishingShortly": "Lõpetan õige pea",
|
||||
"context": "Avastamist saab kasutada pärast seda, kui jälgitavate objektide manustamine on uuesti indekseerimise lõpetanud."
|
||||
},
|
||||
"title": "Avastamine pole saadaval",
|
||||
"downloadingModels": {
|
||||
"context": "Frigate laadib alla semantilise otsingu funktsiooni toetamiseks vajalikke manustamismudeleid. See võib võtta mitu minutit, olenevalt teie võrguühenduse kiirusest.",
|
||||
"setup": {
|
||||
"visionModel": "Nägemismudel",
|
||||
"visionModelFeatureExtractor": "Nägemismudeli tunnuste eraldaja",
|
||||
"textModel": "Tekstimudel",
|
||||
"textTokenizer": "Teksti tokenisaator"
|
||||
},
|
||||
"tips": {
|
||||
"context": "Pärast mudelite allalaadimist tuleks oma jälgitavate objektide manused uuesti indekseerida."
|
||||
},
|
||||
"error": "Tekkis viga. Kontrollige Frigate'i logisid."
|
||||
"finishingShortly": "Lõpetan õige pea"
|
||||
}
|
||||
},
|
||||
"type": {
|
||||
@@ -147,52 +107,8 @@
|
||||
},
|
||||
"recognizedLicensePlate": "Tuvastatud sõiduki numbrimärk",
|
||||
"description": {
|
||||
"aiTips": "Frigate ei küsi sinu generatiivse tehisaru teenusepakkujalt kirjeldust enne, kui jälgitava objekti elutsükkel on lõppenud.",
|
||||
"label": "Kirjeldus",
|
||||
"placeholder": "Jälgitava objekti kirjeldus"
|
||||
},
|
||||
"label": "Silt",
|
||||
"editSubLabel": {
|
||||
"title": "Muuda alamsilti",
|
||||
"desc": "Sisesta sildile '{{label}}' uus alamsilt",
|
||||
"descNoLabel": "Sisesta sellele jälgitavale objektile uus alamsilt"
|
||||
},
|
||||
"camera": "Kaamera",
|
||||
"zones": "Tsoonid",
|
||||
"title": {
|
||||
"label": "Pealkiri"
|
||||
},
|
||||
"button": {
|
||||
"findSimilar": "Leia sarnane",
|
||||
"regenerate": {
|
||||
"title": "Taasloomine",
|
||||
"label": "Jälgitava objekti kirjelduse uuesti genereerimine"
|
||||
}
|
||||
},
|
||||
"topScore": {
|
||||
"label": "Parim punktiskoor",
|
||||
"info": "Kõrgeim skoor on jälgitava objekti kõrgeim mediaanskoor, seega võib see erineda otsingutulemuste pisipildil kuvatavast skoorist."
|
||||
},
|
||||
"objects": "Objektid",
|
||||
"tips": {
|
||||
"descriptionSaved": "Kirjeldus salvestati edukalt",
|
||||
"saveDescriptionFailed": "Kirjelduse uuendamine ebaõnnestus: {{errorMessage}}"
|
||||
},
|
||||
"attributes": "Klassifikatsiooni atribuudid",
|
||||
"estimatedSpeed": "Hinnanguline kiirus",
|
||||
"editAttributes": {
|
||||
"title": "Atribuutide muutmine",
|
||||
"desc": "Valige selle sildi '{{label}}' jaoks klassifikatsiooniatribuudid"
|
||||
"aiTips": "Frigate ei küsi sinu generatiivse tehisaru teenusepakkujalt kirjeldust enne, kui jälgitava objekti elutsükkel on lõppenud."
|
||||
}
|
||||
},
|
||||
"trackedObjectDetails": "Jälgitava objekti üksikasjad",
|
||||
"aiAnalysis": {
|
||||
"title": "Tehisintellekti analüüs"
|
||||
},
|
||||
"concerns": {
|
||||
"label": "Mured"
|
||||
},
|
||||
"objectLifecycle": {
|
||||
"noImageFound": "Selle jälgitava objekti kohta ei leitud pilti."
|
||||
}
|
||||
"trackedObjectDetails": "Jälgitava objekti üksikasjad"
|
||||
}
|
||||
|
||||
@@ -16,15 +16,12 @@
|
||||
"downloadVideo": "Laadi video alla",
|
||||
"editName": "Muuda nime",
|
||||
"deleteExport": "Kustuta eksporditud sisu",
|
||||
"assignToCase": "Lisa juhtumile",
|
||||
"removeFromCase": "Eemalda juhtumist"
|
||||
"assignToCase": "Lisa juhtumile"
|
||||
},
|
||||
"toast": {
|
||||
"error": {
|
||||
"renameExportFailed": "Eksporditud sisu nime muutmine ei õnnestunud: {{errorMessage}}",
|
||||
"assignCaseFailed": "Juhtumiga seose uuendamine ei õnnestunud: {{errorMessage}}",
|
||||
"caseSaveFailed": "Juhtumi salvestamine ei õnnestunud: {{errorMessage}}",
|
||||
"caseDeleteFailed": "Juhtumi kustutamine ei õnnestunud: {{errorMessage}}"
|
||||
"assignCaseFailed": "Juhtumiga seose uuendamine ei õnnestunud: {{errorMessage}}"
|
||||
}
|
||||
},
|
||||
"headings": {
|
||||
@@ -38,44 +35,5 @@
|
||||
"nameLabel": "Juhtumi nimi",
|
||||
"descriptionLabel": "Kirjeldus",
|
||||
"description": "Vali olemasolev juhtum või lisa uus."
|
||||
},
|
||||
"toolbar": {
|
||||
"newCase": "Uus juhtum",
|
||||
"addExport": "Lisa eksportimiseks",
|
||||
"editCase": "Muuda juhtumit",
|
||||
"deleteCase": "Kustuta juhtum"
|
||||
},
|
||||
"deleteCase": {
|
||||
"label": "Kustuta juhtum",
|
||||
"desc": "Kas oled kindel, et soovid „{{caseName}}“ juhtumi kustutada?"
|
||||
},
|
||||
"caseCard": {
|
||||
"emptyCase": "Eksportimise veel pole"
|
||||
},
|
||||
"jobCard": {
|
||||
"defaultName": "Eksportimine kaamerast „{{camera}}“",
|
||||
"queued": "Lisatud järjekorda",
|
||||
"running": "Töös",
|
||||
"preparing": "Ettevalmistamisel",
|
||||
"copying": "Kopeerimisel",
|
||||
"encoding": "Kodeerimisel",
|
||||
"encodingRetry": "Kodeerimisel (uuesti)",
|
||||
"finalizing": "Lõpetamisel"
|
||||
},
|
||||
"caseView": {
|
||||
"noDescription": "Kirjeldust pole",
|
||||
"createdAt": "Loodud {{value}}",
|
||||
"exportCount_one": "1 eksportimine",
|
||||
"exportCount_other": "{{count}} eksportimist",
|
||||
"cameraCount_one": "1 kaamera",
|
||||
"cameraCount_other": "{{count}} kaamerat",
|
||||
"showMore": "Näita rohkem",
|
||||
"showLess": "Näita vähem",
|
||||
"emptyTitle": "See juhtum on tühi"
|
||||
},
|
||||
"caseEditor": {
|
||||
"namePlaceholder": "Juhtumi nimi",
|
||||
"editTitle": "Muuda juhtumit",
|
||||
"createTitle": "Lisa juhtum"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
{
|
||||
"button": {
|
||||
"uploadImage": "Laadi pilt üles",
|
||||
"deleteFaceAttempts": "Kustuta näod",
|
||||
"addFace": "Lisa nägu",
|
||||
"renameFace": "Nimeta nägu ümber",
|
||||
"deleteFace": "Kustuta nägu",
|
||||
"reprocessFace": "Käivita näotuvastus uuesti"
|
||||
"uploadImage": "Laadi pilt üles"
|
||||
},
|
||||
"collections": "Kogumikud",
|
||||
"description": {
|
||||
@@ -16,41 +11,28 @@
|
||||
},
|
||||
"documentTitle": "Näoteek - Frigate",
|
||||
"createFaceLibrary": {
|
||||
"new": "Lisa uus nägu",
|
||||
"nextSteps": "Tugeva tuvastusaluse loomiseks:<li>Kasuta vahekaarti \"Hiljutised tuvastused\", et valida pilte ja treenida isikutuvastust.</li><li>Parima tulemuse saavutamiseks keskendu otsepiltidele; väldi nurga all olevaid nägusid treenimiseks.</li></ul>"
|
||||
"new": "Lisa uus nägu"
|
||||
},
|
||||
"deleteFaceLibrary": {
|
||||
"title": "Kustuta nimi",
|
||||
"desc": "Kas oled kindel, et soovid isiku '{{name}}' kollektsiooni kustutada? See kustutab jäädavalt kõik seotud näod."
|
||||
"title": "Kustuta nimi"
|
||||
},
|
||||
"toast": {
|
||||
"error": {
|
||||
"addFaceLibraryFailed": "Näo sidumine nimega ei õnnestunud: {{errorMessage}}",
|
||||
"updateFaceScoreFailed": "Näo punktiskoori uuendamine ei õnnestunud: {{errorMessage}}",
|
||||
"uploadingImageFailed": "Pildi üleslaadimine ebaõnnestus: {{errorMessage}}",
|
||||
"deleteFaceFailed": "Kustutamine ebaõnnestus: {{errorMessage}}",
|
||||
"deleteNameFailed": "Nime kustutamine ebaõnnestus: {{errorMessage}}",
|
||||
"renameFaceFailed": "Näo ümbernimetamine ebaõnnestus: {{errorMessage}}",
|
||||
"trainFailed": "Treenimine ebaõnnestus: {{errorMessage}}",
|
||||
"reclassifyFailed": "Näo ümberklassifitseerimine ebaõnnestus: {{errorMessage}}"
|
||||
"updateFaceScoreFailed": "Näo punktiskoori uuendamine ei õnnestunud: {{errorMessage}}"
|
||||
},
|
||||
"success": {
|
||||
"addFaceLibrary": "Lisamine nägude kogusse õnnestus: {{name}}!",
|
||||
"addFaceLibrary": "Lisamine Näoteeki õnnestus: {{name}}!",
|
||||
"deletedFace_one": "{{count}} näo kustutamine õnnestus.",
|
||||
"deletedFace_other": "{{count}} näo kustutamine õnnestus.",
|
||||
"deletedName_one": "{{count}} näo kustutamine õnnestus.",
|
||||
"deletedName_other": "{{count}} näo kustutamine õnnestus.",
|
||||
"updatedFaceScore": "Näo punktiskoori uuendamine õnnestus: {{name}} ({{score}}).",
|
||||
"uploadedImage": "Pildi üleslaadimine õnnestus.",
|
||||
"renamedFace": "Näo ümbernimetamine õnnestus, uus nimi on {{name}}",
|
||||
"trainedFace": "Edukalt treenitud nägu.",
|
||||
"reclassifiedFace": "Näo ümberklassifitseerimine õnnestus."
|
||||
"updatedFaceScore": "Näo punktiskoori uuendamine õnnestus: {{name}} ({{score}})."
|
||||
}
|
||||
},
|
||||
"deleteFaceAttempts": {
|
||||
"desc_one": "Kas oled kindel, et soovid kustutada {{count}} näo? Seda tegevust ei saa tagasi pöörata.",
|
||||
"desc_other": "Kas oled kindel, et soovid kustutada {{count}} nägu? Seda tegevust ei saa tagasi pöörata.",
|
||||
"title": "Kustuta näod"
|
||||
"desc_other": "Kas oled kindel, et soovid kustutada {{count}} nägu? Seda tegevust ei saa tagasi pöörata."
|
||||
},
|
||||
"details": {
|
||||
"timestamp": "Ajatampel",
|
||||
@@ -60,40 +42,5 @@
|
||||
"uploadFaceImage": {
|
||||
"title": "Laadi näopilt üles",
|
||||
"desc": "Laadi üles pilt, et otsida sellelt nägusid ja lisada see {{pageToggle}}'i jaoks"
|
||||
},
|
||||
"steps": {
|
||||
"faceName": "Lisa näole nimi",
|
||||
"uploadFace": "Lae näopilt üles",
|
||||
"nextSteps": "Järgmised sammud",
|
||||
"description": {
|
||||
"uploadFace": "Laadi üles pilt isikust '{{name}}', mis näitab tema nägu eestvaates. Ainult nägu ei pea pildilt välja lõikama."
|
||||
}
|
||||
},
|
||||
"train": {
|
||||
"title": "Hiljutised tuvastamised",
|
||||
"titleShort": "Hiljutised",
|
||||
"aria": "Vali hiljutised tuvastamised",
|
||||
"empty": "Hiljutisi näotuvastuse katseid pole",
|
||||
"emptyNoLibrary": {
|
||||
"title": "Laadi üles nägu",
|
||||
"description": "Näotuvastuse toimimiseks peate lisama vähemalt ühe näo kogusse."
|
||||
}
|
||||
},
|
||||
"renameFace": {
|
||||
"title": "Nimeta nägu ümber",
|
||||
"desc": "Sisesta uus nimi isiku '{{name}}' jaoks"
|
||||
},
|
||||
"imageEntry": {
|
||||
"validation": {
|
||||
"selectImage": "Palun vali pildifail."
|
||||
},
|
||||
"dropActive": "Lohista pilt siia…",
|
||||
"dropInstructions": "Lohistage või kleepige pilt siia või klõpsake valimiseks",
|
||||
"maxSize": "Maksimum suurus: {{size}}MB"
|
||||
},
|
||||
"nofaces": "Nägusid pole saadaval",
|
||||
"trainFaceAs": "Treeni nägu kui:",
|
||||
"trainFace": "Treeni nägu",
|
||||
"reclassifyFaceAs": "Liigita nägu ümber järgmiselt:",
|
||||
"reclassifyFace": "Näo ümberklassifitseerimine"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,78 +1,4 @@
|
||||
{
|
||||
"documentTitle": "Liikumise tuvastus - Frigate",
|
||||
"title": "Liikumise otsing",
|
||||
"cancelSearch": "Tühista",
|
||||
"startSearch": "Alusta otsingut",
|
||||
"selectCamera": "Liikumisotsingut laaditakse",
|
||||
"description": "Joonesta hulknurk, et määratleda huvipakkuv piirkond, ja määra ajavahemik, mille jooksul otsida liikumise muutusi selles piirkonnas.",
|
||||
"searchStarted": "Otsing alustatud",
|
||||
"searchCancelled": "Otsing tühistatud",
|
||||
"searching": "Otsing on pooleli.",
|
||||
"searchComplete": "Otsing lõpetatud",
|
||||
"noResultsYet": "Käivita otsing valitud piirkonnas liikumise muutuste leidmiseks",
|
||||
"noChangesFound": "Valitud piirkonnas ei tuvastatud pikslimuutusi",
|
||||
"results": "Tulemused",
|
||||
"polygonControls": {
|
||||
"drawMode": "Joonista",
|
||||
"moveMode": "Liiguta",
|
||||
"reset": "Lähtesta hulknurk",
|
||||
"undo": "Tühista viimane punkt",
|
||||
"points_one": "{{count}} punkt",
|
||||
"points_other": "{{count}} punkti"
|
||||
},
|
||||
"newSearch": "Uus otsing",
|
||||
"clearResults": "Tühista tulemused",
|
||||
"clearROI": "Tühista hulknurk",
|
||||
"dialog": {
|
||||
"cameraLabel": "Kaamera",
|
||||
"title": "Liikumisotsing",
|
||||
"previewAlt": "Kaamera '{{camera}}' eelvaade"
|
||||
},
|
||||
"timeRange": {
|
||||
"title": "Otsinguvahemik",
|
||||
"start": "Algusaeg",
|
||||
"end": "Lõppaeg"
|
||||
},
|
||||
"settings": {
|
||||
"title": "Otsinguseaded",
|
||||
"parallelMode": "Paralleelrežiim",
|
||||
"parallelModeDesc": "Skanni mitut salvestusvahemikku korraga (kiirem; kasutab rohkem dekodeerimisressursse)",
|
||||
"threshold": "Tundlikkuse lävi",
|
||||
"thresholdDesc": "Väiksemad väärtused tuvastavad väiksemaid muutusi (1–255)",
|
||||
"minArea": "Minimaalne muutusala",
|
||||
"minAreaDesc": "Ühe liikuva piirkonna minimaalne suurus protsentides huvipakkuvast piirkonnast",
|
||||
"maxResults": "Maksimaalselt tulemusi",
|
||||
"maxResultsDesc": "Peata pärast nii paljude ajatemplite sobivust"
|
||||
},
|
||||
"errors": {
|
||||
"noCamera": "Palun vali kaamera",
|
||||
"noROI": "Palun joonistage huvipakkuv piirkond",
|
||||
"noTimeRange": "Palun valige ajavahemik",
|
||||
"invalidTimeRange": "Lõppaeg peab olema pärast algusaega",
|
||||
"searchFailed": "Otsing ebaõnnestus: {{message}}",
|
||||
"polygonTooSmall": "Hulknurgal peab olema vähemalt 3 punkti",
|
||||
"unknown": "Tundmatu viga"
|
||||
},
|
||||
"changePercentage": "{{percentage}}% muutus",
|
||||
"metrics": {
|
||||
"title": "Otsingumõõdikud",
|
||||
"segmentsScanned": "Skannitud segmente",
|
||||
"segmentsProcessed": "Töödeldud",
|
||||
"segmentsSkippedInactive": "Vahele jäetud (tegevust pole)",
|
||||
"segmentsSkippedHeatmap": "Vahele jäetud (kattuvaid piirkondi pole)",
|
||||
"fallbackFullRange": "Varurežiimis täisulatusega skaneerimine",
|
||||
"framesDecoded": "Kaadreid dekodeeritud",
|
||||
"wallTime": "Otsingu aeg",
|
||||
"seconds": "{{seconds}}s",
|
||||
"minutesSeconds": "{{minutes}}m {{seconds}}s",
|
||||
"segmentErrors": "Segmendi vead",
|
||||
"scanSummary": "{{segments}} segmenti · {{time}}"
|
||||
},
|
||||
"jumpToTime": "Hüppa sellele ajale",
|
||||
"framesProcessed": "{{count}} kaadrit töödeldud",
|
||||
"changesFound_one": "Tuvastatud {{count}} liikumine",
|
||||
"changesFound_other": "Tuvastatud {{count}} liikumist",
|
||||
"motionHeatmapLabel": "Liikumise soojakaart",
|
||||
"showSegmentHeatmap": "Soojakaart",
|
||||
"scanning": "Skannimine {{time}}"
|
||||
"title": "Liikumise otsing"
|
||||
}
|
||||
|
||||
@@ -12,48 +12,7 @@
|
||||
"selectFromTimeline": "Vali",
|
||||
"starting": "Käivitan kordust…",
|
||||
"startLabel": "Algus",
|
||||
"endLabel": "Lõpp",
|
||||
"title": "Alusta silumise taasesitust",
|
||||
"description": "Looge ajutine taasesituskaamera, mis kordab ajaloolist salvestist objektide tuvastamise ja jälgimise probleemide silumiseks. Taasesituskaameral on sama tuvastusseadistus mis lähtekaameral. Valige algusaeg.",
|
||||
"toast": {
|
||||
"error": "Silumise taasesitus ebaõnnestus: {{error}}",
|
||||
"alreadyActive": "Kordusseanss on juba aktiivne",
|
||||
"stopError": "Silumise taasesituse peatamine ebaõnnestus: {{error}}",
|
||||
"goToReplay": "Mine kordusesse"
|
||||
}
|
||||
"endLabel": "Lõpp"
|
||||
},
|
||||
"title": "Kordus veaotsinguks",
|
||||
"websocket_messages": "Sõnumid",
|
||||
"description": "Mängi kaamera salvestisi veaotsinguks. Objektide loend näitab tuvastatud objektide ajalist viivitust ja vahekaart „Sõnumid” näitab Fregati sisemiste sõnumite voogu taasesituse materjalist.",
|
||||
"page": {
|
||||
"noSession": "Aktiivset silumis- ja taasesitusseanssi pole",
|
||||
"noSessionDesc": "Alusta silumissalvestise taasesitust ajaloo vaates, klõpsates tööriistaribal nupul \"Toimingud\" ja valides silumissalvestise taasesituse.",
|
||||
"goToRecordings": "Mine ajaloo vaatesse",
|
||||
"preparingClip": "Klipi ettevalmistamine…",
|
||||
"preparingClipDesc": "Frigate koondab valitud ajavahemiku salvestisi. Pikemate vahemike puhul võib see võtta kauem.",
|
||||
"startingCamera": "Silumise taasesituse käivitamine…",
|
||||
"startError": {
|
||||
"title": "Silumise taasesituse käivitamine ebaõnnestus",
|
||||
"back": "Tagasi ajaloo vaatesse"
|
||||
},
|
||||
"sourceCamera": "Lähtekaamera",
|
||||
"replayCamera": "Taasesituse kaamera",
|
||||
"initializingReplay": "Silumise taasesituse initsialiseerimine...",
|
||||
"stoppingReplay": "Silumise taasesituse peatamine...",
|
||||
"stopReplay": "Peata kordusesitus",
|
||||
"confirmStop": {
|
||||
"title": "Peata silumise kordusesitus?",
|
||||
"description": "See peatab seansi ja kustutab kõik ajutised andmed. Kas oled kindel?",
|
||||
"confirm": "Peata kordusesitus",
|
||||
"cancel": "Tühista"
|
||||
},
|
||||
"activity": "Toimingud",
|
||||
"objects": "Objekti loend",
|
||||
"audioDetections": "Audio tuvastused",
|
||||
"noActivity": "Ühtegi tegevust ei tuvastatud",
|
||||
"activeTracking": "Aktiivne jälgimine",
|
||||
"noActiveTracking": "Aktiivset jälgimist pole",
|
||||
"configuration": "Seaded",
|
||||
"configurationDesc": "Peenhäälesta liikumistuvastuse ja objektide jälgimise sätteid silumis- ja taasesituskaamera jaoks. Frigate'i konfiguratsiooni faili muudatusi ei salvestata."
|
||||
}
|
||||
"title": "Kordus veaotsinguks"
|
||||
}
|
||||
|
||||
@@ -7,28 +7,7 @@
|
||||
"connectionSettings": "Ühenduse seadistused",
|
||||
"port": "Port",
|
||||
"username": "Kasutajanimi",
|
||||
"usernamePlaceholder": "Valikuline",
|
||||
"cameraName": "Kaamera nimi",
|
||||
"cameraNamePlaceholder": "näiteks: eesmine_uks või Hoovi ülevaade",
|
||||
"host": "Host/IP-aadress",
|
||||
"cameraBrand": "Kaamera bränd",
|
||||
"selectBrand": "Vali URL malli jaoks kaamera bränd",
|
||||
"customUrl": "Kohandatud voo URL",
|
||||
"brandInformation": "Brändi teave",
|
||||
"brandUrlFormat": "Kaamerate puhul, mille RTSP URL-i vorming on järgmine: {{exampleUrl}}",
|
||||
"selectTransport": "Valige transpordiprotokoll",
|
||||
"description": "Sisestage oma kaamera andmed ja valige, kas soovite kaamerat tuvastada või valida tootja käsitsi.",
|
||||
"onvifPort": "ONVIF port",
|
||||
"probeMode": "Tuvasta kaamera",
|
||||
"manualMode": "Manuaalne valik",
|
||||
"errors": {
|
||||
"nameRequired": "Kaamera nimi on kohustuslik",
|
||||
"nameLength": "Kaamera nimi peab olema kuni 64 tähemärki pikk",
|
||||
"invalidCharacters": "Kaamera nimi sisaldab sobimatuid märke",
|
||||
"nameExists": "Kaamera nimi on juba olemas",
|
||||
"brandOrCustomUrlRequired": "Valige kas kaamera bränd koos hosti/IP-aadressiga või valige „Muu” kohandatud URL-iga"
|
||||
},
|
||||
"detectionMethod": "Vootuvastus meetod"
|
||||
"usernamePlaceholder": "Valikuline"
|
||||
},
|
||||
"step3": {
|
||||
"streamUrlPlaceholder": "rtsp://kasutajanimi:salasõna@host:port/asukoht",
|
||||
@@ -38,37 +17,17 @@
|
||||
"roles": "Rollid",
|
||||
"roleLabels": {
|
||||
"record": "Salvestamine",
|
||||
"audio": "Heliriba",
|
||||
"detect": "Objektituvastus"
|
||||
"audio": "Heliriba"
|
||||
},
|
||||
"connected": "Ühendatud",
|
||||
"featuresTitle": "Funktsionaalsused",
|
||||
"selectStream": "Vali voog",
|
||||
"selectQuality": "Valige kvaliteet",
|
||||
"notConnected": "Pole ühendatud",
|
||||
"testFailedTitle": "Test ebaõnnestus",
|
||||
"testStream": "Testi ühendust",
|
||||
"testSuccess": "Voo test edukas!",
|
||||
"testFailed": "Voo test ebaõnnestus",
|
||||
"selectResolution": "Vali resolutsioon",
|
||||
"noStreamFound": "Voogu ei leitud",
|
||||
"addAnotherStream": "Lisa järgmine voog",
|
||||
"streamTitle": "Voog {{number}}",
|
||||
"streamUrl": "Voo URL",
|
||||
"addStream": "Lisa voog",
|
||||
"description": "Seadista voogedastusrolle ja lisa oma kaamerale täiendavaid vooge.",
|
||||
"streamsTitle": "Kaamera vood"
|
||||
"featuresTitle": "Funktsionaalsused"
|
||||
},
|
||||
"steps": {
|
||||
"probeOrSnapshot": "Võta proov või tee hetkvõte",
|
||||
"nameAndConnection": "Nimi ja ühendus",
|
||||
"streamConfiguration": "Voo seaded",
|
||||
"validationAndTesting": "Valideerimine ja testimine"
|
||||
"probeOrSnapshot": "Võta proov või tee hetkvõte"
|
||||
},
|
||||
"step2": {
|
||||
"testing": {
|
||||
"fetchingSnapshot": "Laadin kaamera hetkvõtet alla...",
|
||||
"probingMetadata": "Tuvastan kaamera metaandmeid..."
|
||||
"fetchingSnapshot": "Laadin kaamera hetkvõtet alla..."
|
||||
},
|
||||
"retry": "Proovi uuesti",
|
||||
"manufacturer": "Tootja",
|
||||
@@ -78,30 +37,7 @@
|
||||
"presets": "Eelseadistused",
|
||||
"useCandidate": "Kasuta",
|
||||
"uriCopy": "Kopeeri",
|
||||
"connected": "Ühendatud",
|
||||
"testSuccess": "Ühenduse test õnnestus!",
|
||||
"testFailed": "Ühenduse test ebaõnnestus. Palun kontrollige sisestatud andmeid ja proovige uuesti.",
|
||||
"testFailedTitle": "Test ebaõnnestus",
|
||||
"streamDetails": "Voo üksikasjad",
|
||||
"probing": "Tuvastan kaamerat...",
|
||||
"ptzSupport": "PTZ tugi",
|
||||
"testConnection": "Testi ühendust",
|
||||
"toggleUriView": "Klõpsake täieliku URI vaate sisse/välja lülitamiseks",
|
||||
"notConnected": "Pole ühendatud",
|
||||
"errors": {
|
||||
"hostRequired": "Hosti/IP-aadress on kohustuslik"
|
||||
},
|
||||
"candidateStreamTitle": "Kandidaat {{number}}",
|
||||
"probeSuccessful": "Tuvastamine õnnestus",
|
||||
"probeError": "Tuvastamise viga",
|
||||
"probeNoSuccess": "Tuvastamine ebaõnnestus",
|
||||
"deviceInfo": "Seadme info",
|
||||
"autotrackingSupport": "Automaatse jälgimise tugi",
|
||||
"uriCopied": "URI kopeeriti lõikelauale",
|
||||
"rtspCandidates": "RTSP kandidaadid",
|
||||
"probingDevice": "Tuvastan seadet...",
|
||||
"description": "Tuvasta kaamera vooge või seadista käsitsi seaded vastavalt valitud tuvastusmeetodile.",
|
||||
"probeFailed": "Kaamera tuvastamine ebaõnnestus: {{error}}"
|
||||
"connected": "Ühendatud"
|
||||
},
|
||||
"testResultLabels": {
|
||||
"resolution": "Resolutsioon",
|
||||
@@ -120,17 +56,7 @@
|
||||
"roles": "Rollid",
|
||||
"none": "Määramata",
|
||||
"error": "Viga"
|
||||
},
|
||||
"commonErrors": {
|
||||
"noUrl": "Palun sisestage kehtiv voogesituse URL",
|
||||
"testFailed": "Voo test ebaõnnestus: {{error}}"
|
||||
},
|
||||
"save": {
|
||||
"success": "Uue kaamera '{{cameraName}}' salvestamine õnnestus.",
|
||||
"failure": "Viga kaamera '{{cameraName}}' salvestamisel."
|
||||
},
|
||||
"title": "Lisa kaamera",
|
||||
"description": "Uue kaamera lisamiseks oma Frigate paigaldisesse järgige alltoodud samme."
|
||||
}
|
||||
},
|
||||
"users": {
|
||||
"updatePassword": "Lähtesta salasõna",
|
||||
@@ -246,32 +172,24 @@
|
||||
},
|
||||
"documentTitle": {
|
||||
"default": "Seadistused - Frigate",
|
||||
"authentication": "Autentimise seaded - Frigate",
|
||||
"cameraReview": "Kaamerate kordusvaatuste seaded - Frigate",
|
||||
"general": "Profiili seaded - Frigate",
|
||||
"frigatePlus": "Frigate+ seaded - Frigate",
|
||||
"notifications": "Teavituste seaded - Frigate",
|
||||
"authentication": "Autentimise seadistused - Frigate",
|
||||
"cameraReview": "Kaamerate kordusvaatuste seadistused - Frigate",
|
||||
"general": "Profiili seadistused - Frigate",
|
||||
"frigatePlus": "Frigate+ seadistused - Frigate",
|
||||
"notifications": "Teavituste seadistused - Frigate",
|
||||
"cameraManagement": "Kaamerate haldus - Frigate",
|
||||
"masksAndZones": "Maskide ja tsoonide haldus - Frigate",
|
||||
"object": "Silumine ja veaotsing - Frigate",
|
||||
"enrichments": "Rikastamise seaded - Frigate",
|
||||
"motionTuner": "Liikumise häälestaja – Frigate",
|
||||
"globalConfig": "Globaalsed seaded – Frigate",
|
||||
"cameraConfig": "Kaamera seaded - Frigate",
|
||||
"detectorsAndModel": "Detektorid ja mudel – Frigate",
|
||||
"maintenance": "Hooldus – Frigate",
|
||||
"profiles": "Profiilid - Frigate"
|
||||
"object": "Silumine ja veaotsing - Frigate"
|
||||
},
|
||||
"general": {
|
||||
"title": "Kasutajaliidese seadistused",
|
||||
"title": "Profiili seadistused",
|
||||
"cameraGroupStreaming": {
|
||||
"clearAll": "Kustuta kõik voogedastuse seadistused"
|
||||
},
|
||||
"liveDashboard": {
|
||||
"title": "Töölaud reaalajas",
|
||||
"automaticLiveView": {
|
||||
"label": "Automaatne otseülekande vaade",
|
||||
"desc": "Aktiveerib automaatselt kaamera reaalajas vaate, kui tuvastatakse tegevus. Selle valiku keelamisel uuendatakse kaamerapilti töölaual ainult üks kord minutis."
|
||||
"label": "Automaatne otseülekande vaade"
|
||||
}
|
||||
},
|
||||
"calendar": {
|
||||
@@ -417,7 +335,7 @@
|
||||
},
|
||||
"menu": {
|
||||
"ui": "Kasutajaliides",
|
||||
"cameraManagement": "Kaamera haldus",
|
||||
"cameraManagement": "Haldus",
|
||||
"masksAndZones": "Maskid ja tsoonid",
|
||||
"triggers": "Päästikud",
|
||||
"debug": "Silumine ja veaotsing",
|
||||
@@ -455,37 +373,7 @@
|
||||
"systemMqtt": "MQTT",
|
||||
"systemGo2rtcStreams": "go2rtc voogedastus",
|
||||
"integrationSemanticSearch": "Semantiline otsing",
|
||||
"integrationGenerativeAi": "Generatiivne tehisaru",
|
||||
"general": "Üldine",
|
||||
"globalConfig": "Globaalsed seaded",
|
||||
"system": "Süsteem",
|
||||
"integrations": "Integratsioonid",
|
||||
"cameras": "Kaamera seaded",
|
||||
"integrationFaceRecognition": "Nöotuvastus",
|
||||
"cameraDetect": "Objektituvastus",
|
||||
"cameraFfmpeg": "Vood (FFmpeg)",
|
||||
"cameraRecording": "Salvestus",
|
||||
"cameraSnapshots": "Hetktõmmised",
|
||||
"cameraMotion": "Liikumistuvastus",
|
||||
"cameraObjects": "Objektid",
|
||||
"cameraConfigReview": "Ülevaade",
|
||||
"cameraAudioEvents": "audiotuvastus",
|
||||
"cameraAudioTranscription": "Audio transkriptsioon",
|
||||
"cameraNotifications": "Teated",
|
||||
"cameraLivePlayback": "Otseülekanne",
|
||||
"integrationAudioTranscription": "Audio transkriptsioon",
|
||||
"integrationObjectClassification": "Objektide klassifitseerimine",
|
||||
"cameraFaceRecognition": "Näotuvastus",
|
||||
"cameraMqttConfig": "MQTT",
|
||||
"cameraOnvif": "ONVIF",
|
||||
"cameraUi": "Kaamera kasutajaliides",
|
||||
"cameraTimestampStyle": "Ajatempli stiil",
|
||||
"cameraMqtt": "Kaamera MQTT",
|
||||
"maintenance": "Hooldus",
|
||||
"mediaSync": "Meedia sünkroonimine",
|
||||
"regionGrid": "Regioonide ruudustik",
|
||||
"enrichments": "Andmete rikastamine",
|
||||
"motionTuner": "Liikumistuvastuse seadistaja"
|
||||
"integrationGenerativeAi": "Generatiivne tehisaru"
|
||||
},
|
||||
"dialog": {
|
||||
"unsavedChanges": {
|
||||
@@ -501,11 +389,7 @@
|
||||
"semanticSearch": {
|
||||
"reindexNow": {
|
||||
"confirmButton": "Indekseeri uuesti",
|
||||
"label": "Indekseeri kohe uuesti",
|
||||
"alreadyInProgress": "Ümberindekseerimine on juba käimas.",
|
||||
"error": "Uuesti indekseerimise alustamine ebaõnnestus: {{errorMessage}}",
|
||||
"success": "Ümberindekseerimine algas edukalt.",
|
||||
"confirmTitle": "Kinnita uuesti indekseerimine"
|
||||
"label": "Indekseeri uuesti kohe"
|
||||
},
|
||||
"modelSize": {
|
||||
"small": {
|
||||
@@ -513,9 +397,7 @@
|
||||
},
|
||||
"large": {
|
||||
"title": "suur"
|
||||
},
|
||||
"label": "Mudeli suurus",
|
||||
"desc": "Semantilise otsingu manustamiseks kasutatava mudeli suurus."
|
||||
}
|
||||
},
|
||||
"title": "Semantiline otsing"
|
||||
},
|
||||
@@ -526,23 +408,14 @@
|
||||
},
|
||||
"large": {
|
||||
"title": "suur"
|
||||
},
|
||||
"label": "Mudeli suurus",
|
||||
"desc": "Näotuvastuseks kasutatava mudeli suurus."
|
||||
},
|
||||
"title": "Näotuvastus"
|
||||
}
|
||||
}
|
||||
},
|
||||
"birdClassification": {
|
||||
"title": "Lindude klassifikatsioon"
|
||||
},
|
||||
"licensePlateRecognition": {
|
||||
"title": "Sõidukite numbrimärkide tuvastus"
|
||||
},
|
||||
"title": "Andmerikastuse seaded",
|
||||
"restart_required": "Taaskäivitamine on vajalik (Andmerikastuse seadeid on muudetud)",
|
||||
"toast": {
|
||||
"success": "Andmerikastamise seaded on salvestatud. Muudatuste rakendamiseks taaskäivitage Frigate.",
|
||||
"error": "Seadete muudatuste salvestamine ebaõnnestus: {{errorMessage}}"
|
||||
}
|
||||
},
|
||||
"cameraReview": {
|
||||
@@ -624,31 +497,5 @@
|
||||
"lpr": {
|
||||
"vehicleNotTracked": "Sõidukite numbrimärkide tuvastus eeldab, et auto või mootorratas on jälgitav. Lülita menüüst Objektid sell kaamera jaoks sisse valikud „auto“ või „mootorratas“."
|
||||
}
|
||||
},
|
||||
"button": {
|
||||
"overriddenGlobal": "Ülekirjutatud (Globaalne)",
|
||||
"overriddenGlobalTooltip": "Käesolev kaamera kirjutab selles jaotises üle globaalsed seaded",
|
||||
"overriddenGlobalHeading_one": "See kaamera sürjutab {{count}} üldise seadistuse välja:",
|
||||
"overriddenGlobalHeading_other": "See kaamera sürjutab {{count}} üldise seadistuse välja:"
|
||||
},
|
||||
"saveAllPreview": {
|
||||
"title": "Salvestatavad muudatused",
|
||||
"triggerLabel": "Vaadake üle ootel olevad muudatused",
|
||||
"empty": "Ootel muudatusi pole.",
|
||||
"scope": {
|
||||
"label": "Ulatus",
|
||||
"global": "Globaalne",
|
||||
"camera": "Kaamera: {{cameraName}}"
|
||||
},
|
||||
"profile": {
|
||||
"label": "Profiil"
|
||||
},
|
||||
"field": {
|
||||
"label": "Väli"
|
||||
},
|
||||
"value": {
|
||||
"label": "Uus väärtus",
|
||||
"reset": "Lähtesta"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,7 @@
|
||||
"documentTitle": {
|
||||
"general": "Üldine statistika - Frigate",
|
||||
"cameras": "Kaamerate statistika - Frigate",
|
||||
"storage": "Andmeruumi statistika - Frigate",
|
||||
"logs": {
|
||||
"frigate": "Frigate logid - Frigate",
|
||||
"go2rtc": "Go2RTC logid - Frigate",
|
||||
"nginx": "Nginx logid - Frigate",
|
||||
"websocket": "Sõnumite logid - Frigate"
|
||||
},
|
||||
"enrichments": "Rikastus statistika - Frigate"
|
||||
"storage": "Andmeruumi statistika - Frigate"
|
||||
},
|
||||
"logs": {
|
||||
"download": {
|
||||
@@ -23,29 +16,11 @@
|
||||
"websocket": {
|
||||
"filter": {
|
||||
"cameras_count_one": "{{count}} kaamera",
|
||||
"cameras_count_other": "{{count}} kaamerat",
|
||||
"camera": "Kaamera",
|
||||
"all_cameras": "Kõik kaamerad",
|
||||
"events": "Sündmused",
|
||||
"reviews": "Ülevaated",
|
||||
"system": "Süsteem",
|
||||
"topics": "Teemad",
|
||||
"all": "Kõik teemad",
|
||||
"face_recognition": "Näotuvastus",
|
||||
"classification": "Klassifikatsioon",
|
||||
"camera_activity": "Kaamera aktiivsus",
|
||||
"lpr": "Numbrimärgituvastus"
|
||||
"cameras_count_other": "{{count}} kaamerat"
|
||||
},
|
||||
"empty": "Ühtegi sõnumit pole veel hõivatud",
|
||||
"count_one": "{{count}} sõnum",
|
||||
"count_other": "{{count}} sõnumit",
|
||||
"pause": "Peata",
|
||||
"resume": "Jätka",
|
||||
"label": "Sõnumid",
|
||||
"clear": "Tühista",
|
||||
"expanded": {
|
||||
"payload": "Last"
|
||||
}
|
||||
"count_other": "{{count}} sõnumit"
|
||||
},
|
||||
"type": {
|
||||
"label": "Tüüp",
|
||||
@@ -61,170 +36,5 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"title": "Süsteem",
|
||||
"enrichments": {
|
||||
"embeddings": {
|
||||
"object_description_events_per_second": "Objekti kirjeldus",
|
||||
"face_recognition": "Näotuvastus",
|
||||
"plate_recognition": "Numbrimärgi tuvastus",
|
||||
"object_description": "Objekti kirjeldus",
|
||||
"review_description_events_per_second": "Ülevaate kirjeldus",
|
||||
"review_description": "Ülevaate kirjeldus",
|
||||
"yolov9_plate_detection": "YOLOv9 numbrimärgi tuvastus",
|
||||
"yolov9_plate_detection_speed": "YOLOv9 numbrimärgi tuvastuskiirus",
|
||||
"plate_recognition_speed": "Numbrimärgituvastuse kiirus",
|
||||
"face_recognition_speed": "Näotuvastuse kiirus"
|
||||
},
|
||||
"title": "Andmerikastused"
|
||||
},
|
||||
"cameras": {
|
||||
"connectionQuality": {
|
||||
"reconnectsLastHour": "Uuesti ühendumisi (viimase tunni jooksul)",
|
||||
"stallsLastHour": "Seiskumisi (viimase tunni jooksul)",
|
||||
"title": "Ühenduse kvaliteet",
|
||||
"excellent": "Suurepärane",
|
||||
"fair": "Rahuldav",
|
||||
"poor": "Kehv",
|
||||
"unusable": "Mittekasutatav",
|
||||
"fps": "Kaadrisagedus",
|
||||
"expectedFps": "Eeldatav kaadrisagedus (FPS)"
|
||||
},
|
||||
"label": {
|
||||
"camera": "kaamera",
|
||||
"detect": "tuvasta",
|
||||
"skipped": "vahele jäetud",
|
||||
"ffmpeg": "FFmpeg",
|
||||
"cameraFfmpeg": "{{camName}} FFmpeg",
|
||||
"cameraGpu": "{{camName}} GPU",
|
||||
"cameraDetect": "{{camName}} tuvastus",
|
||||
"overallFramesPerSecond": "kaadreid sekundis kokku",
|
||||
"overallDetectionsPerSecond": "kogutuvastusi sekundis",
|
||||
"overallSkippedDetectionsPerSecond": "vahelejäänud tuvastusi sekundis kokku",
|
||||
"cameraFramesPerSecond": "{{camName}} kaadreid sekundis",
|
||||
"cameraDetectionsPerSecond": "{{camName}} tuvastusi sekundis",
|
||||
"cameraSkippedDetectionsPerSecond": "{{camName}} vahelejäänud tuvastusi sekundis",
|
||||
"capture": "jäädvustamine"
|
||||
},
|
||||
"noCameras": {
|
||||
"title": "Ühtegi kaamerat ei leitud"
|
||||
},
|
||||
"framesAndDetections": "Kaadreid / Tuvastusi",
|
||||
"info": {
|
||||
"keyframes": {
|
||||
"recordDisabled": "Selle kaamera salvestamine on välja lülitatud.",
|
||||
"segmentLength": "Salvestuse segmendi pikkus:",
|
||||
"recordStream": "Salvestusvoog:",
|
||||
"keyframeCount": "Vaadeldud võtmekaadrid:",
|
||||
"observedDuration": "Vaadeldud kestus:"
|
||||
},
|
||||
"audio": "Audio:",
|
||||
"error": "Viga: {{error}}",
|
||||
"codec": "Koodek:",
|
||||
"resolution": "Resolutsioon:",
|
||||
"video": "Video:",
|
||||
"aspectRatio": "kuvasuhe",
|
||||
"unknown": "Tundmatu",
|
||||
"fetching": "Kaameraandmete toomine",
|
||||
"stream": "Voog {{idx}}",
|
||||
"streamDataFromFFPROBE": "Vooandmed saadakse <code>ffprobe</code> abil.",
|
||||
"fps": "Kaadrisagedus (FPS):"
|
||||
},
|
||||
"title": "Kaamerad",
|
||||
"overview": "Ülevaade"
|
||||
},
|
||||
"lastRefreshed": "Viimati uuendatud: ",
|
||||
"stats": {
|
||||
"healthy": "Süsteem on töökorras",
|
||||
"detectIsSlow": "{{detect}} on aeglane ({{speed}} ms)",
|
||||
"detectIsVerySlow": "{{detect}} on väga aeglane ({{speed}} ms)",
|
||||
"cameraIsOffline": "{{camera}} on ühenduseta"
|
||||
},
|
||||
"storage": {
|
||||
"cameraStorage": {
|
||||
"camera": "Kaamera",
|
||||
"unused": {
|
||||
"title": "Kasutamata",
|
||||
"tips": "See väärtus ei pruugi Frigate'i jaoks saadaolevat vaba ruumi täpselt kajastada, kui teie draivil on lisaks Frigate'i salvestistele ka muid faile. Frigate ei jälgi salvestusruumi kasutamist väljaspool oma salvestisi."
|
||||
},
|
||||
"bandwidth": "Ribalaius",
|
||||
"storageUsed": "Salvestusmaht",
|
||||
"percentageOfTotalUsed": "protsent kogusummast",
|
||||
"unusedStorageInformation": "Kasutamata salvestusmahu info",
|
||||
"title": "Kaamera salvestusmaht"
|
||||
},
|
||||
"title": "Säilitus",
|
||||
"overview": "Ülevaade",
|
||||
"recordings": {
|
||||
"title": "Salvestused",
|
||||
"earliestRecording": "Varaseim saadaolev salvestis:"
|
||||
},
|
||||
"shm": {
|
||||
"title": "SHM (jagatud mälu) eraldus",
|
||||
"frameLifetime": {
|
||||
"title": "Kaadri eluiga"
|
||||
}
|
||||
}
|
||||
},
|
||||
"metrics": "Süsteemi mõõdikud",
|
||||
"general": {
|
||||
"title": "Üldine",
|
||||
"hardwareInfo": {
|
||||
"gpuUsage": "GPU kasutus",
|
||||
"gpuMemory": "GPU mälu",
|
||||
"gpuInfo": {
|
||||
"vainfoOutput": {
|
||||
"title": "Vainfo väljund",
|
||||
"processOutput": "Protsessi väljund:",
|
||||
"processError": "Protsessi viga:",
|
||||
"returnCode": "Tagastuskood: {{code}}"
|
||||
},
|
||||
"closeInfo": {
|
||||
"label": "Sulge GPU info"
|
||||
},
|
||||
"copyInfo": {
|
||||
"label": "Kopeeri GPU info"
|
||||
},
|
||||
"nvidiaSMIOutput": {
|
||||
"title": "Nvidia SMI väljund",
|
||||
"name": "Nimi: {{name}}",
|
||||
"driver": "Draiver: {{driver}}",
|
||||
"cudaComputerCapability": "CUDA arvutusvõimekus: {{cuda_compute}}",
|
||||
"vbios": "VBios info: {{vbios}}"
|
||||
},
|
||||
"toast": {
|
||||
"success": "GPU info kopeeriti lõikelauale"
|
||||
}
|
||||
},
|
||||
"gpuDecoder": "GPU dekooder",
|
||||
"gpuTemperature": "GPU temperatuur",
|
||||
"gpuEncoder": "GPU kodeerija",
|
||||
"gpuCompute": "GPU arvutus / kodeerimine",
|
||||
"title": "Riistvara info",
|
||||
"npuUsage": "NPU kasutus",
|
||||
"npuMemory": "NPU mälu",
|
||||
"npuTemperature": "NPU temperatuur",
|
||||
"intelGpuWarning": {
|
||||
"title": "Inteli GPU statistika hoiatus",
|
||||
"message": "GPU statistika pole saadaval"
|
||||
}
|
||||
},
|
||||
"otherProcesses": {
|
||||
"series": {
|
||||
"go2rtc": "go2rtc",
|
||||
"recording": "salvestus",
|
||||
"review_segment": "Segmendi ülevaade",
|
||||
"audio_detector": "audio detektor"
|
||||
},
|
||||
"processCpuUsage": "Protsessi CPU kasutus",
|
||||
"processMemoryUsage": "Protsessi mälukasutus"
|
||||
},
|
||||
"detector": {
|
||||
"title": "Detektorid",
|
||||
"memoryUsage": "Detektori mälukasutus",
|
||||
"cpuUsage": "Detektori CPU kasutus",
|
||||
"temperature": "Detektori temperatuur",
|
||||
"inferenceSpeed": "Detektori järelduskiirus",
|
||||
"cpuUsageInformation": "Protsessori võimsus, mida kasutatakse tuvastusmudelite sisend- ja väljundandmete ettevalmistamisel. See väärtus ei mõõda järelduste kasutamist isegi siis, kui kasutatakse graafikaprotsessorit või kiirendit."
|
||||
}
|
||||
}
|
||||
"title": "Süsteem"
|
||||
}
|
||||
|
||||
@@ -26,8 +26,7 @@
|
||||
"max_speed": "Maksimi nopeus",
|
||||
"recognized_license_plate": "Tunnistettu rekisterikilpi",
|
||||
"has_clip": "Leike löytyy",
|
||||
"has_snapshot": "Tilannekuva löytyy",
|
||||
"attributes": "Muuttujat"
|
||||
"has_snapshot": "Tilannekuva löytyy"
|
||||
},
|
||||
"searchType": {
|
||||
"thumbnail": "Kuvake",
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
"whoop": "Cri strident",
|
||||
"sigh": "Soupir",
|
||||
"singing": "Chant",
|
||||
"choir": "Chœur",
|
||||
"choir": "Chorale",
|
||||
"yodeling": "Yodel",
|
||||
"chant": "Chant",
|
||||
"mantra": "Mantra",
|
||||
@@ -33,7 +33,7 @@
|
||||
"snoring": "Ronflement",
|
||||
"gasp": "Souffle coupé",
|
||||
"pant": "halètement",
|
||||
"snort": "Reniflement",
|
||||
"snort": "Ébrouement",
|
||||
"camera": "Caméra",
|
||||
"cough": "Toux",
|
||||
"groan": "Gémissement",
|
||||
@@ -104,7 +104,7 @@
|
||||
"toothbrush": "Brosse à dents",
|
||||
"sink": "Évier",
|
||||
"scissors": "Ciseaux",
|
||||
"humming": "Fredonnement",
|
||||
"humming": "Bourdonnement",
|
||||
"shuffle": "Pas traînants",
|
||||
"footsteps": "Bruits de pas",
|
||||
"hiccup": "Hoquet",
|
||||
|
||||
@@ -67,8 +67,7 @@
|
||||
"error": {
|
||||
"failed": "Échec du démarrage de l'exportation : {{error}}",
|
||||
"endTimeMustAfterStartTime": "L'heure de fin doit être postérieure à l'heure de début.",
|
||||
"noVaildTimeSelected": "La plage horaire sélectionnée n'est pas valide.",
|
||||
"noValidTimeSelected": "Interval de temps invalide"
|
||||
"noVaildTimeSelected": "La plage horaire sélectionnée n'est pas valide."
|
||||
},
|
||||
"success": "Exportation démarrée avec succès. Consultez le fichier sur la page des exportations.",
|
||||
"view": "Vue",
|
||||
@@ -89,9 +88,7 @@
|
||||
"export": "Exporter",
|
||||
"fromTimeline": {
|
||||
"saveExport": "Enregistrer l'exportation",
|
||||
"previewExport": "Aperçu de l'exportation",
|
||||
"queueingExport": "Traitement de l'export...",
|
||||
"useThisRange": "Utiliser cet interval"
|
||||
"previewExport": "Aperçu de l'exportation"
|
||||
},
|
||||
"case": {
|
||||
"label": "Dossier",
|
||||
@@ -198,10 +195,6 @@
|
||||
"markAsReviewed": "Marquer comme traité",
|
||||
"deleteNow": "Supprimer maintenant",
|
||||
"markAsUnreviewed": "Marquer comme non traité"
|
||||
},
|
||||
"shareTimestamp": {
|
||||
"label": "Partager cette date",
|
||||
"title": "Partager cette date"
|
||||
}
|
||||
},
|
||||
"imagePicker": {
|
||||
|
||||
@@ -8,59 +8,12 @@
|
||||
"sigh": "Suspiro",
|
||||
"singing": "Cantando",
|
||||
"motorcycle": "Motocicleta",
|
||||
"bus": "Autobús",
|
||||
"bus": "Bus",
|
||||
"train": "Tren",
|
||||
"boat": "Barco",
|
||||
"boat": "Bote",
|
||||
"bird": "Paxaro",
|
||||
"cat": "Gato",
|
||||
"bellow": "Bramido",
|
||||
"whoop": "Berro de alegría",
|
||||
"whispering": "Susurro",
|
||||
"laughter": "Risa",
|
||||
"choir": "Coro",
|
||||
"chant": "Canto",
|
||||
"child_singing": "Neno Cantando",
|
||||
"rapping": "Rapeando",
|
||||
"horse": "Cabalo",
|
||||
"pig": "Porco",
|
||||
"goat": "Cabra",
|
||||
"sheep": "Ovella",
|
||||
"wild_animals": "Animais salvaxes",
|
||||
"crow": "Corvo",
|
||||
"dogs": "Cans",
|
||||
"snicker": "Risa abafada",
|
||||
"yodeling": "Iolando",
|
||||
"humming": "Tarareo",
|
||||
"groan": "Xemido",
|
||||
"grunt": "Gruñido",
|
||||
"synthetic_singing": "Canto Sintético",
|
||||
"whistling": "Asubío",
|
||||
"breathing": "Respiración",
|
||||
"wheeze": "Sibilancia",
|
||||
"snoring": "Ronquido",
|
||||
"gasp": "Inspiración brusca",
|
||||
"pant": "Respiración axitada",
|
||||
"snort": "Bufido",
|
||||
"cough": "Tose",
|
||||
"throat_clearing": "Carraspeo",
|
||||
"sneeze": "Espirro",
|
||||
"sniff": "Cheirada",
|
||||
"run": "Correr",
|
||||
"shuffle": "Arrastre de pés",
|
||||
"footsteps": "Pasos",
|
||||
"hands": "Mans",
|
||||
"dog": "Can",
|
||||
"fart": "Peido",
|
||||
"applause": "Aplauso",
|
||||
"chatter": "Parloteo",
|
||||
"crowd": "Multitude",
|
||||
"children_playing": "Nenos Xogando",
|
||||
"animal": "Animal",
|
||||
"pets": "Mascotas",
|
||||
"bark": "Ladrido",
|
||||
"yip": "Gañido",
|
||||
"howl": "Ouveo",
|
||||
"clapping": "Aplausos",
|
||||
"heartbeat": "Latexo do corazón",
|
||||
"heart_murmur": "Sopro cardíaco"
|
||||
"bellow": "Abaixo",
|
||||
"whoop": "Ei carballeira",
|
||||
"whispering": "Murmurando"
|
||||
}
|
||||
|
||||
@@ -10,8 +10,5 @@
|
||||
"untilRestart": "Ata o reinicio",
|
||||
"ago": "Fai {{timeAgo}}"
|
||||
},
|
||||
"readTheDocumentation": "Ler a documentación",
|
||||
"button": {
|
||||
"save": "Gardar"
|
||||
}
|
||||
"readTheDocumentation": "Ler a documentación"
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
"bicycle": "Bicicleta",
|
||||
"airplane": "Avión",
|
||||
"motorcycle": "Motocicleta",
|
||||
"bus": "Autobús",
|
||||
"bus": "Bus",
|
||||
"train": "Tren",
|
||||
"boat": "Barco",
|
||||
"boat": "Bote",
|
||||
"traffic_light": "Luces de tráfico",
|
||||
"fire_hydrant": "Boca de incendio",
|
||||
"street_sign": "Sinal de tráfico",
|
||||
@@ -14,11 +14,5 @@
|
||||
"bench": "Banco",
|
||||
"bird": "Paxaro",
|
||||
"cat": "Gato",
|
||||
"car": "Coche",
|
||||
"horse": "Cabalo",
|
||||
"goat": "Cabra",
|
||||
"sheep": "Ovella",
|
||||
"dog": "Can",
|
||||
"animal": "Animal",
|
||||
"bark": "Ladrido"
|
||||
"car": "Coche"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"description": {
|
||||
"addFace": "Engade unha nova colección á Biblioteca de rostros subindo a túa primeira imaxe.",
|
||||
"addFace": "Navegar para engadir unha nova colección á Libraría de Caras.",
|
||||
"placeholder": "Introduce un nome para esta colección",
|
||||
"invalidName": "Nome non válido. Os nomes só poden incluír letras, números, espazos, apóstrofes, guións baixos e guións."
|
||||
},
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"search": "Pesquisar",
|
||||
"savedSearches": "Pesquisas gardadas",
|
||||
"button": {
|
||||
"save": "Gardar procura",
|
||||
"save": "Gardar pesquisa",
|
||||
"filterActive": "Filtros activos",
|
||||
"clear": "Borrar pesquisa"
|
||||
},
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"default": "Preferencias - Frigate",
|
||||
"authentication": "Configuracións de Autenticación - Frigate",
|
||||
"camera": "Configuracións da Cámara - Frigate",
|
||||
"general": "Configuracións UI - Frigate",
|
||||
"general": "Configuracións xerais - Frigate",
|
||||
"notifications": "Configuración de Notificacións - Frigate",
|
||||
"enrichments": "Configuración complementarias - Frigate",
|
||||
"masksAndZones": "Editor de máscaras e zonas - Frigate"
|
||||
|
||||
@@ -433,22 +433,5 @@
|
||||
"trickle": "Csörgedezés",
|
||||
"gush": "Folyás",
|
||||
"stir": "Kavarás",
|
||||
"thump": "Puffanás",
|
||||
"arrow": "Nyíl",
|
||||
"bouncing": "Pattog",
|
||||
"vibration": "Vibrálás",
|
||||
"inside": "Belül",
|
||||
"outside": "Kívül",
|
||||
"mains_hum": "Hálózati zaj",
|
||||
"distortion": "Torzulás",
|
||||
"throbbing": "Lüktetés",
|
||||
"flap": "Csapkodás",
|
||||
"scratch": "Kapar",
|
||||
"scrape": "Karcolás",
|
||||
"rub": "Dörzsölés",
|
||||
"roll": "Gördül",
|
||||
"crushing": "Összenyom",
|
||||
"crumpling": "Gyűrődés",
|
||||
"beep": "Sípolás",
|
||||
"clang": "Csengés"
|
||||
"thump": "Puffanás"
|
||||
}
|
||||
|
||||
@@ -24,9 +24,6 @@
|
||||
},
|
||||
"state": {
|
||||
"submitted": "Terkirim"
|
||||
},
|
||||
"toast": {
|
||||
"error": "Gagal submit ke Frigate+. Harap periksa koneksi jaringan Anda dan coba lagi."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -60,8 +57,7 @@
|
||||
"view": "Melihat",
|
||||
"batchSuccess_other": "{{count}} Ekspor dimulai. Membuka kasusnya sekarang.",
|
||||
"batchPartial": "Ekspor berhasil dimulai sebanyak {{successful}} dari total {{total}} ekspor. Kamera yang gagal: {{failedCameras}}",
|
||||
"batchFailed": "Gagal memulai ekspor sebanyak {{total}}. Kamera yang gagal: {{failedCameras}}",
|
||||
"batchQueuedPartial": "Antrian ekspor berhasil sebanyak {{successful}} dari total {{total}} ekspor. Kamera yang gagal: {{failedCameras}}"
|
||||
"batchFailed": "Gagal memulai ekspor sebanyak {{total}}. Kamera yang gagal: {{failedCameras}}"
|
||||
},
|
||||
"case": {
|
||||
"newCaseOption": "Membuat Kasus Baru",
|
||||
@@ -91,9 +87,7 @@
|
||||
"selectGroup": "Pilih grup",
|
||||
"noMatchingCameras": "Tidak ada kamera yang sesuai dengan pencarian Anda",
|
||||
"selectedCount": "{{terpilih}} / {{total}} terpilih",
|
||||
"namePlaceholder": "Nama dasar opsional untuk ekspor ini",
|
||||
"searchOrSelectGroup": "Cari, atau pilih grup kamera...",
|
||||
"selectAll": "Pilih semua kamera"
|
||||
"namePlaceholder": "Nama dasar opsional untuk ekspor ini"
|
||||
},
|
||||
"multi": {
|
||||
"title_other": "Ekspor {{count}} Ulasan",
|
||||
|
||||
@@ -67,10 +67,7 @@
|
||||
"desc": "このオプションは、ライブストリームに色のアーティファクトが表示され、画像右側に斜めの線が出る場合にのみ有効にしてください。"
|
||||
}
|
||||
}
|
||||
},
|
||||
"showAll": "全てのカメラグループを表示",
|
||||
"showLess": "表示を縮小",
|
||||
"editGroups": "カメラグループを編集"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"options": {
|
||||
|
||||
@@ -24,9 +24,6 @@
|
||||
},
|
||||
"state": {
|
||||
"submitted": "送信済み"
|
||||
},
|
||||
"toast": {
|
||||
"error": "Frigate+への送信に失敗しました。ネットワーク接続を確認して、もう一度お試しください。"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -59,8 +56,7 @@
|
||||
"error": {
|
||||
"failed": "エクスポートキューの開始に失敗しました: {{error}}",
|
||||
"endTimeMustAfterStartTime": "終了時間は開始時間より後である必要があります",
|
||||
"noVaildTimeSelected": "有効な時間範囲が選択されていません",
|
||||
"noValidTimeSelected": "有効な時間範囲が選択されていません"
|
||||
"noVaildTimeSelected": "有効な時間範囲が選択されていません"
|
||||
},
|
||||
"view": "表示",
|
||||
"queued": "エクスポートがキューに追加されました。進捗状況はエクスポートページで確認できます。",
|
||||
@@ -89,14 +85,7 @@
|
||||
"detectionCount_other": "{{count}} 追跡対象",
|
||||
"nameLabel": "エクスポート名",
|
||||
"namePlaceholder": "これらのエクスポート用オプションのベース名",
|
||||
"exportButton_other": "{{count}} 台のカメラをエクスポート",
|
||||
"searchOrSelectGroup": "検索するか、カメラグループを選択してください...",
|
||||
"selectAll": "全てのカメラを選択",
|
||||
"clearSelection": "選択を解除",
|
||||
"selectWithActivity": "追跡対象のあるカメラ",
|
||||
"selectGroup": "グループを選択",
|
||||
"noMatchingCameras": "検索条件に一致するカメラはありません",
|
||||
"selectedCount": "{{selected}} / {{total}} 個が選択されました"
|
||||
"exportButton_other": "{{count}} 台のカメラをエクスポート"
|
||||
},
|
||||
"case": {
|
||||
"newCaseOption": "新しいケースを作成",
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
},
|
||||
"listen": {
|
||||
"label": "リスニングタイプ",
|
||||
"description": "検出対象の音声イベントの種類の一覧(例:吠え声、火災報知器、会話、叫び声)。"
|
||||
"description": "検知対象の音声イベントの種類一覧(例:吠え声、火災報知器、悲鳴、会話、叫び声)。"
|
||||
},
|
||||
"enabled_in_config": {
|
||||
"label": "元の音声状態",
|
||||
@@ -192,11 +192,11 @@
|
||||
"description": "このカメラの通知を有効化・制御する設定。"
|
||||
},
|
||||
"ffmpeg": {
|
||||
"label": "ストリーム(FFmpeg)",
|
||||
"description": "カメラストリームの入力およびFFmpegのオプション(バイナリパス、引数、ハードウェアアクセラレーション、ロールごとの出力引数など)。",
|
||||
"label": "FFmpeg",
|
||||
"description": "FFmpeg の設定。バイナリパス、引数、ハードウェアアクセラレーション、ロール別の出力引数を含みます。",
|
||||
"path": {
|
||||
"label": "FFmpeg パス",
|
||||
"description": "使用する FFmpeg バイナリへのパス、またはバージョンのエイリアス(「7.0」または「8.0」)。"
|
||||
"description": "使用する FFmpeg バイナリのパス、またはバージョンエイリアス(「5.0」または「7.0」)。"
|
||||
},
|
||||
"global_args": {
|
||||
"label": "FFmpeg グローバル引数",
|
||||
@@ -512,9 +512,6 @@
|
||||
"max_concurrent": {
|
||||
"label": "同時エクスポート数の上限",
|
||||
"description": "同時に処理するエクスポートジョブの最大数。"
|
||||
},
|
||||
"chapters": {
|
||||
"label": "エクスポートされた録画に埋め込むチャプターメタデータ"
|
||||
}
|
||||
},
|
||||
"preview": {
|
||||
@@ -869,10 +866,6 @@
|
||||
"dashboard": {
|
||||
"label": "UI に表示",
|
||||
"description": "このカメラを Frigate UI 全体に表示するかを切り替えます。無効化した場合、再表示するには設定ファイルを手動編集する必要があります。"
|
||||
},
|
||||
"review": {
|
||||
"label": "再生画面に表示",
|
||||
"description": "このカメラを再生画面(再生ページおよびそのカメラフィルター、モーション再生、履歴表示)に表示するかどうかを切り替えます。"
|
||||
}
|
||||
},
|
||||
"webui_url": {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user