Files
PlantAI-rag-new/sdk/app/main.py
T

101 lines
3.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""main.py —— BFF 应用入口(ARCHITECTURE.md §2/§3)。
- 挂全部 5 个 router(qa/kg/extraction 为 A2/A3 实现,import 路径不变)。
- CORS:允许 http://localhost:5180 与 http://127.0.0.1:5180(Vite dev)。
- lifespan:init_db(幂等迁移);关闭回收 httpx 客户端与 Neo4j 连接。
- 全局 RequestValidationError → VALIDATION 信封(API.md §1,2026-08-25 PM 集成)。
- docgen(P2):routers/docgen.py 对 services/docgen/*(dev1 归属)按契约 import,
模块缺失时自动回落到内置最小接口桩(生成/编辑返回 503),不阻断 BFF 启动。
- 生产形态(M6):ui/dist 存在时静态托管(ARCHITECTURE.md §3)。
"""
from __future__ import annotations
import logging
from contextlib import asynccontextmanager
from pathlib import Path
from fastapi import FastAPI, Request
from fastapi.exceptions import RequestValidationError
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from fastapi.staticfiles import StaticFiles
from .config import get_settings
from .db import close_db, init_db
from .routers import capabilities, docgen, extraction, figures, health, kg, legacy, qa, sessions
from .routers import bioflow_proxy
from .upstream import close_client
logging.basicConfig(level=logging.INFO)
_ALLOWED_ORIGINS = [
"http://localhost:5180",
"http://127.0.0.1:5180",
]
def create_app() -> FastAPI:
settings = get_settings()
app = FastAPI(title=settings.app_name, version=settings.version)
app.add_middleware(
CORSMiddleware,
allow_origins=_ALLOWED_ORIGINS,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.include_router(health.router)
app.include_router(sessions.router)
app.include_router(qa.router)
app.include_router(capabilities.router)
app.include_router(kg.router)
app.include_router(extraction.router)
app.include_router(figures.router)
app.include_router(legacy.router)
app.include_router(docgen.router) # docgen(P2)
if get_settings().bioflow_enabled:
app.include_router(bioflow_proxy.router) # 生信反代(BIOFLOW_ENABLED 开关,FR-BIO-028)
@app.exception_handler(RequestValidationError)
async def _validation_handler(_: Request, exc: RequestValidationError) -> JSONResponse:
# API.md §1 已裁决:参数校验错误收敛为统一 VALIDATION 信封(422)
return JSONResponse(
status_code=422,
content={
"ok": False,
"error": {"code": "VALIDATION", "message": "请求参数不合法", "degraded": False},
},
)
@asynccontextmanager
async def _lifespan(_app: FastAPI):
await init_db()
try:
yield
finally:
await close_client()
try:
from .services.neo4j import close_neo4j # A3 提供;缺失则跳过
await close_neo4j()
except ImportError:
pass
await close_db()
app.router.lifespan_context = _lifespan
# 生产形态:静态托管 ui/dist(存在时挂载;本地开发期可无)。
# 2026-08-25 PM 修复:dist 路径必须基于项目根解析(BFF 工作目录是 sdk/,
# 相对路径会解析成 sdk/ui/dist);sync.sh 排除 dist,需单独同步。
project_root = Path(__file__).resolve().parent.parent.parent
dist = project_root / settings.frontend_dist_dir if not Path(settings.frontend_dist_dir).is_absolute() else Path(settings.frontend_dist_dir)
if dist.is_dir():
app.mount("/", StaticFiles(directory=str(dist), html=True), name="frontend")
return app
app = create_app()