Files
tps-dashboard/backend/app/api/knowledge.py
T
simonkoson 8be51ebbde feat: 知识库笔记工坊立项 + contributor 功能 + Fable5 视角文档
- 知识库笔记工坊子项目立项:PRD v1.0 + 寄存条 + CLAUDE.md 登记
- 后端:知识库上传记录 contributor、新增 /contributors 接口
- 前端:知识库列表支持按贡献人筛选
- 新增 Fable5 视角模式库/案例集/建议文档

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-07-10 18:06:42 +08:00

149 lines
4.6 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.
"""
知识库 API — 上传 / 列表 / 删除 / 来源筛选 / 语义搜索
"""
from typing import Optional
from pydantic import BaseModel
from fastapi import APIRouter, Depends, HTTPException, UploadFile, File, Query, status
from sqlmodel import Session
from app.core.deps import get_current_user, require_role
from app.db.session import get_session
from app.models.user import User, UserRole
from app.services.knowledge_service import KnowledgeService
router = APIRouter(prefix="/api/knowledge", tags=["知识库"])
@router.post("/upload")
async def upload_md_files(
files: list[UploadFile] = File(...),
session: Session = Depends(get_session),
current_user: User = Depends(require_role(UserRole.zhipianren, UserRole.zebian)),
):
"""
上传单个或多个 .md 文件,解析 frontmatter,写入知识库(含向量)。
仅制片人/责编可用。
"""
svc = KnowledgeService()
results = []
errors = []
for f in files:
if not f.filename.endswith(".md"):
errors.append({"file": f.filename, "error": "仅支持 .md 文件"})
continue
try:
content = await f.read()
item = svc.store_md_file(content, f.filename, contributor=current_user.display_name or current_user.username)
results.append({
"id": item.id,
"title": item.title,
"source_type": item.source_type,
})
except Exception as e:
errors.append({"file": f.filename, "error": str(e)})
return {"uploaded": results, "errors": errors}
@router.get("/items")
def list_knowledge_items(
source_type: Optional[str] = Query(None),
session: Session = Depends(get_session),
current_user: User = Depends(require_role(UserRole.zhipianren, UserRole.zebian, UserRole.biandao)),
):
"""
知识库列表,支持按 source_type 筛选。三角色均可读。
"""
svc = KnowledgeService()
items = svc.list_items(source_type=source_type)
return items
@router.delete("/items/{item_id}")
def delete_knowledge_item(
item_id: int,
session: Session = Depends(get_session),
current_user: User = Depends(require_role(UserRole.zhipianren, UserRole.zebian)),
):
"""
删除知识库条目(级联删除向量)。仅制片人/责编可用。
"""
svc = KnowledgeService()
deleted = svc.delete_item(item_id)
if not deleted:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="条目不存在")
return {"message": "删除成功"}
@router.get("/sources")
def list_distinct_sources(
session: Session = Depends(get_session),
current_user: User = Depends(require_role(UserRole.zhipianren, UserRole.zebian, UserRole.biandao)),
):
"""
返回库里所有不重复的具体出处(source_detail),供来源筛选下拉动态生成。
三角色均可读。
"""
svc = KnowledgeService()
sources = svc.get_distinct_sources()
return [{"source": s} for s in sources]
@router.get("/contributors")
def list_distinct_contributors(
session: Session = Depends(get_session),
current_user: User = Depends(require_role(UserRole.zhipianren, UserRole.zebian, UserRole.biandao)),
):
svc = KnowledgeService()
contributors = svc.get_distinct_contributors()
return [{"contributor": c} for c in contributors]
@router.get("/grouped")
def get_grouped_knowledge_items(
session: Session = Depends(get_session),
current_user: User = Depends(require_role(UserRole.zhipianren, UserRole.zebian, UserRole.biandao)),
):
"""
返回按 source_type → source_detail 两层聚合的树形结构,
含「全部」根节点,供知识库树形导航使用。
三角色均可读。
"""
svc = KnowledgeService()
return svc.get_grouped_items()
class SearchRequest(BaseModel):
query: str
top_k: int = 10
min_similarity: float = 0.3
@router.post("/search")
def search_knowledge(
body: SearchRequest,
session: Session = Depends(get_session),
current_user: User = Depends(require_role(UserRole.zhipianren, UserRole.zebian, UserRole.biandao)),
):
"""
语义检索:输入一段文字,返回最相关的知识库条目及相似度。
查询向量用 type="query"(区分于存入时的 type="db")。
top_k 默认 10min_similarity 默认 0.3 过滤低相关条目。
三角色均可读。
"""
svc = KnowledgeService()
results = svc.search_similar(
query_text=body.query,
top_k=body.top_k,
min_similarity=body.min_similarity,
)
return {
"results": results,
"query": body.query,
"count": len(results),
}