- Introduce a new model structure for managing interface definitions and model resources, enhancing the backend's capability to handle various service integrations. - Update the Makefile to reflect changes in database seeding and resource management commands. - Remove the deprecated credentials management routes and replace them with a unified model registry API. - Modify existing routes and schemas to align with the new model structure, ensuring seamless integration with the frontend. - Enhance database seeding scripts to populate new model resources and their configurations. - Update README documentation to reflect the new architecture and usage instructions for model resources and interface definitions.
103 lines
3.3 KiB
Python
103 lines
3.3 KiB
Python
"""知识库 CRUD。前端助手编辑页的"知识库"下拉对接这里。
|
|
|
|
KB 自身引用一个 Embedding 模型资源。被助手引用时禁止删除
|
|
(DB 层 ON DELETE RESTRICT),这里把外键冲突翻译成 409。
|
|
"""
|
|
|
|
import uuid
|
|
|
|
from db.models import KnowledgeBase, ModelResource
|
|
from db.session import get_session
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from schemas import KnowledgeBaseOut, KnowledgeBaseUpsert
|
|
from sqlalchemy import select
|
|
from sqlalchemy.exc import IntegrityError
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
router = APIRouter(prefix="/api/knowledge-bases", tags=["knowledge-bases"])
|
|
|
|
|
|
async def _validate_embedding_resource(
|
|
session: AsyncSession, resource_id: str | None
|
|
) -> None:
|
|
if not resource_id:
|
|
return
|
|
resource = await session.get(ModelResource, resource_id)
|
|
if not resource or resource.capability != "Embedding":
|
|
raise HTTPException(400, "知识库必须引用 Embedding 模型资源")
|
|
|
|
|
|
def _to_out(kb: KnowledgeBase) -> KnowledgeBaseOut:
|
|
return KnowledgeBaseOut(
|
|
id=kb.id,
|
|
name=kb.name,
|
|
description=kb.description,
|
|
embedding_model_resource_id=kb.embedding_model_resource_id,
|
|
status=kb.status,
|
|
updated_at=kb.updated_at.isoformat() if kb.updated_at else None,
|
|
)
|
|
|
|
|
|
@router.get("", response_model=list[KnowledgeBaseOut])
|
|
async def list_knowledge_bases(session: AsyncSession = Depends(get_session)):
|
|
rows = (
|
|
await session.execute(select(KnowledgeBase).order_by(KnowledgeBase.name))
|
|
).scalars().all()
|
|
return [_to_out(kb) for kb in rows]
|
|
|
|
|
|
@router.post("", response_model=KnowledgeBaseOut)
|
|
async def create_knowledge_base(
|
|
body: KnowledgeBaseUpsert, session: AsyncSession = Depends(get_session)
|
|
):
|
|
await _validate_embedding_resource(session, body.embedding_model_resource_id)
|
|
kb = KnowledgeBase(id=f"kb_{uuid.uuid4().hex[:12]}", **body.model_dump())
|
|
session.add(kb)
|
|
await session.commit()
|
|
await session.refresh(kb)
|
|
return _to_out(kb)
|
|
|
|
|
|
@router.get("/{kb_id}", response_model=KnowledgeBaseOut)
|
|
async def get_knowledge_base(
|
|
kb_id: str, session: AsyncSession = Depends(get_session)
|
|
):
|
|
kb = await session.get(KnowledgeBase, kb_id)
|
|
if not kb:
|
|
raise HTTPException(404, "知识库不存在")
|
|
return _to_out(kb)
|
|
|
|
|
|
@router.put("/{kb_id}", response_model=KnowledgeBaseOut)
|
|
async def update_knowledge_base(
|
|
kb_id: str,
|
|
body: KnowledgeBaseUpsert,
|
|
session: AsyncSession = Depends(get_session),
|
|
):
|
|
kb = await session.get(KnowledgeBase, kb_id)
|
|
if not kb:
|
|
raise HTTPException(404, "知识库不存在")
|
|
await _validate_embedding_resource(session, body.embedding_model_resource_id)
|
|
for k, v in body.model_dump().items():
|
|
setattr(kb, k, v)
|
|
await session.commit()
|
|
await session.refresh(kb)
|
|
return _to_out(kb)
|
|
|
|
|
|
@router.delete("/{kb_id}")
|
|
async def delete_knowledge_base(
|
|
kb_id: str, session: AsyncSession = Depends(get_session)
|
|
):
|
|
kb = await session.get(KnowledgeBase, kb_id)
|
|
if not kb:
|
|
raise HTTPException(404, "知识库不存在")
|
|
try:
|
|
await session.delete(kb)
|
|
await session.commit()
|
|
except IntegrityError:
|
|
# 被助手引用(ON DELETE RESTRICT):先解绑再删
|
|
await session.rollback()
|
|
raise HTTPException(409, "知识库正被助手引用,无法删除")
|
|
return {"ok": True}
|