From adc8c2a6e848bbb6a443d4a17bafd745a1cdb638 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Wed, 1 Apr 2026 10:23:42 -0500 Subject: [PATCH] Settings UI tweaks (#22722) * set edgetpu for multi-instance * improve error messages when mixing/matching detectors * allow custom add button text via uiSchema * clarify language in docs for configuring detectors via the UI --- docs/docs/configuration/object_detectors.md | 84 +++++++++---------- web/public/locales/en/views/settings.json | 7 +- .../config-form/section-configs/detectors.ts | 2 +- .../config-form/theme/components/index.tsx | 4 +- .../theme/fields/DetectorHardwareField.tsx | 67 ++++++++++++++- 5 files changed, 118 insertions(+), 46 deletions(-) diff --git a/docs/docs/configuration/object_detectors.md b/docs/docs/configuration/object_detectors.md index 5d74ec392..53aee4747 100644 --- a/docs/docs/configuration/object_detectors.md +++ b/docs/docs/configuration/object_detectors.md @@ -91,7 +91,7 @@ See [common Edge TPU troubleshooting steps](/troubleshooting/edgetpu) if the Edg -Navigate to and select the **EdgeTPU** detector type with device set to `usb`. +Navigate to and select **EdgeTPU** from the detector type dropdown and click **Add**, then set device to `usb`. @@ -111,7 +111,7 @@ detectors: -Navigate to and add multiple Edge TPU detectors, specifying `usb:0` and `usb:1` as the device for each. +Navigate to and select **EdgeTPU** from the detector type dropdown and click **Add** to add multiple detectors, specifying `usb:0` and `usb:1` as the device for each. @@ -136,7 +136,7 @@ _warning: may have [compatibility issues](https://github.com/blakeblackshear/fri -Navigate to and select the **EdgeTPU** detector type with the device field left empty. +Navigate to and select **EdgeTPU** from the detector type dropdown and click **Add**, then leave the device field empty. @@ -156,7 +156,7 @@ detectors: -Navigate to and select the **EdgeTPU** detector type with device set to `pci`. +Navigate to and select **EdgeTPU** from the detector type dropdown and click **Add**, then set device to `pci`. @@ -176,7 +176,7 @@ detectors: -Navigate to and add multiple Edge TPU detectors, specifying `pci:0` and `pci:1` as the device for each. +Navigate to and select **EdgeTPU** from the detector type dropdown and click **Add** to add multiple detectors, specifying `pci:0` and `pci:1` as the device for each. @@ -199,7 +199,7 @@ detectors: -Navigate to and add multiple Edge TPU detectors with different device types (e.g., `usb` and `pci`). +Navigate to and select **EdgeTPU** from the detector type dropdown and click **Add** to add multiple detectors with different device types (e.g., `usb` and `pci`). @@ -246,7 +246,7 @@ After placing the downloaded files for the tflite model and labels in your confi -Navigate to and select the **EdgeTPU** detector type with device set to `usb`. Then navigate to and configure the model settings: +Navigate to and select **EdgeTPU** from the detector type dropdown and click **Add**, then set device to `usb`. Then navigate to and configure the model settings: | Field | Value | | ---------------------------------------- | ----------------------------------------------------------------- | @@ -303,7 +303,7 @@ Use this configuration for YOLO-based models. When no custom model path or URL i -Navigate to and select the **Hailo-8/Hailo-8L** detector type with device set to `PCIe`. Then navigate to and configure the model settings: +Navigate to and select **Hailo-8/Hailo-8L** from the detector type dropdown and click **Add**, then set device to `PCIe`. Then navigate to and configure the model settings: | Field | Value | | ---------------------------------------- | ----------------------- | @@ -359,7 +359,7 @@ For SSD-based models, provide either a model path or URL to your compiled SSD mo -Navigate to and select the **Hailo-8/Hailo-8L** detector type with device set to `PCIe`. Then navigate to and configure the model settings: +Navigate to and select **Hailo-8/Hailo-8L** from the detector type dropdown and click **Add**, then set device to `PCIe`. Then navigate to and configure the model settings: | Field | Value | | --------------------------------------- | ------ | @@ -404,7 +404,7 @@ The Hailo detector supports all YOLO models compiled for Hailo hardware that inc -Navigate to and select the **Hailo-8/Hailo-8L** detector type with device set to `PCIe`. Then navigate to and configure the model settings to match your custom model dimensions and format. +Navigate to and select **Hailo-8/Hailo-8L** from the detector type dropdown and click **Add**, then set device to `PCIe`. Then navigate to and configure the model settings to match your custom model dimensions and format. @@ -459,7 +459,7 @@ When using many cameras one detector may not be enough to keep up. Multiple dete -Navigate to and add multiple **OpenVINO** detectors, each targeting `GPU` or `NPU`. +Navigate to and select **OpenVINO** from the detector type dropdown and click **Add** to add multiple detectors, each targeting `GPU` or `NPU`. @@ -502,7 +502,7 @@ Use the model configuration shown below when using the OpenVINO detector with th -Navigate to and select the **OpenVINO** detector type with device set to `GPU` (or `NPU`). Then navigate to and configure: +Navigate to and select **OpenVINO** from the detector type dropdown and click **Add**, then set device to `GPU` (or `NPU`). Then navigate to and configure: | Field | Value | | ---------------------------------------- | ------------------------------------------ | @@ -552,7 +552,7 @@ After placing the downloaded onnx model in your config folder, use the following -Navigate to and select the **OpenVINO** detector type with device set to `GPU`. Then navigate to and configure: +Navigate to and select **OpenVINO** from the detector type dropdown and click **Add**, then set device to `GPU`. Then navigate to and configure: | Field | Value | | ---------------------------------------- | ------------------------------------------------- | @@ -614,7 +614,7 @@ After placing the downloaded onnx model in your config folder, use the following -Navigate to and select the **OpenVINO** detector type with device set to `GPU` (or `NPU`). Then navigate to and configure: +Navigate to and select **OpenVINO** from the detector type dropdown and click **Add**, then set device to `GPU` (or `NPU`). Then navigate to and configure: | Field | Value | | ---------------------------------------- | -------------------------------------------------------- | @@ -670,7 +670,7 @@ After placing the downloaded onnx model in your `config/model_cache` folder, use -Navigate to and select the **OpenVINO** detector type with device set to `GPU`. Then navigate to and configure: +Navigate to and select **OpenVINO** from the detector type dropdown and click **Add**, then set device to `GPU`. Then navigate to and configure: | Field | Value | | --------------------------------------- | --------------------------------- | @@ -722,7 +722,7 @@ After placing the downloaded onnx model in your config/model_cache folder, use t -Navigate to and select the **OpenVINO** detector type with device set to `CPU`. Then navigate to and configure: +Navigate to and select **OpenVINO** from the detector type dropdown and click **Add**, then set device to `CPU`. Then navigate to and configure: | Field | Value | | ---------------------------------------- | ---------------------------------- | @@ -776,7 +776,7 @@ Using the detector config below will connect to the client: -Navigate to and select the **ZMQ IPC** detector type with the endpoint set to `tcp://host.docker.internal:5555`. +Navigate to and select **ZMQ IPC** from the detector type dropdown and click **Add**, then set the endpoint to `tcp://host.docker.internal:5555`. @@ -810,7 +810,7 @@ When Frigate is started with the following config it will connect to the detecto -Navigate to and select the **ZMQ IPC** detector type with the endpoint set to `tcp://host.docker.internal:5555`. Then navigate to and configure: +Navigate to and select **ZMQ IPC** from the detector type dropdown and click **Add**, then set the endpoint to `tcp://host.docker.internal:5555`. Then navigate to and configure: | Field | Value | | ---------------------------------------- | -------------------------------------------------------- | @@ -971,7 +971,7 @@ When using many cameras one detector may not be enough to keep up. Multiple dete -Navigate to and add multiple **ONNX** detectors. +Navigate to and select **ONNX** from the detector type dropdown and click **Add** to add multiple detectors. @@ -1019,7 +1019,7 @@ After placing the downloaded onnx model in your config folder, use the following -Navigate to and select the **ONNX** detector type. Then navigate to and configure: +Navigate to and select **ONNX** from the detector type dropdown and click **Add**. Then navigate to and configure: | Field | Value | | ---------------------------------------- | ------------------------------------------------- | @@ -1078,7 +1078,7 @@ After placing the downloaded onnx model in your config folder, use the following -Navigate to and select the **ONNX** detector type. Then navigate to and configure: +Navigate to and select **ONNX** from the detector type dropdown and click **Add**. Then navigate to and configure: | Field | Value | | ---------------------------------------- | -------------------------------------------------------- | @@ -1127,7 +1127,7 @@ After placing the downloaded onnx model in your config folder, use the following -Navigate to and select the **ONNX** detector type. Then navigate to and configure: +Navigate to and select **ONNX** from the detector type dropdown and click **Add**. Then navigate to and configure: | Field | Value | | ---------------------------------------- | -------------------------------------------------------- | @@ -1176,7 +1176,7 @@ After placing the downloaded onnx model in your `config/model_cache` folder, use -Navigate to and select the **ONNX** detector type. Then navigate to and configure: +Navigate to and select **ONNX** from the detector type dropdown and click **Add**. Then navigate to and configure: | Field | Value | | --------------------------------------- | --------------------------------- | @@ -1221,7 +1221,7 @@ After placing the downloaded onnx model in your `config/model_cache` folder, use -Navigate to and select the **ONNX** detector type. Then navigate to and configure: +Navigate to and select **ONNX** from the detector type dropdown and click **Add**. Then navigate to and configure: | Field | Value | | ---------------------------------------- | ------------------------------------------- | @@ -1275,7 +1275,7 @@ A TensorFlow Lite model is provided in the container at `/cpu_model.tflite` and -Navigate to and select the **CPU** detector type. Configure the number of threads and add additional CPU detectors as needed (one per camera is recommended). +Navigate to and select **CPU** from the detector type dropdown and click **Add**. Configure the number of threads and click **Add** again to add additional CPU detectors as needed (one per camera is recommended). @@ -1311,7 +1311,7 @@ To integrate CodeProject.AI into Frigate, configure the detector as follows: -Navigate to and select the **DeepStack** detector type. Set the API URL to point to your CodeProject.AI server (e.g., `http://:/v1/vision/detection`). +Navigate to and select **DeepStack** from the detector type dropdown and click **Add**. Set the API URL to point to your CodeProject.AI server (e.g., `http://:/v1/vision/detection`). @@ -1350,7 +1350,7 @@ To configure the MemryX detector, use the following example configuration: -Navigate to and select the **MemryX** detector type with device set to `PCIe:0`. +Navigate to and select **MemryX** from the detector type dropdown and click **Add**, then set device to `PCIe:0`. @@ -1370,7 +1370,7 @@ detectors: -Navigate to and add multiple **MemryX** detectors, specifying `PCIe:0`, `PCIe:1`, `PCIe:2`, etc. as the device for each. +Navigate to and select **MemryX** from the detector type dropdown and click **Add** to add multiple detectors, specifying `PCIe:0`, `PCIe:1`, `PCIe:2`, etc. as the device for each. @@ -1414,7 +1414,7 @@ Below is the recommended configuration for using the **YOLO-NAS** (small) model -Navigate to and select the **MemryX** detector type with device set to `PCIe:0`. Then navigate to and configure: +Navigate to and select **MemryX** from the detector type dropdown and click **Add**, then set device to `PCIe:0`. Then navigate to and configure: | Field | Value | | ---------------------------------------- | ------------------------------------------------- | @@ -1462,7 +1462,7 @@ Below is the recommended configuration for using the **YOLOv9** (small) model wi -Navigate to and select the **MemryX** detector type with device set to `PCIe:0`. Then navigate to and configure: +Navigate to and select **MemryX** from the detector type dropdown and click **Add**, then set device to `PCIe:0`. Then navigate to and configure: | Field | Value | | ---------------------------------------- | ------------------------------------------------- | @@ -1509,7 +1509,7 @@ Below is the recommended configuration for using the **YOLOX** (small) model wit -Navigate to and select the **MemryX** detector type with device set to `PCIe:0`. Then navigate to and configure: +Navigate to and select **MemryX** from the detector type dropdown and click **Add**, then set device to `PCIe:0`. Then navigate to and configure: | Field | Value | | ---------------------------------------- | ----------------------- | @@ -1556,7 +1556,7 @@ Below is the recommended configuration for using the **SSDLite MobileNet v2** mo -Navigate to and select the **MemryX** detector type with device set to `PCIe:0`. Then navigate to and configure: +Navigate to and select **MemryX** from the detector type dropdown and click **Add**, then set device to `PCIe:0`. Then navigate to and configure: | Field | Value | | ---------------------------------------- | ----------------------- | @@ -1695,7 +1695,7 @@ Use the config below to work with generated TRT models: -Navigate to and select the **TensorRT** detector type with the device set to `0` (the default GPU index). Then navigate to and configure: +Navigate to and select **TensorRT** from the detector type dropdown and click **Add**, then set the device to `0` (the default GPU index). Then navigate to and configure: | Field | Value | | ---------------------------------------- | ------------------------------------------------------------ | @@ -1752,14 +1752,14 @@ Use the model configuration shown below when using the synaptics detector with t -Navigate to and select the **Synaptics** detector type. Then navigate to and configure: +Navigate to and select **Synaptics** from the detector type dropdown and click **Add**. Then navigate to and configure: | Field | Value | | ---------------------------------------- | ---------------------------- | | **Custom object detector model path** | `/synaptics/mobilenet.synap` | | **Object detection model input width** | `224` | | **Object detection model input height** | `224` | -| **Tensor format** | `nhwc` | +| **Model Input Tensor Shape** | `nhwc` | | **Label map for custom object detector** | `/labelmap/coco-80.txt` | @@ -1774,7 +1774,7 @@ model: # required path: /synaptics/mobilenet.synap # required width: 224 # required height: 224 # required - tensor_format: nhwc # default value (optional. If you change the model, it is required) + input_tensor: nhwc # default value (optional. If you change the model, it is required) labelmap_path: /labelmap/coco-80.txt # required ``` @@ -1800,7 +1800,7 @@ When using many cameras one detector may not be enough to keep up. Multiple dete -Navigate to and add multiple **RKNN** detectors, each with `num_cores` set to `0` for automatic selection. +Navigate to and select **RKNN** from the detector type dropdown and click **Add** to add multiple detectors, each with `num_cores` set to `0` for automatic selection. @@ -1842,7 +1842,7 @@ This `config.yml` shows all relevant options to configure the detector and expla -Navigate to and select the **RKNN** detector type. Set `num_cores` to `0` for automatic selection (increase for better performance on multicore NPUs, e.g., set to `3` on rk3588). +Navigate to and select **RKNN** from the detector type dropdown and click **Add**. Set `num_cores` to `0` for automatic selection (increase for better performance on multicore NPUs, e.g., set to `3` on rk3588). @@ -2059,7 +2059,7 @@ Once completed, configure the detector as follows: -Navigate to and select the **DeGirum** detector type. Set the location to your AI server (e.g., service name, container name, or `host:port`), the zoo to `degirum/public`, and provide your authentication token if needed. +Navigate to and select **DeGirum** from the detector type dropdown and click **Add**. Set the location to your AI server (e.g., service name, container name, or `host:port`), the zoo to `degirum/public`, and provide your authentication token if needed. @@ -2102,7 +2102,7 @@ It is also possible to eliminate the need for an AI server and run the hardware -Navigate to and select the **DeGirum** detector type. Set the location to `@local`, the zoo to `degirum/public`, and provide your authentication token. +Navigate to and select **DeGirum** from the detector type dropdown and click **Add**. Set the location to `@local`, the zoo to `degirum/public`, and provide your authentication token. @@ -2139,7 +2139,7 @@ If you do not possess whatever hardware you want to run, there's also the option -Navigate to and select the **DeGirum** detector type. Set the location to `@cloud`, the zoo to `degirum/public`, and provide your authentication token. +Navigate to and select **DeGirum** from the detector type dropdown and click **Add**. Set the location to `@cloud`, the zoo to `degirum/public`, and provide your authentication token. @@ -2189,7 +2189,7 @@ Use the model configuration shown below when using the axengine detector with th -Navigate to and select the **AXEngine NPU** detector type. Then navigate to and configure: +Navigate to and select **AXEngine NPU** from the detector type dropdown and click **Add**. Then navigate to and configure: | Field | Value | | ---------------------------------------- | ----------------------- | diff --git a/web/public/locales/en/views/settings.json b/web/public/locales/en/views/settings.json index e075c7e0e..18c277cfc 100644 --- a/web/public/locales/en/views/settings.json +++ b/web/public/locales/en/views/settings.json @@ -1409,7 +1409,8 @@ "keyDuplicate": "Detector name already exists.", "noSchema": "No detector schemas are available.", "none": "No detector instances configured.", - "add": "Add detector" + "add": "Add detector", + "addCustomKey": "Add custom key" }, "record": { "title": "Recording Settings" @@ -1637,6 +1638,10 @@ }, "snapshots": { "detectDisabled": "Object detection is disabled. Snapshots are generated from tracked objects and will not be created." + }, + "detectors": { + "mixedTypes": "All detectors must use the same type. Remove existing detectors to use a different type.", + "mixedTypesSuggestion": "All detectors must use the same type. Remove existing detectors or select {{type}}." } } } diff --git a/web/src/components/config-form/section-configs/detectors.ts b/web/src/components/config-form/section-configs/detectors.ts index 3ca2dd81d..5cc5a929f 100644 --- a/web/src/components/config-form/section-configs/detectors.ts +++ b/web/src/components/config-form/section-configs/detectors.ts @@ -16,7 +16,7 @@ const detectors: SectionConfigOverrides = { uiSchema: { "ui:field": "DetectorHardwareField", "ui:options": { - multiInstanceTypes: ["cpu", "onnx", "openvino"], + multiInstanceTypes: ["cpu", "onnx", "openvino", "edgetpu"], typeOrder: ["onnx", "openvino", "edgetpu"], hiddenByType: {}, hiddenFields: detectorHiddenFields, diff --git a/web/src/components/config-form/theme/components/index.tsx b/web/src/components/config-form/theme/components/index.tsx index 85519313e..2f8fe376e 100644 --- a/web/src/components/config-form/theme/components/index.tsx +++ b/web/src/components/config-form/theme/components/index.tsx @@ -60,7 +60,9 @@ export function AddPropertyButton({ className="gap-2" > - {t("button.add", { ns: "common", defaultValue: "Add" })} + {typeof uiSchema?.["ui:options"]?.addButtonText === "string" + ? uiSchema["ui:options"].addButtonText + : t("button.add", { ns: "common", defaultValue: "Add" })} ); } diff --git a/web/src/components/config-form/theme/fields/DetectorHardwareField.tsx b/web/src/components/config-form/theme/fields/DetectorHardwareField.tsx index 871131111..b9e15ced2 100644 --- a/web/src/components/config-form/theme/fields/DetectorHardwareField.tsx +++ b/web/src/components/config-form/theme/fields/DetectorHardwareField.tsx @@ -374,6 +374,18 @@ export function DetectorHardwareField(props: FieldProps) { [detectors], ); + const getExistingType = useCallback( + (excludeKey?: string): string | undefined => { + for (const [key, value] of Object.entries(detectors)) { + if (excludeKey && key === excludeKey) continue; + const type = getInstanceType(value); + if (type) return type; + } + return undefined; + }, + [detectors], + ); + const handleAdd = useCallback(() => { if (!addType) { setAddError( @@ -400,6 +412,28 @@ export function DetectorHardwareField(props: FieldProps) { return; } + const existingType = getExistingType(); + if (existingType && existingType !== addType) { + const canAddExisting = + multiInstanceSet.has(existingType) || + !resolveDuplicateType(existingType); + setAddError( + canAddExisting + ? t("configMessages.detectors.mixedTypesSuggestion", { + ns: "views/settings", + defaultValue: + "All detectors must use the same type. Remove existing detectors or select {{type}}.", + type: getTypeLabel(existingType), + }) + : t("configMessages.detectors.mixedTypes", { + ns: "views/settings", + defaultValue: + "All detectors must use the same type. Remove existing detectors to use a different type.", + }), + ); + return; + } + const baseKey = addType; let nextKey = baseKey; let index = 2; @@ -427,8 +461,10 @@ export function DetectorHardwareField(props: FieldProps) { configNamespace, detectors, getDetectorDefaults, + getExistingType, getTypeLabel, isSingleInstanceType, + multiInstanceSet, resolveDuplicateType, updateDetectors, ]); @@ -523,6 +559,29 @@ export function DetectorHardwareField(props: FieldProps) { return; } + const existingType = getExistingType(key); + if (existingType && existingType !== nextType) { + const canAddExisting = + multiInstanceSet.has(existingType) || + !resolveDuplicateType(existingType, key); + setTypeErrors((prev) => ({ + ...prev, + [key]: canAddExisting + ? t("configMessages.detectors.mixedTypesSuggestion", { + ns: "views/settings", + defaultValue: + "All detectors must use the same type. Remove existing detectors or select {{type}}.", + type: getTypeLabel(existingType), + }) + : t("configMessages.detectors.mixedTypes", { + ns: "views/settings", + defaultValue: + "All detectors must use the same type. Remove existing detectors to use a different type.", + }), + })); + return; + } + setTypeErrors((prev) => { const { [key]: _, ...rest } = prev; return rest; @@ -538,8 +597,10 @@ export function DetectorHardwareField(props: FieldProps) { [ detectors, getDetectorDefaults, + getExistingType, getTypeLabel, isSingleInstanceType, + multiInstanceSet, resolveDuplicateType, t, updateDetectors, @@ -556,6 +617,10 @@ export function DetectorHardwareField(props: FieldProps) { const nestedOverrides = { "ui:options": { disableNestedCard: true, + addButtonText: t("configForm.detectors.addCustomKey", { + ns: "views/settings", + defaultValue: "Add custom key", + }), }, } as UiSchema; @@ -567,7 +632,7 @@ export function DetectorHardwareField(props: FieldProps) { ); return mergeUiSchema(withTypeHiddenAndOptions, nestedOverrides); }, - [globalHiddenFields, hiddenByType, uiSchema?.additionalProperties], + [globalHiddenFields, hiddenByType, t, uiSchema?.additionalProperties], ); const renderInstanceForm = useCallback(