Spaces:
Running
Running
| import os | |
| import sys | |
| import atexit | |
| import asyncio | |
| import argparse | |
| import subprocess | |
| from pathlib import Path | |
| import tomli | |
| import uvicorn | |
| from loguru import logger | |
| from upgrade_codes.upgrade_manager import UpgradeManager | |
| from src.open_llm_vtuber.server import WebSocketServer | |
| from src.open_llm_vtuber.config_manager import Config, read_yaml, validate_config | |
| os.environ["HF_HOME"] = str(Path(__file__).parent / "models") | |
| os.environ["MODELSCOPE_CACHE"] = str(Path(__file__).parent / "models") | |
| upgrade_manager = UpgradeManager() | |
| def load_env_file(env_path: str = ".env") -> None: | |
| """Load key-value pairs from a .env file into environment variables. | |
| Existing environment variables are preserved and not overridden. | |
| """ | |
| path = Path(env_path) | |
| if not path.exists(): | |
| return | |
| loaded_count = 0 | |
| for raw_line in path.read_text(encoding="utf-8").splitlines(): | |
| line = raw_line.strip() | |
| if not line or line.startswith("#"): | |
| continue | |
| if line.startswith("export "): | |
| line = line[len("export ") :].strip() | |
| if "=" not in line: | |
| continue | |
| key, value = line.split("=", 1) | |
| key = key.strip() | |
| value = value.strip() | |
| if not key: | |
| continue | |
| if ( | |
| len(value) >= 2 | |
| and value[0] == value[-1] | |
| and value[0] in {'"', "'"} | |
| ): | |
| value = value[1:-1] | |
| if key not in os.environ: | |
| os.environ[key] = value | |
| loaded_count += 1 | |
| logger.info(f"Loaded {loaded_count} variables from {path}") | |
| def get_version() -> str: | |
| with open("pyproject.toml", "rb") as f: | |
| pyproject = tomli.load(f) | |
| return pyproject["project"]["version"] | |
| def init_logger(console_log_level: str = "INFO") -> None: | |
| logger.remove() | |
| # Console output | |
| logger.add( | |
| sys.stderr, | |
| level=console_log_level, | |
| format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> | {message}", | |
| colorize=True, | |
| ) | |
| # File output | |
| logger.add( | |
| "logs/debug_{time:YYYY-MM-DD}.log", | |
| rotation="10 MB", | |
| retention="30 days", | |
| level="DEBUG", | |
| format="{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | {name}:{function}:{line} | {message} | {extra}", | |
| backtrace=True, | |
| diagnose=True, | |
| ) | |
| def check_frontend_submodule(lang=None): | |
| """ | |
| Check if the frontend submodule is initialized. If not, attempt to initialize it. | |
| If initialization fails, log an error message. | |
| """ | |
| if lang is None: | |
| lang = upgrade_manager.lang | |
| frontend_path = Path(__file__).parent / "frontend" / "index.html" | |
| if not frontend_path.exists(): | |
| if lang == "id": | |
| logger.warning("Tidak ditemukan submodul front-end. Mencoba menginisialisasi submodul...") | |
| else: | |
| logger.warning( | |
| "Frontend submodule not found, attempting to initialize submodules..." | |
| ) | |
| try: | |
| subprocess.run( | |
| ["git", "submodule", "update", "--init", "--recursive"], check=True | |
| ) | |
| if frontend_path.exists(): | |
| if lang == "id": | |
| logger.info("π Submodul front-end (dan submodul lainnya) berhasil diinisialisasi.") | |
| else: | |
| logger.info( | |
| "π Frontend submodule (and other submodules) initialized successfully." | |
| ) | |
| else: | |
| if lang == "id": | |
| logger.critical( | |
| 'Gagal menginisialisasi submodul.\nAnda mungkin akan melihat pesan kesalahan {{"detail":"Not Found"}} di browser. Silakan periksa panduan cepat memulai dan halaman masalah umum untuk informasi lebih lanjut.' | |
| ) | |
| logger.error( | |
| "Did you manually change or delete the `frontend` folder? \n" | |
| + "It's a Git submodule β you shouldn't modify it directly. \n" | |
| + "If you did, discard your changes with `git restore frontend`, then try again.\n" | |
| ) | |
| else: | |
| logger.critical( | |
| 'Failed to initialize submodules. \nYou might see {{"detail":"Not Found"}} in your browser. Please check our quick start guide and common issues page from our documentation.' | |
| ) | |
| logger.error( | |
| "Frontend files are still missing after submodule initialization.\n" | |
| + "Did you manually change or delete the `frontend` folder? \n" | |
| + "It's a Git submodule β you shouldn't modify it directly. \n" | |
| + "If you did, discard your changes with `git restore frontend`, then try again.\n" | |
| ) | |
| except Exception as e: | |
| if lang == "id": | |
| logger.critical( | |
| f'Gagal menginisialisasi submodul: {e}γ\nAnda mungkin mengalami masalah jaringan dengan GitHub. Anda mungkin akan melihat pesan kesalahan {{"detail":"Not Found"}} di browser. Silakan periksa panduan cepat memulai dan halaman masalah umum untuk informasi lebih lanjut.\n' | |
| ) | |
| else: | |
| logger.critical( | |
| f'Failed to initialize submodules: {e}. \nYou might see {{"detail":"Not Found"}} in your browser. Please check our quick start guide and common issues page from our documentation.\n' | |
| ) | |
| def parse_args(): | |
| parser = argparse.ArgumentParser(description="Open-LLM-VTuber Server") | |
| parser.add_argument("--verbose", action="store_true", help="Enable verbose logging") | |
| parser.add_argument( | |
| "--hf_mirror", action="store_true", help="Use Hugging Face mirror" | |
| ) | |
| return parser.parse_args() | |
| def run(console_log_level: str): | |
| init_logger(console_log_level) | |
| logger.info(f"Open-LLM-VTuber, version v{get_version()}") | |
| # Get selected language | |
| lang = upgrade_manager.lang | |
| # Check if the frontend submodule is initialized | |
| check_frontend_submodule(lang) | |
| # Sync user config with default config | |
| try: | |
| upgrade_manager.sync_user_config() | |
| except Exception as e: | |
| logger.error(f"Error syncing user config: {e}") | |
| atexit.register(WebSocketServer.clean_cache) | |
| # Load configurations from yaml file | |
| config: Config = validate_config(read_yaml("conf.yaml")) | |
| server_config = config.system_config | |
| if server_config.enable_proxy: | |
| logger.info("Proxy mode enabled - /proxy-ws endpoint will be available") | |
| # Initialize the WebSocket server (synchronous part) | |
| server = WebSocketServer(config=config) | |
| # Perform asynchronous initialization (loading context, etc.) | |
| logger.info("Initializing server context...") | |
| try: | |
| asyncio.run(server.initialize()) | |
| logger.info("Server context initialized successfully.") | |
| except Exception as e: | |
| logger.error(f"Failed to initialize server context: {e}") | |
| sys.exit(1) # Exit if initialization fails | |
| # Run the Uvicorn server | |
| logger.info(f"Starting server on {server_config.host}:{server_config.port}") | |
| uvicorn.run( | |
| app=server.app, | |
| host=server_config.host, | |
| port=server_config.port, | |
| log_level=console_log_level.lower(), | |
| ) | |
| if __name__ == "__main__": | |
| load_env_file() | |
| args = parse_args() | |
| console_log_level = "DEBUG" if args.verbose else "INFO" | |
| if args.verbose: | |
| logger.info("Running in verbose mode") | |
| else: | |
| logger.info( | |
| "Running in standard mode. For detailed debug logs, use: uv run run_server.py --verbose" | |
| ) | |
| if args.hf_mirror: | |
| os.environ["HF_ENDPOINT"] = "https://hf-mirror.com" | |
| run(console_log_level=console_log_level) | |