Commit Graph
6514 Commits
Author SHA1 Message Date
Josh Hawkins 3fe51fbbe2 Record the image variant in each Dockerfile 2026-10-29 16:01:36 -05:00
Josh Hawkins 3b527c19a1 Generate the analytics schema and check it in CI 2026-10-29 16:01:27 -05:00
Josh Hawkins f3ab6cbda7 Add the analytics preview API 2026-10-29 16:01:27 -05:00
Josh Hawkins 2a9a9edff4 Send the daily analytics report from the main process 2026-10-29 16:01:14 -05:00
Josh Hawkins 2fd9c11dde Add the analytics report transport 2026-10-29 16:01:14 -05:00
Josh Hawkins 89745dc903 Build analytics reports from the section collectors 2026-10-29 16:01:14 -05:00
Josh Hawkins e474db5008 Add the health analytics collector 2026-10-29 16:01:14 -05:00
Josh Hawkins df40ffd932 Add the features analytics collector 2026-10-29 16:01:14 -05:00
Josh Hawkins e0d9ef762b Add the cameras analytics collector 2026-10-29 16:01:14 -05:00
Josh Hawkins a155e0d79c Add the detection analytics collector 2026-10-29 16:01:14 -05:00
Josh Hawkins e0764dae58 Add the install and hardware analytics collectors 2026-10-29 16:01:14 -05:00
Josh Hawkins 6cbae92f18 Add the analytics state file 2026-10-29 16:01:14 -05:00
Josh Hawkins 355dc6fe93 Add the analytics report schema 2026-10-29 16:01:14 -05:00
Josh Hawkins 47d7d6348e Add analytics opt-in setting, prompt notice kind, and notice watermarks 2026-10-29 16:01:14 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Josh Hawkins
a6b2a29c4c Bump protobuf from 3.20.3 to 5.29.6 in /docker/tensorrt in the pip-trt-security group across 1 directory (#24825)
CI / AMD64 Build (push) Waiting to run
CI / AMD64 Smoke Test (push) Blocked by required conditions
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* Bump protobuf

Bumps the pip-trt-security group with 1 update in the /docker/tensorrt directory: [protobuf](https://developers.google.com/protocol-buffers/).


Updates `protobuf` from 3.20.3 to 5.29.6

---
updated-dependencies:
- dependency-name: protobuf
  dependency-version: 5.29.6
  dependency-type: direct:production
  dependency-group: pip-trt-security
...

Signed-off-by: dependabot[bot] <support@github.com>

* keep amd64 tensorrt protobuf on 7.36

Dependabot moved every protobuf pin in docker/tensorrt to 5.29, but the security alerts only cover the aarch64 pin. On amd64 that would downgrade protobuf below what TensorFlow 2.21 requires (>=6.31.1), and the image would build with a pip warning and fail at import tensorflow. This keeps the aarch64 change to 5.29.6, which is the same change verified on #24350 (onnx 1.14.0 and TensorFlow 2.19 both work on it).

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com>
2026-10-29 14:04:22 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
40aa2da22a Bump the web-security group across 1 directory with 2 updates (#24826)
Bumps the web-security group with 2 updates in the /web directory: [fast-uri](https://github.com/fastify/fast-uri) and [postcss-selector-parser](https://github.com/postcss/postcss-selector-parser).


Updates `fast-uri` from 3.1.8 to 3.1.9
- [Release notes](https://github.com/fastify/fast-uri/releases)
- [Commits](https://github.com/fastify/fast-uri/compare/v3.1.8...v3.1.9)

Updates `fast-uri` from 4.2.1 to 4.2.3
- [Release notes](https://github.com/fastify/fast-uri/releases)
- [Commits](https://github.com/fastify/fast-uri/compare/v3.1.8...v3.1.9)

Updates `postcss-selector-parser` from 6.1.4 to 6.1.5
- [Release notes](https://github.com/postcss/postcss-selector-parser/releases)
- [Changelog](https://github.com/postcss/postcss-selector-parser/blob/6.1.5/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss-selector-parser/compare/6.1.4...6.1.5)

---
updated-dependencies:
- dependency-name: fast-uri
  dependency-version: 3.1.9
  dependency-type: indirect
  dependency-group: web-security
- dependency-name: fast-uri
  dependency-version: 4.2.3
  dependency-type: indirect
  dependency-group: web-security
- dependency-name: postcss-selector-parser
  dependency-version: 6.1.5
  dependency-type: indirect
  dependency-group: web-security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-29 13:16:34 -05:00
Nicolas MowenandGitHub 3dd59d9a44 Optimize Python Tests (#24823)
* Optimize tests

* Address comments

* Fix test
2026-10-29 12:39:21 -05:00
Nicolas MowenandGitHub bbf23ccce7 Refactor TFL so code is shared among all detectors (#24822)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
2026-10-29 08:49:18 -06:00
Josh HawkinsandGitHub 4953c19a71 Miscellaneous fixes (#24820)
* keep base path in logout redirect

* store manual event sub labels as verified objects

Manual events created with a sub label were stored in the review item as "label: sub_label", so review previews and collapsed History cards showed a generic icon, the review label filter missed them, and the sub label never reached sub_labels for chips, notifications, or GenAI prompts. The object processor now publishes the label and sub label separately, and the review maintainer stores them as label-verified plus a sub_labels entry, the same as tracked objects.

* only expire snapshots for events that still have one

Snapshot expiry selected every event older than snapshot retention, including events whose snapshot was already deleted, so with snapshot retention shorter than alert/detection retention the same missing files were unlinked again every cleanup cycle until the event row expired. That was nearly free on local disk but caused constant metadata load on network shares. The expiry queries now filter on has_snapshot so each snapshot is deleted once.
2026-10-29 09:04:16 -05:00
Nicolas MowenandGitHub ff2cd6a417 Add LFM to recommended local models (#24812) 2026-10-27 21:58:47 -05:00
Gleb NikiforovandGitHub 4f03480afd Fix audio worker startup after enabling a disabled camera (#24806)
CI / AMD64 Build (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
* Fix audio worker startup after enabling a disabled camera

* Document audio lifecycle test helpers

* Focus audio startup coverage on the enabled update regression
2026-10-26 17:44:48 -05:00
Josh HawkinsandGitHub 9769741713 Set modified time on case zip entries (#24803)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
* set modified time on case download zip entries

Case download zip entries were written with the zip format's 1980 placeholder date, so extracted files showed a blank or 1980 modified date. Each entry now uses the export's recording start time, converted with the UI timezone since zip times have no zone and extractors read them as local time.

* clamp case zip entry dates to 1980
2026-10-26 13:17:48 -05:00
Josh HawkinsandGitHub 0dc05305ae Improve History playback after camera audio dropouts (#24793)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
* skip vod clips that start after their audio ends

When a camera's audio dropped out, a recording segment could end its audio early. If a playback range started past that point in the segment, nginx-vod saw no audio track in the first clip, failed the whole range with a track count mismatch, and left the player spinning for up to an hour of footage. Recording now stores each segment's audio length alongside its keyframe index, from the same ffprobe pass, and plan_clip skips a clip whose window starts at or after its audio ends when the range has other clips. A range made of only that clip still plays video-only, and legacy rows without the new column are unchanged.

* keep audio skip consistent with playback

Clips were skipped even when the range would be served video-only, and seeking into a skipped span landed on later footage. The skip now only applies when every row in the range carries audio, and seeks inside a zero-duration span land on the next clip.
2026-10-26 06:25:21 -06:00
Josh HawkinsandGitHub 975f346618 Export dialog improvements (#24787)
* show validation errors in multi-camera export

Clearing part of a time field in the export time picker set the range to NaN, while the picker kept showing a valid fallback time. The multi-camera Export button then stayed disabled with no explanation, and non-admins could never start an export because a case name was required even though they can't see the case field. The picker now ignores incomplete time values. The multi-camera tab shows inline errors for an invalid range, no selected cameras, and a blank case name, only requires a case name from admins, and prefills a default case name.

* add viewer export test and remove stale non-admin case text

* fix test
2026-10-26 06:24:34 -06:00
Josh HawkinsandGitHub 9fec1c76b5 Update zod to 4 (#24791)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
* fix races in ui settings import e2e tests

confirmImport clicked any button named "Import", so when the file parse was slow it hit the Import Settings button before the dialog opened and the page never reloaded. The click is now scoped to the dialog. The legacy layouts test also wrote naturalAspectLayout after the view had already read it, so it reloads the view after the write.

* update zod to 4.6.7

zod 4 types the input of z.coerce.number() as unknown, so the zone, camera wizard, and classification edit forms pass number to keep their field types. The ONVIF port error showed zod's built-in English text, which zod 4 rewords, so it now uses a translated message. New e2e tests cover zone inertia validation and camera wizard step 1 validation.
2026-10-25 20:44:39 -06:00
Josh HawkinsandGitHub 7d4b87946e Miscellaneous fixes (#24790)
* stagger the daily region grid rebuild across cameras

Every camera requested its region grid at exactly 02:00, so the requests queued up in the dispatcher and held up recording segment inserts behind them. Each camera now picks a random offset of up to an hour.

* only log ffmpeg crashes when restarting

* round preview skeleton corners to match the player
2026-10-25 18:13:00 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
7738f022e7 Update openai requirement from ==3.35.* to ==3.36.* in /docker/main (#24784)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
Updates the requirements on [openai](https://github.com/openai/openai-python) to permit the latest version.
- [Release notes](https://github.com/openai/openai-python/releases)
- [Changelog](https://github.com/openai/openai-python/blob/main/CHANGELOG.md)
- [Commits](https://github.com/openai/openai-python/compare/v3.35.0...v3.36.1)

---
updated-dependencies:
- dependency-name: openai
  dependency-version: 3.36.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-25 08:14:20 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
ba6e3717f4 Update google-genai requirement (#24779)
Updates the requirements on [google-genai](https://github.com/googleapis/python-genai) to permit the latest version.

Updates `google-genai` to 2.32.0
- [Release notes](https://github.com/googleapis/python-genai/releases)
- [Changelog](https://github.com/googleapis/python-genai/blob/main/CHANGELOG.md)
- [Commits](https://github.com/googleapis/python-genai/compare/v2.31.0...v2.32.0)

---
updated-dependencies:
- dependency-name: google-genai
  dependency-version: 2.32.0
  dependency-type: direct:production
  dependency-group: pydantic-genai
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-25 08:14:12 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
197ed252d2 Update onnxruntime requirement from ==1.30.* to ==1.31.* in /docker/main (#24781)
Updates the requirements on [onnxruntime](https://github.com/microsoft/onnxruntime) to permit the latest version.
- [Release notes](https://github.com/microsoft/onnxruntime/releases)
- [Changelog](https://github.com/microsoft/onnxruntime/blob/main/docs/ReleaseNotesWorkflow.md)
- [Commits](https://github.com/microsoft/onnxruntime/compare/v1.30.0...v1.31.0)

---
updated-dependencies:
- dependency-name: onnxruntime
  dependency-version: 1.31.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-25 08:14:01 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
14ddaf9df3 Bump tzlocal in /docker/main in the pip-main-minor-patch group (#24780)
Bumps the pip-main-minor-patch group in /docker/main with 1 update: [tzlocal](https://github.com/regebro/tzlocal).


Updates `tzlocal` from 5.4.4 to 5.4.5
- [Changelog](https://github.com/regebro/tzlocal/blob/master/CHANGES.txt)
- [Commits](https://github.com/regebro/tzlocal/compare/5.4.4...5.4.5)

---
updated-dependencies:
- dependency-name: tzlocal
  dependency-version: 5.4.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: pip-main-minor-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-25 08:12:21 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Josh HawkinsClaude Opus 5.5
113d499a61 Update fastapi requirement from ==0.153.* to ==0.159.* in /docker/main (#24783)
* Update fastapi requirement from ==0.153.* to ==0.159.* in /docker/main

Updates the requirements on [fastapi](https://github.com/fastapi/fastapi) to permit the latest version.
- [Release notes](https://github.com/fastapi/fastapi/releases)
- [Commits](https://github.com/fastapi/fastapi/compare/0.153.0...0.159.1)

---
updated-dependencies:
- dependency-name: fastapi
  dependency-version: 0.159.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* Move enum param hints to json_schema_extra for fastapi 0.159

FastAPI 0.159 no longer accepts extra keyword arguments on Path() and
Query(), so passing enum= raised a TypeError on import.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 08:09:44 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
ccb58bdff4 Bump actions/setup-python (#24782)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
Bumps the actions group with 1 update in the / directory: [actions/setup-python](https://github.com/actions/setup-python).


Updates `actions/setup-python` from 7.0.0 to 7.1.0
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v7.0.0...v7.1.0)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: 7.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-25 08:03:37 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
68acbe98b2 Bump the web-minor-patch group in /web with 8 updates (#24785)
Bumps the web-minor-patch group in /web with 8 updates:

| Package | From | To |
| --- | --- | --- |
| [apexcharts](https://github.com/apexcharts/apexcharts.js) | `8.3.1` | `8.4.1` |
| [framer-motion](https://github.com/motiondivision/motion) | `14.4.0` | `14.6.0` |
| [i18next](https://github.com/i18next/i18next) | `26.5.3` | `26.5.5` |
| [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) | `1.60.0` | `1.61.0` |
| [react-i18next](https://github.com/i18next/react-i18next) | `17.1.0` | `17.1.1` |
| [virtua](https://github.com/inokawa/virtua) | `0.53.5` | `0.53.6` |
| [@types/lodash](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/lodash) | `4.17.26` | `4.17.27` |
| [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) | `8.3.4` | `8.3.5` |


Updates `apexcharts` from 8.3.1 to 8.4.1
- [Release notes](https://github.com/apexcharts/apexcharts.js/releases)
- [Commits](https://github.com/apexcharts/apexcharts.js/compare/v8.3.1...v8.4.1)

Updates `framer-motion` from 14.4.0 to 14.6.0
- [Changelog](https://github.com/motiondivision/motion/blob/main/CHANGELOG.md)
- [Commits](https://github.com/motiondivision/motion/compare/v14.4.0...v14.6.0)

Updates `i18next` from 26.5.3 to 26.5.5
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v26.5.3...v26.5.5)

Updates `lucide-react` from 1.60.0 to 1.61.0
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/1.61.0/packages/lucide-react)

Updates `react-i18next` from 17.1.0 to 17.1.1
- [Changelog](https://github.com/i18next/react-i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/react-i18next/compare/v17.1.0...v17.1.1)

Updates `virtua` from 0.53.5 to 0.53.6
- [Release notes](https://github.com/inokawa/virtua/releases)
- [Commits](https://github.com/inokawa/virtua/compare/0.53.5...0.53.6)

Updates `@types/lodash` from 4.17.26 to 4.17.27
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/lodash)

Updates `vite` from 8.3.4 to 8.3.5
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v8.3.5/packages/vite)

---
updated-dependencies:
- dependency-name: apexcharts
  dependency-version: 8.4.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: web-minor-patch
- dependency-name: framer-motion
  dependency-version: 14.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: web-minor-patch
- dependency-name: i18next
  dependency-version: 26.5.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: lucide-react
  dependency-version: 1.61.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: web-minor-patch
- dependency-name: react-i18next
  dependency-version: 17.1.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: virtua
  dependency-version: 0.53.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: "@types/lodash"
  dependency-version: 4.17.27
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: vite
  dependency-version: 8.3.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-25 08:03:32 -05:00
David McNettandGitHub 04c62c2ce3 Fix classification model card missing cover image when first category is empty (#24768)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
The cover image only checked the first category returned by the dataset
API (after skipping none/unknown) and gave up if it had no images. Since
category order follows the dataset directory listing, a model whose first
listed category is still empty showed the skeleton placeholder even when
other categories had plenty of images.

Use the first category that actually has images instead.
2026-10-24 08:12:33 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
f7d532a09d Update fastapi requirement from ==0.142.* to ==0.153.* in /docker/main (#24763)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
Updates the requirements on [fastapi](https://github.com/fastapi/fastapi) to permit the latest version.
- [Release notes](https://github.com/fastapi/fastapi/releases)
- [Commits](https://github.com/fastapi/fastapi/compare/0.142.0...0.153.0)

---
updated-dependencies:
- dependency-name: fastapi
  dependency-version: 0.152.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-23 09:13:35 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Josh Hawkins
0171a54207 Bump the web-minor-patch group across 1 directory with 24 updates (#24765)
* Bump the web-minor-patch group across 1 directory with 24 updates

Bumps the web-minor-patch group with 24 updates in the /web directory:

| Package | From | To |
| --- | --- | --- |
| [framer-motion](https://github.com/motiondivision/motion) | `14.0.0` | `14.4.0` |
| [i18next](https://github.com/i18next/i18next) | `26.4.2` | `26.5.3` |
| [i18next-http-backend](https://github.com/i18next/i18next-http-backend) | `4.0.2` | `4.0.4` |
| [js-yaml](https://github.com/nodeca/js-yaml) | `5.4.3` | `5.5.0` |
| [konva](https://github.com/konvajs/konva) | `10.7.1` | `10.9.0` |
| [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) | `1.52.0` | `1.60.0` |
| [react](https://github.com/react/react/tree/HEAD/packages/react) | `19.3.0` | `19.3.1` |
| [react-dom](https://github.com/react/react/tree/HEAD/packages/react-dom) | `19.3.0` | `19.3.1` |
| [react-dropzone](https://github.com/react-dropzone/react-dropzone) | `20.1.2` | `20.1.4` |
| [react-hook-form](https://github.com/react-hook-form/react-hook-form) | `7.89.0` | `7.90.0` |
| [react-i18next](https://github.com/i18next/react-i18next) | `17.0.16` | `17.1.0` |
| [react-konva](https://github.com/konvajs/react-konva) | `19.3.0` | `19.3.2` |
| [tailwind-merge](https://github.com/dcastil/tailwind-merge/tree/HEAD/packages/tailwind-merge) | `2.4.0` | `2.6.1` |
| [virtua](https://github.com/inokawa/virtua) | `0.53.3` | `0.53.5` |
| [@playwright/test](https://github.com/microsoft/playwright) | `1.64.0` | `1.64.1` |
| [@types/lodash](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/lodash) | `4.17.25` | `4.17.26` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `26.6.4` | `26.6.5` |
| [eslint](https://github.com/eslint/eslint) | `10.12.0` | `10.13.0` |
| [eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier) | `5.5.6` | `5.5.7` |
| [monaco-editor](https://github.com/microsoft/monaco-editor) | `0.52.2` | `0.53.0` |
| [postcss](https://github.com/postcss/postcss) | `8.5.29` | `8.5.31` |
| [prettier](https://github.com/prettier/prettier) | `3.9.9` | `3.9.10` |
| [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.71.1` | `8.72.0` |
| [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) | `8.3.3` | `8.3.4` |



Updates `framer-motion` from 14.0.0 to 14.4.0
- [Changelog](https://github.com/motiondivision/motion/blob/main/CHANGELOG.md)
- [Commits](https://github.com/motiondivision/motion/compare/v14.0.0...v14.4.0)

Updates `i18next` from 26.4.2 to 26.5.3
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v26.4.2...v26.5.3)

Updates `i18next-http-backend` from 4.0.2 to 4.0.4
- [Changelog](https://github.com/i18next/i18next-http-backend/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next-http-backend/compare/v4.0.2...v4.0.4)

Updates `js-yaml` from 5.4.3 to 5.5.0
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/5.4.3...5.5.0)

Updates `konva` from 10.7.1 to 10.9.0
- [Release notes](https://github.com/konvajs/konva/releases)
- [Changelog](https://github.com/konvajs/konva/blob/master/CHANGELOG.md)
- [Commits](https://github.com/konvajs/konva/compare/10.7.1...10.9.0)

Updates `lucide-react` from 1.52.0 to 1.60.0
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/1.60.0/packages/lucide-react)

Updates `react` from 19.3.0 to 19.3.1
- [Release notes](https://github.com/react/react/releases)
- [Changelog](https://github.com/react/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/react/react/commits/v19.3.1/packages/react)

Updates `react-dom` from 19.3.0 to 19.3.1
- [Release notes](https://github.com/react/react/releases)
- [Changelog](https://github.com/react/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/react/react/commits/v19.3.1/packages/react-dom)

Updates `react-dropzone` from 20.1.2 to 20.1.4
- [Release notes](https://github.com/react-dropzone/react-dropzone/releases)
- [Commits](https://github.com/react-dropzone/react-dropzone/compare/v20.1.2...v20.1.4)

Updates `react-hook-form` from 7.89.0 to 7.90.0
- [Release notes](https://github.com/react-hook-form/react-hook-form/releases)
- [Changelog](https://github.com/react-hook-form/react-hook-form/blob/master/CHANGELOG.md)
- [Commits](https://github.com/react-hook-form/react-hook-form/compare/v7.89.0...v7.90.0)

Updates `react-i18next` from 17.0.16 to 17.1.0
- [Changelog](https://github.com/i18next/react-i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/react-i18next/compare/v17.0.16...v17.1.0)

Updates `react-konva` from 19.3.0 to 19.3.2
- [Release notes](https://github.com/konvajs/react-konva/releases)
- [Changelog](https://github.com/konvajs/react-konva/blob/master/RELEASE_NOTES.md)
- [Commits](https://github.com/konvajs/react-konva/compare/v19.3.0...v19.3.2)

Updates `tailwind-merge` from 2.4.0 to 2.6.1
- [Release notes](https://github.com/dcastil/tailwind-merge/releases)
- [Commits](https://github.com/dcastil/tailwind-merge/commits/v2.6.1/packages/tailwind-merge)

Updates `virtua` from 0.53.3 to 0.53.5
- [Release notes](https://github.com/inokawa/virtua/releases)
- [Commits](https://github.com/inokawa/virtua/compare/0.53.3...0.53.5)

Updates `@playwright/test` from 1.64.0 to 1.64.1
- [Release notes](https://github.com/microsoft/playwright/releases)
- [Commits](https://github.com/microsoft/playwright/compare/v1.64.0...v1.64.1)

Updates `@types/lodash` from 4.17.25 to 4.17.26
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/lodash)

Updates `@types/node` from 26.6.4 to 26.6.5
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `eslint` from 10.12.0 to 10.13.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](https://github.com/eslint/eslint/compare/v10.12.0...v10.13.0)

Updates `eslint-plugin-prettier` from 5.5.6 to 5.5.7
- [Release notes](https://github.com/prettier/eslint-plugin-prettier/releases)
- [Changelog](https://github.com/prettier/eslint-plugin-prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/eslint-plugin-prettier/compare/v5.5.6...v5.5.7)

Updates `monaco-editor` from 0.52.2 to 0.53.0
- [Release notes](https://github.com/microsoft/monaco-editor/releases)
- [Changelog](https://github.com/microsoft/monaco-editor/blob/main/CHANGELOG.md)
- [Commits](https://github.com/microsoft/monaco-editor/compare/v0.52.2...v0.53.0)

Updates `postcss` from 8.5.29 to 8.5.31
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.5.29...8.5.31)

Updates `prettier` from 3.9.9 to 3.9.10
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.9.9...3.9.10)

Updates `typescript-eslint` from 8.71.1 to 8.72.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.72.0/packages/typescript-eslint)

Updates `vite` from 8.3.3 to 8.3.4
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v8.3.4/packages/vite)

---
updated-dependencies:
- dependency-name: framer-motion
  dependency-version: 14.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: web-minor-patch
- dependency-name: i18next
  dependency-version: 26.5.3
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: web-minor-patch
- dependency-name: i18next-http-backend
  dependency-version: 4.0.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: js-yaml
  dependency-version: 5.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: web-minor-patch
- dependency-name: konva
  dependency-version: 10.9.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: web-minor-patch
- dependency-name: lucide-react
  dependency-version: 1.60.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: web-minor-patch
- dependency-name: react
  dependency-version: 19.3.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: react-dom
  dependency-version: 19.3.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: react-dropzone
  dependency-version: 20.1.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: react-hook-form
  dependency-version: 7.90.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: web-minor-patch
- dependency-name: react-i18next
  dependency-version: 17.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: web-minor-patch
- dependency-name: react-konva
  dependency-version: 19.3.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: tailwind-merge
  dependency-version: 2.6.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: web-minor-patch
- dependency-name: virtua
  dependency-version: 0.53.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: "@playwright/test"
  dependency-version: 1.64.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: "@types/lodash"
  dependency-version: 4.17.26
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: "@types/node"
  dependency-version: 26.6.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: eslint
  dependency-version: 10.13.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: web-minor-patch
- dependency-name: eslint-plugin-prettier
  dependency-version: 5.5.7
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: monaco-editor
  dependency-version: 0.53.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: web-minor-patch
- dependency-name: postcss
  dependency-version: 8.5.31
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: prettier
  dependency-version: 3.9.10
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: typescript-eslint
  dependency-version: 8.72.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: web-minor-patch
- dependency-name: vite
  dependency-version: 8.3.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* keep monaco's textarea input in the config editor

monaco-editor 0.53 focuses EditContext's host div, which the command
menu doesn't treat as a text field, so typing "/" or Ctrl+K in the
config editor opened the command menu.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com>
2026-10-23 09:03:13 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
356bf04840 Bump apexcharts from 7.8.0 to 8.3.1 in /web (#24766)
Bumps [apexcharts](https://github.com/apexcharts/apexcharts.js) from 7.8.0 to 8.3.1.
- [Release notes](https://github.com/apexcharts/apexcharts.js/releases)
- [Commits](https://github.com/apexcharts/apexcharts.js/compare/v7.8.0...v8.3.1)

---
updated-dependencies:
- dependency-name: apexcharts
  dependency-version: 8.3.1
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-23 08:51:07 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
304b676267 Bump @hookform/resolvers from 5.9.1 to 6.0.0 in /web (#24767)
Bumps [@hookform/resolvers](https://github.com/react-hook-form/resolvers) from 5.9.1 to 6.0.0.
- [Release notes](https://github.com/react-hook-form/resolvers/releases)
- [Commits](https://github.com/react-hook-form/resolvers/compare/v5.9.1...v6.0.0)

---
updated-dependencies:
- dependency-name: "@hookform/resolvers"
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-23 08:51:02 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
9d1bb704a4 Bump follow-redirects (#24735)
Bumps the web-security group with 1 update in the /web directory: [follow-redirects](https://github.com/follow-redirects/follow-redirects).


Updates `follow-redirects` from 1.16.0 to 1.16.1
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.16.0...v1.16.1)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-version: 1.16.1
  dependency-type: indirect
  dependency-group: web-security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-23 08:50:56 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
92f479831d Update starlette requirement from ==1.7.* to ==1.9.* in /docker/main (#24762)
Updates the requirements on [starlette](https://github.com/Kludex/starlette) to permit the latest version.
- [Release notes](https://github.com/Kludex/starlette/releases)
- [Changelog](https://github.com/Kludex/starlette/blob/main/docs/release-notes.md)
- [Commits](https://github.com/Kludex/starlette/compare/1.7.0...1.9.0)

---
updated-dependencies:
- dependency-name: starlette
  dependency-version: 1.9.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-23 08:50:42 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
09c145d4e4 Update openai requirement from ==3.26.* to ==3.35.* in /docker/main (#24764)
Updates the requirements on [openai](https://github.com/openai/openai-python) to permit the latest version.
- [Release notes](https://github.com/openai/openai-python/releases)
- [Changelog](https://github.com/openai/openai-python/blob/main/CHANGELOG.md)
- [Commits](https://github.com/openai/openai-python/compare/v3.26.0...v3.35.1)

---
updated-dependencies:
- dependency-name: openai
  dependency-version: 3.35.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-23 08:50:37 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
6b21499186 Update transformers requirement in /docker/main (#24761)
Updates the requirements on [transformers](https://github.com/huggingface/transformers) to permit the latest version.
- [Release notes](https://github.com/huggingface/transformers/releases)
- [Commits](https://github.com/huggingface/transformers/compare/v5.19.0...v5.20.2)

---
updated-dependencies:
- dependency-name: transformers
  dependency-version: 5.20.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-23 08:50:32 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1ebd12b52f Bump ruff in /docker/main in the pip-main-minor-patch group (#24760)
Bumps the pip-main-minor-patch group in /docker/main with 1 update: [ruff](https://github.com/astral-sh/ruff).


Updates `ruff` from 0.17.0 to 0.17.1
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.17.0...0.17.1)

---
updated-dependencies:
- dependency-name: ruff
  dependency-version: 0.17.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: pip-main-minor-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-23 08:50:26 -05:00
Josh HawkinsandGitHub b68c6561d9 hold react-zoom-pan-pinch above 3.4.4 and monaco-editor from 0.54 (#24712) 2026-10-23 06:33:14 -06:00
61fd753aed Add accelerated input transform support to zmq detector protocol (#24731)
* Let the zmq detector skip the input transform when the detector applies it

_transform_input converts the frame to the model's layout and dtype before
the detector sees it. For a remote detector that can apply the transform
itself, often on a GPU, that work is done twice over and the tensor is sent
in its most expensive form.

The detector now reports input_transform_offload in the model handshake. When
it does, Frigate sends the frame as captured (uint8 NHWC) and adds the model's
expected input_tensor and input_dtype to the request header, so the detector
can apply them. The model config is unchanged either way: the expected format
is relayed, not overridden.

The choice is read per frame rather than cached, because the detector redoes
its handshake on a timeout or socket error, so restarting or upgrading it
while Frigate runs already works and keeps working here.

Negotiated rather than configured, for two reasons. The detector is what knows
whether it can apply the transform, and a user who merely believed it could
would send unconverted frames to a model that cannot take them. It also needs
no config surface, which the device string format has no room for.

On a 640x640 region, measured on a Ryzen 9 5900XT, the host-side cost of
handing the detector a frame drops from about 4 ms to under 0.1 ms per
detection, and the payload from 4.9 MB to 1.2 MB. Nearly all of it is
tobytes(): np.transpose returns a view and astype keeps its strides by
default, so the transpose is deferred to serialization, where it becomes a
strided gather over the whole float32 tensor. The YUV to RGB conversion is
unaffected and stays on the host.

* Test that the handshake decides whether the input transform is applied

Parameterized over the three handshake values against the header the detector
ends up sending: reported, the frame goes over as captured uint8 NHWC with the
model's input_tensor and input_dtype declared; not reported or absent, the
existing transform runs and those fields are omitted.

A second case drives a real reconnect -- a timed out request, then a handshake
from an upgraded detector -- and checks the next frame follows the new answer
rather than the one from startup.

---------

Co-authored-by: Eric <eric@localhost>
2026-10-23 06:26:47 -06:00
Josh HawkinsandGitHub 6e185ed36e Keep post capture after review items end (#24726)
* keep post capture segments after a review item ends

The recording maintainer only loaded review items whose end_time was after the oldest cached segment, so once an item closed in the database the segments in its post_capture window no longer matched it. With continuous recording off and no motion after the item, everything past roughly the review cutoff_time was deleted from the cache instead of being kept for the full post_capture. The query bound now subtracts the camera's largest post_capture, and the per-item check still decides the exact cutoff.

* fix mypy and add docstring
2026-10-23 06:25:21 -06:00
Josh HawkinsandGitHub a85526187e check every overlapping review item before dropping a recording (#24728)
Recording retention around review items applied only the first review item, in start order, whose pre and post capture window covered a segment. When an alert and a detection were close together, a quiet segment covered by both was dropped by the detection's motion mode without checking the alert's all mode. The loop also stopped at a review item that started too late to reach the segment, even when a later alert with a longer pre_capture did reach it. Both the recording maintainer and cleanup now check every review item whose window covers the segment and keep it if any of their retain modes would.
2026-10-23 06:22:47 -06:00
Josh HawkinsandGitHub f385065981 Miscellaneous fixes (#24753)
* materialize event counts in metrics endpoint

The metrics endpoint stored a lazy peewee query on the shared Prometheus collector, and collect() ran it later. Overlapping scrapes run in separate threadpool threads, so two requests could execute and step the same query's sqlite cursor at once. The rows are now read with list() before they reach the collector.

* fix fps overflow restarting ffmpeg after 3 seconds instead of 3 retry intervals

This is a regression from 0.18. The watchdog has restarted ffmpeg after 3 consecutive fps overflow checks since #13651, which was 3 retry intervals (30s by default) when the loop ran every retry_interval. #21297 moved the loop to 1s ticks without converting the count, so the window shrank to 3s. camera_fps is a 10s average, so one burst of buffered frames after a stream hiccup could keep it over the limit long enough to restart a healthy camera, and the next reconnect burst could repeat it. The threshold is now 3 * retry_interval ticks. When the count filled while restarts were still rate limited, the watchdog logged "Exiting ffmpeg...", marked the camera offline and reset the count without restarting. The check now waits for can_restart, so the log, status and restart always happen together.

* keep recording cleanup running after a failed pass

An exception anywhere in a cleanup pass, such as an OSError from a read-only or unmounted storage path, ended the recording cleanup thread with nothing logged. Retention stopped until restart, and recordings, previews and database rows kept growing. Each pass now logs the exception and the loop continues.

* expose frigate_camera_events as a gauge

The metric reports the current count of events in the database, which drops when retention prunes old events. As a counter, each prune read as a counter reset, so increase() and rate() inflated event counts. The series name changes from frigate_camera_events_total to frigate_camera_events. The test's porch/inside assertion was missing its `in event.text` and always passed.

* keep uvicorn idle connections open longer than nginx's upstream keepalive

uvicorn closed idle connections after its 5s default while nginx kept them pooled for 60s, so a request nginx sent on a connection uvicorn was closing got a 502. nginx retries that on a fresh connection for most methods, but not for POST or PATCH.

* snapshot websocket clients under the manager lock in the output loop

The output loop iterated ws4py's live websocket dict without its lock, so a client connecting or disconnecting mid-iteration raised "dictionary changed size during iteration" and killed the output loop. It now copies the clients under manager.lock once per frame and skips terminated ones, matching the jsmpeg and birdseye broadcasters.

* only cache preview frames when recording is enabled

The segment-end check tested the record config object instead of record.enabled, and the first frame after startup was written unconditionally. With recording disabled, the first segment still cached frames and encoded a preview.

* fix untranslated unknown resolution text in camera info dialog

* detect all AMD GPUs from vainfo

The vainfo check only matched "AMD Radeon Graphics", so drivers reporting names like "AMD Radeon Vega 8 Graphics", "AMD Radeon RX 6600", "AMD Custom GPU 0405", or older codename strings fell through and their GPU stats were collected as Intel. It now matches Mesa's "for AMD" driver string.

* return a 500 instead of raising when go2rtc is unreachable

The two go2rtc stream GETs had no exception handling or timeout, so a go2rtc outage raised a connection error with a traceback, and a hung go2rtc held the request open indefinitely. Both now catch request errors, log the cause, and use a timeout. The per-stream probe gets a 35s read timeout because go2rtc probes each source in turn, and one unresponsive source takes about 10s.

* retry camera snapshots after a failed load

AutoUpdatingCameraImage only scheduled the next frame from onLoad, so a single failed latest.webp request froze the image until the component remounted. It now retries on error, dropping the periodic cache key so the retry requests a fresh URL.

* reuse pooled upstream connections for nginx auth subrequests

The /auth subrequest proxied to a variable address, which nginx can't pool, and its location-level headers dropped the inherited Connection header so nginx sent Connection: close. Every authenticated request opened and closed its own loopback connection to the API. It now proxies to the frigate_api upstream with an empty Connection header so the keepalive pool is reused.
2026-10-23 06:20:01 -06:00
Patryk OrwatGitHubPatryk Watkowskigreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
91e91c68ef Add Axelera Metis NPU detector plugin v.0.19 (#24270)
CI / AMD64 Build (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
* Add Axelera Metis NPU object detector plugin

Runs Frigate inference on the Axelera Metis NPU through the vendor's
low-level axelera.runtime API with pip-installed, sha256-pinned wheels
from Axelera's public artifactory (self-contained: auditwheel-repaired
libs + bundled firmware).

- async send_input/receive_output contract (FIFO pairing, overload emits
  zero rows instead of raising, frames are copied out of camera shm)
- generic YOLO-family decoder driven by the compiled model's manifest.json
  (padded input geometry, dequant params, baked postprocess graph via onnx)
- labels come from the compiled model's model_info.json; empty labelmaps
  fail loudly at init

* object_detection: async runner path for the axelera detector

* detectors: detect_axelera probe (/dev/metis*) + device node init

* stats: Axelera Metis board temperature poller

The card exposes no utilization counter usable next to a live detector, so
the poller reports the board-controller temperature read via axcmd (cached
5s; the read must not race detector init).

* docs: Axelera Metis detector (install, config, model catalog, downloads)

* axelera: expose Metis colon-name device node and image deps for runtime enumeration

The Axelera runtime enumerates Metis cards via the colon-separated node
name created by the vendor udev rule on the host (e.g. /dev/metis-0:1:0)
and probes kernel state with lsmod/lspci. Containers only receive the
raw /dev/metis-0-1-0 node, so the detector never found the card.

- init-devices: create /dev/metis-BB:DD:F aliases for each Metis node
- install_deps: add kmod and pciutils so the runtime's driver check works

* axelera: review round 2 (downloader, stop release, pixel format, docs size, per-class NMS)

- download model zips through ModelDownloader (atomic .part rename; a
  truncated download no longer poisons the cache)
- stop(): release the Context (releases connection/model/instance); the
  previous instance.free() call never existed in the runtime API and was
  silently swallowed
- honor input_pixel_format: flip to RGB planes only when Frigate delivers
  BGR (input_pixel_format: bgr); with rgb the frame passes through as-is
- docs/catalog: width/height = compiled 640x640 input (square regions no
  longer get squashed twice), document input_pixel_format: bgr
- NMS via xyxy_to_xywh_for_nms + per-class cv2.dnn.NMSBoxes, matching the
  other detector plugins instead of a hand-rolled class-agnostic pass

* axelera: report Metis temperature only on the NPU card

The same board readout was surfaced twice on the System page: once as
the detector temperature (get_hardware_temperatures) and once on the
NPU card (npu_usages). Keep the NPU card, where the value belongs.

* axelera: report AIPU utilization as the detector run duty cycle

The runtime exposes no device-side usage counter (mvm_utilisation is a
configuration limit, not a readout), so the NPU card rendered empty.
ModelInstance.run blocks until the AIPU completes: the detector process
now times each run and publishes busy/wall over a 2s window through a
small file under the tmp cache dir; the stats poller reads it and sets
the npu key. A stale file (detector idle/restarting) reports nothing
rather than a stale number.

* axelera: cut hot-path allocations in preprocess and dequantise

Preprocess reused three fresh arrays per frame (resize output, quantised
copy, strided channel flip at write time) and refilled the whole padded
input buffer. Now resize writes into a scratch with cv2 dst=, the BGR->RGB
swap is a cvtColor into scratch (no strided copy), the int8 quantise runs
with out=, and only the border strips the content rect does not cover get
memset. Measured 39% faster on the 704x576 -> 640x640 path.

Dequantise allocated two fp32 temporaries per head (astype then the
dequant expression) before the transpose copy. copyto now casts int8->fp32
while transposing straight into a reused fp32 feed buffer, and the zp/scale
math runs in place. Measured 78% faster for the YOLOX-S head set, outputs
bit-identical (int8->fp32 cast is lossless).

Argmax+gather replaces max+argmax (one class-axis reduction instead of
two), and the postprocess session pins intra_op_num_threads=1: one frame
is in flight through the decoder, extra ORT threads only add context
switches.

* axelera: publish the run duty cycle through a shared Value

Replace the tmp-file duty-cycle handoff (and the FRIGATE_TMP env var
nothing else reads) with a third multiprocessing.Value alongside
avg_inference_speed and detection_start: ObjectDetectProcess creates it,
AsyncDetectorRunner passes it to the detector, and the plugin publishes
busy/wall of the blocking ModelInstance.run over a 2s window, mirroring
how memryx receives its shared state. No filesystem path, no staleness
window, no atomic rename, and stats/hardware.py no longer imports the
plugin module to find the file.

The producer also ticks the window while the queue is empty, so the duty
cycle falls to 0 when the card idles instead of sticking at its last
value.

Name it what it is: host-side occupancy of the run call, including DMA
and driver time, not an AIPU core counter (the runtime exposes no
device-side one). The NPU entry now reads temperature from the board
controller plus the detector-reported run duty cycle folded in where
the detector processes are in reach.

* axelera: enumerate devices explicitly and fail with an actionable error

Context.list_devices() keys off the lspci BDF and needs the colon-form
node to be present, so surface an empty enumeration at init with the
fix-it hint instead of a bare device_connect(None) ConnectionError
several frames deeper. Uses the DeviceInfo the runtime enumerated
rather than relying on the pick-first implicit path.

* axelera: deliver every accepted result under backpressure, reset duty cycle on restart

Greptile P1: _push_result dropped a completion when the result queue was
full, stranding the runner's send_times entry and the input SHM mapping
(1 submission : 1 result contract). Replace the drop with a stop-aware
blocking put so an accepted submission always produces exactly one
delivered completion.

Greptile P2: start_or_restart did not clear run_duty_cycle when starting
a replacement process, so stats could show the previous process's duty
cycle while the new detector was still initializing. Reset it to the
-1.0 sentinel alongside detection_start, inside the async branch.

Greptile P2 (offline docs): list axelera among the detector types whose
pre-seeded runtime files live under /config/model_cache/runtimes/<type>.

* axelera: reviewer round 3 (plugin-owned enumeration tools, generic DEVICE_ALIASES, generic duty-cycle fold)

install_deps.sh: drop kmod/pciutils from the base image. The runtime's
list_devices() only greps popen'd lspci/lsmod output over /sys and /proc,
so the plugin now installs shell stand-ins in its own
/config/model_cache/axelera/bin and prepends it to PATH when the real
tools are missing (hardware-verified: the stand-in lspci prints the
Device 1f9d:<id> line the runtime matches, the lsmod shape matches
/proc/modules).

init-devices: replace the Metis-keyed alias block with a generic
DEVICE_ALIASES env var (comma separated alias=target pairs, next to
DEVICE_ACL_PATHS). Docker rejects colon-named nodes in --device AND in
bind mounts (probed: 'too many colons' on both the long volume form and
the mount form), so the in-container symlink stays necessary; docs carry
the pair users must set.

stats/util.py: fold any detector's published run_duty_cycle into the
matching npu_usages entry generically; _axelera_run_duty_cycle and the
per-vendor branch are gone.

plugin: the no-device RuntimeError now names the raw dash-form node
(--device rejects colons, users can only pass the raw node) and points
at DEVICE_ALIASES for the colon alias.

* axelera: reviewer round 4 (aggregate shared-type duty cycles, american spellings)

stats/util.py: several detector processes can share one hardware type (e.g.
two axelera cards on one host). Iterating and assigning made the displayed
NPU usage depend on dict order, last writer wins. Collect the published
windows per type and write the busiest one, matching what the removed
per-vendor helper did with max().

plugin: the remaining British spellings (dequantise family) corrected to
the American forms the repo requires.

plugin: model path resolution follows hailo8l's single-string pattern (URL
or local path or preset name in one value), the download uses urllib
directly like memryx, and _find_model_json now raises on an ambiguous
multi-model directory instead of returning whichever sorts first.

plugin: AxeleraDetector exposes shutdown() (the async contract hook base.py
calls) instead of close(); __del__ guards a partially initialised instance.

* axelera: download URL models through the atomic ModelDownloader

* axelera: bring the detector unit tests in tree

* init-devices: create DEVICE_ALIASES before the ACL-mode exits

An alias is not an ACL grant: users running with FRIGATE_RUN_AS_ROOT or
FRIGATE_DEVICE_ACLS=false still need the colon-form node the runtime
enumerates, so create the aliases right after the euid check. Document
DEVICE_ALIASES next to DEVICE_ACL_PATHS and note it cannot work under
docker's user: mode (the container cannot write to /dev).

* detectors: cover the Axelera Metis probe in test_detector_hardware

* Update docs/docs/configuration/non_root.md

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* axelera: address the 2026-10-12 review round

- hash directory models deterministically in compute_model_hash instead of
  raising IsADirectoryError at startup
- keep canonical model labels addressable after user renames in the
  labelmap lookup (two classes can share one renamed name)
- key the URL model cache by source and archive content, extract replaced
  archives into fresh directories, prune superseded variants conservatively
- keep publishing the run duty cycle when the hardware poll has no entry
  (duty-only npu_usages entry instead of a hidden detector)
- document the user: mode device reach instead of host-only alias creation

* axelera: prune only generated cache entries

A fresh download matched user-provided layouts (the docs-recommended
<name>/ directory, <name>.zip archives) and look-alike model names
(yolox.zip vs yolox-s-*) by prefix. Pruning is now gated on the exact
generated identity pattern <name>-<source>-<32 hex digits>, so downloads
never touch user-provided directories, other models, or other sources.

* axelera: narrow the model path design to memryx-style zips

- path is always a .zip of the compiled output (local or http(s) URL),
  extracted fresh on every start under a lock, like the memryx
  custom-model flow
- _decode returns the raw class index and Frigate's labelmap names it;
  _build_label_lookup and _read_model_labels are gone, and the YOLOX
  objectness check keys off model_type
- scheme-less URL support and the quantized/manifest.json fallback are
  dropped
- width/height must equal the compiled input size; init raises otherwise
  instead of letterboxing
- compute_model_hash is back to the unchanged file-only hashing; the
  .extracted marker, source/content cache-name hashes and
  _prune_model_cache are removed

* Update frigate/test/test_axelera_detector.py

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* axelera: drop the run duty cycle, match the hailo temperature flow

- no other accelerator reports NPU usage and the published value was time
  blocked in run(), not device utilization from the vendor API; removing
  it leaves the runner selection as the only core change
- the board temperature moves to a get_hardware_temperatures branch like
  hailo, so it renders on the detector card; _poll_axelera, its POLLERS
  entry and the _scan_detectors line are gone
- axelera_runtime2 is not installed: axelera.runtime imports it only
  inside a try for its separate new-runtime API, and the low-level API
  the plugin uses (Context, load_model, device_connect,
  load_model_instance) lives in axelera.runtime.objects

* axelera: follow-ups from the 2026-10-13 review round

- the offline-setup table no longer lists the axelera_runtime2 wheels,
  which are not installed
- a failed board temperature read starts a 60s cooldown so an
  unresponsive axcmd does not delay every stats update

* axelera: drop the model-hash test, fix the model.json error messages

* axelera: drop DEVICE_ALIASES, document the CDI device spec

* axelera: use ln -sf in the CDI hook example

---------

Co-authored-by: Patryk Watkowski <patrykorwat@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-10-20 09:53:28 -05:00
Josh HawkinsandGitHub 5bb2cde8b3 Reject cross-origin websocket connections (#24714)
CI / AMD64 Build (push) Canceled after 0s
CI / AMD64 Smoke Test (push) Canceled after 0s
CI / ARM Build (push) Canceled after 0s
CI / Jetson Jetpack 6 (push) Canceled after 0s
CI / AMD64 Extra Build (push) Canceled after 0s
CI / ARM Extra Build (push) Canceled after 0s
CI / Synaptics Build (push) Canceled after 0s
CI / Assemble and push default build (push) Canceled after 0s
* reject cross-origin websocket handshakes

Neither /ws nor the jsmpeg websockets checked Origin, and the internal port grants admin to everyone, so any page a LAN user visited could open ws://frigate:5000/ws and send commands or read streams. Both servers now reject a browser handshake whose Origin host matches neither Host nor X-Forwarded-Host, and allow handshakes without an Origin for non-browser clients. nginx now forwards an outer proxy's X-Forwarded-Host instead of overwriting it, so proxies that rewrite Host and the Home Assistant integration's proxy still match.

* apply runtime role changes to jsmpeg streams

The output process never subscribed to config/auth, so role edits from the Roles UI (requires_restart 0) did not reach it and jsmpeg kept streaming cameras that had been removed from a role until restart. The output process now replaces its auth config on config/auth updates, which the camera and birdseye broadcast threads read through the shared config.

* tidy origin check docstring and auth update comment

* reject cross-origin go2rtc stream requests in /auth

The go2rtc websockets and the webrtc offer POST still accepted any Origin, since go2rtc runs with origin "*" and /auth grants admin on the internal port, so a page on another site could pull live video through a LAN user's browser. nginx now passes Origin, Host, X-Forwarded-Host and Upgrade to /auth, which rejects a websocket upgrade or go2rtc stream request with a foreign Origin before the internal-port early return. The hostname rule moves to frigate/util/origin.py so /auth and the ws4py servers share it.

* set Host in the nginx proxy doc examples

* drain all queued auth updates in the output process

* note that cards must stream through the integration proxy

* strip the query before matching go2rtc paths in the origin check
2026-10-19 20:19:40 -10:00