Spaces:
Paused
Paused
| import os | |
| import aiohttp | |
| import logging | |
| from fastapi import FastAPI, Request, HTTPException | |
| from fastapi.responses import JSONResponse, FileResponse | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from fastapi.staticfiles import StaticFiles | |
| from fastapi.exceptions import RequestValidationError | |
| from .config import Config | |
| from .key_manager import KeyManager | |
| from .api import main_router | |
| from .api.dependencies import session_pool | |
| # 配置日志 | |
| logging.basicConfig( | |
| level=getattr(logging, os.getenv("LOG_LEVEL", "INFO").upper()), | |
| format="%(asctime)s [%(levelname)s] %(message)s", | |
| datefmt="%Y-%m-%d %H:%M:%S" | |
| ) | |
| logger = logging.getLogger("sora-api") | |
| # 全局键管理器 | |
| key_manager = KeyManager(storage_file=Config.KEYS_STORAGE_FILE) | |
| # 创建FastAPI应用 | |
| app = FastAPI( | |
| title="OpenAI Compatible Sora API", | |
| description="为Sora提供OpenAI兼容接口的API服务", | |
| version="2.0.0", | |
| docs_url="/docs", | |
| redoc_url="/redoc", | |
| ) | |
| # 配置CORS中间件 | |
| origins = [ | |
| "http://localhost", | |
| "http://localhost:8890", | |
| f"http://{Config.HOST}:{Config.PORT}", | |
| Config.BASE_URL, | |
| ] | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=origins, | |
| allow_credentials=True, | |
| allow_methods=["GET", "POST", "PUT", "DELETE"], | |
| allow_headers=["Authorization", "Content-Type"], | |
| ) | |
| # 异常处理 | |
| async def validation_exception_handler(request: Request, exc: RequestValidationError): | |
| """处理请求验证错误""" | |
| return JSONResponse( | |
| status_code=422, | |
| content={"detail": f"请求验证错误: {str(exc)}"} | |
| ) | |
| async def global_exception_handler(request: Request, exc: Exception): | |
| """全局异常处理器""" | |
| # 记录错误 | |
| logger.error(f"全局异常: {str(exc)}", exc_info=True) | |
| # 如果是已知的HTTPException,保持原始状态码和详情 | |
| if isinstance(exc, HTTPException): | |
| return JSONResponse( | |
| status_code=exc.status_code, | |
| content={"detail": exc.detail} | |
| ) | |
| # 其他异常返回500状态码 | |
| return JSONResponse( | |
| status_code=500, | |
| content={"detail": f"服务器内部错误: {str(exc)}"} | |
| ) | |
| # 应用启动和关闭事件 | |
| async def startup_event(): | |
| """应用启动时执行的操作""" | |
| global session_pool | |
| # 创建共享会话池 | |
| session_pool = aiohttp.ClientSession() | |
| logger.info("应用已启动,创建了全局会话池") | |
| # 初始化时保存管理员密钥 | |
| Config.save_admin_key() | |
| # 确保静态文件目录存在 | |
| os.makedirs(os.path.join(Config.STATIC_DIR, "admin"), exist_ok=True) | |
| os.makedirs(os.path.join(Config.STATIC_DIR, "admin/js"), exist_ok=True) | |
| os.makedirs(os.path.join(Config.STATIC_DIR, "admin/css"), exist_ok=True) | |
| os.makedirs(os.path.join(Config.STATIC_DIR, "images"), exist_ok=True) | |
| # 打印配置信息 | |
| Config.print_config() | |
| async def shutdown_event(): | |
| """应用关闭时执行的操作""" | |
| # 关闭会话池 | |
| if session_pool: | |
| await session_pool.close() | |
| logger.info("应用已关闭,清理了全局会话池") | |
| # 挂载静态文件目录 | |
| app.mount("/static", StaticFiles(directory=Config.STATIC_DIR), name="static") | |
| # 管理界面路由 | |
| async def admin_panel(): | |
| """返回管理面板HTML页面""" | |
| return FileResponse(os.path.join(Config.STATIC_DIR, "admin/index.html")) | |
| # 注册所有API路由 | |
| app.include_router(main_router) | |
| # 应用入口点(供uvicorn直接调用) | |
| if __name__ == "__main__": | |
| import uvicorn | |
| uvicorn.run( | |
| "app:app", | |
| host=Config.HOST, | |
| port=Config.PORT, | |
| reload=Config.VERBOSE_LOGGING | |
| ) |