diff --git a/docker/main/requirements-wheels.txt b/docker/main/requirements-wheels.txt index 4ab7e03e6..6f905be4a 100644 --- a/docker/main/requirements-wheels.txt +++ b/docker/main/requirements-wheels.txt @@ -37,9 +37,9 @@ opencv-python-headless == 4.11.0.* opencv-contrib-python == 4.11.0.* scipy == 1.14.* # OpenVino & ONNX -openvino == 2024.4.* -onnxruntime-openvino == 1.20.* ; platform_machine == 'x86_64' -onnxruntime == 1.20.* ; platform_machine == 'aarch64' +openvino == 2025.0.* +onnxruntime-openvino == 1.21.0 ; platform_machine == 'x86_64' +onnxruntime == 1.21.0 ; platform_machine == 'aarch64' # Embeddings transformers == 4.45.* # Generative AI diff --git a/docker/tensorrt/requirements-amd64.txt b/docker/tensorrt/requirements-amd64.txt index 0e003ca3d..795953359 100644 --- a/docker/tensorrt/requirements-amd64.txt +++ b/docker/tensorrt/requirements-amd64.txt @@ -13,5 +13,5 @@ nvidia-cudnn-cu12 == 9.5.0.*; platform_machine == 'x86_64' nvidia-cufft-cu11==10.*; platform_machine == 'x86_64' nvidia-cufft-cu12==11.*; platform_machine == 'x86_64' onnx==1.16.*; platform_machine == 'x86_64' -onnxruntime-gpu==1.20.*; platform_machine == 'x86_64' +onnxruntime-gpu==1.21.0; platform_machine == 'x86_64' protobuf==3.20.3; platform_machine == 'x86_64' diff --git a/docs/docs/configuration/authentication.md b/docs/docs/configuration/authentication.md index 129547d1b..f83659c52 100644 --- a/docs/docs/configuration/authentication.md +++ b/docs/docs/configuration/authentication.md @@ -77,7 +77,7 @@ Changing the secret will invalidate current tokens. Frigate can be configured to leverage features of common upstream authentication proxies such as Authelia, Authentik, oauth2_proxy, or traefik-forward-auth. -If you are leveraging the authentication of an upstream proxy, you likely want to disable Frigate's authentication. Optionally, if communication between the reverse proxy and Frigate is over an untrusted network, you should set an `auth_secret` in the `proxy` config and configure the proxy to send the secret value as a header named `X-Proxy-Secret`. Assuming this is an untrusted network, you will also want to [configure a real TLS certificate](tls.md) to ensure the traffic can't simply be sniffed to steal the secret. +If you are leveraging the authentication of an upstream proxy, you likely want to disable Frigate's authentication as there is no correspondence between users in Frigate's database and users authenticated via the proxy. Optionally, if communication between the reverse proxy and Frigate is over an untrusted network, you should set an `auth_secret` in the `proxy` config and configure the proxy to send the secret value as a header named `X-Proxy-Secret`. Assuming this is an untrusted network, you will also want to [configure a real TLS certificate](tls.md) to ensure the traffic can't simply be sniffed to steal the secret. Here is an example of how to disable Frigate's authentication and also ensure the requests come only from your known proxy. @@ -109,6 +109,14 @@ proxy: Frigate supports both `admin` and `viewer` roles (see below). When using port `8971`, Frigate validates these headers and subsequent requests use the headers `remote-user` and `remote-role` for authorization. +A default role can be provided. Any value in the mapped `role` header will override the default. + +```yaml +proxy: + ... + default_role: viewer +``` + #### Port Considerations **Authenticated Port (8971)** diff --git a/docs/docs/configuration/face_recognition.md b/docs/docs/configuration/face_recognition.md index 928aaef8a..b78995cd2 100644 --- a/docs/docs/configuration/face_recognition.md +++ b/docs/docs/configuration/face_recognition.md @@ -47,7 +47,7 @@ face_recognition: ## Advanced Configuration -Fine-tune face recognition with these optional parameters: +Fine-tune face recognition with these optional parameters at the global level of your config. The only optional parameters that can be set at the camera level are `enabled` and `min_area`. ### Detection diff --git a/docs/docs/configuration/reference.md b/docs/docs/configuration/reference.md index f03c668cd..dbea03678 100644 --- a/docs/docs/configuration/reference.md +++ b/docs/docs/configuration/reference.md @@ -78,16 +78,19 @@ proxy: # Optional: Mapping for headers from upstream proxies. Only used if Frigate's auth # is disabled. # NOTE: Many authentication proxies pass a header downstream with the authenticated - # user name. Not all values are supported. It must be a whitelisted header. + # user name and role. Not all values are supported. It must be a whitelisted header. # See the docs for more info. header_map: user: x-forwarded-user + role: x-forwarded-role # Optional: Url for logging out a user. This sets the location of the logout url in # the UI. logout_url: /api/logout # Optional: Auth secret that is checked against the X-Proxy-Secret header sent from # the proxy. If not set, all requests are trusted regardless of origin. auth_secret: None + # Optional: The default role to use for proxy auth. Must be "admin" or "viewer" + default_role: viewer # Optional: Authentication configuration auth: diff --git a/frigate/api/app.py b/frigate/api/app.py index 8a1310b93..2301d1be1 100644 --- a/frigate/api/app.py +++ b/frigate/api/app.py @@ -74,7 +74,7 @@ def go2rtc_streams(): ) stream_data = r.json() for data in stream_data.values(): - for producer in data.get("producers", []): + for producer in data.get("producers") or []: producer["url"] = clean_camera_user_pass(producer.get("url", "")) return JSONResponse(content=stream_data) diff --git a/frigate/api/auth.py b/frigate/api/auth.py index 7d7c2ba8d..710661be3 100644 --- a/frigate/api/auth.py +++ b/frigate/api/auth.py @@ -261,14 +261,14 @@ def auth(request: Request): role_header = proxy_config.header_map.role role = ( - request.headers.get(role_header, default="viewer") + request.headers.get(role_header, default=proxy_config.default_role) if role_header - else "viewer" + else proxy_config.default_role ) - # if comma-separated with "admin", use "admin", else "viewer" + # if comma-separated with "admin", use "admin", else use default role success_response.headers["remote-role"] = ( - "admin" if role and "admin" in role else "viewer" + "admin" if role and "admin" in role else proxy_config.default_role ) return success_response diff --git a/frigate/config/proxy.py b/frigate/config/proxy.py index df8a665fb..ef1529f9e 100644 --- a/frigate/config/proxy.py +++ b/frigate/config/proxy.py @@ -30,3 +30,6 @@ class ProxyConfig(FrigateBaseModel): default=None, title="Secret value for proxy authentication.", ) + default_role: Optional[str] = Field( + default="viewer", title="Default role for proxy users." + ) diff --git a/frigate/ptz/onvif.py b/frigate/ptz/onvif.py index eec57dbac..8b133469c 100644 --- a/frigate/ptz/onvif.py +++ b/frigate/ptz/onvif.py @@ -74,7 +74,7 @@ class OnvifController: "features": [], "presets": {}, } - except ONVIFError as e: + except (Fault, ONVIFError, TransportError, Exception) as e: logger.error(f"Failed to create ONVIF camera instance for {cam_name}: {e}") # track initial failures self.failed_cams[cam_name] = { @@ -100,7 +100,7 @@ class OnvifController: # this will fire an exception if camera is not a ptz capabilities = onvif.get_definition("ptz") logger.debug(f"Onvif capabilities for {camera_name}: {capabilities}") - except (ONVIFError, Fault, TransportError) as e: + except (Fault, ONVIFError, TransportError, Exception) as e: logger.error( f"Unable to get Onvif capabilities for camera: {camera_name}: {e}" ) @@ -109,7 +109,7 @@ class OnvifController: try: profiles = await media.GetProfiles() logger.debug(f"Onvif profiles for {camera_name}: {profiles}") - except (ONVIFError, Fault, TransportError) as e: + except (Fault, ONVIFError, TransportError, Exception) as e: logger.error( f"Unable to get Onvif media profiles for camera: {camera_name}: {e}" ) @@ -263,7 +263,7 @@ class OnvifController: # setup existing presets try: presets: list[dict] = await ptz.GetPresets({"ProfileToken": profile.token}) - except ONVIFError as e: + except (Fault, ONVIFError, TransportError, Exception) as e: logger.warning(f"Unable to get presets from camera: {camera_name}: {e}") presets = [] @@ -392,7 +392,7 @@ class OnvifController: try: asyncio.run(self.cams[camera_name]["ptz"].ContinuousMove(move_request)) - except ONVIFError as e: + except (Fault, ONVIFError, TransportError, Exception) as e: logger.warning(f"Onvif sending move request to {camera_name} failed: {e}") def _move_relative(self, camera_name: str, pan, tilt, zoom, speed) -> None: @@ -593,7 +593,7 @@ class OnvifController: self._zoom(camera_name, command) else: self._move(camera_name, command) - except ONVIFError as e: + except (Fault, ONVIFError, TransportError, Exception) as e: logger.error(f"Unable to handle onvif command: {e}") async def get_camera_info(self, camera_name: str) -> dict[str, any]: diff --git a/frigate/util/model.py b/frigate/util/model.py index 2bb64357d..5528c15ca 100644 --- a/frigate/util/model.py +++ b/frigate/util/model.py @@ -340,7 +340,6 @@ def get_ort_providers( providers.append(provider) options.append( { - "arena_extend_strategy": "kSameAsRequested", "cache_dir": os.path.join(MODEL_CACHE_DIR, "openvino/ort"), "device_type": device, } diff --git a/web/public/locales/en/views/events.json b/web/public/locales/en/views/events.json index 8fd64f14e..98bc7c422 100644 --- a/web/public/locales/en/views/events.json +++ b/web/public/locales/en/views/events.json @@ -33,5 +33,6 @@ }, "selected_one": "{{count}} selected", "selected_other": "{{count}} selected", - "camera": "Camera" + "camera": "Camera", + "detected": "detected" } diff --git a/web/public/locales/en/views/explore.json b/web/public/locales/en/views/explore.json index 76baa7888..e8a5153ee 100644 --- a/web/public/locales/en/views/explore.json +++ b/web/public/locales/en/views/explore.json @@ -190,6 +190,7 @@ "trackedObjectsCount_one": "{{count}} tracked object ", "trackedObjectsCount_other": "{{count}} tracked objects ", "searchResult": { + "tooltip": "Matched {{type}} at {{confidence}}%", "deleteTrackedObject": { "toast": { "success": "Tracked object deleted successfully.", diff --git a/web/src/components/card/AnimatedEventCard.tsx b/web/src/components/card/AnimatedEventCard.tsx index 1fc37b36f..d46509eb6 100644 --- a/web/src/components/card/AnimatedEventCard.tsx +++ b/web/src/components/card/AnimatedEventCard.tsx @@ -229,7 +229,7 @@ export function AnimatedEventCard({ .map((text) => text.charAt(0).toUpperCase() + text.substring(1)) .sort() .join(", ") - .replaceAll("-verified", "")} detected`} + .replaceAll("-verified", "")} ` + t("detected")} ); diff --git a/web/src/components/overlay/detail/SearchDetailDialog.tsx b/web/src/components/overlay/detail/SearchDetailDialog.tsx index f8f79e021..d1917cf05 100644 --- a/web/src/components/overlay/detail/SearchDetailDialog.tsx +++ b/web/src/components/overlay/detail/SearchDetailDialog.tsx @@ -1167,9 +1167,9 @@ export function ObjectSnapshotTab({ ns="components/dialog" values={{ untranslatedLabel: search?.label, - translatedLabel: t( - "filter.label." + search?.label, - ), + translatedLabel: t(search?.label, { + ns: "objects", + }), }} > explore.plus.review.question.ask_full diff --git a/web/src/utils/dateUtil.ts b/web/src/utils/dateUtil.ts index d974521f8..8b1ef2ff4 100644 --- a/web/src/utils/dateUtil.ts +++ b/web/src/utils/dateUtil.ts @@ -28,9 +28,6 @@ export const getNowYesterdayInLong = (): number => { * The `timezone` option allows you to specify a specific timezone for the output, otherwise the user's browser timezone will be used. * The `use12hour` option allows you to display time in a 12-hour format if true, and 24-hour format if false. * The `dateStyle` and `timeStyle` options allow you to specify pre-defined formats for displaying the date and time. - * The `strftime_fmt` option allows you to specify a custom format using the strftime syntax. - * - * If both `strftime_fmt` and `dateStyle`/`timeStyle` are provided, `strftime_fmt` takes precedence. * * @param unixTimestamp The Unix timestamp to format * @param config An object containing the configuration options for date/time display diff --git a/web/src/views/live/LiveCameraView.tsx b/web/src/views/live/LiveCameraView.tsx index 6866118c5..3294888c0 100644 --- a/web/src/views/live/LiveCameraView.tsx +++ b/web/src/views/live/LiveCameraView.tsx @@ -531,11 +531,9 @@ export default function LiveCameraView({ Icon={mic ? FaMicrophone : FaMicrophoneSlash} isActive={mic} title={ - (mic - ? t("button.disable", { ns: "common" }) - : t("button.enable", { ns: "common" })) + - " " + - t("button.twoWayTalk", { ns: "common" }) + mic + ? t("twoWayTalk.disable", { ns: "views/live" }) + : t("twoWayTalk.enable", { ns: "views/live" }) } onClick={() => { setMic(!mic); @@ -553,11 +551,9 @@ export default function LiveCameraView({ Icon={audio ? GiSpeaker : GiSpeakerOff} isActive={audio ?? false} title={ - (audio - ? t("button.disable", { ns: "common" }) - : t("button.enable", { ns: "common" })) + - " " + - t("button.cameraAudio", { ns: "common" }) + audio + ? t("cameraAudio.disable", { ns: "views/live" }) + : t("cameraAudio.enable", { ns: "views/live" }) } onClick={() => setAudio(!audio)} disabled={!cameraEnabled} diff --git a/web/src/views/search/SearchView.tsx b/web/src/views/search/SearchView.tsx index d6803f5de..d72d3dbf4 100644 --- a/web/src/views/search/SearchView.tsx +++ b/web/src/views/search/SearchView.tsx @@ -31,7 +31,7 @@ import { import Chip from "@/components/indicators/Chip"; import { TooltipPortal } from "@radix-ui/react-tooltip"; import SearchActionGroup from "@/components/filter/SearchActionGroup"; -import { useTranslation } from "react-i18next"; +import { Trans, useTranslation } from "react-i18next"; type SearchViewProps = { search: string; @@ -608,8 +608,21 @@ export default function SearchView({ - Matched {value.search_source} at{" "} - {zScoreToConfidence(value.search_distance)}% + + searchResult.tooltip +