Spaces:
Sleeping
Sleeping
fix: add config to backend
Browse files- config/.env.example +0 -0
- config/config.yaml +40 -0
- config/settings.py +143 -0
- main.py +1 -1
config/.env.example
ADDED
|
File without changes
|
config/config.yaml
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Shared defaults values that work for most people or envs
|
| 2 |
+
# TODO, mostly this might not work in docker, due to the "\", feel free to replace it by [*proj_dir, ai, dl_models] for exmple
|
| 3 |
+
|
| 4 |
+
project_name: Tracking Config
|
| 5 |
+
# This one called Literal block, there is another one called Folded (>)
|
| 6 |
+
project_desc: |
|
| 7 |
+
Tracking System for detection, providing real-time camera status throught a Dashboard.
|
| 8 |
+
task: indoor
|
| 9 |
+
|
| 10 |
+
intervals:
|
| 11 |
+
system_metrics_seconds: 3.0 # Logging system metrics every
|
| 12 |
+
frames_summary_every: 30 # Number of frames to create a logs summary
|
| 13 |
+
realtime_updates_every: 2 # backend send updates every n seconds?
|
| 14 |
+
|
| 15 |
+
prometheus_port: 9091
|
| 16 |
+
|
| 17 |
+
paths:
|
| 18 |
+
project_dir: &proj_dir G:\MyComputer\Workspace\Projects\gp-tracking-dashboard\tracking_dashboard
|
| 19 |
+
models_dir: &models_dir !join [*proj_dir, ai, dl_models]
|
| 20 |
+
logs_dir: !join [*proj_dir, config, logs, logs]
|
| 21 |
+
|
| 22 |
+
yolo:
|
| 23 |
+
model_path: !join [*models_dir, yolo26s.pt]
|
| 24 |
+
classes:
|
| 25 |
+
- person
|
| 26 |
+
batch_size: 16
|
| 27 |
+
epochs: 100
|
| 28 |
+
wandb: True
|
| 29 |
+
augment: True
|
| 30 |
+
data_path: ""
|
| 31 |
+
|
| 32 |
+
security_detector:
|
| 33 |
+
model_path: !join [*models_dir, "yolo_smoke_fire.pt"]
|
| 34 |
+
classes:
|
| 35 |
+
- fire
|
| 36 |
+
- smoke
|
| 37 |
+
|
| 38 |
+
depth:
|
| 39 |
+
model_path: !join [*models_dir, depth_anything_v2_vits.pth]
|
| 40 |
+
encoder: "vits"
|
config/settings.py
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from pathlib import Path
|
| 2 |
+
from typing import Literal, List
|
| 3 |
+
from pydantic import BaseModel
|
| 4 |
+
from pydantic_settings import BaseSettings, DotEnvSettingsSource, EnvSettingsSource, SettingsConfigDict, PydanticBaseSettingsSource, YamlConfigSettingsSource
|
| 5 |
+
import yaml
|
| 6 |
+
|
| 7 |
+
def join_tag(loader, node):
|
| 8 |
+
"""
|
| 9 |
+
Help joining pathes in config.YAML directly.
|
| 10 |
+
"""
|
| 11 |
+
parts = loader.construct_sequence(node)
|
| 12 |
+
path = Path(*(str(part) for part in parts)).resolve()
|
| 13 |
+
return str(path)
|
| 14 |
+
# It didn't work before, After some research, .SafeLoaded is unmentioned must for my case.
|
| 15 |
+
yaml.SafeLoader.add_constructor("!join", join_tag)
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
class PathsConfig(BaseModel):
|
| 19 |
+
"""Contains paths of directories"""
|
| 20 |
+
project_dir: str
|
| 21 |
+
models_dir: str
|
| 22 |
+
logs_dir: str
|
| 23 |
+
|
| 24 |
+
class YoloConfig(BaseModel):
|
| 25 |
+
"""Contains yolo configurations"""
|
| 26 |
+
model_path: str
|
| 27 |
+
classes: List[str]
|
| 28 |
+
batch_size: int
|
| 29 |
+
epochs: int
|
| 30 |
+
wandb: bool
|
| 31 |
+
augment: bool
|
| 32 |
+
data_path: str
|
| 33 |
+
|
| 34 |
+
class SecurityDetector(BaseModel):
|
| 35 |
+
"Contains Security Detectors like Smoke - Fire"
|
| 36 |
+
model_path: str
|
| 37 |
+
classes: List[str]
|
| 38 |
+
|
| 39 |
+
class DepthConfig(BaseModel):
|
| 40 |
+
"Contains depths estimation configurations"
|
| 41 |
+
model_path: str
|
| 42 |
+
encoder: Literal["vits", "vitb", "vitl", "vitg"]
|
| 43 |
+
|
| 44 |
+
class IntervalsConfig(BaseModel):
|
| 45 |
+
system_metrics_seconds: float
|
| 46 |
+
frames_summary_every: int
|
| 47 |
+
realtime_updates_every: float
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
class AppConfig(BaseSettings):
|
| 51 |
+
"""
|
| 52 |
+
Main app Configuration
|
| 53 |
+
- Gets defaults from config.yaml (via load_config)
|
| 54 |
+
- Override values with .env
|
| 55 |
+
"""
|
| 56 |
+
|
| 57 |
+
# Note that it doesn't show error, Take care.
|
| 58 |
+
model_config = SettingsConfigDict(
|
| 59 |
+
env_file=Path(__file__).parent / ".env",
|
| 60 |
+
env_file_encoding="utf-8",
|
| 61 |
+
yaml_file=Path(__file__).parent / "config.yaml",
|
| 62 |
+
# case_sensitive=False, # default True
|
| 63 |
+
# env_prefix="YOLO_", # Means configs we are talking about starts with YOLO_
|
| 64 |
+
# env_nested_delimiter="__", # Means we use _ instead of spaces for the same var
|
| 65 |
+
extra="ignore" # Ignore other settings in yaml and env as they are not mentioedhere
|
| 66 |
+
)
|
| 67 |
+
|
| 68 |
+
project_name:str
|
| 69 |
+
project_desc:str
|
| 70 |
+
task: Literal["indoor", "outdoor"]
|
| 71 |
+
|
| 72 |
+
paths: PathsConfig
|
| 73 |
+
yolo: YoloConfig
|
| 74 |
+
security_detector: SecurityDetector
|
| 75 |
+
depth: DepthConfig
|
| 76 |
+
intervals: IntervalsConfig
|
| 77 |
+
|
| 78 |
+
# Backend
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
@classmethod
|
| 82 |
+
def settings_customise_sources(cls,
|
| 83 |
+
settings_cls: type[BaseSettings], # Base param.
|
| 84 |
+
# init_settings: PydanticBaseSettingsSource, # Values passed to __init__
|
| 85 |
+
# env_settings: PydanticBaseSettingsSource, # OS Env variables
|
| 86 |
+
# dotenv_settings: PydanticBaseSettingsSource,
|
| 87 |
+
# file_secret_settings: PydanticBaseSettingsSource # Secret Directories
|
| 88 |
+
**kwargs
|
| 89 |
+
) -> tuple[PydanticBaseSettingsSource, ...] :
|
| 90 |
+
"""
|
| 91 |
+
Once you use this, no need to use load_config, it is already the same.
|
| 92 |
+
But this time it fixs the priority part, order by parameters priority.
|
| 93 |
+
"""
|
| 94 |
+
|
| 95 |
+
# Order by priority
|
| 96 |
+
return (
|
| 97 |
+
DotEnvSettingsSource(settings_cls), # Most important
|
| 98 |
+
EnvSettingsSource(settings_cls), # This allow for ex. hugging face to override .env values with its values.
|
| 99 |
+
YamlConfigSettingsSource(settings_cls),
|
| 100 |
+
) # The return must be a tuple
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
# @classmethod
|
| 104 |
+
# def load_config(cls, yaml_path: Path | str = Path(__file__).parent / "config.yaml") -> "AppConfig":
|
| 105 |
+
# """Loading confiuration and settings from Config.yaml file then override using .env"""
|
| 106 |
+
|
| 107 |
+
# yaml_path = Path(yaml_path).resolve() # Absolute path
|
| 108 |
+
# if not yaml_path.is_file():
|
| 109 |
+
# raise FileNotFoundError(f"Config file not found: {yaml_path}")
|
| 110 |
+
|
| 111 |
+
# with yaml_path.open("r") as f:
|
| 112 |
+
# yaml_data = yaml.safe_load(f) or {}
|
| 113 |
+
|
| 114 |
+
# # env_data = cls() # This one loaded .env and not Yaml
|
| 115 |
+
# # When this project grow, you are going to create different types of .yaml files for products and debugging and so on
|
| 116 |
+
# # Feel free to stack them here, so we use the yaml required for our testing
|
| 117 |
+
# # Note that in debuging.yaml file, we only override the base, not starting from scratch.
|
| 118 |
+
# # return cls(**{
|
| 119 |
+
# # **yaml_data, # Loading config.yaml configurations
|
| 120 |
+
# # # **env_data.model_dump() # TODO(FIX) Overriding everything using .env
|
| 121 |
+
# # })
|
| 122 |
+
# return cls(**yaml_data)
|
| 123 |
+
|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
|
| 127 |
+
if __name__ == "__main__":
|
| 128 |
+
# Note that we must use AppConfig without () to take .env in mind.
|
| 129 |
+
# Checking for YAML part.
|
| 130 |
+
# config = AppConfig.load_config()
|
| 131 |
+
# print(config.model_dump())
|
| 132 |
+
# print(config.model_dump()["project_name"])
|
| 133 |
+
|
| 134 |
+
# Checking for .env file.
|
| 135 |
+
# config = AppConfig()
|
| 136 |
+
# print(f".env Path we are talking about: {Path(__file__).parent / ".env"}")
|
| 137 |
+
# print(config.model_config)
|
| 138 |
+
# print(config.project_name)
|
| 139 |
+
|
| 140 |
+
# Trying to checking both yaml and .env. This works really fine now.
|
| 141 |
+
config = AppConfig()
|
| 142 |
+
print(config.model_dump())
|
| 143 |
+
print(config.model_dump()["project_name"])
|
main.py
CHANGED
|
@@ -2,7 +2,7 @@ from fastapi import FastAPI
|
|
| 2 |
# from prometheus_client import metrics
|
| 3 |
from ai.depth.depth_anything import DepthAnything
|
| 4 |
from ai.detectors.yolo_detector import YOLO_Detector
|
| 5 |
-
from config.settings import AppConfig
|
| 6 |
from backend.api.routers.metrics import metrics_asgi_app
|
| 7 |
from infra.system_metrics import log_system_metrics
|
| 8 |
from backend.api.routers import camera_stream
|
|
|
|
| 2 |
# from prometheus_client import metrics
|
| 3 |
from ai.depth.depth_anything import DepthAnything
|
| 4 |
from ai.detectors.yolo_detector import YOLO_Detector
|
| 5 |
+
from backend.config.settings import AppConfig
|
| 6 |
from backend.api.routers.metrics import metrics_asgi_app
|
| 7 |
from infra.system_metrics import log_system_metrics
|
| 8 |
from backend.api.routers import camera_stream
|