import os import sys import logging from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.staticfiles import StaticFiles from fastapi.middleware.cors import CORSMiddleware from app.config import settings, BASE_DIR from app.database import init_db from app.api import files, extraction, stories, matching, export, settings as settings_api logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) def _get_frontend_dir() -> str: """获取前端静态文件目录(支持 PyInstaller 打包)""" if getattr(sys, 'frozen', False): # 打包后:exe 同级目录下的 frontend/dist return os.path.join(BASE_DIR, "frontend", "dist") else: # 开发模式:项目根目录下的 frontend/dist return os.path.join(os.path.dirname(BASE_DIR), "frontend", "dist") @asynccontextmanager async def lifespan(app: FastAPI): """应用生命周期:启动时初始化数据库""" logger.info("初始化数据库...") await init_db() logger.info("数据库初始化完成") yield logger.info("应用关闭") app = FastAPI( title="Story Extractor", description="直播文字稿故事提取工具", version="1.0.0", lifespan=lifespan, ) # CORS app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # API 路由 app.include_router(files.router, prefix="/api/v1") app.include_router(extraction.router, prefix="/api/v1") app.include_router(stories.router, prefix="/api/v1") app.include_router(matching.router, prefix="/api/v1") app.include_router(export.router, prefix="/api/v1") app.include_router(settings_api.router, prefix="/api/v1") # 托管前端静态文件(放在最后,作为 fallback) frontend_dist = _get_frontend_dir() if os.path.exists(frontend_dist): app.mount("/", StaticFiles(directory=frontend_dist, html=True), name="static")