feat: 完成全量功能开发,包括前端管理后台与后端服务优化

此提交实现了完整的知识库管理系统:
1. 新增Vue3 + Antd Vue前端管理后台,包含登录、文档管理、检索、类目设置等完整页面
2. 重构后端LLM调用抽象层,支持Ollama与OpenAI兼容服务动态切换
3. 调整默认嵌入模型配置为本地bge-m3模式
4. 优化入库任务去重逻辑与缓存清理机制
5. 完善Docker镜像构建与docker-compose部署配置
6. 修复多项测试用例与兼容性问题
7. 新增运行时配置API,支持动态调整系统参数
This commit is contained in:
2026-07-31 12:05:25 +08:00
parent fdb664e546
commit 2ab8b56a01
52 changed files with 7030 additions and 171 deletions
+114
View File
@@ -0,0 +1,114 @@
"""运行时配置 APIGET/PUT /api/v1/settings、GET /api/v1/settings/schema、POST /api/v1/settings/reset
GET 任何登录用户可读;PUT/reset 需 admin。PUT 后会清空 LLM 客户端 / 解析插件 /
去重策略三处进程级缓存,使新配置立即对后续请求生效。
"""
from typing import Any
import structlog
from fastapi import APIRouter, Depends
from pydantic import BaseModel
from app.api.response import ApiError, ok
from app.core.auth import AuthUser, get_current_user, require_admin
from app.core.dedup import invalidate_dedup_strategy_cache
from app.core.file_parser import (
list_docx_plugins,
list_ocr_plugins,
list_pdf_plugins,
invalidate_parser_plugin_cache,
)
from app.core.runtime_settings import (
RuntimeSettings,
get_runtime_settings,
reset_runtime_settings,
update_runtime_settings,
)
from app.services.llm import invalidate_llm_client_cache
logger = structlog.get_logger()
router = APIRouter(prefix="/api/v1", tags=["settings"])
class SettingsUpdateRequest(BaseModel):
"""Settings PATCH body:任意子树可缺省,缺省字段保留原值
例:{"models": {"summarize": {"model": "qwen2.5:3b"}}}、
{"parsers": {"ocr": {"plugin": "tesseract"}}}、
{"dedup": {"strategy": "simhash", "simhash_threshold": 5}}
"""
models: dict[str, Any] | None = None
parsers: dict[str, Any] | None = None
dedup: dict[str, Any] | None = None
@router.get("/settings")
async def get_settings(user: AuthUser = Depends(get_current_user)) -> dict[str, Any]:
"""返回当前 RuntimeSettings(任何登录用户可读)"""
cfg = get_runtime_settings()
return ok(cfg.model_dump(mode="json"))
@router.put("/settings")
async def update_settings(
body: SettingsUpdateRequest,
user: AuthUser = Depends(require_admin),
) -> dict[str, Any]:
"""部分更新 RuntimeSettings(仅 admin
更新成功后清空 LLM 客户端 / 解析插件 / 去重策略三处进程级缓存,
使新配置立即对后续请求生效。
"""
patch = body.model_dump(exclude_none=True)
if not patch:
raise ApiError(1001, "请求体为空,未提供任何待更新字段")
try:
cfg = update_runtime_settings(patch)
except Exception as exc:
logger.error("RuntimeSettings 更新失败", error=str(exc), exc_info=True)
raise ApiError(2000, f"配置更新失败: {exc}") from exc
# 清缓存:让后续读取拿到新配置
invalidate_llm_client_cache()
invalidate_parser_plugin_cache()
invalidate_dedup_strategy_cache()
logger.info("RuntimeSettings 已更新并清理缓存", operator=user.username)
return ok(cfg.model_dump(mode="json"))
@router.get("/settings/schema")
async def get_settings_schema(
user: AuthUser = Depends(get_current_user),
) -> dict[str, Any]:
"""返回可选插件与策略列表(前端 Settings 页渲染选项用)"""
return ok(
{
"llm_providers": ["ollama", "openai_compatible"],
"pdf_plugins": list_pdf_plugins(),
"docx_plugins": list_docx_plugins(),
"ocr_plugins": list_ocr_plugins(),
"dedup_strategies": ["none", "sha256", "simhash"],
}
)
@router.post("/settings/reset")
async def reset_settings(
user: AuthUser = Depends(require_admin),
) -> dict[str, Any]:
"""重置 RuntimeSettings 为默认值(仅 admin),同时清缓存"""
try:
cfg = reset_runtime_settings()
except Exception as exc:
logger.error("RuntimeSettings 重置失败", error=str(exc), exc_info=True)
raise ApiError(2000, f"配置重置失败: {exc}") from exc
invalidate_llm_client_cache()
invalidate_parser_plugin_cache()
invalidate_dedup_strategy_cache()
logger.info("RuntimeSettings 已重置为默认值", operator=user.username)
return ok(cfg.model_dump(mode="json"))