feat(ai): diff弹窗文档对比高亮 + 二次修改未弹窗修复

- 引入diff库,实现字符级差异比对
- diffModal左右两侧增加diff高亮:左侧删除内容标红,右侧新增内容标绿
- systemPrompt增加绝对强制条款:无论指令多小都必须返回updatedHtml
- 前端校验兜底:修改模式下未返回updatedHtml时在聊天面板给出提示
- confirmAiInjection注入前清理diff高亮span,避免污染编辑器
This commit is contained in:
2026-04-19 22:08:05 +08:00
parent 7275906f3c
commit 1ec25065ad
7 changed files with 312 additions and 20 deletions

View File

@@ -880,3 +880,37 @@ if (aiRegion && targetRegionEl) {
**D. 后续如何避免问题**
- 在 `contentEditable` 环境中修改内容时,**优先使用 `Range.selectNodeContents` + `execCommand('insertHTML')` 而非直接 `innerHTML` 赋值**,前者能让浏览器原生撤销/重做栈正常工作。
- 当大模型返回的 HTML 缺少必要的内联样式时,应在**前端后处理阶段**统一注入样式,而不是依赖大模型生成完整的样式代码(大模型对样式生成的稳定性较差)。
---
## 记录 37AI 二次修改未弹窗 + diff 弹窗增加文档对比高亮
**A. 具体问题**
1. 第一次 AI 修改正常弹出 diff 弹窗,第二次输入微调指令(如"把 5x3x2 变成 5x3x10")后没有弹窗。
2. diff 弹窗左侧和右侧只是简单渲染两段 HTML无法直观看到 AI 具体修改了哪些字词。
**B. 产生问题原因**
1. **未弹窗**:大模型在微小修改指令时可能"偷懒",只返回 `reply` 而不返回 `updatedHtml`。当前逻辑 `if (responseJson.updatedHtml && aiModifyEnabled)` 会跳过弹窗,用户没有任何反馈。
2. **无对比**:没有使用差异比对算法来标记变更,用户只能通过肉眼对比左右两侧发现差异。
**C. 解决问题方案**
1. **强化 systemPrompt**:增加第 8 条:「⚠️ 绝对强制:无论用户的修改指令多么微小,你都必须返回 updatedHtml。绝对不允许只返回 reply 而不返回 updatedHtml
2. **前端校验兜底**:在 `updatedHtml` 处理分支前增加:
```ts
if (aiModifyEnabled && !responseJson.updatedHtml) {
setChatMessages(prev => [...prev, { id: Date.now().toString(), role: 'model', content: '【系统提示】AI 未能生成修改内容,请尝试重新描述您的需求。' }]);
}
```
3. **引入 diff 库**`npm install diff`,使用 `diffChars` 进行字符级差异比对。
4. **左右两侧 diff 高亮**
- 左侧(原始版本):删除的内容标红(`background-color:#fee2e2; color:#dc2626; text-decoration:line-through;`
- 右侧AI 版本):新增的内容标绿(`background-color:#dcfce7; color:#16a34a;`
5. **注入前清理**`confirmAiInjection` 中去掉 diff 高亮 span
```ts
const cleanHtml = newHtml.replace(/<span class="diff-(added|removed)"[^>]*>(.*?)<\/span>/gi, '$2');
```
**D. 后续如何避免问题**
- 大模型对「必须返回某字段」的遵循度与 prompt 中该字段的强调程度正相关。对于关键输出字段,应在 systemPrompt 中使用「绝对强制」「绝对不允许」等最强措辞,并在前端增加缺失校验兜底。
- 在 diff 对比场景中,**纯文本层面的差异比对**比 HTML 层面的比对更可靠。应先将 HTML strip 为纯文本,再做 diff最后把结果渲染为 HTML。