Files
amb_rag/backend/app/services/kb_public_service.py
T
2026-09-01 13:00:36 +08:00

101 lines
3.7 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.
"""公共知识库服务(Phase 10/11/12 统一数据来源)。
HTML/MD/TXT/JSON/搜索全部通过此 Service 获取数据,不各自写查询逻辑。
"""
from app.core.errors import NotFoundError
from app.core.security import hash_token
from app.models.document import Document
from app.models.knowledge_base import KnowledgeBase
from app.repositories.doc_repo import DocumentRepository
from app.repositories.kb_repo import KnowledgeBaseRepository
from sqlalchemy.orm import Session
class KbPublicService:
def __init__(self, session: Session) -> None:
self._session = session
self._kb_repo = KnowledgeBaseRepository(session)
self._doc_repo = DocumentRepository(session)
def get_kb_by_token(self, token: str) -> KnowledgeBase:
"""通过 token 获取知识库。不存在/禁用/删除 → 404。"""
token_hash = hash_token(token)
kb = self._kb_repo.get_by_token_hash(token_hash)
if kb is None or not kb.enabled or kb.status == "DELETED":
raise NotFoundError("知识库不存在。")
return kb
def list_documents(
self, kb: KnowledgeBase, *, page: int = 1, page_size: int = 50
) -> tuple[list[Document], int]:
"""获取知识库的文档列表(仅 READY 状态)。"""
return self._doc_repo.list_by_knowledge_base(
kb.id, page=page, page_size=page_size, status="READY"
)
def get_document_by_token(self, kb: KnowledgeBase, doc_token: str) -> Document:
"""通过 token 获取单个文档。"""
doc_token_hash = hash_token(doc_token)
doc = self._doc_repo.get_by_doc_token_hash(doc_token_hash)
if doc is None or doc.knowledge_base_id != kb.id or doc.status != "READY":
raise NotFoundError("文档不存在。")
return doc
def get_document_markdown(self, doc: Document) -> str:
"""读取文档的 Markdown 内容。"""
from app.storage.local_storage import get_storage
if not doc.markdown_path:
return ""
storage = get_storage()
content = storage.read(doc.markdown_path)
return content.decode("utf-8")
def search_documents(
self, kb: KnowledgeBase, query: str, *, page: int = 1, page_size: int = 20
) -> tuple[list[dict], int]:
"""关键词搜索文档(Phase 12SQLite LIKE / FTS5)。"""
# MVP 简化:使用 LIKE 搜索标题+描述+关键词
from sqlalchemy import func, or_, select
conditions = [
Document.knowledge_base_id == kb.id,
Document.status == "READY",
]
like_pattern = f"%{query}%"
search_condition = or_(
Document.title.like(like_pattern),
Document.description.like(like_pattern),
Document.keywords.like(like_pattern),
Document.content_summary.like(like_pattern),
)
conditions.append(search_condition)
count_stmt = select(func.count()).select_from(Document).where(*conditions)
total = self._session.scalar(count_stmt) or 0
stmt = (
select(Document)
.where(*conditions)
.order_by(Document.created_at.desc())
.offset((page - 1) * page_size)
.limit(page_size)
)
docs = list(self._session.scalars(stmt).all())
results = []
for doc in docs:
results.append({
"id": doc.id,
"title": doc.title or doc.original_filename,
"description": doc.description,
"keywords": doc.keywords,
"file_type": doc.file_ext,
"updated_at": doc.updated_at,
"url_hint": doc.doc_token_hint,
})
return results, total