File size: 1,716 Bytes
1c0c94d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
"""Central settings. Everything tunable lives here, not in literals across the code."""

from __future__ import annotations

from functools import lru_cache

from pydantic_settings import BaseSettings, SettingsConfigDict


class Settings(BaseSettings):
    model_config = SettingsConfigDict(env_file=".env", extra="ignore")

    # storage
    database_url: str = "sqlite:///./avis.db"
    image_dir: str = "./data/images"

    # models
    detector_weights: str = "yolo11n.pt"  # ultralytics auto-downloads on first run
    detector_conf: float = 0.05
    helmet_weights: str = ""  # empty => helmet status unknown (routes to VLM/human)
    helmet_conf: float = 0.35  # confidence floor for the helmet model
    helmet_match_iou: float = 0.4  # IoU to link a helmet box to an existing rider

    # attribute checks (Tier B is quota-costly -> off by default; enable for demo)
    seatbelt_check: bool = False

    # plates
    plate_provider: str = "null"  # null | fastalpr
    plate_detector_model: str = "yolo-v9-t-384-license-plate-end2end"
    plate_ocr_model: str = "global-plates-mobile-vit-v2-model"

    # vlm
    llm_provider: str = "null"  # null | gemini
    gemini_api_key: str = ""
    gemini_model: str = "gemini-2.5-flash"

    # routing thresholds
    auto_confirm_threshold: float = 0.85
    review_threshold: float = 0.55

    # image quality gate
    quality_min_side: int = 64
    quality_blur_threshold: float = 8.0
    quality_dark_threshold: float = 15.0
    quality_bright_threshold: float = 245.0

    # fusion weights
    w_detection: float = 0.3
    w_rule: float = 0.4
    w_attribute: float = 0.3
    w_vlm: float = 0.4


@lru_cache
def get_settings() -> Settings:
    return Settings()