mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-09-30 03:46:50 +03:00
Handle form validation
This commit is contained in:
@@ -286,6 +286,42 @@ test.describe("Detection models settings @high", () => {
|
||||
).toBeDisabled();
|
||||
});
|
||||
|
||||
test("two models without a path share the detector's default model", async ({
|
||||
frigateApp,
|
||||
}) => {
|
||||
await installRoutes(frigateApp.page, [
|
||||
{ scene: "default", devices: ["cpu"] },
|
||||
{ scene: "driveway", devices: ["cpu"] },
|
||||
]);
|
||||
await openPage(frigateApp);
|
||||
|
||||
await expect(frigateApp.page.locator("#pageRoot")).toContainText(
|
||||
"The Default and driveway models use the same model file",
|
||||
);
|
||||
});
|
||||
|
||||
test("another spelling of the same path is the same model", async ({
|
||||
frigateApp,
|
||||
}) => {
|
||||
await installRoutes(frigateApp.page, [
|
||||
{
|
||||
scene: "default",
|
||||
devices: ["openvino:GPU.0"],
|
||||
path: "/config/model_cache/yolo.onnx",
|
||||
},
|
||||
{
|
||||
scene: "driveway",
|
||||
devices: ["openvino:GPU.1"],
|
||||
path: "/config//model_cache/./tmp/../yolo.onnx",
|
||||
},
|
||||
]);
|
||||
await openPage(frigateApp);
|
||||
|
||||
await expect(frigateApp.page.locator("#pageRoot")).toContainText(
|
||||
"The Default and driveway models use the same model file",
|
||||
);
|
||||
});
|
||||
|
||||
test("one model file may run on different detectors", async ({
|
||||
frigateApp,
|
||||
}) => {
|
||||
|
||||
@@ -3,6 +3,51 @@ import type { TFunction } from "i18next";
|
||||
import { isJsonObject } from "@/lib/utils";
|
||||
import { DEFAULT_SCENE, getSceneLabel } from "@/utils/modelUtil";
|
||||
|
||||
/** The model the backend loads for a detector when no path is configured. */
|
||||
function defaultModelPath(detector: string): string | undefined {
|
||||
if (detector === "cpu" || detector.endsWith("_tfl")) {
|
||||
return "/cpu_model.tflite";
|
||||
}
|
||||
|
||||
if (detector === "edgetpu") {
|
||||
return "/edgetpu_model.tflite";
|
||||
}
|
||||
|
||||
if (detector === "openvino") {
|
||||
return "/openvino-model/ssdlite_mobilenet_v2.xml";
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapse `//`, `.`, and `..` so spellings of one file path compare equal,
|
||||
* as the backend's realpath does. Symlinks and copies can only be seen by the
|
||||
* backend, which still combines them at startup.
|
||||
*/
|
||||
function normalizeModelPath(path: string): string {
|
||||
// plus://<id> and other URLs are compared as written
|
||||
if (path.includes("://")) {
|
||||
return path;
|
||||
}
|
||||
|
||||
const segments: string[] = [];
|
||||
|
||||
for (const segment of path.split("/")) {
|
||||
if (segment === "" || segment === ".") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (segment === ".." && segments.length && segments.at(-1) !== "..") {
|
||||
segments.pop();
|
||||
} else if (segment !== ".." || !path.startsWith("/")) {
|
||||
segments.push(segment);
|
||||
}
|
||||
}
|
||||
|
||||
return `${path.startsWith("/") ? "/" : ""}${segments.join("/")}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* A camera that names no scene runs the model whose scene is `default`.
|
||||
* Without one the backend rejects the config outright once a second model
|
||||
@@ -38,14 +83,23 @@ export function validateModelScenes(
|
||||
const seen = new Map<string, string>();
|
||||
|
||||
formData.forEach((model, index) => {
|
||||
if (!isJsonObject(model) || typeof model.path !== "string" || !model.path) {
|
||||
if (!isJsonObject(model)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const devices = Array.isArray(model.devices) ? model.devices : [];
|
||||
const detector =
|
||||
typeof devices[0] === "string" ? devices[0].split(":")[0] : "";
|
||||
const key = `${detector}|${model.path}`;
|
||||
const path =
|
||||
typeof model.path === "string" && model.path
|
||||
? normalizeModelPath(model.path)
|
||||
: defaultModelPath(detector);
|
||||
|
||||
if (!path) {
|
||||
return;
|
||||
}
|
||||
|
||||
const key = `${detector}|${path}`;
|
||||
const other = seen.get(key);
|
||||
|
||||
if (other === undefined) {
|
||||
|
||||
Reference in New Issue
Block a user