from fastapi import APIRouter, Depends, HTTPException, Query from pydantic import BaseModel from typing import Optional import aiosqlite from database import get_db router = APIRouter(prefix="/api/knowledge", tags=["knowledge"]) class KnowledgePatch(BaseModel): content: str @router.get("") async def list_knowledge( keyword: Optional[str] = None, db: aiosqlite.Connection = Depends(get_db) ): if keyword: # FTS5 查询前先用 jieba 分词,提高中文召回率 from services.fts import build_match_query fts_query = build_match_query(keyword) if not fts_query: return [] async with db.execute( "SELECT k.id, k.topic_id, k.created_at, k.updated_at, t.title, t.group_id, g.name as group_name " "FROM knowledge_docs k JOIN topics t ON k.topic_id=t.id " "LEFT JOIN groups g ON t.group_id=g.id " "WHERE k.id IN (SELECT doc_id FROM knowledge_fts WHERE knowledge_fts MATCH ?)", (fts_query,) ) as cur: return [dict(r) for r in await cur.fetchall()] async with db.execute( "SELECT k.id, k.topic_id, k.created_at, k.updated_at, t.title, t.group_id, g.name as group_name " "FROM knowledge_docs k JOIN topics t ON k.topic_id=t.id " "LEFT JOIN groups g ON t.group_id=g.id " "ORDER BY g.name, k.updated_at DESC" ) as cur: return [dict(r) for r in await cur.fetchall()] @router.get("/{doc_id}") async def get_knowledge(doc_id: int, db: aiosqlite.Connection = Depends(get_db)): async with db.execute("SELECT * FROM knowledge_docs WHERE id=?", (doc_id,)) as cur: row = await cur.fetchone() if not row: raise HTTPException(404, "not found") return dict(row) @router.patch("/{doc_id}") async def patch_knowledge(doc_id: int, body: KnowledgePatch, db: aiosqlite.Connection = Depends(get_db)): await db.execute( "UPDATE knowledge_docs SET content=?, updated_at=CURRENT_TIMESTAMP, curated_at=CURRENT_TIMESTAMP WHERE id=?", (body.content, doc_id) ) await db.commit() # update FTS async with db.execute("SELECT topic_id FROM knowledge_docs WHERE id=?", (doc_id,)) as cur: row = await cur.fetchone() if row: async with db.execute("SELECT title FROM topics WHERE id=?", (row["topic_id"],)) as cur: topic = await cur.fetchone() await db.execute("DELETE FROM knowledge_fts WHERE doc_id=?", (doc_id,)) from services.fts import tokenize await db.execute( "INSERT INTO knowledge_fts (doc_id, title, content) VALUES (?, ?, ?)", (doc_id, tokenize(topic["title"]), tokenize(body.content)) ) await db.commit() return {"ok": True}