# Checklist ## 多格式文件文本提取 - [x] `app/core/file_parser.py` 存在并实现 `parse_file(filename, content)` 与 `supported_extensions()` - [x] 支持 .txt/.md(UTF-8 解码 errors=replace) - [x] 支持 .html/.htm(html.parser 剥离 script/style 后提取可见文本) - [x] 支持 .pdf(pypdf 逐页 extract_text 拼接) - [x] 支持 .docx(python-docx 段落文本拼接) - [x] 未识别扩展名抛 `ValueError("不支持的文件类型: {ext}")` - [x] 解析异常包装为 `ValueError("文件解析失败: {detail}")` 并保留原异常链 - [x] `tests/test_file_parser.py` 13 例覆盖各格式 + 异常路径 ## 文件上传入库端点 - [x] `POST /api/v1/documents/upload` 端点存在,接收 multipart/form-data(file + 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` ## 管理后台 UI(Task 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 测试套件)