Files
PlantAI-rag-new/sdk/app/routers/kg.py
T
jerryandClaude Fable 5 0875bb036c P0/M1: 四部分重构——frontend→ui、backend→sdk 改名 + 引用修复 + 骨架
- git mv 保留历史:ui/(Vue3+Vite)、sdk/(BFF 中间层)
- 路径语义修正:db_path/figures_cache 改相对 sdk/(BFF cwd),
  历史库 sdk/backend/data 迁移至 sdk/data/(会话/图片缓存无损)
- 引用修复 ~15 处:config.py、deploy/*.sh、vitest/playwright 配置、
  单测导入路径、docs、README、gitignore、.env.example
- 骨架:agent/{qa,methodology,legacy-rag,vendor}、knowledge/manifest.yaml、
  tooling/{compile,kb,crypto,assemble,audit,tools,scripts} + README
- 门禁验证:sdk pytest 125 通过、ui vitest 158 通过、
  生产 BFF 脚本重启四上游全绿 + 静态托管 + 会话库无损

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 12:56:47 +08:00

106 lines
2.8 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.
"""routers/kg.py —— 知识图谱浏览(BFF Bolt 直连 Neo4j,API.md §6)。
Neo4j 不可用 → 503 UPSTREAM_DOWN 降级信封;未命中实体 → 404 NOT_FOUND。
错误信封与 mock_server 一致:直接返回 JSONResponse,信封在顶层
(不用 HTTPException,避免被 FastAPI 包成 {"detail": {...}})。
"""
from __future__ import annotations
import logging
from typing import Any
from fastapi import APIRouter, Query
from fastapi.responses import JSONResponse
from ..services import neo4j as _neo4j
from ..services.neo4j import Neo4jUnavailable
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api/kg", tags=["kg"])
_UPSTREAM_DOWN_MSG = "知识图谱服务当前不可用,请稍后重试"
def _down(exc: BaseException | None = None) -> JSONResponse:
logger.warning("kg: Neo4j 不可用:%s", exc)
return JSONResponse(
status_code=503,
content={
"ok": False,
"error": {
"code": "UPSTREAM_DOWN",
"message": _UPSTREAM_DOWN_MSG,
"degraded": True,
},
},
)
def _not_found() -> JSONResponse:
return JSONResponse(
status_code=404,
content={
"ok": False,
"error": {
"code": "NOT_FOUND",
"message": "未找到该实体",
"degraded": False,
},
},
)
@router.get("/status")
async def kg_status():
try:
return await _neo4j.service.kg_status()
except Neo4jUnavailable as exc:
return _down(exc)
@router.get("/overview")
async def kg_overview():
try:
return await _neo4j.service.kg_overview()
except Neo4jUnavailable as exc:
return _down(exc)
@router.get("/entities")
async def kg_entities(
q: str = Query("", description="实体名(name_norm 精确或前缀匹配)"),
limit: int = Query(20, ge=1, le=20),
) -> dict[str, Any]:
try:
results = await _neo4j.service.search_entities(q, limit=limit)
except Neo4jUnavailable as exc:
return _down(exc)
return {"query": q, "results": results}
@router.get("/entities/{entity_id}")
async def kg_entity(entity_id: str) -> dict[str, Any]:
try:
entity = await _neo4j.service.entity(entity_id)
except Neo4jUnavailable as exc:
return _down(exc)
if entity is None:
return _not_found()
return entity
@router.get("/entities/{entity_id}/neighborhood")
async def kg_neighborhood(
entity_id: str,
depth: int = Query(1, ge=1, le=2),
limit: int = Query(50, ge=1, le=200),
) -> dict[str, Any]:
try:
result = await _neo4j.service.neighborhood(entity_id, depth=depth, limit=limit)
except Neo4jUnavailable as exc:
return _down(exc)
if result.get("center") is None:
return _not_found()
return result