from fastapi import FastAPI, HTTPException, Request from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse from fastapi.staticfiles import StaticFiles import logging import dashscope from pathlib import Path from contextlib import asynccontextmanager from lover.routers import config as config_router from lover.routers import lover as lover_router from lover.routers import user_basic as user_basic_router from lover.response import ApiResponse from lover.routers import outfit as outfit_router from lover.routers import chat as chat_router from lover.routers import voice_call as voice_call_router from lover.routers import dance as dance_router from lover.routers import dynamic as dynamic_router from lover.routers import sing as sing_router from lover.routers import friend as friend_router from lover.routers import msg as msg_router from lover.routers import huanxin as huanxin_router from lover.routers import user as user_router from lover.task_queue import start_sing_workers from lover.config import settings # 初始化 DashScope API Key if settings.DASHSCOPE_API_KEY: dashscope.api_key = settings.DASHSCOPE_API_KEY # 配置日志 logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) @asynccontextmanager async def lifespan(app: FastAPI): # 启动时执行 logger = logging.getLogger("main") logger.info("应用启动中...") start_sing_workers() logger.info("应用启动完成") yield # 关闭时执行 logger.info("应用关闭") app = FastAPI(title="LOVER API", lifespan=lifespan) # 创建 TTS 文件目录 tts_dir = Path("public/tts") tts_dir.mkdir(parents=True, exist_ok=True) # 挂载静态文件服务(用于提供 TTS 音频文件) app.mount("/tts", StaticFiles(directory=str(tts_dir)), name="tts") app.add_middleware( CORSMiddleware, allow_origins=[ "http://localhost", "http://localhost:5173", "http://localhost:8080", "http://127.0.0.1", "http://127.0.0.1:5173", "http://127.0.0.1:8080", ], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) app.include_router(config_router.router) app.include_router(lover_router.router) app.include_router(user_basic_router.router) app.include_router(outfit_router.router) app.include_router(chat_router.router) app.include_router(voice_call_router.router) app.include_router(dance_router.router) app.include_router(dynamic_router.router) app.include_router(sing_router.router) app.include_router(friend_router.router) app.include_router(msg_router.router) app.include_router(huanxin_router.router) app.include_router(user_router.router) @app.exception_handler(HTTPException) async def http_exception_handler(request: Request, exc: HTTPException): # 统一错误响应结构,便于前端通过 code 判定 detail = exc.detail msg = detail if isinstance(detail, str) else str(detail) return JSONResponse( status_code=exc.status_code, content={"code": exc.status_code, "msg": msg, "data": None}, ) @app.exception_handler(Exception) async def generic_exception_handler(request: Request, exc: Exception): logging.exception("Unhandled error", exc_info=exc) return JSONResponse( status_code=500, content={"code": 500, "msg": "服务器内部错误", "data": None}, ) @app.get("/health", response_model=ApiResponse[dict]) async def health(): return ApiResponse(code=1, msg="ok", data={"status": "ok"}) @app.get("/debug/auth") async def debug_auth(request: Request): """调试认证信息""" headers = dict(request.headers) return { "app_env": settings.APP_ENV, "debug": settings.DEBUG, "headers": headers, "token": headers.get("token"), "authorization": headers.get("authorization"), }