Compare commits

...

5 Commits

Author SHA1 Message Date
Josh Hawkins
35f956438e
Merge 4fcf467507 into cfeb86646f 2026-01-17 15:49:58 +13:00
Josh Hawkins
4fcf467507 add retry params to gemini 2026-01-16 10:08:11 -06:00
Josh Hawkins
dcff06906c lpr docs tweaks 2026-01-16 06:57:44 -06:00
Josh Hawkins
f428a64948 update copilot instructions 2026-01-15 20:42:24 -06:00
Josh Hawkins
32f6114573 misc triggers tweaks
i18n fixes
fix toaster color
fix clicking on labels selecting incorrect checkbox
2026-01-15 20:41:39 -06:00
7 changed files with 37 additions and 18 deletions

View File

@ -1,2 +1,3 @@
Never write strings in the frontend directly, always write to and reference the relevant translations file. - For Frigate NVR, never write strings in the frontend directly. Since the project uses `react-i18next`, use `t()` and write the English string in the relevant translations file in `web/public/locales/en`.
Always conform new and refactored code to the existing coding style in the project. - Always conform new and refactored code to the existing coding style in the project.
- Always have a way to test your work and confirm your changes. When running backend tests, use `python3 -u -m unittest`.

View File

@ -68,8 +68,8 @@ Fine-tune the LPR feature using these optional parameters at the global level of
- Default: `1000` pixels. Note: this is intentionally set very low as it is an _area_ measurement (length x width). For reference, 1000 pixels represents a ~32x32 pixel square in your camera image. - Default: `1000` pixels. Note: this is intentionally set very low as it is an _area_ measurement (length x width). For reference, 1000 pixels represents a ~32x32 pixel square in your camera image.
- Depending on the resolution of your camera's `detect` stream, you can increase this value to ignore small or distant plates. - Depending on the resolution of your camera's `detect` stream, you can increase this value to ignore small or distant plates.
- **`device`**: Device to use to run license plate detection _and_ recognition models. - **`device`**: Device to use to run license plate detection _and_ recognition models.
- Default: `CPU` - Default: `None`
- This can be `CPU`, `GPU`, or the GPU's device number. For users without a model that detects license plates natively, using a GPU may increase performance of the YOLOv9 license plate detector model. See the [Hardware Accelerated Enrichments](/configuration/hardware_acceleration_enrichments.md) documentation. However, for users who run a model that detects `license_plate` natively, there is little to no performance gain reported with running LPR on GPU compared to the CPU. - This is auto-selected by Frigate and can be `CPU`, `GPU`, or the GPU's device number. For users without a model that detects license plates natively, using a GPU may increase performance of the YOLOv9 license plate detector model. See the [Hardware Accelerated Enrichments](/configuration/hardware_acceleration_enrichments.md) documentation. However, for users who run a model that detects `license_plate` natively, there is little to no performance gain reported with running LPR on GPU compared to the CPU.
- **`model_size`**: The size of the model used to identify regions of text on plates. - **`model_size`**: The size of the model used to identify regions of text on plates.
- Default: `small` - Default: `small`
- This can be `small` or `large`. - This can be `small` or `large`.
@ -432,6 +432,6 @@ If you are using a model that natively detects `license_plate`, add an _object m
If you are not using a model that natively detects `license_plate` or you are using dedicated LPR camera mode, only a _motion mask_ over your text is required. If you are not using a model that natively detects `license_plate` or you are using dedicated LPR camera mode, only a _motion mask_ over your text is required.
### I see "Error running ... model" in my logs. How can I fix this? ### I see "Error running ... model" in my logs, or my inference time is very high. How can I fix this?
This usually happens when your GPU is unable to compile or use one of the LPR models. Set your `device` to `CPU` and try again. GPU acceleration only provides a slight performance increase, and the models are lightweight enough to run without issue on most CPUs. This usually happens when your GPU is unable to compile or use one of the LPR models. Set your `device` to `CPU` and try again. GPU acceleration only provides a slight performance increase, and the models are lightweight enough to run without issue on most CPUs.

View File

@ -24,6 +24,14 @@ class GeminiClient(GenAIClient):
http_options_dict = { http_options_dict = {
"api_version": "v1", "api_version": "v1",
"timeout": int(self.timeout * 1000), # requires milliseconds "timeout": int(self.timeout * 1000), # requires milliseconds
"retry_options": types.HttpRetryOptions(
attempts=3,
initial_delay=1.0,
max_delay=60.0,
exp_base=2.0,
jitter=1.0,
http_status_codes=[429, 500, 502, 503, 504],
),
} }
if isinstance(self.genai_config.provider_options, dict): if isinstance(self.genai_config.provider_options, dict):

View File

@ -3,6 +3,7 @@
"untilForTime": "Until {{time}}", "untilForTime": "Until {{time}}",
"untilForRestart": "Until Frigate restarts.", "untilForRestart": "Until Frigate restarts.",
"untilRestart": "Until restart", "untilRestart": "Until restart",
"never": "Never",
"ago": "{{timeAgo}} ago", "ago": "{{timeAgo}} ago",
"justNow": "Just now", "justNow": "Just now",
"today": "Today", "today": "Today",

View File

@ -268,7 +268,7 @@ export default function CreateTriggerDialog({
<FormItem className="flex flex-row items-center justify-between"> <FormItem className="flex flex-row items-center justify-between">
<div className="space-y-0.5"> <div className="space-y-0.5">
<FormLabel className="text-base"> <FormLabel className="text-base">
{t("enabled", { ns: "common" })} {t("button.enabled", { ns: "common" })}
</FormLabel> </FormLabel>
<div className="text-sm text-muted-foreground"> <div className="text-sm text-muted-foreground">
{t("triggers.dialog.form.enabled.description")} {t("triggers.dialog.form.enabled.description")}
@ -394,7 +394,10 @@ export default function CreateTriggerDialog({
</FormLabel> </FormLabel>
<div className="space-y-2"> <div className="space-y-2">
{availableActions.map((action) => ( {availableActions.map((action) => (
<div key={action} className="flex items-center space-x-2"> <label
key={action}
className="flex cursor-pointer items-center space-x-2"
>
<FormControl> <FormControl>
<Checkbox <Checkbox
checked={form checked={form
@ -416,10 +419,10 @@ export default function CreateTriggerDialog({
}} }}
/> />
</FormControl> </FormControl>
<FormLabel className="text-sm font-normal"> <span className="text-sm font-normal">
{t(`triggers.actions.${action}`)} {t(`triggers.actions.${action}`)}
</FormLabel> </span>
</div> </label>
))} ))}
</div> </div>
<FormDescription> <FormDescription>

View File

@ -142,7 +142,10 @@ export default function Step3ThresholdAndActions({
<FormLabel>{t("triggers.dialog.form.actions.title")}</FormLabel> <FormLabel>{t("triggers.dialog.form.actions.title")}</FormLabel>
<div className="space-y-2"> <div className="space-y-2">
{availableActions.map((action) => ( {availableActions.map((action) => (
<div key={action} className="flex items-center space-x-2"> <label
key={action}
className="flex cursor-pointer items-center space-x-2"
>
<FormControl> <FormControl>
<Checkbox <Checkbox
checked={form checked={form
@ -164,10 +167,10 @@ export default function Step3ThresholdAndActions({
}} }}
/> />
</FormControl> </FormControl>
<FormLabel className="text-sm font-normal"> <span className="text-sm font-normal">
{t(`triggers.actions.${action}`)} {t(`triggers.actions.${action}`)}
</FormLabel> </span>
</div> </label>
))} ))}
</div> </div>
<FormDescription> <FormDescription>

View File

@ -1,6 +1,7 @@
import { useCallback, useEffect, useMemo, useState } from "react"; import { useCallback, useEffect, useMemo, useState } from "react";
import { Trans, useTranslation } from "react-i18next"; import { Trans, useTranslation } from "react-i18next";
import { Toaster, toast } from "sonner"; import { toast } from "sonner";
import { Toaster } from "@/components/ui/sonner";
import useSWR from "swr"; import useSWR from "swr";
import axios from "axios"; import axios from "axios";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
@ -598,7 +599,7 @@ export default function TriggerView({
date_style: "medium", date_style: "medium",
}, },
) )
: "Never"} : t("never", { ns: "common" })}
</span> </span>
{trigger_status?.triggers[trigger.name] {trigger_status?.triggers[trigger.name]
?.triggering_event_id && ( ?.triggering_event_id && (
@ -663,7 +664,9 @@ export default function TriggerView({
<TableHeader className="sticky top-0 bg-muted/50"> <TableHeader className="sticky top-0 bg-muted/50">
<TableRow> <TableRow>
<TableHead className="w-4"></TableHead> <TableHead className="w-4"></TableHead>
<TableHead>{t("name", { ns: "common" })}</TableHead> <TableHead>
{t("name", { ns: "triggers.table.name" })}
</TableHead>
<TableHead>{t("triggers.table.type")}</TableHead> <TableHead>{t("triggers.table.type")}</TableHead>
<TableHead> <TableHead>
{t("triggers.table.lastTriggered")} {t("triggers.table.lastTriggered")}
@ -759,7 +762,7 @@ export default function TriggerView({
date_style: "medium", date_style: "medium",
}, },
) )
: "Never"} : t("time.never", { ns: "common" })}
</span> </span>
{trigger_status?.triggers[trigger.name] {trigger_status?.triggers[trigger.name]
?.triggering_event_id && ( ?.triggering_event_id && (