#!/usr/bin/env python3 """ Backend entry point for embedded deployment. Loads configuration from config.json and starts uvicorn server. """ import json import os import sys def get_base_dir() -> str: """Get base directory, supporting PyInstaller frozen executables.""" if getattr(sys, "frozen", False): # Running as PyInstaller bundle return os.path.dirname(sys.executable) else: # Running as script return os.path.dirname(os.path.abspath(__file__)) def load_config(config_path: str | None = None) -> dict: """Load configuration from config.json file.""" if config_path is None: base_dir = get_base_dir() config_path = os.path.join(base_dir, "config.json") if os.path.exists(config_path): # Use utf-8-sig to handle Windows BOM (Byte Order Mark) with open(config_path, "r", encoding="utf-8-sig") as f: return json.load(f) return {} def apply_config_to_env(config: dict) -> None: """ Apply config.json values to environment variables. Environment variables take precedence (already set values are not overwritten). """ backend_config = config.get("backend", {}) # Server configuration if "host" in backend_config: os.environ.setdefault("BACKEND_HOST", backend_config["host"]) if "port" in backend_config: os.environ.setdefault("BACKEND_PORT", str(backend_config["port"])) # Database configuration - use direct assignment to ensure config values are used db_config = backend_config.get("database", {}) if "host" in db_config: os.environ["DB_HOST"] = db_config["host"] if "port" in db_config: os.environ["DB_PORT"] = str(db_config["port"]) if "user" in db_config: os.environ["DB_USER"] = db_config["user"] if "password" in db_config: os.environ["DB_PASS"] = db_config["password"] if "database" in db_config: os.environ["DB_NAME"] = db_config["database"] if "poolSize" in db_config: os.environ["DB_POOL_SIZE"] = str(db_config["poolSize"]) # External API configuration - use direct assignment api_config = backend_config.get("externalApis", {}) if "authApiUrl" in api_config: os.environ["AUTH_API_URL"] = api_config["authApiUrl"] if "difyApiUrl" in api_config: os.environ["DIFY_API_URL"] = api_config["difyApiUrl"] if "difyApiKey" in api_config: os.environ["DIFY_API_KEY"] = api_config["difyApiKey"] if "difySttApiKey" in api_config: os.environ["DIFY_STT_API_KEY"] = api_config["difySttApiKey"] # Authentication configuration - use direct assignment auth_config = backend_config.get("auth", {}) if "adminEmail" in auth_config: os.environ["ADMIN_EMAIL"] = auth_config["adminEmail"] if "jwtSecret" in auth_config: os.environ["JWT_SECRET"] = auth_config["jwtSecret"] if "jwtExpireHours" in auth_config: os.environ["JWT_EXPIRE_HOURS"] = str(auth_config["jwtExpireHours"]) # File configuration - set TEMPLATE_DIR and RECORD_DIR relative to base base_dir = get_base_dir() if not os.environ.get("TEMPLATE_DIR"): template_dir = os.path.join(base_dir, "template") if os.path.exists(template_dir): os.environ["TEMPLATE_DIR"] = template_dir if not os.environ.get("RECORD_DIR"): record_dir = os.path.join(base_dir, "record") os.makedirs(record_dir, exist_ok=True) os.environ["RECORD_DIR"] = record_dir def main(): """Main entry point.""" import argparse parser = argparse.ArgumentParser(description="Meeting Assistant Backend Server") parser.add_argument( "--config", type=str, help="Path to config.json file", ) parser.add_argument( "--host", type=str, help="Host to bind to (overrides config)", ) parser.add_argument( "--port", type=int, help="Port to bind to (overrides config)", ) args = parser.parse_args() # Load and apply configuration config = load_config(args.config) # Debug: print loaded config print(f"DEBUG: Config path: {args.config}", flush=True) print(f"DEBUG: Loaded config keys: {list(config.keys())}", flush=True) backend_config = config.get("backend", {}) db_config = backend_config.get("database", {}) print(f"DEBUG: DB config: host={db_config.get('host')}, user={db_config.get('user')}, pass={'***' if db_config.get('password') else 'EMPTY'}", flush=True) apply_config_to_env(config) # Debug: print env vars after setting print(f"DEBUG: ENV DB_HOST={os.environ.get('DB_HOST')}", flush=True) print(f"DEBUG: ENV DB_USER={os.environ.get('DB_USER')}", flush=True) print(f"DEBUG: ENV DB_PASS={'***' if os.environ.get('DB_PASS') else 'EMPTY'}", flush=True) # Command line arguments override everything if args.host: os.environ["BACKEND_HOST"] = args.host if args.port: os.environ["BACKEND_PORT"] = str(args.port) # Get final host/port values host = os.environ.get("BACKEND_HOST", "127.0.0.1") port = int(os.environ.get("BACKEND_PORT", "8000")) print(f"Starting backend server on {host}:{port}", flush=True) # Import and run uvicorn import uvicorn uvicorn.run( "app.main:app", host=host, port=port, log_level="info", ) if __name__ == "__main__": main()