"""中心服务端入口:收各校桌面端上报的经验草稿,审核后发布回去。 启动:npm run hub (= .venv\\Scripts\\python.exe server/main.py) 后台:http://127.0.0.1:8801/ (构建过 console 后可用:npm run hub:build) 自检:server/main.py --selfcheck """ import sys from pathlib import Path ROOT = Path(__file__).resolve().parent.parent if str(ROOT) not in sys.path: sys.path.insert(0, str(ROOT)) from dotenv import load_dotenv # noqa: E402 load_dotenv(ROOT / ".env") from server.config import CONSOLE_DIST, settings # noqa: E402 def selfcheck() -> int: import json import server.api.routes # noqa: F401 from server.db.database import SCHEMA_PATH print(json.dumps({ "ok": True, "port": settings.port, "db": f"{settings.pg_host}:{settings.pg_port}/{settings.pg_database}", "schema_sql": SCHEMA_PATH.exists(), "console_built": CONSOLE_DIST.exists(), "console_auth": bool(settings.console_token), "llm_ready": bool(settings.llm_api_key), }, ensure_ascii=False)) return 0 if "--selfcheck" in sys.argv: sys.exit(selfcheck()) import uvicorn # noqa: E402 from fastapi import FastAPI # noqa: E402 from fastapi.middleware.cors import CORSMiddleware # noqa: E402 from fastapi.responses import FileResponse # noqa: E402 from fastapi.staticfiles import StaticFiles # noqa: E402 from server.api.routes import router # noqa: E402 from server.db.database import init_db # noqa: E402 init_db() app = FastAPI(title="School Assistant Hub", version="0.1.0") app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) app.include_router(router) # 后台界面:构建产物存在就一并伺候,不必单独起前端服务 if CONSOLE_DIST.exists(): app.mount("/assets", StaticFiles(directory=CONSOLE_DIST / "assets"), name="assets") @app.get("/") async def console_index(): return FileResponse(CONSOLE_DIST / "index.html") else: @app.get("/") async def console_missing(): return {"name": "school-assistant-hub", "console": "尚未构建,执行 npm run hub:build", "docs": "/docs"} if __name__ == "__main__": print(f"[hub] 后台 http://127.0.0.1:{settings.port}/ 接口文档 /docs", flush=True) uvicorn.run(app, host="127.0.0.1", port=settings.port, reload=False)