e1250 commited on
Commit
e515383
·
1 Parent(s): 8202ef2

fix: add config to backend

Browse files
Files changed (4) hide show
  1. config/.env.example +0 -0
  2. config/config.yaml +40 -0
  3. config/settings.py +143 -0
  4. 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