"""应用入口。""" from __future__ import annotations import logging from contextlib import asynccontextmanager from pathlib import Path from fastapi import FastAPI, Request from fastapi.responses import FileResponse, JSONResponse from fastapi.staticfiles import StaticFiles import app.models # noqa: F401 注册全部表 from app.api import router from app.database import Base, engine from app.errors import AppError from app.scheduler import start_scheduler, stop_scheduler logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s %(message)s") @asynccontextmanager async def lifespan(_: FastAPI): Base.metadata.create_all(bind=engine) start_scheduler() try: yield finally: stop_scheduler() WEB_DIR = Path(__file__).resolve().parent.parent / "web" app = FastAPI(title="HyperNode-AI", version="1.0.0", lifespan=lifespan) app.include_router(router) app.mount("/static", StaticFiles(directory=WEB_DIR), name="static") @app.get("/") def console() -> FileResponse: return FileResponse(WEB_DIR / "index.html") @app.exception_handler(AppError) async def handle_app_error(_: Request, exc: AppError) -> JSONResponse: return JSONResponse(status_code=exc.status_code, content={"detail": exc.message}) @app.get("/health") def health() -> dict[str, str]: return {"status": "ok"}