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
+29 -11
View File
@@ -111,10 +111,17 @@ def test_parse_file_no_extension_raises() -> None:
parse_file("noext", b"text")
def test_parse_file_corrupted_pdf_raises() -> None:
"""损坏的 PDF 抛 ValueErrormessage 含'文件解析失败'"""
with pytest.raises(ValueError, match=r"文件解析失败"):
parse_file("bad.pdf", b"not a real pdf")
def test_parse_file_corrupted_pdf_returns_empty(
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""损坏的 PDF:插件化后文本层提取失败被捕获,OCR 关闭时返回空字符串
原 test_parse_file_corrupted_pdf_raises 期望 ValueError,但插件化重构后
file_parser 设计为优雅降级(pypdf 失败 → OCR 兜底 → 都失败返回空),
不再向上抛异常。关闭 OCR 避免触发 rapidocr 模型下载拖慢测试。
"""
monkeypatch.setattr(settings, "pdf_ocr_enabled", False)
assert parse_file("bad.pdf", b"not a real pdf") == ""
def test_parse_file_empty_html_returns_empty_string() -> None:
@@ -152,12 +159,23 @@ def test_supported_extensions_contains_expected_set() -> None:
@pytest.fixture(autouse=True)
def _reset_ocr_state() -> Any:
"""每个 OCR 测试前后重置模块级 OCR 引擎状态,避免相互污染"""
saved_engine = fp_module._ocr_engine
saved_unavailable = fp_module._ocr_unavailable
"""每个 OCR 测试前后重置 RapidocrOcrEngine/TesseractOcrEngine 类级状态与插件缓存
file_parser 插件化后,模块级 _ocr_engine/_ocr_unavailable 已移除,
RapidocrOcrEngine 用类级字段 _engine/_unavailable 单例化。
测试前重置为干净状态(避免上个测试残留),测试后清理插件缓存。
"""
# 测试前:重置为干净状态
fp_module.RapidocrOcrEngine._engine = None
fp_module.RapidocrOcrEngine._unavailable = False
fp_module.TesseractOcrEngine._unavailable = False
fp_module._ocr_plugin_cache.clear()
yield
fp_module._ocr_engine = saved_engine
fp_module._ocr_unavailable = saved_unavailable
# 测试后:再次清理,避免污染后续非 OCR 测试
fp_module.RapidocrOcrEngine._engine = None
fp_module.RapidocrOcrEngine._unavailable = False
fp_module.TesseractOcrEngine._unavailable = False
fp_module._ocr_plugin_cache.clear()
class _FakeTextPage:
@@ -281,7 +299,7 @@ def test_parse_pdf_ocr_returns_empty_when_dependency_unavailable(
monkeypatch.setattr(settings, "pdf_ocr_enabled", True)
assert parse_file("scan.pdf", b"fake pdf bytes") == ""
assert fp_module._ocr_unavailable is True
assert fp_module.RapidocrOcrEngine._unavailable is True
def test_parse_pdf_ocr_runtime_exception_falls_back_to_empty(
@@ -324,4 +342,4 @@ def test_parse_pdf_text_layer_present_skips_ocr(
result = parse_file("text.pdf", b"fake pdf bytes")
assert result == "这是文本层的内容"
assert fp_module._ocr_engine is None
assert fp_module.RapidocrOcrEngine._engine is None