183 lines
5.7 KiB
Markdown
183 lines
5.7 KiB
Markdown
# AI 文档模板生成系统 · 需求规格说明书
|
||
|
||
## 一、功能需求
|
||
|
||
### 1.1 模板管理
|
||
| 功能 | 描述 | 优先级 |
|
||
|------|------|--------|
|
||
| 模板列表 | 卡片式展示所有模板,含名称、段落数、状态、最后编辑时间 | P0 |
|
||
| 新建模板 | 上传 .docx 文件,自动解析段落结构 | P0 |
|
||
| 模板编辑器(三栏) | 左栏段落列表、中栏文档预览、右栏段落配置 | P0 |
|
||
| 段落标注 | 配置每个段落的编辑方式、模型、提示词、参考文件 | P0 |
|
||
| 保存模板 | 将段落配置持久化到数据库 | P0 |
|
||
|
||
### 1.2 模型管理
|
||
| 功能 | 描述 | 优先级 |
|
||
|------|------|--------|
|
||
| 模型列表 | 卡片式展示所有 AI 模型,含启用/禁用开关 | P0 |
|
||
| 添加/编辑模型 | 弹窗表单:名称、厂商、API 格式、地址、Key(加密存储) | P0 |
|
||
| 默认模型分配 | 设置文本/表格/图表各自的默认生成模型 | P0 |
|
||
|
||
### 1.3 执行生成
|
||
| 功能 | 描述 | 优先级 |
|
||
|------|------|--------|
|
||
| 选择模板 | 下拉选择已保存的模板 | P0 |
|
||
| 上传参考文件 | 按段落需上传的文件类型提示并上传 | P0 |
|
||
| 开始生成 | 启动多段落并行 AI 生成 | P0 |
|
||
| 实时进度 | SSE 推送每个段落的生成状态 | P0 |
|
||
| 取消生成 | 中断正在进行的生成任务 | P1 |
|
||
|
||
### 1.4 生成记录
|
||
| 功能 | 描述 | 优先级 |
|
||
|------|------|--------|
|
||
| 统计卡片 | 总次数、成功、失败、中断 | P0 |
|
||
| 历史列表 | 卡片式展示已生成文档 | P0 |
|
||
| 筛选 | 按模板、按状态筛选 | P1 |
|
||
| 预览 | 跳转到预览编辑页 | P0 |
|
||
| 下载 | 下载已生成的 Word 文档 | P0 |
|
||
|
||
### 1.5 预览编辑
|
||
| 功能 | 描述 | 优先级 |
|
||
|------|------|--------|
|
||
| 富文本编辑 | 在线编辑文档内容 | P0 |
|
||
| AI 内容标注 | AI 生成的段落标紫色边框+模型来源 | P0 |
|
||
| 重新生成单段落 | 对某一段落单独重新请求 AI | P0 |
|
||
| 导出 Word | 保留原始模板样式 | P0 |
|
||
| 导出 PDF | 通过 LibreOffice 转换 | P1 |
|
||
|
||
## 二、段落解析规则
|
||
|
||
### 2.1 段落边界定义
|
||
段落以 Word 内置标题样式为边界:
|
||
|
||
```
|
||
Heading 1 → 一级段落(如 "一、经营指标")
|
||
Heading 2 → 二级段落(如 "1.1 营收分析")
|
||
Heading 3 → 三级段落
|
||
无标题样式 → 合并到上一个标题下的正文内容
|
||
表格 → 独立段落,归属于前一个标题
|
||
```
|
||
|
||
### 2.2 标题下的正文内容
|
||
标题与下一个标题之间的所有正文、表格、图片:
|
||
- 作为该段落的 `content` 字段
|
||
- 供 AI 生成时作为上下文参考
|
||
- 导出时保留原样式
|
||
|
||
### 2.3 AI 返回格式约定
|
||
AI 输出必须是结构化 JSON:
|
||
|
||
```json
|
||
{
|
||
"content": [
|
||
{"type": "text", "text": "正文内容..."},
|
||
{"type": "table", "headers": ["列1","列2"], "rows": [["a","b"],["c","d"]]},
|
||
{"type": "text", "text": "更多正文..."}
|
||
]
|
||
}
|
||
```
|
||
|
||
后端解析逻辑:
|
||
- type=text → 替换文档中对应段落的文本
|
||
- type=table → 在对应位置插入 Word 表格,表格样式参照该段落附近已有表格
|
||
|
||
### 2.4 正文内编号处理
|
||
AI 生成的 1、2、3 编号属于该段落的内部子结构,不拆分为新段落。导出时作为该段落的正文内容,应用该段落的样式。
|
||
|
||
## 三、导出策略
|
||
|
||
采用 **基于原模板替换内容** 策略:
|
||
|
||
1. 解析时记录每个段落在原始 docx 中的段落索引 + xpath
|
||
2. 导出时复制原始模板文件
|
||
3. 遍历每个段落,找到对应位置替换内容:
|
||
- 纯文本:替换 `<w:t>` 节点文本
|
||
- 表格:删除原有表格占位,插入新表格的 XML 节点
|
||
4. 样式完全不修改(字体、字号、颜色、行距、段间距、页边距、页眉页脚、页码全部保留)
|
||
|
||
## 四、AI 并行生成设计
|
||
|
||
```
|
||
用户点击"开始生成"
|
||
│
|
||
▼
|
||
解析模板段落依赖关系(当前无依赖,全部并行)
|
||
│
|
||
▼
|
||
创建 asyncio.Task 池,Semaphore 控制并发数(默认 5)
|
||
│
|
||
├── 段落1 → AI 请求 → SSE 推送完成
|
||
├── 段落2 → AI 请求 → SSE 推送完成
|
||
├── 段落3 → AI 请求 → SSE 推送完成
|
||
├── 段落4 → AI 请求 → SSE 推送完成
|
||
└── 段落5 → AI 请求 → SSE 推送完成
|
||
│
|
||
▼
|
||
所有 Task 完成后,统一更新文档状态为 completed
|
||
│
|
||
▼
|
||
SSE 推送 "全部完成",前端跳转到预览编辑
|
||
```
|
||
|
||
## 五、数据结构
|
||
|
||
### 5.1 模板 (template)
|
||
```
|
||
id: int (PK)
|
||
name: str
|
||
description: str
|
||
file_path: str # 原始模板文件路径
|
||
paragraph_count: int
|
||
status: str # draft / ready
|
||
created_at: datetime
|
||
updated_at: datetime
|
||
```
|
||
|
||
### 5.2 段落 (paragraph)
|
||
```
|
||
id: int (PK)
|
||
template_id: int (FK)
|
||
sort_index: int
|
||
title: str # 段落标题
|
||
content: str # 正文内容(供 AI 参考)
|
||
style_json: json # 完整样式定义
|
||
is_table: bool
|
||
table_json: json # 表格结构
|
||
edit_mode: str # manual / ai
|
||
model_id: int (FK, nullable)
|
||
need_prompt: bool
|
||
prompt_text: str
|
||
need_file: bool
|
||
file_note: str
|
||
output_format: str # text / table / mixed / chart
|
||
created_at: datetime
|
||
updated_at: datetime
|
||
```
|
||
|
||
### 5.3 AI 模型 (ai_model)
|
||
```
|
||
id: int (PK)
|
||
name: str
|
||
provider: str
|
||
api_format: str # anthropic / openai
|
||
api_endpoint: str
|
||
api_key_encrypted: str
|
||
status: str # enabled / disabled
|
||
created_at: datetime
|
||
updated_at: datetime
|
||
```
|
||
|
||
### 5.4 生成文档 (document)
|
||
```
|
||
id: int (PK)
|
||
template_id: int (FK)
|
||
name: str
|
||
para_count_done: int
|
||
para_count_total: int
|
||
status: str # pending / generating / completed / failed / cancelled
|
||
file_path: str # 生成的文档路径
|
||
error: str
|
||
created_at: datetime
|
||
updated_at: datetime
|
||
```
|