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
+50 -4
View File
@@ -5,13 +5,14 @@ from pathlib import Path
import structlog
from fastapi import FastAPI, Request
from fastapi.exceptions import RequestValidationError
from fastapi.responses import FileResponse, JSONResponse
from fastapi.responses import FileResponse, JSONResponse, RedirectResponse
from app.api.response import ApiError, error
from app.api.v1.auth import router as auth_router
from app.api.v1.document import router as document_router
from app.api.v1.knowledge import router as knowledge_router
from app.api.v1.search import router as search_router
from app.api.v1.settings import router as settings_router
from app.config import settings
from app.core.auth import ensure_default_admin
from app.services.qdrant import QdrantService
@@ -53,6 +54,7 @@ app.include_router(auth_router)
app.include_router(search_router)
app.include_router(document_router)
app.include_router(knowledge_router)
app.include_router(settings_router)
@app.exception_handler(ApiError)
@@ -84,10 +86,54 @@ async def health() -> dict[str, str]:
return {"status": "ok"}
_ADMIN_HTML = Path(__file__).resolve().parent / "static" / "admin.html"
_STATIC_DIR = Path(__file__).resolve().parent / "static"
_ADMIN_HTML = _STATIC_DIR / "admin.html"
_ADMIN_SPA_DIR = _STATIC_DIR / "admin"
def _spa_index() -> Path | None:
"""SPA 入口文件路径;不存在返回 None(回退旧 admin.html"""
index = _ADMIN_SPA_DIR / "index.html"
return index if index.is_file() else None
@app.get("/admin", include_in_schema=False)
async def admin_page() -> FileResponse:
"""管理后台单页(单文件静态 HTML,零外部依赖)"""
async def admin_page():
"""管理后台:优先服务 Vue SPA,回退到旧单文件 admin.html"""
spa = _spa_index()
if spa is not None:
return FileResponse(spa, media_type="text/html")
return FileResponse(_ADMIN_HTML, media_type="text/html")
@app.get("/admin/", include_in_schema=False)
async def admin_page_trailing_slash():
"""带斜杠的 /admin/ 重定向到 /admin"""
return RedirectResponse(url="/admin", status_code=307)
@app.get("/admin/{rest:path}", include_in_schema=False)
async def admin_spa(rest: str):
"""SPA 静态资源与客户端路由兜底
- 真实文件(assets/*.js, *.css 等)→ 直接返回
- 其余路径(/overview, /documents 等客户端路由)→ 返回 index.html
- SPA 目录不存在时 → 404(旧 admin.html 无子路由需求)
"""
spa_dir = _ADMIN_SPA_DIR
if not spa_dir.is_dir():
return JSONResponse(
status_code=404, content={"code": 1002, "message": "Not found"}
)
# 安全校验:防止路径越界
file_path = (spa_dir / rest).resolve()
try:
file_path.relative_to(spa_dir.resolve())
except ValueError:
return FileResponse(spa_dir / "index.html", media_type="text/html")
if file_path.is_file():
return FileResponse(file_path)
# SPA 客户端路由兜底
return FileResponse(spa_dir / "index.html", media_type="text/html")