"""FastAPI 应用入口。""" import logging import os from fastapi import FastAPI from fastapi.staticfiles import StaticFiles from starlette.staticfiles import StaticFiles as StarletteStaticFiles from app.config import settings from app.database import engine from app.models import 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__) def create_app() -> FastAPI: app = FastAPI( title="HF Daily Papers", description="HuggingFace Daily Papers — 中文论文导览站", version="0.1.0", ) # 确保数据目录存在 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") # Phase 5: 论文图片静态服务 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) # 调度器(Phase 4) @app.on_event("startup") async def _start_scheduler(): from app.services.scheduler import start_scheduler start_scheduler() # Phase 5: 初始化 ChromaDB @app.on_event("startup") async def _init_chroma(): from app.services.embedder import init_chroma init_chroma() @app.on_event("shutdown") async def _stop_scheduler(): from app.services.scheduler import stop_scheduler stop_scheduler() 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, )