"""FastAPI 应用入口。""" import logging import os from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.staticfiles import StaticFiles from app.config import settings from app.database import engine, init_db from app.routes.admin import router as admin_router from app.routes.compare import router as compare_router from app.routes.pages import router as pages_router from app.routes.search import router as search_router from app.routes.trends import router as trends_router from app.routes.user import router as user_router logging.basicConfig( level=logging.DEBUG if settings.APP_DEBUG else logging.INFO, format="%(asctime)s [%(levelname)s] %(name)s: %(message)s", ) logger = logging.getLogger(__name__) @asynccontextmanager async def lifespan(app: FastAPI): """应用生命周期管理:启动与关闭。""" # ── startup ── from app.services.scheduler import start_scheduler from app.services.embedder import init_chroma start_scheduler() init_chroma() yield # ── shutdown ── from app.services.scheduler import stop_scheduler stop_scheduler() def create_app() -> FastAPI: app = FastAPI( title="HF Daily Papers", description="HuggingFace Daily Papers — 中文论文导览站", version="0.1.0", lifespan=lifespan, ) # 确保数据目录存在 os.makedirs(settings.db_path.parent, exist_ok=True) # 初始化数据库 init_db(engine) logger.info("Database initialized at %s", settings.db_path) # 安全警告 if settings.ADMIN_TOKEN == "change-me": logger.warning( "⚠️ ADMIN_TOKEN is the default value 'change-me'. Please change it in .env!" ) if settings.APP_HOST not in ("127.0.0.1", "localhost", "::1"): logger.warning( "⚠️ APP_HOST=%s is not localhost. " "Ensure ADMIN_TOKEN is properly set and access is restricted.", settings.APP_HOST, ) # 静态文件 app.mount("/static", StaticFiles(directory="app/static"), name="static") # 论文图片静态服务 papers_images_dir = os.path.join("data", "papers") os.makedirs(papers_images_dir, exist_ok=True) app.mount("/papers", StaticFiles(directory=papers_images_dir), name="papers") # 路由 app.include_router(pages_router) app.include_router(admin_router) app.include_router(search_router) app.include_router(user_router) app.include_router(trends_router) app.include_router(compare_router) return app app = create_app() if __name__ == "__main__": import uvicorn uvicorn.run( "app.main:app", host=settings.APP_HOST, port=settings.APP_PORT, reload=settings.APP_DEBUG, )