diff --git a/release.md b/release.md index d2b3aaa..7ba633b 100644 --- a/release.md +++ b/release.md @@ -543,3 +543,230 @@ npm run dev --- +## v1.0.4 + +发布时间: 2025-10-15 + +### 🎯 重大功能:停止生成 & UI 优化 + +本版本实现了完整的停止生成功能,参考 Cherry Studio 的 PAUSED 状态设计,提供更好的用户体验。 + +#### ✨ 核心功能 + +**⏸️ 智能停止生成** +- 点击停止按钮立即中断 AI 回复(响应时间 < 100ms) +- 保留已生成的内容,标记为"已停止"状态 +- 区分用户主动停止和系统错误 +- 停止后可立即继续对话 + +**🎨 UI 体验优化** +- 按钮文字从"确认"改为"发送" +- 停止后显示黄色"已停止"标签(而非红色"发送失败") +- 停止的消息可以复制、重新生成、删除 +- 实时状态反馈(发送中 → 已停止 → 可操作) + +**🔄 状态管理增强** +- 新增 `paused` 消息状态 +- 新增 `paused` 流式事件类型 +- 完整的 AbortController 信号传递链 +- 流读取循环实时检查中止信号 + +#### 🛠️ 技术实现 + +**按钮事件修复** +- 修复点击事件绑定问题(从三元表达式改为函数调用) +- 运行时动态判断状态,而非编译时 +```typescript +// Before: @click="store.state.isSending ? handleStopGeneration : handleSendMessage" +// After: @click="handleButtonClick" +const handleButtonClick = () => { + if (store.state.isSending) { + handleStopGeneration() + } else { + handleSendMessage() + } +} +``` + +**中止信号传递链** +``` +UI (点击停止) + ↓ handleStopGeneration() + ↓ store.stopGeneration() + ↓ abortController.abort() + ↓ chatService.sendMessageStream(signal) + ↓ modelServiceManager.makeChatRequestStream(signal) + ↓ while循环检查 signal.aborted + ↓ reader.cancel() + 抛出 AbortError + ↓ 状态设置为 'paused' + ↓ UI 更新显示"已停止" +``` + +**流读取中止检查** +```typescript +while (true) { + // ⚠️ 关键:每次读取前检查中止信号 + if (signal?.aborted) { + console.log('🛑 检测到中止信号,停止读取流') + reader.cancel() + throw new DOMException('用户中止操作', 'AbortError') + } + + const { done, value } = await reader.read() + if (done) break + + // 处理数据... +} +``` + +**错误处理优化** +```typescript +catch (error) { + const isAborted = error instanceof Error && error.name === 'AbortError' + + if (isAborted) { + // 用户主动停止 - 标记为 paused,保留内容 + assistantMessage.status = 'paused' + assistantMessage.error = undefined + onChunk({ type: 'paused', messageId: assistantMessage.id }) + + // ✅ 关键:更新消息列表,触发 UI 刷新 + state.messages = [...chatService.getMessages(currentTopicId)] + } else { + // 真实错误 - 标记为 error + assistantMessage.status = 'error' + assistantMessage.error = error.message + } +} +``` + +#### 🐛 Bug 修复 + +- ✅ 修复按钮点击无响应问题(事件绑定错误) +- ✅ 修复停止后仍显示"发送中..."状态 +- ✅ 修复停止后消息列表不更新 +- ✅ 修复 AbortError 被错误标记为失败 +- ✅ 修复按钮文字显示"确认"而非"发送" + +#### 🔧 修改的文件 + +**类型定义** +- `/web/src/types/chat.ts` + - MessageStatus 添加 `'paused'` 类型 + - StreamEvent 添加 `'paused'` 事件类型 + +**UI 组件** +- `/web/src/components/Chat/ChatLayout.vue` + - 修复按钮点击事件绑定 + - 按钮文字改为"发送" + - 添加"已停止"状态标签显示 + - paused 状态消息显示操作按钮 + +**服务层** +- `/web/src/services/chatService.ts` + - 区分 AbortError 和其他错误 + - 设置 paused 状态和事件 + +- `/web/src/services/modelServiceManager.ts` + - 流读取循环中检查 signal.aborted + - 调用 reader.cancel() 中止读取 + - 正确处理 AbortError + +**状态管理** +- `/web/src/stores/chatStore.ts` + - 在 catch 块中更新消息列表 + - 确保 UI 显示最新状态 + +#### 💡 使用示例 + +``` +1. 用户发送:"请详细介绍 Vue 3 的新特性" +2. AI 开始回复,显示"发送中..." +3. 用户点击"停止"按钮 +4. 立即响应: + - 输出停止 + - 标签变为"已停止"(黄色) + - 显示已生成的内容 + - 显示操作按钮 +5. 用户可以: + - 复制已生成的内容 + - 重新生成完整回复 + - 删除该消息 + - 继续发送新消息 +``` + +#### 🎯 设计亮点 + +1. **参考 Cherry Studio** - 借鉴成熟产品的设计理念 +2. **立即响应** - 停止操作 < 100ms 响应 +3. **内容保留** - 部分生成的内容依然有价值 +4. **状态区分** - paused vs error,语义更清晰 +5. **完整操作** - 停止的消息仍可进行各种操作 +6. **信号传递** - 完整的中止信号链,确保可靠性 + +#### 📊 用户体验对比 + +**修复前 ❌** +- 点击停止无反应 +- 继续显示"发送中..." +- 显示 loading 动画 +- 按钮文字为"确认" + +**修复后 ✅** +- 点击立即停止 +- 显示"已停止"(黄色) +- 隐藏 loading 动画 +- 按钮文字为"发送" +- 可以操作停止的消息 +- 立即可继续对话 + +#### 📚 相关文档 + +- `STOP_GENERATION_SUMMARY.md` - 修复总结 +- `STOP_GENERATION_FIX.md` - 详细技术文档 +- `STOP_GENERATION_PATCH.md` - 补充修复说明 +- `STOP_GENERATION_TEST.md` - 测试指南 +- `STOP_GENERATION_VERIFY.md` - 快速验证清单 + +#### 🚀 升级指南 + +```bash +# 拉取最新代码 +git pull origin main + +# 安装依赖 +cd web && npm install + +# 启动开发服务器 +npm run dev + +# 测试停止功能 +# 1. 发送消息 +# 2. 在 AI 回复时点击"停止" +# 3. 验证显示"已停止"标签 +# 4. 验证可以继续对话 +``` + +#### ✅ 验收标准 + +- [x] 按钮点击有明显反应 +- [x] 流输出在 100ms 内停止 +- [x] 显示"已停止"而非"失败" +- [x] 保留已生成内容 +- [x] 停止后可立即继续对话 +- [x] 可对停止的消息进行操作 +- [x] 无意外错误日志 + +#### 🔜 下一步计划 + +- 停止后自动保存草稿 +- 停止历史记录统计 +- 批量停止多个会话 +- 停止原因记录(用户主动/超时/错误) +- 性能监控和优化 + +**v1.0.3 - 完美的停止体验,让对话更可控!** 🎉⏸️ + +--- + +