diff --git a/app_prd/Document Converter Backend Service.md b/app_prd/Document Converter Backend Service.md index 7b69409..858b0f7 100644 --- a/app_prd/Document Converter Backend Service.md +++ b/app_prd/Document Converter Backend Service.md @@ -1,271 +1,225 @@ -这是一个为后端开发团队准备的、基于 RESTful 标准的**通用文档转换服务(Universal Document Converter, UDC)**的产品需求文档(PRD)。 ---- -# 产品需求文档:通用文档转换服务 (UDC) -**Universal Document Converter - Backend Service** - -| 文档版本 | V1.0 | +| 文档版本 | V2.0 (集成文档管理) | | :--- | :--- | | **最后更新** | 2025-12-09 | | **状态** | 待开发 | -| **涉及端** | 后端 API, 异步 Worker, 对象存储 | +| **涉及端** | 后端 API, 异步 Worker, 对象存储, 关系型数据库 | --- ## 1. 项目背景与目标 ### 1.1 背景 -在构建智能题库、知识库或 RAG(检索增强生成)应用时,需要处理大量非结构化文档(PDF, Word, Excel, 图片等)。当前的痛点在于不同格式的解析方式不统一,且由 OCR 产生的图片资源难以直接被大模型引用。 +在构建智能题库、知识库或 RAG 应用时,文档不仅是需要被“消费”的临时素材,更是核心的**数字资产**。当前的痛点在于: +1. 缺乏统一的文档仓库,原始文件容易丢失。 +2. 不同格式(PDF, Word, Excel)解析标准不一。 +3. 解析过程中的图片/公式资源难以复用。 ### 1.2 目标 -构建一个独立、无状态、高性能的**文档转换微服务**。 -* **输入**:支持 PDF, DOCX, DOC, XLSX, PPTX, JPG/PNG, Markdown。 -* **核心能力**: - 1. **格式统一**:将异构文档转换为标准 Markdown(便于 LLM 处理)。 - 2. **逆向生成**:将 Markdown 转换为排版精美的 DOCX/PDF(便于人类阅读)。 - 3. **资产云化**:自动提取文档中的图片/公式截图,上传至 MinIO,并替换 Markdown 中的链接为永久 URL。 - 4. **样式定制**:支持通过 Word 模板定义输出文档的排版样式。 -* **输出**:标准 RESTful API,提供转换结果的 JSON 数据(含 MinIO 链接)或文件流。 +构建一个**具备资产管理能力**的高性能文档服务。 +* **资产沉淀**:所有上传的原始文档(PDF, DOCX, XLSX, 图片等)均永久存储,并支持去重和历史记录查询。 +* **格式归一**:将异构文档转换为标准 Markdown(供 AI 使用)或 PDF/DOCX(供人阅读)。 +* **资源云化**:自动提取文档内的图片/公式,转为 MinIO 永久链接。 +* **样式定制**:支持 Word 模板渲染。 --- ## 2. 系统架构设计 -系统采用 **异步任务队列** 架构,以应对 MinerU (OCR) 等高算力消耗场景。 +系统采用 **API 服务 + 关系型数据库 + 异步任务队列** 的架构。 ### 2.1 核心组件 -1. **API Gateway (FastAPI)**: 接收 HTTP 请求,鉴权,文件校验,上传源文件至 MinIO `raw/` 桶,发布任务至 Redis。 -2. **Task Broker (Redis)**: 维护任务队列(区分 `gpu-queue` 和 `cpu-queue`)。 -3. **Worker Cluster (Celery)**: - * **GPU Worker**: 部署 MinerU (Magic-PDF),处理 PDF/Image -> Markdown。 - * **CPU Worker**: 部署 Pandoc, Python-Pandas, WPS-Python-RPC。处理 Docx/Excel -> Markdown 以及 Markdown -> Docx。 -4. **Storage (MinIO)**: - * `udc-raw`: 存放用户上传的原始文件。 - * `udc-assets`: 存放解析出的图片资源(永久保存)。 - * `udc-results`: 存放生成的 Markdown/Docx 结果文件(永久保存)。 - * `udc-templates`: 存放用户上传的 Word 样式模板。 +1. **API Gateway (FastAPI)**: + * 提供文档上传、查询、转换接口。 + * 负责文件 Hash 计算与秒传校验。 +2. **Metadata DB (PostgreSQL)**: + * 存储文档元数据(文件名、大小、Hash、上传人)。 + * 存储转换任务记录(Task History)。 +3. **Task Broker (Redis)**: 维护任务队列 (`gpu-queue`, `cpu-queue`)。 +4. **Worker Cluster (Celery)**: + * **GPU Worker**: MinerU (PDF/Image -> Markdown)。 + * **CPU Worker**: Pandoc/Pandas/WPS-RPC (Office -> Markdown, Markdown -> Docx)。 +5. **Storage (MinIO)**: + * `udc-raw`: **[永久]** 存放用户上传的原始文件(按 `hash/filename` 存储)。 + * `udc-assets`: **[永久]** 存放解析出的图片资源。 + * `udc-results`: **[永久]** 存放转换结果(MD/PDF)。 + * `udc-templates`: **[永久]** 样式模板。 --- ## 3. 功能需求详细说明 -### 3.1 核心转换逻辑 (Router Strategy) +### 3.1 文档管理 (DMS Core) +* **上传与去重**:用户上传文件时,计算 SHA256。若库中已存在该 Hash,则直接返回现有的 `document_id`(秒传),不重复上传 MinIO。 +* **版本/历史**:同一个 `document_id` 可以对应多个 `task_id`(例如:第一次解析失败,修正 bug 后重新解析;或者分别转换为 Markdown 和 PDF)。 +* **元数据检索**:支持按文件名、上传时间、文件类型查询文档。 -根据输入文件类型 (`input_format`) 和目标格式 (`target_format`) 自动路由。 +### 3.2 转换路由策略 (Conversion Strategy) -| 输入格式 | 目标格式 | 处理引擎/逻辑 | 资源处理 | 备注 | -| :--- | :--- | :--- | :--- | :--- | -| **PDF / Image** | Markdown | **MinerU (GPU)** | 提取截图 -> 上传 MinIO -> 替换链接 | 核心场景 | -| **DOCX** | Markdown | **Pandoc** | Extract Media -> 上传 MinIO -> 替换链接 | 保留公式 Latex | -| **DOC** | Markdown | **LibreOffice/WPS** 转 PDF -> **MinerU** | 同 PDF 流程 | 解决旧版公式问题 | -| **XLSX / XLS** | Markdown | **Pandas** | 纯文本/Markdown Table 拼接 | 忽略 Excel 内嵌图 | -| **Markdown** | DOCX | **Pandoc** (+Reference Doc) | 下载网络图 -> 嵌入 Word | 支持样式模板 | -| **Markdown** | PDF | **Pandoc** -> DOCX -> **LibreOffice** | 同上 | 间接生成 | +| 输入格式 | 目标格式 | 引擎 | 逻辑说明 | +| :--- | :--- | :--- | :--- | +| **PDF / Image** | Markdown | **MinerU** (GPU) | 强依赖 GPU,提取截图并替换链接。 | +| **DOCX** | Markdown | **Pandoc** | 提取内嵌图片,保留 LaTeX 公式。 | +| **DOC** | Markdown | **WPS-RPC** -> PDF -> **MinerU** | 解决老旧 MathType 公式渲染问题。 | +| **XLSX** | Markdown | **Pandas** | 纯文本拼接,忽略内嵌图。 | +| **Markdown** | DOCX | **Pandoc** | 支持 `--reference-doc` 模板定制。 | -### 3.2 资产管理 (Asset Pipeline) -任何转换过程中产生的本地图片(如 OCR 截图、Word 中的插图),必须经过以下流水线: -1. **提取**: 解析器将图片存放在临时目录 `/tmp/task_id/images/`。 -2. **哈希重命名**: 计算文件 MD5,重命名为 `md5.jpg` (防止重复存储)。 -3. **上传**: 上传至 MinIO `udc-assets/{date}/{md5}.jpg`。 -4. **替换**: 在生成的 Markdown 文本中,将 `![](images/a.jpg)` 替换为 `![](https://minio.host/udc-assets/.../md5.jpg)`。 - -### 3.3 样式模板管理 -* 允许用户上传 `.docx` 文件作为“参考文档” (Reference Doc)。 -* 在 Markdown -> DOCX 转换时,通过 `--reference-doc` 参数应用字体、字号、页边距等样式。 +### 3.3 资产与链接处理 +* **图片处理**:所有转换产生的图片,均重命名为 MD5 Hash,存入 `udc-assets`。 +* **Markdown 清洗**:输出的 Markdown 中,所有图片链接必须是 MinIO 的完整 URL(如 `https://oss.example.com/udc-assets/a1b2...jpg`),禁止出现相对路径。 --- -## 4. API 接口定义 (RESTful) +## 4. 数据库设计 (PostgreSQL Schema) + +使用 SQLModel 定义,支撑 DMS 能力。 + +### 4.1 Table: `documents` (文档主表) +| 字段 | 类型 | 说明 | +| :--- | :--- | :--- | +| `id` | UUID (PK) | 文档唯一标识 | +| `file_hash` | VARCHAR(64) | SHA256,唯一索引 (Unique) | +| `filename` | VARCHAR | 原始文件名 | +| `file_type` | VARCHAR | 扩展名 (pdf, docx) | +| `file_size` | BIGINT | 字节数 | +| `storage_path` | VARCHAR | MinIO 路径 (`udc-raw/hash/filename`) | +| `created_at` | TIMESTAMP | 上传时间 | + +### 4.2 Table: `conversion_tasks` (转换历史表) +| 字段 | 类型 | 说明 | +| :--- | :--- | :--- | +| `id` | UUID (PK) | 任务 ID | +| `document_id` | UUID (FK) | 关联文档 | +| `target_format` | VARCHAR | markdown, pdf, docx | +| `status` | VARCHAR | queued, processing, success, failed | +| `result_url` | VARCHAR | 结果文件下载链接 | +| `error_msg` | TEXT | 失败原因 | +| `created_at` | TIMESTAMP | 任务创建时间 | +| `completed_at` | TIMESTAMP | 完成时间 | + +--- + +## 5. API 接口定义 (RESTful) **Base URL**: `/api/v1` -### 4.1 提交转换任务 -* **Endpoint**: `POST /conversions` -* **Content-Type**: `multipart/form-data` -* **Description**: 提交一个文件进行转换。 +### 5.1 文档管理 +* **POST** `/documents` + * **功能**:上传新文档(支持秒传)。 + * **Body**: `file` (binary) + * **Response**: `{"document_id": "...", "is_exist": true/false}` +* **GET** `/documents` + * **功能**:分页查询文档列表。 + * **Query**: `page`, `size`, `keyword` -**Request Parameters:** +### 5.2 转换服务 +* **POST** `/conversions` + * **功能**:发起转换任务。 + * **Body**: + * `document_id` (必填): 指向已上传的文档 ID。 + * `target_format` (必填): `markdown`, `docx` 等。 + * `template_id` (选填): 样式模板 ID。 + * `force_ocr` (选填): Boolean。 + * **Response**: `{"task_id": "..."}` -| 参数名 | 类型 | 必填 | 说明 | -| :--- | :--- | :--- | :--- | -| `file` | File | 是 | 二进制文件流 | -| `target_format` | String | 是 | `markdown`, `docx`, `pdf` | -| `output_mode` | String | 否 | `url` (默认,存MinIO返回链接), `archive` (返回ZIP流) | -| `template_id` | String | 否 | 仅当 `target_format=docx` 时有效,指定使用的样式模板ID | -| `is_ocr` | Boolean | 否 | 默认 `false`。若为 `true`,即使是电子版 PDF 也强制走 OCR | -| `callback_url` | String | 否 | 任务完成后的 Webhook 回调地址 | +### 5.3 任务与结果 +* **GET** `/conversions/{task_id}` + * **功能**:查询状态及结果。 + * **Response**: + ```json + { + "status": "success", + "result": { + "content": "# Markdown内容...", + "file_url": "https://minio.../res.md" + } + } + ``` -**Response (202 Accepted):** -```json -{ - "task_id": "550e8400-e29b-41d4-a716-446655440000", - "status": "queued", - "eta_seconds": 30 -} -``` - -### 4.2 查询任务状态/结果 -* **Endpoint**: `GET /conversions/{task_id}` -* **Description**: 轮询任务状态。 - -**Response (Processing):** -```json -{ - "task_id": "...", - "status": "processing", - "progress": 45 // 0-100 -} -``` - -**Response (Success - URL Mode):** -```json -{ - "task_id": "...", - "status": "success", - "completed_at": "2025-12-09T10:00:00Z", - "result": { - // 如果目标是 Markdown,直接把内容返回来方便前端预览/LLM读取 - "content": "# 标题\n\n正文内容...![](https://minio.../img.jpg)", - // 结果文件的下载地址 - "file_url": "https://minio.host/udc-results/task_id/result.md", - // 提取出的图片列表 (方便调试) - "images": [ - "https://minio.host/udc-assets/2025/abc.jpg", - "https://minio.host/udc-assets/2025/def.png" - ] - } -} -``` - -### 4.3 上传样式模板 -* **Endpoint**: `POST /templates` -* **Content-Type**: `multipart/form-data` -* **Description**: 上传一个 `.docx` 文件作为排版模板。 - -**Request:** `file` (binary), `name` (string) - -**Response (201 Created):** -```json -{ - "template_id": "tpl_01HE...", - "name": "学校试卷标准模板", - "url": "https://minio.host/udc-templates/tpl_01HE.docx" -} -``` - -### 4.4 预览/下载文件 (Proxy) -* **Endpoint**: `GET /files/{bucket}/{path}` -* **Description**: (可选) 如果 MinIO 不对外直接暴露,通过此接口代理下载或预览文件。 +### 5.4 辅助接口 +* **POST** `/templates`: 上传 Word 样式模板。 +* **GET** `/files/{path}`: 文件代理下载(用于预览)。 --- -## 5. 数据存储方案 +## 6. 存储策略 (MinIO) -### 5.1 Redis Key 设计 -* `task:queue:gpu`: List, 待处理的 OCR 任务。 -* `task:queue:cpu`: List, 待处理的 Office/Pandoc 任务。 -* `task:status:{task_id}`: Hash, 存储任务状态、进度、结果 JSON。过期时间 24 小时。 - -### 5.2 MinIO Bucket 策略 -* **udc-raw**: Lifecycle Rule = expire after 1 day. -* **udc-assets**: Policy = ReadOnly (Public or Signed URL). -* **udc-templates**: Policy = ReadOnly. +* **udc-raw**: **永久存储**。目录结构建议:`/{year}/{month}/{hash}.ext`。 +* **udc-assets**: **永久存储**。用于存放 OCR 截图,目录结构:`/{hash_prefix}/{hash}.jpg`。 +* **udc-results**: **永久存储**。建议保留转换历史。 +* **udc-temp**: **1天过期**。用于打包下载的临时 ZIP 文件。 --- +## 7. 非功能需求 (NFR) -## 6. 非功能需求 (NFR) - -1. **幂等性**: 对同一文件的重复上传(MD5相同),如果参数一致,应直接返回之前的 `task_id` 或缓存结果(可选优化)。 -2. **并发控制**: MinerU 极其消耗显存。需要通过 Celery 的 `worker_concurrency` 严格限制 GPU Worker 的并发数(例如 1个 GPU 对应 1-2 个并发),防止 OOM。 -3. **超时处理**: - * Docx 转换超时:60秒。 - * PDF OCR 超时:300秒(视页数而定)。 -4. **异常处理**: - * 如果 OCR 失败,应在 Response 中返回 `error_code` 和 `error_msg`。 - * 支持“部分成功”:如果文档有 100 页,解析到 99 页挂了,应尽量返回已解析的内容。 +1. **大文件支持**: API 需支持 Stream 上传,避免内存溢出;Nginx 需放开 `client_max_body_size`。 +2. **GPU 调度**: 通过 Celery 限制 GPU Worker 的并发数(建议 1:1 或 1:2),防止显存 OOM。 +3. **超时控制**: + * PDF/OCR 任务:超时设定为 10 分钟。 + * Office 转换任务:超时设定为 1 分钟。 +4. **可观测性**: 关键节点(开始转换、MinerU调用、上传MinIO)需打 Log,并在 Redis 记录进度百分比。 --- -## 7. 错误码定义 - -| Code | Message | Description | -| :--- | :--- | :--- | -| `4001` | `unsupported_format` | 不支持的文件扩展名 | -| `4002` | `template_not_found` | 指定的 Template ID 不存在 | -| `5001` | `ocr_engine_error` | MinerU 内部错误 (显存不足或模型加载失败) | -| `5002` | `conversion_timeout` | 转换超时 | -| `5003` | `storage_error` | MinIO 上传失败 | - ---- -## 8. 技术选型 +## 8. 技术选型与开发规范 (Technology Stack) 本系统采用 **"AI-Native"** 的开发策略,技术选型优先考虑与大模型(LLM)的兼容性、社区文档丰富度以及类型系统的完备性,以实现极致的 **Vibe Coding** 开发体验。 ### 8.1 核心技术栈 (Core Stack) -| 组件 | 选型 | 版本要求 | 选型理由 | -| :--------- | :------------- | :-------- | :----------------------------------------------------------- | -| **开发语言** | **Python** | **3.10+** | 必须启用强类型提示 (Type Hints);MinerU/Pandas 等核心库的原生语言;LLM 生成代码质量最高。 | -| **Web 框架** | **FastAPI** | Latest | 自动生成 OpenAPI 文档;基于 Pydantic 的类型验证是 AI 理解业务逻辑的最佳桥梁。 | -| **数据验证** | **Pydantic** | **V2** | 通过定义 Class Schema 驱动开发,AI 可根据 Schema 自动补全业务代码。 | -| **异步队列** | **Celery** | Latest | 处理 PDF OCR 等长耗时任务的工业级标准;配合 Redis 使用。 | -| **包管理** | **uv** | Latest | 极速 Python 包管理器(比 pip 快 10-100 倍),保障开发心流不被打断。 | -| **数据库** | **PostgreSQL** | 14+ | 优异的 JSONB 支持(存储试题结构);pgvector 扩展方便未来做向量检索。 | -| **对象存储** | **MinIO** | Latest | S3 兼容协议;用于存储文档、图片及中间产物。 | -| **ORM 框架** | **SQLModel** | Latest | 结合了 SQLAlchemy 和 Pydantic,让数据库操作与数据验证统一,降低 AI 上下文切换成本。 | +| 组件 | 选型 | 版本要求 | 选型理由 | +| :--- | :--- | :--- | :--- | +| **开发语言** | **Python** | **3.10+** | 必须启用强类型提示 (Type Hints);MinerU/Pandas 等核心库的原生语言;LLM 生成代码质量最高。 | +| **Web 框架** | **FastAPI** | Latest | 自动生成 OpenAPI 文档;基于 Pydantic 的类型验证是 AI 理解业务逻辑的最佳桥梁。 | +| **数据验证** | **Pydantic** | **V2** | 通过定义 Class Schema 驱动开发,AI 可根据 Schema 自动补全业务代码。 | +| **异步队列** | **Celery** | Latest | 处理 PDF OCR 等长耗时任务的工业级标准;配合 Redis 使用。 | +| **包管理** | **uv** | Latest | 极速 Python 包管理器(比 pip 快 10-100 倍),保障开发心流不被打断。 | +| **数据库** | **PostgreSQL** | 14+ | 优异的 JSONB 支持;配合 SQLModel 使用体验最佳。 | +| **ORM 框架** | **SQLModel** | Latest | 结合 SQLAlchemy 和 Pydantic,让数据库操作与数据验证统一,降低 AI 上下文切换成本。 | +| **对象存储** | **MinIO** | Latest | S3 兼容协议;用于存储海量非结构化数据。 | ### 8.2 Vibe Coding 开发工作流 为确保 AI 辅助编码的准确性和可维护性,开发过程需严格遵循以下工作流: 1. **Schema First (模型驱动)**: - * 在编写业务逻辑前,**必须先定义 Pydantic Model**(输入/输出数据结构)。 - * *理由*:一旦 Schema 定义清晰,AI 能以接近 100% 的准确率自动生成 API 接口代码和数据库迁移脚本。 + * 在编写业务逻辑前,**必须先定义 Pydantic/SQLModel**。 + * *理由*:Schema 是 AI 理解数据的“骨架”,骨架定义好,AI 填充“血肉”(逻辑)的准确率极高。 2. **微提交策略 (Micro-Commits)**: * **原则**:将 Git Commit 视为“游戏存档点”。 - * **操作**:每当 AI 完成一个独立功能函数(Function)或修复一个 Bug 并验证通过后,**立即 Commit**。 - * *理由*:AI 有时会产生“幻觉”改坏现有逻辑。高频提交允许开发者随时回滚到上一个“稳态”,避免代码崩坏。 + * **操作**:每当 AI 完成一个独立功能(如“完成MinIO上传函数”),**立即 Commit**。 3. **模块化上下文 (Modular Context)**: - * **禁止**将所有代码写在 `main.py` 或单文件中。 - * **强制**按功能分包:`routers/`, `services/`, `models/`, `tasks/`, `core/`。 - * *理由*:AI 的上下文窗口有限。模块化让开发者可以只将相关文件(如 `minio_service.py`)喂给 AI,从而获得更精准的代码生成。 + * **强制分包**:`routers/`, `services/`, `models/`, `tasks/`。 + * *理由*:模块化让开发者可以只将相关文件喂给 AI,避免 Token 超限和幻觉。 -4. **环境隔离与极速构建**: - * 使用 `uv venv` 创建虚拟环境。 - * 依赖变更后立即运行 `uv sync`。 - * *理由*:保持环境纯净,避免依赖冲突导致的 AI 调试死循环。 +4. **环境隔离**: + * 使用 `uv venv` 创建虚拟环境,依赖变更后运行 `uv sync`。 ### 8.3 关键依赖库 * **PDF/OCR**: `magic-pdf` (MinerU SDK) - **需 GPU 环境**。 -* **Word**: `pypandoc` (Pandoc 包装), `python-docx` (后处理)。 +* **Word**: `pypandoc` (Pandoc 包装), `python-docx`。 * **Excel**: `pandas`, `openpyxl`。 -* **LLM 交互**: `openai` (官方 SDK, 兼容 DeepSeek)。 -* **文档生成**: `jinja2` (配合 Pandoc 做模板渲染)。 +* **WPS调用**: `pywpsrpc` (如果部署在 Linux) 或 `pywin32` (如果部署在 Windows 节点)。 -### 8.4 Git 提交规范 -推荐使用 `Conventional Commits` 规范,以便 AI 自动生成 Changelog: -* `feat: add pdf parser service` -* `fix: resolve minio upload timeout` -* `chore: update dependencies via uv` -* `refactor: optimize celery task structure` +--- ## 9. 开发阶段规划 -### Phase 1: 基础框架 (CPU Worker) -* 完成 FastAPI + Redis + Celery 搭建。 -* 实现 Pandoc 转换逻辑 (Docx <-> Markdown)。 -* 实现 MinIO 上传与链接替换逻辑。 +### Phase 1: 核心资产管理 (DMS) +* 搭建 FastAPI + PostgreSQL + MinIO。 +* 实现文件上传、SHA256 去重、元数据存储。 +* 实现基础的 API:`POST /documents`, `GET /documents`。 -### Phase 2: GPU 核心 (GPU Worker) -* 集成 MinerU SDK。 -* 处理 PDF 转 Markdown 流程。 -* 优化大文件上传和处理超时设置。 +### Phase 2: CPU 转换能力 +* 集成 Redis + Celery。 +* 实现 `Pandoc` (Docx->MD) 和 `Pandas` (Excel->MD) Worker。 +* 实现 Markdown 图片提取与 MinIO 上传逻辑。 -### Phase 3: 模板与优化 -* 实现 `/templates` 接口。 -* 实现 Pandoc `reference-doc` 逻辑。 -* Docker 镜像封装 (分离 CPU/GPU 镜像)。 \ No newline at end of file +### Phase 3: GPU 转换能力与优化 +* 部署 MinerU 环境,实现 PDF -> Markdown。 +* 实现 WPS/Windows 节点集成(解决老旧 Doc 公式)。 +* 完善样式模板功能。 \ No newline at end of file