merge: T6 知识库实体与图谱(T-P2-01/05)
This commit is contained in:
+115
-3
@@ -1,10 +1,122 @@
|
||||
"""知识库实体路由(骨架,T6 填充实现)。
|
||||
"""kb 实体路由(FR-KB-01/02/05):实体 CRUD + 状态机 + 1~3 跳图谱查询。
|
||||
|
||||
GET /kb/items 等;实现契约见 docs/开发任务包/T6-知识库实体与图谱.md。
|
||||
写接口暂不挂鉴权以外的前置(后台运营角色属 T-P2-09,先 ``CurrentUserId``,
|
||||
``updated_by`` 记录操作者)。统一信封见架构文档 §9.2;跨域响应模型在
|
||||
``packages/kb/schemas.py``(``apps/api/schemas.py`` 本轮禁改)。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
|
||||
from apps.api.deps import CurrentUserId, SessionDep
|
||||
from packages.kb.schemas import (
|
||||
MAX_GRAPH_HOPS,
|
||||
EntityCreate,
|
||||
EntityOut,
|
||||
EntityStatus,
|
||||
EntityType,
|
||||
EntityUpdate,
|
||||
)
|
||||
from packages.kb.service import KbService
|
||||
from packages.shared.models import KbEntity
|
||||
from packages.shared.response import ok
|
||||
|
||||
router = APIRouter(prefix="/kb", tags=["kb"])
|
||||
|
||||
|
||||
def kb_service_dep(session: SessionDep) -> KbService:
|
||||
"""``apps/api/deps.py`` 本轮禁改,kb 的服务装配放路由文件内就近完成。"""
|
||||
return KbService(session)
|
||||
|
||||
|
||||
KbServiceDep = Annotated[KbService, Depends(kb_service_dep)]
|
||||
|
||||
|
||||
def _serialize(entity: KbEntity) -> dict[str, object]:
|
||||
return EntityOut(
|
||||
entity_id=str(entity.entity_id),
|
||||
entity_type=entity.entity_type,
|
||||
name=entity.name,
|
||||
attrs=dict(entity.attrs),
|
||||
status=entity.status,
|
||||
version=entity.version,
|
||||
source=entity.source,
|
||||
license=entity.license,
|
||||
updated_by=entity.updated_by,
|
||||
created_at=entity.created_at,
|
||||
updated_at=entity.updated_at,
|
||||
).model_dump()
|
||||
|
||||
|
||||
@router.get("/items", summary="实体列表:entity_type / status 过滤 + 名称模糊 + 分页")
|
||||
async def list_items(
|
||||
user_id: CurrentUserId,
|
||||
kb: KbServiceDep,
|
||||
entity_type: EntityType | None = Query(default=None, description="12 类本体之一"),
|
||||
status: EntityStatus | None = Query(default=None),
|
||||
name: str | None = Query(default=None, max_length=128, description="名称模糊匹配"),
|
||||
limit: int = Query(default=20, ge=1, le=100),
|
||||
offset: int = Query(default=0, ge=0),
|
||||
) -> dict[str, object]:
|
||||
rows, total = await kb.search_entities(
|
||||
entity_type=entity_type,
|
||||
status=status,
|
||||
name_ilike=name,
|
||||
limit=limit,
|
||||
offset=offset,
|
||||
)
|
||||
return ok(
|
||||
{
|
||||
"items": [_serialize(row) for row in rows],
|
||||
"total": total,
|
||||
"limit": limit,
|
||||
"offset": offset,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@router.post("/items", summary="新建实体(draft / version=1 起步)")
|
||||
async def create_entity(
|
||||
payload: EntityCreate,
|
||||
user_id: CurrentUserId,
|
||||
kb: KbServiceDep,
|
||||
) -> dict[str, object]:
|
||||
entity = await kb.create_entity(payload=payload, updated_by=str(user_id))
|
||||
return ok(_serialize(entity))
|
||||
|
||||
|
||||
@router.get("/items/{entity_id}", summary="实体详情")
|
||||
async def get_entity(
|
||||
entity_id: int,
|
||||
user_id: CurrentUserId,
|
||||
kb: KbServiceDep,
|
||||
) -> dict[str, object]:
|
||||
entity = await kb.get_entity(entity_id=entity_id)
|
||||
return ok(_serialize(entity))
|
||||
|
||||
|
||||
@router.patch("/items/{entity_id}", summary="修改内容(draft/reviewing)或推进状态(状态机校验)")
|
||||
async def update_entity(
|
||||
entity_id: int,
|
||||
payload: EntityUpdate,
|
||||
user_id: CurrentUserId,
|
||||
kb: KbServiceDep,
|
||||
) -> dict[str, object]:
|
||||
entity = await kb.update_entity(entity_id=entity_id, payload=payload, updated_by=str(user_id))
|
||||
return ok(_serialize(entity))
|
||||
|
||||
|
||||
@router.get("/items/{entity_id}/graph", summary="从该实体出发的 1~3 跳可解释路径(T-P2-05)")
|
||||
async def get_entity_graph(
|
||||
entity_id: int,
|
||||
user_id: CurrentUserId,
|
||||
kb: KbServiceDep,
|
||||
max_hops: int = Query(
|
||||
default=MAX_GRAPH_HOPS, ge=1, le=MAX_GRAPH_HOPS, description="遍历深度 1~3,超界 422"
|
||||
),
|
||||
) -> dict[str, object]:
|
||||
result = await kb.traverse_graph(entity_id=entity_id, max_hops=max_hops)
|
||||
return ok(result.model_dump())
|
||||
|
||||
Reference in New Issue
Block a user