Files
tps-dashboard/backend/app/api/knowledge.py
T
simonkoson db9d10a795 feat: Obsidian 知识库批量导入 + 语义搜索体验升级
- 新增 import_obsidian_kb.py 批量导入脚本(164篇入库,知识库186条)
- parse_md_file 补强:来源fallback、相关装备/应用领域实体提取、
  Obsidian双链去括号、原始类别/源文件路径存metadata、TYPE_MAP扩充
- search_similar 改进:智能摘要(中文2-gram拆词+加权段落匹配)、
  min_similarity=0.3过滤、top_k 5→10、返回完整content_md
- 前端搜索卡片升级:展开全文、关键词加粗渲染、相关度分档样式
- CLAUDE.md 状态更新

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-07-08 15:26:17 +08:00

139 lines
4.2 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)
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("/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),
}