MacBook pro commited on
Commit
cbbb792
·
1 Parent(s): ba71a1e

feat(config): add environment-driven configuration module and integrate with metrics startup

Browse files
Files changed (2) hide show
  1. app.py +14 -1
  2. config.py +56 -0
app.py CHANGED
@@ -4,10 +4,17 @@ from fastapi.staticfiles import StaticFiles
4
  from pathlib import Path
5
  import traceback
6
  import time
7
- from metrics import metrics
 
8
 
9
  app = FastAPI(title="Mirage Phase 1+2 Scaffold")
10
 
 
 
 
 
 
 
11
  # Mount the static directory
12
  static_dir = Path(__file__).parent / "static"
13
  app.mount("/static", StaticFiles(directory=str(static_dir)), name="static")
@@ -73,6 +80,12 @@ async def get_metrics():
73
  return metrics.snapshot()
74
 
75
 
 
 
 
 
 
 
76
  # Note: The Dockerfile / README launch with: uvicorn app:app --port 7860
77
  if __name__ == "__main__": # Optional direct run helper
78
  import uvicorn # type: ignore
 
4
  from pathlib import Path
5
  import traceback
6
  import time
7
+ from metrics import metrics as _metrics_singleton, Metrics
8
+ from config import config
9
 
10
  app = FastAPI(title="Mirage Phase 1+2 Scaffold")
11
 
12
+ # Potentially reconfigure metrics based on config
13
+ if config.metrics_fps_window != 30: # default in metrics module
14
+ metrics = Metrics(fps_window=config.metrics_fps_window)
15
+ else:
16
+ metrics = _metrics_singleton
17
+
18
  # Mount the static directory
19
  static_dir = Path(__file__).parent / "static"
20
  app.mount("/static", StaticFiles(directory=str(static_dir)), name="static")
 
80
  return metrics.snapshot()
81
 
82
 
83
+ @app.on_event("startup")
84
+ async def log_config():
85
+ # Simple startup log of configuration
86
+ print("[config]", config.as_dict())
87
+
88
+
89
  # Note: The Dockerfile / README launch with: uvicorn app:app --port 7860
90
  if __name__ == "__main__": # Optional direct run helper
91
  import uvicorn # type: ignore
config.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from dataclasses import dataclass
5
+ from typing import Any
6
+
7
+
8
+ def _get_int(name: str, default: int) -> int:
9
+ val = os.getenv(name)
10
+ if val is None:
11
+ return default
12
+ try:
13
+ return int(val)
14
+ except ValueError:
15
+ return default
16
+
17
+
18
+ def _get_bool(name: str, default: bool) -> bool:
19
+ val = os.getenv(name)
20
+ if val is None:
21
+ return default
22
+ val_lower = val.lower().strip()
23
+ if val_lower in {"1", "true", "yes", "on"}:
24
+ return True
25
+ if val_lower in {"0", "false", "no", "off"}:
26
+ return False
27
+ return default
28
+
29
+
30
+ @dataclass(frozen=True)
31
+ class Config:
32
+ chunk_ms: int = 160
33
+ voice_enable: bool = False
34
+ video_max_fps: int = 10
35
+ metrics_fps_window: int = 30
36
+
37
+ @staticmethod
38
+ def load() -> "Config":
39
+ return Config(
40
+ chunk_ms=_get_int("MIRAGE_CHUNK_MS", 160),
41
+ voice_enable=_get_bool("MIRAGE_VOICE_ENABLE", False),
42
+ video_max_fps=_get_int("MIRAGE_VIDEO_MAX_FPS", 10),
43
+ metrics_fps_window=_get_int("MIRAGE_METRICS_FPS_WINDOW", 30),
44
+ )
45
+
46
+ def as_dict(self) -> dict[str, Any]: # JSON-friendly
47
+ return {
48
+ "chunk_ms": self.chunk_ms,
49
+ "voice_enable": self.voice_enable,
50
+ "video_max_fps": self.video_max_fps,
51
+ "metrics_fps_window": self.metrics_fps_window,
52
+ }
53
+
54
+
55
+ # Eagerly loaded singleton pattern (can be reloaded manually if needed)
56
+ config = Config.load()