note/app_prd/Document Converter Backend Service.md

271 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

这是一个为后端开发团队准备的、基于 RESTful 标准的**通用文档转换服务Universal Document Converter, UDC**的产品需求文档PRD
---
# 产品需求文档:通用文档转换服务 (UDC)
**Universal Document Converter - Backend Service**
| 文档版本 | V1.0 |
| :--- | :--- |
| **最后更新** | 2025-12-09 |
| **状态** | 待开发 |
| **涉及端** | 后端 API, 异步 Worker, 对象存储 |
---
## 1. 项目背景与目标
### 1.1 背景
在构建智能题库、知识库或 RAG检索增强生成应用时需要处理大量非结构化文档PDF, Word, Excel, 图片等)。当前的痛点在于不同格式的解析方式不统一,且由 OCR 产生的图片资源难以直接被大模型引用。
### 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 链接)或文件流。
---
## 2. 系统架构设计
系统采用 **异步任务队列** 架构,以应对 MinerU (OCR) 等高算力消耗场景。
### 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`: 存放用户上传的原始文件生命周期1天
* `udc-assets`: 存放解析出的图片资源(永久保存)。
* `udc-results`: 存放生成的 Markdown/Docx 结果文件(永久保存)。
* `udc-templates`: 存放用户上传的 Word 样式模板。
---
## 3. 功能需求详细说明
### 3.1 核心转换逻辑 (Router Strategy)
根据输入文件类型 (`input_format`) 和目标格式 (`target_format`) 自动路由。
| 输入格式 | 目标格式 | 处理引擎/逻辑 | 资源处理 | 备注 |
| :--- | :--- | :--- | :--- | :--- |
| **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** | 同上 | 间接生成 |
### 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` 参数应用字体、字号、页边距等样式。
---
## 4. API 接口定义 (RESTful)
**Base URL**: `/api/v1`
### 4.1 提交转换任务
* **Endpoint**: `POST /conversions`
* **Content-Type**: `multipart/form-data`
* **Description**: 提交一个文件进行转换。
**Request Parameters:**
| 参数名 | 类型 | 必填 | 说明 |
| :--- | :--- | :--- | :--- |
| `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 回调地址 |
**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. 数据存储方案
### 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.
---
## 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 页挂了,应尽量返回已解析的内容。
---
## 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. 技术选型
本系统采用 **"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 上下文切换成本。 |
### 8.2 Vibe Coding 开发工作流
为确保 AI 辅助编码的准确性和可维护性,开发过程需严格遵循以下工作流:
1. **Schema First (模型驱动)**
* 在编写业务逻辑前,**必须先定义 Pydantic Model**(输入/输出数据结构)。
* *理由*:一旦 Schema 定义清晰AI 能以接近 100% 的准确率自动生成 API 接口代码和数据库迁移脚本。
2. **微提交策略 (Micro-Commits)**
* **原则**:将 Git Commit 视为“游戏存档点”。
* **操作**:每当 AI 完成一个独立功能函数Function或修复一个 Bug 并验证通过后,**立即 Commit**。
* *理由*AI 有时会产生“幻觉”改坏现有逻辑。高频提交允许开发者随时回滚到上一个“稳态”,避免代码崩坏。
3. **模块化上下文 (Modular Context)**
* **禁止**将所有代码写在 `main.py` 或单文件中。
* **强制**按功能分包:`routers/`, `services/`, `models/`, `tasks/`, `core/`
* *理由*AI 的上下文窗口有限。模块化让开发者可以只将相关文件(如 `minio_service.py`)喂给 AI从而获得更精准的代码生成。
4. **环境隔离与极速构建**
* 使用 `uv venv` 创建虚拟环境。
* 依赖变更后立即运行 `uv sync`
* *理由*:保持环境纯净,避免依赖冲突导致的 AI 调试死循环。
### 8.3 关键依赖库
* **PDF/OCR**: `magic-pdf` (MinerU SDK) - **需 GPU 环境**
* **Word**: `pypandoc` (Pandoc 包装), `python-docx` (后处理)。
* **Excel**: `pandas`, `openpyxl`
* **LLM 交互**: `openai` (官方 SDK, 兼容 DeepSeek)。
* **文档生成**: `jinja2` (配合 Pandoc 做模板渲染)。
### 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 2: GPU 核心 (GPU Worker)
* 集成 MinerU SDK。
* 处理 PDF 转 Markdown 流程。
* 优化大文件上传和处理超时设置。
### Phase 3: 模板与优化
* 实现 `/templates` 接口。
* 实现 Pandoc `reference-doc` 逻辑。
* Docker 镜像封装 (分离 CPU/GPU 镜像)。