Add config validators (#22704)

* add validator for detect width and height

require both or neither

* coerce semantic search model string to enum

Built-in model names (jinav1, jinav2) get converted to the enum, genai provider names that don't match stay as plain strings and follow the existing validation path

* formatting
This commit is contained in:
Josh Hawkins 2026-03-30 08:34:54 -05:00 committed by GitHub
parent f0a6626c6a
commit a5e3dfd107
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 22 additions and 3 deletions

View File

@ -1,6 +1,6 @@
from typing import Optional from typing import Optional
from pydantic import Field from pydantic import Field, model_validator
from ..base import FrigateBaseModel from ..base import FrigateBaseModel
@ -88,3 +88,11 @@ class DetectConfig(FrigateBaseModel):
title="Annotation offset", title="Annotation offset",
description="Milliseconds to shift detect annotations to better align timeline bounding boxes with recordings; can be positive or negative.", description="Milliseconds to shift detect annotations to better align timeline bounding boxes with recordings; can be positive or negative.",
) )
@model_validator(mode="after")
def validate_dimensions(self) -> "DetectConfig":
if (self.width is None) != (self.height is None):
raise ValueError(
"detect -> both width and height must be specified together, or both omitted"
)
return self

View File

@ -1,7 +1,7 @@
from enum import Enum from enum import Enum
from typing import Dict, List, Optional, Union from typing import Dict, List, Optional, Union
from pydantic import ConfigDict, Field from pydantic import ConfigDict, Field, field_validator
from .base import FrigateBaseModel from .base import FrigateBaseModel
@ -178,6 +178,17 @@ class SemanticSearchConfig(FrigateBaseModel):
title="Semantic search model or GenAI provider name", title="Semantic search model or GenAI provider name",
description="The embeddings model to use for semantic search (for example 'jinav1'), or the name of a GenAI provider with the embeddings role.", description="The embeddings model to use for semantic search (for example 'jinav1'), or the name of a GenAI provider with the embeddings role.",
) )
@field_validator("model", mode="before")
@classmethod
def coerce_model_enum(cls, v):
if isinstance(v, str):
try:
return SemanticSearchModelEnum(v)
except ValueError:
return v
return v
model_size: str = Field( model_size: str = Field(
default="small", default="small",
title="Model size", title="Model size",

View File

@ -1188,7 +1188,7 @@ class TestConfig(unittest.TestCase):
def test_global_detect_merge(self): def test_global_detect_merge(self):
config = { config = {
"mqtt": {"host": "mqtt"}, "mqtt": {"host": "mqtt"},
"detect": {"max_disappeared": 1, "height": 720}, "detect": {"max_disappeared": 1, "height": 720, "width": 1280},
"cameras": { "cameras": {
"back": { "back": {
"ffmpeg": { "ffmpeg": {