From 344efb6bc1e8db164bb5d3ec9bbfc6dbaf44deb7 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Sat, 8 Aug 2026 08:20:09 -0500 Subject: [PATCH] Miscellaneous fixes (0.18 beta) (#23934) * add host npu requirements to docs * allow toggling live audio transcription via mqtt * improve spacing consistency on mobile drawers * fix clearing the region grid not surviving a restart --- docs/docs/configuration/audio_detectors.md | 2 +- docs/docs/configuration/object_detectors.md | 8 ++++++++ docs/docs/integrations/mqtt.md | 12 ++++++++++++ frigate/api/media.py | 17 ++++++++++++++++- frigate/comms/mqtt.py | 6 ++++++ frigate/util/object.py | 12 ++++++------ .../components/filter/LogSettingsButton.tsx | 4 ++-- .../components/filter/ReviewFilterGroup.tsx | 12 +++++++++++- web/src/components/filter/ZoneMaskFilter.tsx | 18 +++++++++++++++--- web/src/components/menu/GeneralSettings.tsx | 9 +++++++-- web/src/components/navigation/Bottombar.tsx | 4 ++-- .../components/overlay/MobileCameraDrawer.tsx | 4 ++-- .../overlay/MobileReviewSettingsDrawer.tsx | 15 ++++++++++++--- .../settings/wizard/Step3StreamConfig.tsx | 4 ++-- web/src/components/ui/drawer.tsx | 2 +- 15 files changed, 103 insertions(+), 26 deletions(-) diff --git a/docs/docs/configuration/audio_detectors.md b/docs/docs/configuration/audio_detectors.md index b541c86707..39ec2e9ff9 100644 --- a/docs/docs/configuration/audio_detectors.md +++ b/docs/docs/configuration/audio_detectors.md @@ -256,7 +256,7 @@ The only field that is valid at the camera level is `enabled`. #### Live transcription -The single camera Live view in the Frigate UI supports live transcription of audio for streams defined with the `audio` role. Use the Enable/Disable Live Audio Transcription button/switch to toggle transcription processing. When speech is heard, the UI will display a black box over the top of the camera stream with text. The MQTT topic `frigate//audio/transcription` will also be updated in real-time with transcribed text. +The single camera Live view in the Frigate UI supports live transcription of audio for streams defined with the `audio` role. Use the Enable/Disable Live Audio Transcription button/switch to toggle transcription processing, or toggle it outside of the UI with the [`frigate//audio_transcription/set`](/integrations/mqtt#frigatecamera_nameaudio_transcriptionset) MQTT topic or the HTTP API. When speech is heard, the UI will display a black box over the top of the camera stream with text. The MQTT topic `frigate//audio/transcription` will also be updated in real-time with transcribed text. Results can be error-prone due to a number of factors, including: diff --git a/docs/docs/configuration/object_detectors.md b/docs/docs/configuration/object_detectors.md index 542d8da687..602ebfcb85 100644 --- a/docs/docs/configuration/object_detectors.md +++ b/docs/docs/configuration/object_detectors.md @@ -297,6 +297,14 @@ detectors: ::: +### Intel NPU host requirements {#intel-npu-requirements} + +The NPU firmware is loaded by the host kernel and is not part of the Frigate image. Everything else the NPU needs is bundled in the container, so host NPU libraries should never be mounted in. + +Frigate bundles a specific version of Intel's [linux-npu-driver](https://github.com/intel/linux-npu-driver/releases), and the host firmware must come from that release or a newer one. Firmware older than the bundled driver may fail with `MAPPED_INFERENCE_VERSION is NOT compatible with the ELF`, where `Expected` is the version the firmware supports and `received` is the version the bundled compiler produced. Distributions often package older firmware than the driver Frigate ships, so check the build date on the host with `sudo dmesg | grep -i vpu` and update it there if needed. + +Intel NPUs cannot be used under Home Assistant OS, which does not include the NPU firmware. + ### Configuration {#configuration-openvino} diff --git a/docs/docs/integrations/mqtt.md b/docs/docs/integrations/mqtt.md index 775adef3ea..08c3926ffd 100644 --- a/docs/docs/integrations/mqtt.md +++ b/docs/docs/integrations/mqtt.md @@ -390,6 +390,18 @@ Topic to turn audio detection for a camera on and off. Expected values are `ON` Topic with current state of audio detection for a camera. Published values are `ON` and `OFF`. +### `frigate//audio_transcription/set` + +Topic to turn [live audio transcription](/configuration/audio_detectors#live-transcription) for a camera on and off. Expected values are `ON` and `OFF`. Transcribed text is published to `frigate//audio/transcription`. + +`ON` is ignored unless audio transcription is enabled in the config for the camera. Unlike the other camera toggles, this one is not persisted across Frigate restarts. + +**NOTE:** Requires audio detection and transcription to be enabled + +### `frigate//audio_transcription/state` + +Topic with current state of live audio transcription for a camera. Published values are `ON` and `OFF`. + ### `frigate//recordings/set` Topic to turn recordings for a camera on and off. Expected values are `ON` and `OFF`. The change is persisted across Frigate restarts (see [Runtime toggle persistence](/configuration/live#runtime-toggle-persistence)). diff --git a/frigate/api/media.py b/frigate/api/media.py index 8d56475c59..c6fa90c068 100644 --- a/frigate/api/media.py +++ b/frigate/api/media.py @@ -53,6 +53,7 @@ from frigate.util.file import ( ) from frigate.util.image import get_image_from_recording, get_image_quality_params from frigate.util.media import get_keyframe_before +from frigate.util.object import create_empty_regions_grid logger = logging.getLogger(__name__) @@ -1083,7 +1084,21 @@ def clear_region_grid(request: Request, camera_name: str): status_code=404, ) - Regions.delete().where(Regions.camera == camera_name).execute() + # store an empty grid instead of deleting the row so the grid is + # rebuilt from newly tracked objects and not from all past history + region = { + Regions.camera: camera_name, + Regions.grid: create_empty_regions_grid(), + Regions.last_update: datetime.now().timestamp(), + } + ( + Regions.insert(region) + .on_conflict( + conflict_target=[Regions.camera], + update=region, + ) + .execute() + ) return JSONResponse( content={"success": True, "message": "Region grid cleared"}, ) diff --git a/frigate/comms/mqtt.py b/frigate/comms/mqtt.py index 979fc6d6c0..b74d4284f9 100644 --- a/frigate/comms/mqtt.py +++ b/frigate/comms/mqtt.py @@ -77,6 +77,11 @@ class MqttClient(Communicator): "ON" if camera.audio.enabled_in_config else "OFF", retain=True, ) + self.publish( + f"{camera_name}/audio_transcription/state", + "ON" if camera.audio_transcription.live_enabled else "OFF", + retain=True, + ) self.publish( f"{camera_name}/detect/state", "ON" if camera.detect.enabled else "OFF", @@ -258,6 +263,7 @@ class MqttClient(Communicator): "snapshots", "detect", "audio", + "audio_transcription", "motion", "improve_contrast", "ptz_autotracker", diff --git a/frigate/util/object.py b/frigate/util/object.py index b4ee72dc07..ecb71003c8 100644 --- a/frigate/util/object.py +++ b/frigate/util/object.py @@ -35,6 +35,11 @@ logger = logging.getLogger(__name__) GRID_SIZE = 8 +def create_empty_regions_grid() -> list[list[dict[str, Any]]]: + """Create a region grid with no learned sizes.""" + return [[{"sizes": []} for _ in range(GRID_SIZE)] for _ in range(GRID_SIZE)] + + def get_camera_regions_grid( name: str, detect: DetectConfig, @@ -47,12 +52,7 @@ def get_camera_regions_grid( grid = regions.grid last_update = regions.last_update except DoesNotExist: - grid = [] - for x in range(GRID_SIZE): - row = [] - for y in range(GRID_SIZE): - row.append({"sizes": []}) - grid.append(row) + grid = create_empty_regions_grid() last_update = 0 # get events for timeline entries diff --git a/web/src/components/filter/LogSettingsButton.tsx b/web/src/components/filter/LogSettingsButton.tsx index 83f2e85b47..849ea72182 100644 --- a/web/src/components/filter/LogSettingsButton.tsx +++ b/web/src/components/filter/LogSettingsButton.tsx @@ -37,7 +37,7 @@ export function LogSettingsButton({ ); const content = ( -
+
{t("filter")}
@@ -77,7 +77,7 @@ export function LogSettingsButton({ return ( {trigger} - + {content} diff --git a/web/src/components/filter/ReviewFilterGroup.tsx b/web/src/components/filter/ReviewFilterGroup.tsx index 3c75dde630..5b7c4414fa 100644 --- a/web/src/components/filter/ReviewFilterGroup.tsx +++ b/web/src/components/filter/ReviewFilterGroup.tsx @@ -26,6 +26,7 @@ import PlatformAwareDialog from "../overlay/dialog/PlatformAwareDialog"; import { useTranslation } from "react-i18next"; import { getTranslatedLabel } from "@/utils/i18n"; import { useAllowedCameras } from "@/hooks/use-allowed-cameras"; +import { cn } from "@/lib/utils"; const REVIEW_FILTERS = [ "cameras", @@ -409,6 +410,7 @@ function GeneralFilterButton({ onUpdateFilter(resetFilter); }} onClose={() => setOpen(false)} + contentClassName="p-4" /> ); @@ -416,6 +418,7 @@ function GeneralFilterButton({ { if (!open) { @@ -444,6 +447,7 @@ type GeneralFilterContentProps = { onApply: () => void; onReset: () => void; onClose: () => void; + contentClassName?: string; }; export function GeneralFilterContent({ allLabels, @@ -454,6 +458,7 @@ export function GeneralFilterContent({ onApply, onReset, onClose, + contentClassName, }: GeneralFilterContentProps) { const { t } = useTranslation(["components/filter", "views/events"]); const { data: config } = useSWR("config", { @@ -476,7 +481,12 @@ export function GeneralFilterContent({ }, [config]); return ( <> -
+
{currentSeverity && (
{trigger} - - {content} + + ); @@ -64,15 +69,22 @@ export function ZoneMaskFilterButton({ type GeneralFilterContentProps = { selectedZoneMask: PolygonType[] | undefined; updateZoneMaskFilter: (labels: PolygonType[] | undefined) => void; + contentClassName?: string; }; export function GeneralFilterContent({ selectedZoneMask, updateZoneMaskFilter, + contentClassName, }: GeneralFilterContentProps) { const { t } = useTranslation(["components/filter"]); return ( <> -
+