# config.py — Centralized configuration using pydantic-settings # .env hanya menyimpan DB credentials & secrets # Runtime config bisa diubah via API tanpa restart import os from pydantic_settings import BaseSettings from functools import lru_cache class Settings(BaseSettings): """Database & secrets — loaded from .env file.""" DB_HOST: str = "localhost" DB_PORT: int = 3306 DB_NAME: str = "sikomo_db" DB_USER: str = "root" DB_PASSWORD: str = "" API_SECRET_KEY: str = "default-key" DASHBOARD_PASSWORD: str = "Bandulan112" @property def DATABASE_URL(self) -> str: return ( f"mysql+pymysql://{self.DB_USER}:{self.DB_PASSWORD}" f"@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}" ) class Config: env_file = ".env" extra = "ignore" @lru_cache() def get_settings() -> Settings: return Settings() class RuntimeConfig: """Runtime configuration — can be changed via dashboard API without restart.""" def __init__(self): self.optuna_trials: int = int(os.getenv("OPTUNA_TRIALS", "30")) self.model_dir: str = os.getenv("MODEL_DIR", "models") self.forecast_days: int = int(os.getenv("FORECAST_DAYS", "7")) self.default_schedules: str = os.getenv("DEFAULT_SCHEDULES", "0 1 * * *") def to_dict(self) -> dict: return { "optuna_trials": self.optuna_trials, "model_dir": self.model_dir, "forecast_days": self.forecast_days, "default_schedules": self.default_schedules, } def update(self, key: str, value: str): allowed = { "optuna_trials": lambda v: setattr(self, "optuna_trials", int(v)), "model_dir": lambda v: setattr(self, "model_dir", v), "forecast_days": lambda v: setattr(self, "forecast_days", int(v)), "default_schedules": lambda v: setattr(self, "default_schedules", v), } if key not in allowed: raise ValueError(f"Key '{key}' tidak diizinkan untuk diubah.") allowed[key](value) runtime_config = RuntimeConfig()