feat(server): 扩展知识库服务,添加knowledge API端点和schema定义,前端新增knowledge服务模块
This commit is contained in:
@@ -1,21 +1,33 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import UTC, datetime
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Body, Depends, HTTPException, Query, status
|
||||
from fastapi.responses import FileResponse
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.api.deps import CurrentUserContext, get_current_user, require_admin_user
|
||||
from app.api.deps import CurrentUserContext, get_current_user, get_db, require_admin_user
|
||||
from app.core.agent_enums import AgentName, AgentPermissionLevel, AgentRunSource, AgentRunStatus
|
||||
from app.models.agent_asset import AgentAsset
|
||||
from app.schemas.common import ErrorResponse
|
||||
from app.schemas.knowledge import (
|
||||
KnowledgeActionResponse,
|
||||
KnowledgeDocumentDetailRead,
|
||||
KnowledgeLibraryRead,
|
||||
LlmWikiDocumentDetailRead,
|
||||
LlmWikiIndexRead,
|
||||
LlmWikiSummaryUpdateWrite,
|
||||
KnowledgeOnlyOfficeCallbackRead,
|
||||
KnowledgeOnlyOfficeCallbackWrite,
|
||||
KnowledgeOnlyOfficeConfigRead,
|
||||
LlmWikiSyncRead,
|
||||
LlmWikiSyncWrite,
|
||||
)
|
||||
from app.services.agent_runs import AgentRunService
|
||||
from app.services.knowledge import KnowledgeService
|
||||
from app.services.llm_wiki import LlmWikiService
|
||||
|
||||
router = APIRouter(prefix="/knowledge")
|
||||
|
||||
@@ -38,6 +50,176 @@ def get_knowledge_library(
|
||||
return KnowledgeService().list_library()
|
||||
|
||||
|
||||
@router.get(
|
||||
"/llm-wiki",
|
||||
response_model=LlmWikiIndexRead,
|
||||
summary="查询 LLM Wiki 索引",
|
||||
description="返回知识库解析目录中的文档索引和同步次数,仅供管理员查看知识候选与规则候选草稿。",
|
||||
responses={
|
||||
status.HTTP_401_UNAUTHORIZED: {
|
||||
"model": ErrorResponse,
|
||||
"description": "未提供知识库访问用户头。",
|
||||
},
|
||||
status.HTTP_403_FORBIDDEN: {
|
||||
"model": ErrorResponse,
|
||||
"description": "只有管理员可以查看 LLM Wiki 草稿内容。",
|
||||
},
|
||||
},
|
||||
)
|
||||
def get_llm_wiki_index(
|
||||
_: Annotated[CurrentUserContext, Depends(require_admin_user)],
|
||||
db: Annotated[Session, Depends(get_db)],
|
||||
) -> LlmWikiIndexRead:
|
||||
return LlmWikiService(db).get_index()
|
||||
|
||||
|
||||
@router.get(
|
||||
"/llm-wiki/documents/{document_id}",
|
||||
response_model=LlmWikiDocumentDetailRead,
|
||||
summary="读取 LLM Wiki 文档解析结果",
|
||||
description="返回指定知识文档的解析文本、分块、知识候选与规则候选,仅供管理员查看。",
|
||||
responses={
|
||||
status.HTTP_401_UNAUTHORIZED: {
|
||||
"model": ErrorResponse,
|
||||
"description": "未提供知识库访问用户头。",
|
||||
},
|
||||
status.HTTP_403_FORBIDDEN: {
|
||||
"model": ErrorResponse,
|
||||
"description": "只有管理员可以查看 LLM Wiki 草稿内容。",
|
||||
},
|
||||
status.HTTP_404_NOT_FOUND: {
|
||||
"model": ErrorResponse,
|
||||
"description": "指定文档尚未生成 LLM Wiki。",
|
||||
},
|
||||
},
|
||||
)
|
||||
def get_llm_wiki_document_detail(
|
||||
document_id: str,
|
||||
_: Annotated[CurrentUserContext, Depends(require_admin_user)],
|
||||
db: Annotated[Session, Depends(get_db)],
|
||||
) -> LlmWikiDocumentDetailRead:
|
||||
try:
|
||||
return LlmWikiService(db).get_document_detail(document_id)
|
||||
except FileNotFoundError as exc:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="指定文档尚未生成 LLM Wiki。") from exc
|
||||
|
||||
|
||||
@router.patch(
|
||||
"/llm-wiki/documents/{document_id}",
|
||||
response_model=LlmWikiDocumentDetailRead,
|
||||
summary="更新 LLM Wiki 知识总结",
|
||||
description="管理员可修改指定知识文档的 LLM Wiki 知识总结预览,不直接改动原始文件。",
|
||||
responses={
|
||||
status.HTTP_401_UNAUTHORIZED: {
|
||||
"model": ErrorResponse,
|
||||
"description": "未提供知识库访问用户头。",
|
||||
},
|
||||
status.HTTP_403_FORBIDDEN: {
|
||||
"model": ErrorResponse,
|
||||
"description": "只有管理员可以修改 LLM Wiki 草稿内容。",
|
||||
},
|
||||
status.HTTP_404_NOT_FOUND: {
|
||||
"model": ErrorResponse,
|
||||
"description": "指定文档尚未生成 LLM Wiki。",
|
||||
},
|
||||
},
|
||||
)
|
||||
def update_llm_wiki_document_summary(
|
||||
document_id: str,
|
||||
payload: LlmWikiSummaryUpdateWrite,
|
||||
_: Annotated[CurrentUserContext, Depends(require_admin_user)],
|
||||
db: Annotated[Session, Depends(get_db)],
|
||||
) -> LlmWikiDocumentDetailRead:
|
||||
try:
|
||||
return LlmWikiService(db).update_document_summary(document_id, payload)
|
||||
except FileNotFoundError as exc:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="指定文档尚未生成 LLM Wiki。") from exc
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@router.post(
|
||||
"/llm-wiki/sync",
|
||||
response_model=LlmWikiSyncRead,
|
||||
summary="触发 Hermes 形成 LLM Wiki 与规则草稿",
|
||||
description="按知识库文档变化情况增量触发系统 Hermes,形成知识候选和规则草稿。",
|
||||
responses={
|
||||
status.HTTP_401_UNAUTHORIZED: {
|
||||
"model": ErrorResponse,
|
||||
"description": "未提供知识库访问用户头。",
|
||||
},
|
||||
status.HTTP_403_FORBIDDEN: {
|
||||
"model": ErrorResponse,
|
||||
"description": "只有管理员可以触发 LLM Wiki 同步。",
|
||||
},
|
||||
},
|
||||
)
|
||||
def sync_llm_wiki(
|
||||
payload: LlmWikiSyncWrite,
|
||||
current_user: Annotated[CurrentUserContext, Depends(require_admin_user)],
|
||||
db: Annotated[Session, Depends(get_db)],
|
||||
) -> LlmWikiSyncRead:
|
||||
run_service = AgentRunService(db)
|
||||
task_asset = db.scalar(
|
||||
select(AgentAsset).where(AgentAsset.code == "task.hermes.llm_wiki_rule_formation")
|
||||
)
|
||||
run = run_service.create_run(
|
||||
agent=AgentName.HERMES.value,
|
||||
source=AgentRunSource.SCHEDULE.value,
|
||||
user_id=current_user.username,
|
||||
task_id=task_asset.id if task_asset is not None else None,
|
||||
permission_level=AgentPermissionLevel.READ.value,
|
||||
status=AgentRunStatus.RUNNING.value,
|
||||
result_summary="Hermes 正在形成 LLM Wiki 与规则草稿。",
|
||||
)
|
||||
|
||||
try:
|
||||
result = LlmWikiService(db).sync_folder(
|
||||
folder=payload.folder,
|
||||
current_user=current_user,
|
||||
document_ids=payload.document_ids,
|
||||
force=payload.force,
|
||||
)
|
||||
run_service.record_tool_call(
|
||||
run_id=run.run_id,
|
||||
tool_type="llm",
|
||||
tool_name="system_hermes_llm_wiki_sync",
|
||||
request_json=payload.model_dump(),
|
||||
response_json=result.model_dump(),
|
||||
status="succeeded",
|
||||
duration_ms=0,
|
||||
)
|
||||
run_service.update_run(
|
||||
run.run_id,
|
||||
status=AgentRunStatus.SUCCEEDED.value,
|
||||
result_summary=result.summary,
|
||||
finished_at=datetime.now(UTC),
|
||||
)
|
||||
return result
|
||||
except Exception as exc:
|
||||
run_service.record_tool_call(
|
||||
run_id=run.run_id,
|
||||
tool_type="llm",
|
||||
tool_name="system_hermes_llm_wiki_sync",
|
||||
request_json=payload.model_dump(),
|
||||
response_json={"error": str(exc)},
|
||||
status="failed",
|
||||
duration_ms=0,
|
||||
error_message=str(exc),
|
||||
)
|
||||
run_service.update_run(
|
||||
run.run_id,
|
||||
status=AgentRunStatus.FAILED.value,
|
||||
error_message=str(exc),
|
||||
finished_at=datetime.now(UTC),
|
||||
)
|
||||
if isinstance(exc, ValueError):
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc
|
||||
if isinstance(exc, FileNotFoundError):
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
|
||||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@router.get(
|
||||
"/documents/{document_id}",
|
||||
response_model=KnowledgeDocumentDetailRead,
|
||||
|
||||
Reference in New Issue
Block a user