feat(ai): diff弹窗内容完整性优化 + HTML空行清洗
- systemPrompt和promptText中明确要求AI生成完整多段落内容,不要只改写现有段落 - systemPrompt增加HTML格式约束:<p>标签包裹、禁止<br>和换行符、紧凑HTML - setDiffModal和execCmd之前增加正则清洗:移除<br>、移除</p>与<p>间空白、trim首尾
This commit is contained in:
101
工程分析/20260419_0413/实现方案.md
Normal file
101
工程分析/20260419_0413/实现方案.md
Normal file
@@ -0,0 +1,101 @@
|
||||
# 实现方案
|
||||
|
||||
## 修改文件
|
||||
- `src/pages/ReportEditor.tsx`
|
||||
|
||||
## 修改位置 1:System Prompt 强化(约 line 905-907)
|
||||
|
||||
在 systemPrompt 中增加对「生成完整性」和「HTML 紧凑性」的明确要求。
|
||||
|
||||
**原代码**:
|
||||
```tsx
|
||||
const systemPrompt = aiModifyEnabled
|
||||
? '你是一名专业的外科医生助理。当前处于【修改模式】。\n我为你提供了当前手术报告的【全局参考内容】作为背景知识,以及你需要修改的【目标区域 HTML 源码】。\n请根据全局内容和用户的【医生指令】,直接重写并输出目标区域的 HTML。\n重要指令:\n1. 必须返回合法的 JSON 对象\n2. 必须包含 "reply"(简短回复话术)和 "updatedHtml"(修改后的完整内部 HTML 代码)两个字段\n3. 绝对不要包含任何 Markdown 标记(如 ```json)'
|
||||
: '你是一名专业的外科医生助理。当前处于【对话模式】。\n请仔细阅读我提供的【全局手术报告参考内容】,并根据【医生指令】进行专业解答。\n重要指令:\n1. 必须返回合法的 JSON 对象\n2. 仅包含 "reply"(你的专业回答)一个字段\n3. 不要返回任何 HTML 代码\n4. 绝对不要包含任何 Markdown 标记';
|
||||
```
|
||||
|
||||
**新代码**:
|
||||
```tsx
|
||||
const systemPrompt = aiModifyEnabled
|
||||
? '你是一名专业的外科医生助理。当前处于【修改模式】。\n我为你提供了当前手术报告的【全局参考内容】作为背景知识,以及你需要修改的【目标区域 HTML 源码】。\n请根据全局内容和用户的【医生指令】,直接重写并输出目标区域的 HTML。\n重要指令:\n1. 必须返回合法的 JSON 对象\n2. 必须包含 "reply"(简短回复话术)和 "updatedHtml"(修改后的完整内部 HTML 代码)两个字段\n3. updatedHtml 必须生成完整、结构化的多段落内容,不要只改写现有段落,要基于全局信息补充完善\n4. 段落必须使用 <p> 标签包裹,段落之间绝对不要使用 <br> 标签,也不要使用任何换行符 (\\n)\n5. 输出的 HTML 必须紧凑,标签之间不要有空格或换行\n6. 绝对不要包含任何 Markdown 标记(如 ```json)'
|
||||
: '你是一名专业的外科医生助理。当前处于【对话模式】。\n请仔细阅读我提供的【全局手术报告参考内容】,并根据【医生指令】进行专业解答。\n重要指令:\n1. 必须返回合法的 JSON 对象\n2. 仅包含 "reply"(你的专业回答)一个字段\n3. 不要返回任何 HTML 代码\n4. 绝对不要包含任何 Markdown 标记';
|
||||
```
|
||||
|
||||
**变更点**:
|
||||
1. 修改模式 systemPrompt 增加第 3 点:明确要求生成完整、结构化的多段落内容,基于全局信息补充完善
|
||||
2. 修改模式 systemPrompt 增加第 4 点:段落必须用 `<p>` 包裹,禁止 `<br>` 和 `\n`
|
||||
3. 修改模式 systemPrompt 增加第 5 点:HTML 必须紧凑,标签间不要有空格或换行
|
||||
|
||||
## 修改位置 2:Prompt 文本强化(约 line 891-895)
|
||||
|
||||
在 `promptText` 中增加对「生成完整性」的强调。
|
||||
|
||||
**原代码**:
|
||||
```tsx
|
||||
let promptText = `【全局手术报告参考内容】:\n${globalContextText}\n\n`;
|
||||
if (aiModifyEnabled && targetRegionEl) {
|
||||
promptText += `【你需要进行修改的目标区域 HTML 源码】:\n${currentHtml || '(当前区域为空)'}\n\n`;
|
||||
}
|
||||
promptText += `【医生指令】: ${text}`;
|
||||
```
|
||||
|
||||
**新代码**:
|
||||
```tsx
|
||||
let promptText = `【全局手术报告参考内容】:\n${globalContextText}\n\n`;
|
||||
if (aiModifyEnabled && targetRegionEl) {
|
||||
promptText += `【你需要进行修改的目标区域 HTML 源码】:\n${currentHtml || '(当前区域为空)'}\n\n`;
|
||||
}
|
||||
promptText += `【医生指令】: ${text}\n\n【格式要求】:\n1. 生成完整、结构化的多段落 HTML 内容,不要只改写现有段落\n2. 段落使用 <p> 标签,段落之间不要使用 <br> 标签或换行符\n3. 输出紧凑 HTML,标签间不要有空格或换行`;
|
||||
```
|
||||
|
||||
**变更点**:
|
||||
1. 在医生指令后追加「格式要求」段落
|
||||
2. 明确要求生成完整多段落内容,不要只改写现有段落
|
||||
3. 强调 `<p>` 标签、禁止 `<br>`、禁止换行符、紧凑 HTML
|
||||
|
||||
## 修改位置 3:HTML 清洗后处理(约 line 938-945)
|
||||
|
||||
在 `setDiffModal` 之前对 `updatedHtml` 进行正则清洗。
|
||||
|
||||
**原代码**:
|
||||
```tsx
|
||||
if (responseJson.updatedHtml && aiModifyEnabled) {
|
||||
if (targetRegionEl) {
|
||||
setDiffModal({
|
||||
isOpen: true,
|
||||
originalHtml: currentHtml,
|
||||
newHtml: responseJson.updatedHtml,
|
||||
targetId: actualTargetId
|
||||
});
|
||||
} else {
|
||||
execCmd('insertHTML', responseJson.updatedHtml);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**新代码**:
|
||||
```tsx
|
||||
if (responseJson.updatedHtml && aiModifyEnabled) {
|
||||
let cleanHtml = responseJson.updatedHtml;
|
||||
cleanHtml = cleanHtml.replace(/<br\s*\/?>/gi, '');
|
||||
cleanHtml = cleanHtml.replace(/<\/p>\s*<p>/gi, '</p><p>');
|
||||
cleanHtml = cleanHtml.trim();
|
||||
if (targetRegionEl) {
|
||||
setDiffModal({
|
||||
isOpen: true,
|
||||
originalHtml: currentHtml,
|
||||
newHtml: cleanHtml,
|
||||
targetId: actualTargetId
|
||||
});
|
||||
} else {
|
||||
execCmd('insertHTML', cleanHtml);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**变更点**:
|
||||
1. 新增 `cleanHtml` 变量,初始值为 `responseJson.updatedHtml`
|
||||
2. 移除 `<br>` 标签(不区分大小写)
|
||||
3. 移除 `</p>` 和 `<p>` 之间的空白字符(空格、换行、回车)
|
||||
4. 移除首尾空白
|
||||
5. `setDiffModal` 和 `execCmd` 均使用 `cleanHtml`
|
||||
52
工程分析/20260419_0413/测试方案.md
Normal file
52
工程分析/20260419_0413/测试方案.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# 测试方案
|
||||
|
||||
## 测试环境
|
||||
- 浏览器访问 `http://localhost:4173/`
|
||||
- 进入「图文报告生成」→ 新建报告
|
||||
|
||||
## 测试用例 1:AI 生成完整多段落内容
|
||||
|
||||
**步骤**:
|
||||
1. 编辑器中插入一个 AI 可编辑区域
|
||||
2. 在区域中只写一句话(如「建立气腹」)
|
||||
3. 在编辑器其他位置写入完整的手术报告信息(患者信息、其他步骤等)
|
||||
4. 勾选「允许修改正文」→ 发送「请完善手术步骤描述」
|
||||
|
||||
**预期结果**:
|
||||
- diff 弹窗左侧显示原有的一句话
|
||||
- diff 弹窗右侧显示 AI 生成的完整多段落内容(包含多个 `<p>` 标签)
|
||||
- 内容应基于全局报告信息补充完善,不只是改写原有的一句话
|
||||
|
||||
## 测试用例 2:右侧无多余空行
|
||||
|
||||
**步骤**:
|
||||
1. 编辑器中插入 AI 可编辑区域,写入多段内容(如 3 个 `<p>` 段落)
|
||||
2. 勾选「允许修改正文」→ 发送「请润色这段内容」
|
||||
3. 观察 diff 弹窗左右两侧的段落间距
|
||||
|
||||
**预期结果**:
|
||||
- 左右两侧段落间距一致
|
||||
- 右侧 AI 版本不应出现额外的空行或 `<br>`
|
||||
- 段落间仅由 `<p>` 标签的自然 margin 分隔
|
||||
|
||||
## 测试用例 3:HTML 清洗兜底
|
||||
|
||||
**步骤**:
|
||||
1. 触发 AI 修改,在浏览器 DevTools 中查看 `responseJson.updatedHtml` 原始值
|
||||
2. 确认原始值中可能包含 `<br>` 或 `\n`
|
||||
3. 观察 diff 弹窗右侧最终渲染结果
|
||||
|
||||
**预期结果**:
|
||||
- 即使原始返回值包含 `<br>` 或 `\n`,diff 弹窗右侧也不应显示多余空行
|
||||
- 清洗后的 HTML 结构紧凑
|
||||
|
||||
## 测试用例 4:编译与部署
|
||||
|
||||
**步骤**:
|
||||
1. 执行 `npm run build`
|
||||
2. 确认无 TypeScript 编译错误
|
||||
3. 预览服务正常启动并返回 200
|
||||
|
||||
**预期结果**:
|
||||
- `vite build` 成功完成
|
||||
- 预览页面可正常访问
|
||||
39
工程分析/20260419_0413/需求分析.md
Normal file
39
工程分析/20260419_0413/需求分析.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# 需求分析
|
||||
|
||||
## 时间戳
|
||||
2026-04-19 04:13
|
||||
|
||||
## 需求来源
|
||||
用户在使用 AI 修改确认弹窗时遇到两个问题:
|
||||
1. diff 弹窗左侧原始版本只显示一段内容,希望 AI 能一次性把全部内容都修改好
|
||||
2. diff 弹窗右侧 AI 提议版本的段落间有多余空行,希望结构和左侧保持一致
|
||||
|
||||
## 问题 1:左侧只显示一段
|
||||
|
||||
**现象**:diff 弹窗左侧「原始版本」只展示了一段文本。
|
||||
|
||||
**根因分析**:
|
||||
- `currentHtml` 取自 `.ai-content` 的 `innerHTML`,如果 `.ai-content` 内确实只有一段内容,左侧自然只显示一段
|
||||
- 这不是代码 Bug,而是当前 AI 区域的内容组织问题
|
||||
- 但用户期望 AI 能基于全局上下文生成更丰富、更完整的内容,而不是仅改写当前已有的段落
|
||||
|
||||
**解决方向**:
|
||||
- 在 systemPrompt 和 prompt 中明确要求 AI 生成完整的、结构化的多段落内容
|
||||
- 强调 AI 应基于全局参考内容补充和完善目标区域,而不是仅做局部改写
|
||||
|
||||
## 问题 2:右侧多余空行
|
||||
|
||||
**现象**:diff 弹窗右侧「AI 提议版本」的段落间出现额外空行,与左侧结构不一致。
|
||||
|
||||
**根因分析**:
|
||||
1. 大模型返回的 HTML 中可能包含 `<br>` 标签或 `\n` 换行符
|
||||
2. `</p>\n<p>` 中的换行符会被浏览器解析为文本节点,产生额外空白
|
||||
3. 不同 LLM 的输出格式随机性导致 HTML 结构不统一
|
||||
|
||||
**解决方向**:
|
||||
1. **输入端控制**:在 systemPrompt 中明确要求紧凑 HTML(禁止 `<br>`、禁止换行符)
|
||||
2. **输出端兜底**:在 `setDiffModal` 之前对 `updatedHtml` 进行正则清洗,移除多余空行和 `<br>`
|
||||
|
||||
## 约束条件
|
||||
- 保持现有 diff 弹窗的左右分栏结构不变
|
||||
- 清洗逻辑不应破坏合法的 HTML 结构(如 `<p>` 标签内的内容)
|
||||
31
工程分析/经验记录.md
31
工程分析/经验记录.md
@@ -718,3 +718,34 @@ ReportEditor 采用 `useRef` 作为自动保存的数据快照机制(避免 Re
|
||||
**D. 后续如何避免问题**
|
||||
- 当功能存在「全局开关 + 局部选择器」两层控制时,**全局开关开启后应自动兜底局部选择器**,避免因用户遗漏局部配置而导致功能降级。
|
||||
- System Prompt 中应显式标注当前模式名称(如「修改模式」「对话模式」),大模型对显式标签的遵循度远高于隐式条件推断。
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 记录 32:AI diff 弹窗内容不完整 + 右侧多余空行
|
||||
|
||||
**A. 具体问题**
|
||||
1. AI 修改确认弹窗左侧原始版本只显示一段内容,用户希望 AI 能一次性生成完整的多段落内容。
|
||||
2. diff 弹窗右侧 AI 提议版本的段落间出现额外空行,与左侧结构不一致。
|
||||
|
||||
**B. 产生问题原因**
|
||||
1. **内容不完整**:大模型被给予的目标区域源码(`currentHtml`)可能只有一段,且 systemPrompt 没有明确要求「生成完整、结构化的多段落内容」,导致 AI 只做局部改写。
|
||||
2. **多余空行**:大模型返回的 HTML 中常包含 `<br>` 标签或 `\n` 换行符。`</p>\n<p>` 中的换行符会被浏览器解析为文本节点,产生额外空白。
|
||||
|
||||
**C. 解决问题方案**
|
||||
1. **输入端控制(System Prompt + Prompt)**:
|
||||
- systemPrompt 增加明确要求:`updatedHtml 必须生成完整、结构化的多段落内容,不要只改写现有段落`
|
||||
- systemPrompt 增加 HTML 格式约束:`段落必须使用 <p> 标签包裹,段落之间绝对不要使用 <br> 标签,也不要使用任何换行符`
|
||||
- promptText 末尾追加「格式要求」段落,再次强调完整多段落、`<p>` 标签、禁止 `<br>`、紧凑 HTML
|
||||
2. **输出端兜底(正则清洗)**:
|
||||
```ts
|
||||
let cleanHtml = responseJson.updatedHtml;
|
||||
cleanHtml = cleanHtml.replace(/<br\s*\/?>/gi, '');
|
||||
cleanHtml = cleanHtml.replace(/<\/p>\s*<p>/gi, '</p><p>');
|
||||
cleanHtml = cleanHtml.trim();
|
||||
```
|
||||
在 `setDiffModal` 和 `execCmd` 之前统一清洗,确保右侧渲染结构与左侧一致。
|
||||
|
||||
**D. 后续如何避免问题**
|
||||
- 当大模型返回的 HTML 需要在前端渲染时,**必须同时在输入端(prompt)和输出端(后处理)进行格式约束**,单靠一端无法完全控制不同 LLM 的输出随机性。
|
||||
- 对于「生成完整性」类需求,必须在 prompt 中明确使用「必须生成完整...」「不要只改写...」等强制性措辞,否则大模型倾向于做最小化修改。
|
||||
|
||||
Reference in New Issue
Block a user