feat: 新增多格式文件上传入库与认证体系

- 新增 JWT 认证模块,支持登录/注册/用户管理
- 新增文件上传接口,支持 .txt/.md/.html/.pdf/.docx 等格式解析入库
- 新增检索结果 AI 总结功能
- 新增文本去重缓存机制
- 新增全局认证夹具简化测试
- 新增配置项与环境变量支持
- 完善文档与测试覆盖
This commit is contained in:
2026-07-30 10:30:15 +08:00
parent 51dc8dc4f6
commit dce9e31bde
31 changed files with 3021 additions and 45 deletions
@@ -0,0 +1,72 @@
# Checklist
## 多格式文件文本提取
- [x] `app/core/file_parser.py` 存在并实现 `parse_file(filename, content)``supported_extensions()`
- [x] 支持 .txt/.mdUTF-8 解码 errors=replace
- [x] 支持 .html/.htmhtml.parser 剥离 script/style 后提取可见文本)
- [x] 支持 .pdfpypdf 逐页 extract_text 拼接)
- [x] 支持 .docxpython-docx 段落文本拼接)
- [x] 未识别扩展名抛 `ValueError("不支持的文件类型: {ext}")`
- [x] 解析异常包装为 `ValueError("文件解析失败: {detail}")` 并保留原异常链
- [x] `tests/test_file_parser.py` 13 例覆盖各格式 + 异常路径
## 文件上传入库端点
- [x] `POST /api/v1/documents/upload` 端点存在,接收 multipart/form-datafile + title/source/metadata
- [x] 扩展名校验基于 `settings.upload_allowed_extensions`,失败抛 code=1001 含扩展名
- [x] 大小校验基于 `settings.upload_max_size_mb`,失败抛 code=1001 含「大小上限」
- [x] 调用 `parse_file` 提取文本,失败抛 code=1001
- [x] 提取文本为空抛 code=1001 含「无法从文件提取文本」
- [x] 落盘到 `settings.upload_dir`,失败仅 warning 不阻塞入库
- [x] 落盘元数据 raw_file_path/original_filename/original_size_bytes 写入 DocumentInput.metadata
- [x] 用户传入 metadata JSON 解析合并(落盘元数据优先级更高,用 setdefault
- [x] 默认 title 取文件名 stem,默认 source 取 `file:{原文件名}`
- [x] 复用现有 IngestTaskManager.submit 提交异步入库流水线
- [x] 返回 202 + `{code:0, data:{task_id, status:"pending", saved_path}}`
- [x] `tests/test_document_upload_api.py` 10 例覆盖合法上传/不支持扩展名/超大/空文本/损坏 PDF/落盘失败降级/metadata JSON/默认 title/source
## 配置项
- [x] `app/config.py` Settings 新增 `upload_dir: str = "./uploads"`
- [x] `app/config.py` Settings 新增 `upload_max_size_mb: int = 20`
- [x] `app/config.py` Settings 新增 `upload_allowed_extensions: str = ".txt,.md,.html,.htm,.pdf,.docx"`
## 依赖声明
- [x] `pyproject.toml` dependencies 含 `python-multipart>=0.0.20`
- [x] `pyproject.toml` dependencies 含 `pypdf>=5.1.0`
- [x] `pyproject.toml` dependencies 含 `python-docx>=1.1.2`
## 应用启动初始化(Task 4.1
- [x] `app/main.py` lifespan 在 `ensure_default_admin` 之后调用 `Path(settings.upload_dir).mkdir(parents=True, exist_ok=True)`
- [x] mkdir 失败仅 warning 不阻塞启动
## 环境变量模板(Task 4.2
- [x] `.env.example` 末尾含 `--- 文件上传 ---` 段落
- [x]`UPLOAD_DIR=./uploads`
- [x]`UPLOAD_MAX_SIZE_MB=20`
- [x]`UPLOAD_ALLOWED_EXTENSIONS=.txt,.md,.html,.htm,.pdf,.docx`
## 管理后台 UITask 5
- [x] `admin.html` `#section-ingest` 区块含「文件上传」子表单
- [x] file input 含 `accept=".txt,.md,.html,.htm,.pdf,.docx"`
- [x] 可选 title 输入框
- [x] 可选 source 输入框
- [x] 提交按钮 id=`btn-upload-submit`
- [x] submit 监听构造 FormData 调用 `/api/v1/documents/upload`
- [x] 复用 `renderIngestHeader` + `startIngestPolling` 展示任务进度
- [x] 提交期间禁用按钮并显示「上传中…」
- [x] 完成(成功/失败)后恢复按钮文案为「上传入库」
## 文档同步(Task 6
- [x] `CLAUDE.md` API 清单含 `POST /api/v1/documents/upload`
- [x] `CLAUDE.md` 「文档入库与三级总结」节简述文件上传通道
## 全量回归(Task 7
- [x] `uv run pytest` 全绿(289 passed,含新增 23 测试 + 既有 266 测试套件)