from __future__ import annotations import json from pathlib import Path from typing import Any BASE_DIR = Path(__file__).resolve().parent SETTINGS_FILE = BASE_DIR / "settings.json" DEFAULT_SETTINGS: dict[str, Any] = { "secret_key": "echo-tavern-dev-secret", "db_path": "echo_tavern.db", "deepseek_api_key": "sk-9e94feccd21640ada969990e792cbc11", "deepseek_base_url": "https://api.deepseek.com", "deepseek_model": "deepseek-chat", "deepseek_timeout": 25, "deepseek_connect_timeout": 8, "deepseek_read_timeout": 90, "deepseek_retries": 2, "llm_api_key": "", "llm_base_url": "", "llm_model": "", "llm_timeout": 25, "llm_connect_timeout": 8, "llm_read_timeout": 90, "llm_retries": 2, "llm_extra_headers": {}, "llm_force_json_mode": True, "max_room_players": 8, "max_action_length": 280, "points_system": { "enabled": True, "room_create_fee_enabled": False, "room_create_fee": 0, "redeem_ip_limit": 12, "redeem_user_limit": 10, }, "season_system": { "enabled": True, "auto_create_enabled": True, "auto_generate_theme": True, "season_duration_days": 30, "rest_days": 3, "daily_card_count": 3, "refresh_hours": [0, 8, 18], "manual_refresh_cost": 60, "premium_pass_price": 680, }, "app_host": "0.0.0.0", "app_port": 8095, "debug": True, "linuxdo_oauth": { "enabled": False, "client_id": "", "client_secret": "", "authorize_url": "https://connect.linux.do/oauth2/authorize", "token_url": "https://connect.linux.do/oauth2/token", "userinfo_url": "https://connect.linux.do/api/user", "scope": "read", }, } def _resolve_db_path(db_path: str) -> str: path = Path(db_path) if path.is_absolute(): return str(path) return str((BASE_DIR / path).resolve()) def _load_settings() -> dict[str, Any]: if not SETTINGS_FILE.exists(): SETTINGS_FILE.write_text( json.dumps(DEFAULT_SETTINGS, ensure_ascii=False, indent=2), encoding="utf-8", ) return dict(DEFAULT_SETTINGS) try: payload = json.loads(SETTINGS_FILE.read_text(encoding="utf-8")) if not isinstance(payload, dict): return dict(DEFAULT_SETTINGS) except (OSError, json.JSONDecodeError): return dict(DEFAULT_SETTINGS) merged = dict(DEFAULT_SETTINGS) merged.update(payload) linuxdo_defaults = DEFAULT_SETTINGS["linuxdo_oauth"] linuxdo_payload = payload.get("linuxdo_oauth", {}) if isinstance(linuxdo_payload, dict): merged["linuxdo_oauth"] = {**linuxdo_defaults, **linuxdo_payload} else: merged["linuxdo_oauth"] = dict(linuxdo_defaults) return merged SETTINGS = _load_settings() class Config: SECRET_KEY = str(SETTINGS.get("secret_key", DEFAULT_SETTINGS["secret_key"])) DB_PATH = _resolve_db_path(str(SETTINGS.get("db_path", DEFAULT_SETTINGS["db_path"]))) DEEPSEEK_API_KEY = str(SETTINGS.get("deepseek_api_key", DEFAULT_SETTINGS["deepseek_api_key"])) DEEPSEEK_BASE_URL = str( SETTINGS.get("deepseek_base_url", DEFAULT_SETTINGS["deepseek_base_url"]) ) DEEPSEEK_MODEL = str(SETTINGS.get("deepseek_model", DEFAULT_SETTINGS["deepseek_model"])) DEEPSEEK_TIMEOUT = float( SETTINGS.get("deepseek_timeout", DEFAULT_SETTINGS["deepseek_timeout"]) ) DEEPSEEK_CONNECT_TIMEOUT = float( SETTINGS.get("deepseek_connect_timeout", DEFAULT_SETTINGS["deepseek_connect_timeout"]) ) DEEPSEEK_READ_TIMEOUT = float( SETTINGS.get("deepseek_read_timeout", DEFAULT_SETTINGS["deepseek_read_timeout"]) ) DEEPSEEK_RETRIES = int(SETTINGS.get("deepseek_retries", DEFAULT_SETTINGS["deepseek_retries"])) LLM_API_KEY = str(SETTINGS.get("llm_api_key") or DEEPSEEK_API_KEY) LLM_BASE_URL = str(SETTINGS.get("llm_base_url") or DEEPSEEK_BASE_URL) LLM_MODEL = str(SETTINGS.get("llm_model") or DEEPSEEK_MODEL) LLM_TIMEOUT = float(SETTINGS.get("llm_timeout", DEEPSEEK_TIMEOUT)) LLM_CONNECT_TIMEOUT = float(SETTINGS.get("llm_connect_timeout", DEEPSEEK_CONNECT_TIMEOUT)) LLM_READ_TIMEOUT = float(SETTINGS.get("llm_read_timeout", DEEPSEEK_READ_TIMEOUT)) LLM_RETRIES = int(SETTINGS.get("llm_retries", DEEPSEEK_RETRIES)) LLM_FORCE_JSON_MODE = bool(SETTINGS.get("llm_force_json_mode", True)) _llm_extra_headers_raw = SETTINGS.get("llm_extra_headers", {}) LLM_EXTRA_HEADERS = _llm_extra_headers_raw if isinstance(_llm_extra_headers_raw, dict) else {} MAX_ROOM_PLAYERS = int( SETTINGS.get("max_room_players", DEFAULT_SETTINGS["max_room_players"]) ) MAX_ACTION_LENGTH = int( SETTINGS.get("max_action_length", DEFAULT_SETTINGS["max_action_length"]) ) APP_HOST = str(SETTINGS.get("app_host", DEFAULT_SETTINGS["app_host"])) APP_PORT = int(SETTINGS.get("app_port", DEFAULT_SETTINGS["app_port"])) DEBUG = bool(SETTINGS.get("debug", DEFAULT_SETTINGS["debug"])) LINUXDO_OAUTH = SETTINGS.get("linuxdo_oauth", DEFAULT_SETTINGS["linuxdo_oauth"]) class TestConfig(Config): TESTING = True SECRET_KEY = "test-secret" DEEPSEEK_API_KEY = "" LLM_API_KEY = ""