Files
Jog/doc/AI文章润色与拼写检查功能需求.md
T
2026-05-23 18:48:35 +08:00

259 lines
21 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.
# AI 文章润色与拼写检查功能 - 需求规格说明书
| 文档版本 | 修订日期 | 修订人 | 修订内容 |
| :------- | :--------- | :----- | :---------------------------------------- |
| V1.0 | 2026-05-23 | — | 初始版本,定义 AI 文章润色功能完整需求 |
---
## 1. 项目概述
### 1.1 功能背景
在博客写作过程中,创作者常面临语法不通顺、用词不当、标点不规范等问题。手动校对耗时且容易遗漏。为提升写作效率与文章质量,在 Jog 博客系统的文章编辑器中新增 **AI 润色** 功能,一键优化文本表达,并提供原文与润色结果的对比视图,允许用户灵活采纳。
### 1.2 功能目标
- 降低创作者校对与润色的时间成本
- 通过 AI 自动优化语法、表达和标点,提升文章专业性
- 提供原文与润色结果的对比视图,让用户掌控修改粒度
- 支持段落级润色,避免一次性替换全文带来的风险
- 复用现有 DashScope 大模型接入能力,降低开发成本
### 1.3 适用范围
| 角色 | 涉及范围 |
| :------------- | :---------------------------------------------------- |
| 产品经理 | 验证功能形态与对比交互流程 |
| 前端开发工程师 | 实现"AI 润色"按钮、对比视图、采纳/撤销交互 |
| 后端开发工程师 | 新增润色 API,复用 DashScope 调用链路 |
| 测试工程师 | 编写自动化测试与回归用例 |
| 运维工程师 | 无需额外配置(复用已有 `dashscope.*` 配置项) |
---
## 2. 名词解释
| 术语 | 说明 |
| :----------------- | :------------------------------------------------------------------------------------- |
| 润色 | 对文本进行语法修正、表达优化、标点规范化,保持原意不变 |
| 对比视图 | 左侧展示原文、右侧展示润色结果的并排布局,方便用户逐段比对 |
| 采纳 | 用户确认使用润色后的文本替换原文 |
| 部分采纳 | 用户仅替换选定段落,而非全文替换 |
| DashScope | 阿里云百炼对外暴露的 API 服务名,本系统对接其 OpenAI 兼容模式 |
| Qwen-Turbo | 通义千问 Turbo 系列模型,速度快、成本低,适合文本润色等任务 |
---
## 3. 功能需求清单
### 3.1 入口与按钮交互(前端)
#### 3.1.1 功能描述
在文章编辑器页面(`/app/editor``/app/editor/:id`)的富文本工具栏右侧新增 **"AI 润色"** 按钮。用户选中需要润色的文本段落后,点击按钮调用后端润色接口,系统展示原文与润色结果的对比视图供用户决策。
#### 3.1.2 业务规则
| 编号 | 规则项 | 业务规则说明 |
| :-------------------- | :--------------- | :---------------------------------------------------------------------------------------------------------------------- |
| FR-AI-POLISH-FE-01 | 按钮位置 | 按钮显示在富文本编辑器工具栏右侧,文案为"AI 润色",可配图标(如钢笔图标),使用 Element Plus `type="warning"` 区分现有按钮 |
| FR-AI-POLISH-FE-02 | 触发前置条件 | 用户需在编辑器中选中文本(纯文本长度 ≥ 20 字符);未选中或选中过短时提示"请先选中至少 20 个字符的文本" |
| FR-AI-POLISH-FE-03 | Loading 状态 | 按钮在请求期间显示 `loading` 态并禁用,防止重复点击 |
| FR-AI-POLISH-FE-04 | 对比视图 | 润色完成后,在编辑器下方弹出对比面板:左侧为"原文"(带浅红背景)、右侧为"润色后"(带浅绿背景),逐段展示差异 |
| FR-AI-POLISH-FE-05 | 段落级操作 | 每段对比行提供"采纳"按钮,用户可逐段替换;面板顶部提供"全部采纳"按钮,一键替换所有段落 |
| FR-AI-POLISH-FE-06 | 采纳行为 | 点击"采纳",将该段润色文本替换回编辑器对应位置;替换后该段高亮闪烁一次以提示用户 |
| FR-AI-POLISH-FE-07 | 关闭对比视图 | 提供"关闭"按钮关闭对比面板;关闭前若有未采纳段落,弹出确认"有未采纳的润色结果,确定关闭?" |
| FR-AI-POLISH-FE-08 | 失败提示 | 接口返回失败时,提示后端返回的 `message`,按钮恢复可点击状态 |
| FR-AI-POLISH-FE-09 | 超时提示 | 请求超过 30 秒未返回,提示"AI 服务响应超时,请稍后再试" |
| FR-AI-POLISH-FE-10 | 多次润色 | 用户可对同一段落多次润色;对比视图始终展示当前原文与最新润色结果的对比 |
#### 3.1.3 验收标准
| 编号 | 验证场景 | 预期结果 |
| :-------------------- | :---------------------------------------------------------- | :-------------------------------------------------------------------------------- |
| AC-AI-POLISH-FE-01 | 未选中文本时点击"AI 润色" | 提示"请先选中至少 20 个字符的文本",不发起后端请求 |
| AC-AI-POLISH-FE-02 | 选中 ≥ 20 字符文本,点击按钮 | 按钮进入 loading 态,请求成功后显示对比视图 |
| AC-AI-POLISH-FE-03 | 对比视图中点击单段"采纳" | 该段原文被润色文本替换,编辑器光标跳转到替换位置 |
| AC-AI-POLISH-FE-04 | 对比视图中点击"全部采纳" | 所有段落被替换,面板自动关闭,提示"已全部采纳" |
| AC-AI-POLISH-FE-05 | 有未采纳段落时点击关闭 | 弹出确认对话框;取消则保持面板;确认则关闭面板 |
| AC-AI-POLISH-FE-06 | 后端返回 5001 错误 | 提示"AI 服务暂时不可用,请稍后再试",按钮恢复可用 |
| AC-AI-POLISH-FE-07 | 在编辑文章(带 `:id`)页面同样可使用润色 | 行为与新建文章一致 |
---
### 3.2 AI 润色接口(后端)
#### 3.2.1 功能描述
后端新增 **`POST /api/app/article/polish`** 接口,接收用户选中的文本段落,调用阿里云百炼大模型进行润色后返回润色结果。
#### 3.2.2 业务规则
| 编号 | 规则项 | 业务规则说明 |
| :-------------------- | :---------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------ |
| FR-AI-POLISH-BE-01 | 接口路径与方法 | `POST /api/app/article/polish`,需登录用户调用(继承 `/api/app/**``USER`/`ADMIN` 权限校验) |
| FR-AI-POLISH-BE-02 | 请求参数 | `text`(必填,最长 10000,为去除 HTML 标签后的纯文本选中内容) |
| FR-AI-POLISH-BE-03 | 入参校验 | `text` 为空或去除 HTML 后字符数 < 20,返回 `400 BAD_REQUEST` 与提示"文本过短,无法润色" |
| FR-AI-POLISH-BE-04 | 内容截断 | 若 `text` 字符数 > 6000,仅取前 6000 字符送入大模型,避免超过模型输入限制 |
| FR-AI-POLISH-BE-05 | 模型与平台 | 复用现有 DashScope OpenAI 兼容模式调用,默认使用 `qwen-turbo` |
| FR-AI-POLISH-BE-06 | 提示词(Prompt | System:你是一名专业的文字编辑,请润色用户提供的中文文本。修正语法错误、优化表达方式、规范标点符号,保持原意不变,使文本更流畅专业。直接输出润色后的文本,不要添加任何解释或标记。<br>User:请润色下面这段中文文本:{用户文本} |
| FR-AI-POLISH-BE-07 | 段落保持 | 润色后的文本应保持与原文相同的段落结构;若模型合并了段落,后端按原文段落数拆分后返回 |
| FR-AI-POLISH-BE-08 | 鉴权方式 | 复用 `dashscope.api-key`,通过 `Authorization: Bearer {key}` 传递 |
| FR-AI-POLISH-BE-09 | 超时与重试 | 单次调用超时 30 秒,不做自动重试;超时返回 `5002` 错误码 |
| FR-AI-POLISH-BE-10 | 限流 | 复用现有 Redis 限流机制,同一用户每分钟最多调用 5 次(与摘要、标签推荐共享配额);超出返回 `429 RATE_LIMITED` |
| FR-AI-POLISH-BE-11 | 异常处理 | DashScope 返回非 2xx 或 JSON 结构异常时,统一抛出 `BusinessException`,错误码 `5001 AI 服务暂时不可用` |
| FR-AI-POLISH-BE-12 | 日志记录 | 记录请求耗时、文本长度、是否成功;不记录请求与响应的完整文本,避免日志膨胀 |
#### 3.2.3 响应数据结构
```json
{
"code": 200,
"message": "success",
"data": {
"original": "这是需要润色的原文文本。",
"polished": "这是经过润色的原文文本。",
"diffSegments": [
{
"index": 0,
"original": "这是需要润色的原文文本。",
"polished": "这是经过润色的原文文本。"
}
],
"model": "qwen-turbo",
"promptTokens": 512,
"completionTokens": 256,
"costMillis": 1420
},
"timestamp": 1716268800000
}
```
| 字段 | 类型 | 说明 |
| :----------------- | :------------ | :------------------------------------------------ |
| original | String | 用户提交的原始文本 |
| polished | String | 润色后的完整文本 |
| diffSegments | Array | 逐段对比数据,前端据此渲染对比视图 |
| diffSegments[].index | int | 段落序号(从 0 开始) |
| diffSegments[].original | String | 该段原文 |
| diffSegments[].polished | String | 该段润色后文本 |
| model | String | 实际使用的模型名称 |
| promptTokens | Integer | 输入消耗的 token 数(可为 null |
| completionTokens | Integer | 输出消耗的 token 数(可为 null |
| costMillis | Long | 接口耗时(毫秒) |
#### 3.2.4 验收标准
| 编号 | 验证场景 | 预期结果 |
| :-------------------- | :---------------------------------------------------------- | :-------------------------------------------------------------------------------- |
| AC-AI-POLISH-BE-01 | 未登录调用接口 | 返回 `401 UNAUTHORIZED` |
| AC-AI-POLISH-BE-02 | 登录用户传入合法文本 | 返回 200`data.polished` 为润色后文本,`diffSegments` 数组非空 |
| AC-AI-POLISH-BE-03 | 文本 < 20 字符 | 返回 `400 BAD_REQUEST`,提示"文本过短,无法润色" |
| AC-AI-POLISH-BE-04 | `dashscope.api-key` 未配置 | 返回 `5005`,提示"AI 服务未配置 API Key" |
| AC-AI-POLISH-BE-05 | DashScope 返回 401API Key 无效) | 返回 `5001`,记录 ERROR 日志 |
| AC-AI-POLISH-BE-06 | 单用户 1 分钟内连续调用 6 次 | 第 6 次返回 `429 RATE_LIMITED` |
---
### 3.3 对比视图交互设计
#### 3.3.1 组件结构
```
┌─────────────────────────────────────────────────────────┐
│ 工具栏 [B][I][H2][H3][列表][引用][分割线] [✨ AI 润色] │
├─────────────────────────────────────────────────────────┤
│ │
│ [富文本编辑器内容区] │
│ │
├─────────────────────────────────────────────────────────┤
│ AI 润色结果对比 [全部采纳] [✕] │
│ ┌─────────────────────┬─────────────────────────────┐ │
│ │ 原文 │ 润色后 │ │
│ │ 这是一段需要润色的 │ 这是一段经过润色的文本。 │ │
│ │ 文本。 │ [采纳] │ │
│ ├─────────────────────┼─────────────────────────────┤ │
│ │ 另一段原文... │ 另一段润色后... [采纳] │ │
│ └─────────────────────┴─────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
```
#### 3.3.2 交互规则
| 编号 | 规则项 | 说明 |
| :-------------------- | :--------------- | :---------------------------------------------------------------------- |
| FR-AI-POLISH-UI-01 | 差异高亮 | 原文与润色后之间的差异字符以不同颜色高亮(红色删除线 = 原文被删,绿色下划线 = 新增) |
| FR-AI-POLISH-UI-02 | 段落边框 | 已采纳的段落行变为灰色并禁用"采纳"按钮,显示"已采纳"标记 |
| FR-AI-POLISH-UI-03 | 全部采纳 | 点击"全部采纳"后,面板显示"全部已采纳"状态 2 秒后自动关闭 |
| FR-AI-POLISH-UI-04 | 快捷键 | `Escape` 键关闭对比面板(触发表 FR-AI-POLISH-FE-07 的确认逻辑) |
| FR-AI-POLISH-UI-05 | 空状态 | 若润色后文本与原文完全一致(无优化空间),展示提示"未发现需要润色的内容" |
---
## 4. 交互流程
```
1. 用户在编辑器中选中一段文本
2. 用户点击工具栏"AI 润色"按钮
3. 系统校验选中文本长度(≥ 20 字符)
4. 按钮进入 loading 态,调用后端润色 API
5. API 返回后,编辑器下方弹出对比视图
6. 用户查看逐段差异:
a. 点击某段"采纳" → 该段原文被润色文本替换
b. 点击"全部采纳" → 全文替换,面板关闭
c. 点击"关闭" → 若有未采纳段落,确认后关闭
7. 完成后,用户可继续编辑或保存文章
```
---
## 5. 接口与代码对齐
### 5.1 后端涉及代码
| 模块 | 文件 | 变更说明 |
| :-------------- | :---------------------------------------------------------------- | :-------------------------------------------- |
| jog-module-blog | `dto/PolishTextDTO.java` | 新增请求 DTO(`text` 字段 + `@NotBlank` |
| jog-module-blog | `dto/PolishResultVO.java` | 新增响应 VO(含 `diffSegments` 对比数组) |
| jog-module-blog | `dto/DiffSegmentVO.java` | 新增段对比 VO(`index``original``polished`|
| jog-module-blog | `service/TextPolishService.java` + `service/impl/TextPolishServiceImpl.java` | 新增润色服务 |
| jog-module-blog | `controller/ArticleController.java` | 新增 `POST /api/app/article/polish` |
### 5.2 前端涉及代码
| 模块 | 文件 | 变更说明 |
| :----------- | :------------------------------------ | :---------------------------------------------------- |
| jog-frontend | `src/api/article.js` | 新增 `polishArticleText(data)` |
| jog-frontend | `src/views/app/ArticleEditor.vue` | 工具栏新增"AI 润色"按钮、新增对比面板组件 |
| jog-frontend | `src/components/PolishDiffPanel.vue` | 新增对比面板组件(原文 vs 润色后,段落级采纳) |
---
## 6. 非功能性需求
| 编号 | 类型 | 需求说明 |
| :------ | :-------- | :------------------------------------------------------------------------- |
| NFR-01 | 性能 | 95 分位响应时间 ≤ 10 秒(取决于 DashScope 服务,由超时 + 限流保护) |
| NFR-02 | 可用性 | DashScope 不可用时,用户仍可手动编辑文本,业务不受阻塞 |
| NFR-03 | 安全性 | API Key 不入库、不入日志、不入仓库;前端不感知 Key 任何信息 |
| NFR-04 | 可扩展性 | 后端通过 `TextPolishService` 接口抽象,未来可扩展拼写检查等独立功能 |
| NFR-05 | 可观测性 | 关键节点输出 INFO/ERROR 日志,包含耗时、文本长度 |
---
## 7. 风险与缓解
| 风险 | 影响 | 缓解措施 |
| :---------------------------- | :---------------------------------- | :------------------------------------------------------------------ |
| 模型输出偏离原意 | 润色结果不可用 | 提示词强调"保持原意不变";对比视图让用户逐段审核 |
| DashScope 服务限流或宕机 | 润色不可用 | 设置超时与降级,前端允许用户手动编辑 |
| 模型返回格式异常 | 对比视图渲染失败 | 后端对返回结果做段落对齐校验,失败时降级为全文对比 |
| 大量用户同时调用 | 超出 API 配额 | Redis 限流每分钟 5 次/用户 |
---
**编写人:** AI 助手
**评审人:** 待评审
**生效日期:** 2026-05-23