Compare commits

...

3 Commits

Author SHA1 Message Date
Nicolas Mowen
212784b68e
implement RKNN downloads for yolov9 and yolox models (#17875)
* Add other rockchip download models

* Specify newer release version

* Specify newer release version

* Update docs for rknn downloads

* Update hardware docs
2025-04-23 12:22:23 -05:00
Josh Hawkins
b061d083ba
Misc fixes (#17871)
* fix check for snapshot score

for manual events, snapScore is 0, so "0" gets displayed instead of a condition being evaluated.

* fix ongoing events from being returned for all review queries

The existing condition will include any record with a null end_time regardless of when it started, as long as the start_time is greater than the after param. With this fix, both the start time needs to be within the specified range, and for events that have already ended, their end time must be before the before param

* Base alert toggles on width not device class

---------

Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com>
2025-04-23 07:06:31 -06:00
Josh Hawkins
44d44f87ac
i18n tweaks (#17865)
* Add plural variant to i18n selected key

Weblate needs both keys to populate other languages

* move smart capitalization logic into language provider

* fix key
2025-04-23 06:19:20 -06:00
10 changed files with 81 additions and 91 deletions

View File

@ -844,14 +844,14 @@ detectors: # required
The inference time was determined on a rk3588 with 3 NPU cores. The inference time was determined on a rk3588 with 3 NPU cores.
| Model | Size in mb | Inference time in ms | | Model | Size in mb | Inference time in ms |
| ------------------- | ---------- | -------------------- | | --------------------- | ---------- | -------------------- |
| deci-fp16-yolonas_s | 24 | 25 | | deci-fp16-yolonas_s | 24 | 25 |
| deci-fp16-yolonas_m | 62 | 35 | | deci-fp16-yolonas_m | 62 | 35 |
| deci-fp16-yolonas_l | 81 | 45 | | deci-fp16-yolonas_l | 81 | 45 |
| yolov9_tiny | 8 | 35 | | frigate-fp16-yolov9-t | 6 | 35 |
| yolox_nano | 3 | 16 | | rock-i8-yolox_nano | 3 | 14 |
| yolox_tiny | 6 | 20 | | rock-i8_yolox_tiny | 6 | 18 |
- All models are automatically downloaded and stored in the folder `config/model_cache/rknn_cache`. After upgrading Frigate, you should remove older models to free up space. - All models are automatically downloaded and stored in the folder `config/model_cache/rknn_cache`. After upgrading Frigate, you should remove older models to free up space.
- You can also provide your own `.rknn` model. You should not save your own models in the `rknn_cache` folder, store them directly in the `model_cache` folder or another subfolder. To convert a model to `.rknn` format see the `rknn-toolkit2` (requires a x86 machine). Note, that there is only post-processing for the supported models. - You can also provide your own `.rknn` model. You should not save your own models in the `rknn_cache` folder, store them directly in the `model_cache` folder or another subfolder. To convert a model to `.rknn` format see the `rknn-toolkit2` (requires a x86 machine). Note, that there is only post-processing for the supported models.
@ -887,10 +887,13 @@ The pre-trained YOLO-NAS weights from DeciAI are subject to their license and ca
model: # required model: # required
# name of model (will be automatically downloaded) or path to your own .rknn model file # name of model (will be automatically downloaded) or path to your own .rknn model file
# possible values are: # possible values are:
# - yolov9-t # - frigate-fp16-yolov9-t
# - yolov9-s # - frigate-fp16-yolov9-s
# - frigate-fp16-yolov9-m
# - frigate-fp16-yolov9-c
# - frigate-fp16-yolov9-e
# your yolo_model.rknn # your yolo_model.rknn
path: /config/model_cache/rknn_cache/yolov9-t.rknn path: frigate-fp16-yolov9-t
model_type: yolo-generic model_type: yolo-generic
width: 320 width: 320
height: 320 height: 320
@ -905,10 +908,12 @@ model: # required
model: # required model: # required
# name of model (will be automatically downloaded) or path to your own .rknn model file # name of model (will be automatically downloaded) or path to your own .rknn model file
# possible values are: # possible values are:
# - yolox_nano # - rock-i8-yolox_nano
# - yolox_tiny # - rock-i8-yolox_tiny
# - rock-fp16-yolox_nano
# - rock-fp16-yolox_tiny
# your yolox_model.rknn # your yolox_model.rknn
path: yolox_tiny path: rock-i8-yolox_nano
model_type: yolox model_type: yolox
width: 416 width: 416
height: 416 height: 416

View File

@ -168,7 +168,7 @@ Frigate supports hardware video processing on all Rockchip boards. However, hard
| Name | YOLOv9 Inference Time | YOLO-NAS Inference Time | YOLOx Inference Time | | Name | YOLOv9 Inference Time | YOLO-NAS Inference Time | YOLOx Inference Time |
| --------------- | --------------------- | --------------------------- | ------------------------- | | --------------- | --------------------- | --------------------------- | ------------------------- |
| rk3588 3 cores | ~ 35 ms | small: ~ 20 ms med: ~ 30 ms | nano: 18 ms tiny: 20 ms | | rk3588 3 cores | tiny: ~ 35 ms | small: ~ 20 ms med: ~ 30 ms | nano: 14 ms tiny: 18 ms |
| rk3566 1 core | | small: ~ 96 ms | | | rk3566 1 core | | small: ~ 96 ms | |

View File

@ -58,13 +58,9 @@ async def review(
) )
clauses = [ clauses = [
( (ReviewSegment.start_time > after)
(ReviewSegment.start_time > after) & (ReviewSegment.start_time < before)
& ( & ((ReviewSegment.end_time.is_null(True)) | (ReviewSegment.end_time < before))
(ReviewSegment.end_time.is_null(True))
| (ReviewSegment.end_time < before)
)
)
] ]
if cameras != "all": if cameras != "all":

View File

@ -19,7 +19,11 @@ DETECTOR_KEY = "rknn"
supported_socs = ["rk3562", "rk3566", "rk3568", "rk3576", "rk3588"] supported_socs = ["rk3562", "rk3566", "rk3568", "rk3576", "rk3588"]
supported_models = {ModelTypeEnum.yolonas: "^deci-fp16-yolonas_[sml]$"} supported_models = {
ModelTypeEnum.yologeneric: "^frigate-fp16-yolov9-[cemst]$",
ModelTypeEnum.yolonas: "^deci-fp16-yolonas_[sml]$",
ModelTypeEnum.yolox: "^rock-(fp16|i8)-yolox_(nano|tiny)$",
}
model_cache_dir = os.path.join(MODEL_CACHE_DIR, "rknn_cache/") model_cache_dir = os.path.join(MODEL_CACHE_DIR, "rknn_cache/")
@ -115,7 +119,7 @@ class Rknn(DetectionApi):
model_props["model_type"] = model_type model_props["model_type"] = model_type
if model_matched: if model_matched:
model_props["filename"] = model_path + f"-{soc}-v2.3.0-1.rknn" model_props["filename"] = model_path + f"-{soc}-v2.3.2-1.rknn"
model_props["path"] = model_cache_dir + model_props["filename"] model_props["path"] = model_cache_dir + model_props["filename"]
@ -136,7 +140,7 @@ class Rknn(DetectionApi):
os.mkdir(model_cache_dir) os.mkdir(model_cache_dir)
urllib.request.urlretrieve( urllib.request.urlretrieve(
f"https://github.com/MarcA711/rknn-models/releases/download/v2.3.0/{filename}", f"https://github.com/MarcA711/rknn-models/releases/download/v2.3.2/{filename}",
model_cache_dir + filename, model_cache_dir + filename,
) )

View File

@ -31,6 +31,7 @@
"label": "View new review items", "label": "View new review items",
"button": "New Items To Review" "button": "New Items To Review"
}, },
"selected": "{{count}} selected", "selected_one": "{{count}} selected",
"selected_other": "{{count}} selected",
"camera": "Camera" "camera": "Camera"
} }

View File

@ -6,13 +6,12 @@ import Sidebar from "@/components/navigation/Sidebar";
import { isDesktop, isMobile } from "react-device-detect"; import { isDesktop, isMobile } from "react-device-detect";
import Statusbar from "./components/Statusbar"; import Statusbar from "./components/Statusbar";
import Bottombar from "./components/navigation/Bottombar"; import Bottombar from "./components/navigation/Bottombar";
import React, { Suspense, lazy } from "react"; import { Suspense, lazy } from "react";
import { Redirect } from "./components/navigation/Redirect"; import { Redirect } from "./components/navigation/Redirect";
import { cn } from "./lib/utils"; import { cn } from "./lib/utils";
import { isPWA } from "./utils/isPWA"; import { isPWA } from "./utils/isPWA";
import ProtectedRoute from "@/components/auth/ProtectedRoute"; import ProtectedRoute from "@/components/auth/ProtectedRoute";
import { AuthProvider } from "@/context/auth-context"; import { AuthProvider } from "@/context/auth-context";
import { useTranslation } from "react-i18next";
const Live = lazy(() => import("@/pages/Live")); const Live = lazy(() => import("@/pages/Live"));
const Events = lazy(() => import("@/pages/Events")); const Events = lazy(() => import("@/pages/Events"));
@ -27,13 +26,6 @@ const Logs = lazy(() => import("@/pages/Logs"));
const AccessDenied = lazy(() => import("@/pages/AccessDenied")); const AccessDenied = lazy(() => import("@/pages/AccessDenied"));
function App() { function App() {
const { i18n } = useTranslation();
// Set the lang attribute on the html element when language changes
React.useEffect(() => {
document.documentElement.lang = i18n.language;
}, [i18n.language]);
return ( return (
<Providers> <Providers>
<AuthProvider> <AuthProvider>

View File

@ -792,7 +792,7 @@ function ObjectDetailsTab({
{topScore}%{subLabelScore && ` (${subLabelScore}%)`} {topScore}%{subLabelScore && ` (${subLabelScore}%)`}
</div> </div>
</div> </div>
{snapScore && ( {snapScore != undefined && (
<div className="flex flex-col gap-1.5"> <div className="flex flex-col gap-1.5">
<div className="text-sm text-primary/40"> <div className="text-sm text-primary/40">
<div className="flex flex-row items-center gap-1"> <div className="flex flex-row items-center gap-1">

View File

@ -45,6 +45,9 @@ export function LanguageProvider({
}, []); }, []);
useEffect(() => { useEffect(() => {
// set document lang for smart capitalization
document.documentElement.lang = language;
if (language === systemLanguage) return; if (language === systemLanguage) return;
i18next.changeLanguage(language); i18next.changeLanguage(language);
}, [language, systemLanguage]); }, [language, systemLanguage]);

View File

@ -279,32 +279,29 @@ export default function EventView({
value="alert" value="alert"
aria-label={t("alerts")} aria-label={t("alerts")}
> >
{isMobileOnly ? ( <div
<div className={cn(
className={cn( "flex size-6 items-center justify-center rounded text-severity_alert sm:hidden",
"flex size-6 items-center justify-center rounded text-severity_alert", severityToggle == "alert" ? "font-semibold" : "font-medium",
severityToggle == "alert" ? "font-semibold" : "font-medium", )}
)} >
> {reviewCounts.alert > -1 ? (
reviewCounts.alert
) : (
<ActivityIndicator className="size-4" />
)}
</div>
<div className="hidden items-center sm:flex">
<MdCircle className="size-2 text-severity_alert md:mr-[10px]" />
<div className="hidden md:flex md:flex-row md:items-center">
{t("alerts")}
{reviewCounts.alert > -1 ? ( {reviewCounts.alert > -1 ? (
reviewCounts.alert `${reviewCounts.alert}`
) : ( ) : (
<ActivityIndicator className="size-4" /> <ActivityIndicator className="ml-2 size-4" />
)} )}
</div> </div>
) : ( </div>
<>
<MdCircle className="size-2 text-severity_alert md:mr-[10px]" />
<div className="hidden md:flex md:flex-row md:items-center">
{t("alerts")}
{reviewCounts.alert > -1 ? (
`${reviewCounts.alert}`
) : (
<ActivityIndicator className="ml-2 size-4" />
)}
</div>
</>
)}
</ToggleGroupItem> </ToggleGroupItem>
<ToggleGroupItem <ToggleGroupItem
className={cn( className={cn(
@ -313,34 +310,29 @@ export default function EventView({
value="detection" value="detection"
aria-label={t("detections")} aria-label={t("detections")}
> >
{isMobileOnly ? ( <div
<div className={cn(
className={cn( "flex size-6 items-center justify-center rounded text-severity_detection sm:hidden",
"flex size-6 items-center justify-center rounded text-severity_detection", severityToggle == "detection" ? "font-semibold" : "font-medium",
severityToggle == "detection" )}
? "font-semibold" >
: "font-medium", {reviewCounts.detection > -1 ? (
)} reviewCounts.detection
> ) : (
<ActivityIndicator className="size-4" />
)}
</div>
<div className="hidden items-center sm:flex">
<MdCircle className="size-2 text-severity_detection md:mr-[10px]" />
<div className="hidden md:flex md:flex-row md:items-center">
{t("detections")}
{reviewCounts.detection > -1 ? ( {reviewCounts.detection > -1 ? (
reviewCounts.detection `${reviewCounts.detection}`
) : ( ) : (
<ActivityIndicator className="size-4" /> <ActivityIndicator className="ml-2 size-4" />
)} )}
</div> </div>
) : ( </div>
<>
<MdCircle className="size-2 text-severity_detection md:mr-[10px]" />
<div className="hidden md:flex md:flex-row md:items-center">
{t("detections")}
{reviewCounts.detection > -1 ? (
`${reviewCounts.detection}`
) : (
<ActivityIndicator className="ml-2 size-4" />
)}
</div>
</>
)}
</ToggleGroupItem> </ToggleGroupItem>
<ToggleGroupItem <ToggleGroupItem
className={cn( className={cn(
@ -350,14 +342,11 @@ export default function EventView({
value="significant_motion" value="significant_motion"
aria-label={t("motion.label")} aria-label={t("motion.label")}
> >
{isMobileOnly ? ( <GiSoundWaves className="size-6 rotate-90 text-severity_significant_motion sm:hidden" />
<GiSoundWaves className="size-6 rotate-90 text-severity_significant_motion" /> <div className="hidden items-center sm:flex">
) : ( <MdCircle className="size-2 text-severity_significant_motion md:mr-[10px]" />
<> <div className="hidden md:block">{t("motion.label")}</div>
<MdCircle className="size-2 text-severity_significant_motion md:mr-[10px]" /> </div>
<div className="hidden md:block">{t("motion.label")}</div>
</>
)}
</ToggleGroupItem> </ToggleGroupItem>
</ToggleGroup> </ToggleGroup>

View File

@ -1758,7 +1758,7 @@ function FrigateCameraFeatures({
isRecording && "animate-pulse bg-red-500 hover:bg-red-600", isRecording && "animate-pulse bg-red-500 hover:bg-red-600",
)} )}
> >
{t("manualRecording." + isRecording ? "end" : "start")} {t("manualRecording." + (isRecording ? "end" : "start"))}
</Button> </Button>
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
{t("manualRecording.tips")} {t("manualRecording.tips")}