#!/usr/bin/env python # -*- coding: utf-8 -*- import os import sys import psutil from contextlib import asynccontextmanager from fastapi import FastAPI, Response from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles from app.core.config import settings from app.core import openai from app.utils.reload_config import RELOAD_CONFIG from app.utils.logger import setup_logger from app.providers import initialize_providers from app.admin import routes as admin_routes from app.admin import api as admin_api from granian import Granian # Setup logger logger = setup_logger(log_dir="logs", debug_mode=settings.DEBUG_LOGGING) @asynccontextmanager async def lifespan(app: FastAPI): # 初始化 Token 数据库 from app.services.token_dao import init_token_database await init_token_database() # 初始化提供商系统 initialize_providers() # 从数据库初始化 token 池(Z.AI 提供商) from app.utils.token_pool import initialize_token_pool_from_db token_pool = await initialize_token_pool_from_db( provider="zai", failure_threshold=settings.TOKEN_FAILURE_THRESHOLD, recovery_timeout=settings.TOKEN_RECOVERY_TIMEOUT ) if not token_pool and not settings.ANONYMOUS_MODE: logger.warning("⚠️ 未找到可用 Token 且未启用匿名模式,服务可能无法正常工作") yield logger.info("🔄 应用正在关闭...") # Create FastAPI app with lifespan # root_path is used for reverse proxy path prefix (e.g., /api or /path-prefix) app = FastAPI(lifespan=lifespan, root_path=settings.ROOT_PATH) # Add CORS middleware app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"], allow_headers=["Content-Type", "Authorization"], ) # 挂载web端静态文件目录 try: app.mount("/static", StaticFiles(directory="app/static"), name="static") except RuntimeError: # 如果 static 目录不存在,创建它 os.makedirs("app/static/css", exist_ok=True) os.makedirs("app/static/js", exist_ok=True) app.mount("/static", StaticFiles(directory="app/static"), name="static") # Include API routers app.include_router(openai.router) # Include admin routers app.include_router(admin_routes.router) app.include_router(admin_api.router) @app.options("/") async def handle_options(): """Handle OPTIONS requests""" return Response(status_code=200) @app.get("/") async def root(): """Root endpoint""" return {"message": "OpenAI Compatible API Server"} def run_server(): service_name = settings.SERVICE_NAME logger.info(f"🚀 启动 {service_name} 服务...") logger.info(f"📡 监听地址: 0.0.0.0:{settings.LISTEN_PORT}") logger.info(f"🔧 调试模式: {'开启' if settings.DEBUG_LOGGING else '关闭'}") logger.info(f"🔐 匿名模式: {'开启' if settings.ANONYMOUS_MODE else '关闭'}") try: Granian( "main:app", interface="asgi", address="0.0.0.0", port=settings.LISTEN_PORT, reload=False, # 生产环境请关闭热重载 process_name=service_name, # 设置进程名称 **RELOAD_CONFIG, # 热重载配置 ).serve() except KeyboardInterrupt: logger.info("🛑 收到中断信号,正在关闭服务...") except Exception as e: logger.error(f"❌ 服务启动失败: {e}") sys.exit(1) if __name__ == "__main__": run_server()