• v1.0.3 e5f69b3aef

    v1.0.3 Stable

    gavin released this 2025-10-15 17:32:46 +08:00 | 8 commits to main since this release

    发布时间: 2025-10-15

    重大功能:停止生成 & UI 优化

    本版本实现了完整的停止生成功能,参考 Cherry Studio 的 PAUSED 状态设计,提供更好的用户体验。

    核心功能

    智能停止生成

    • 点击停止按钮立即中断 AI 回复(响应时间 < 100ms)
    • 保留已生成的内容,标记为"已停止"状态
    • 区分用户主动停止和系统错误
    • 停止后可立即继续对话

    UI 体验优化

    • 按钮文字从"确认"改为"发送"
    • 停止后显示黄色"已停止"标签(而非红色"发送失败")
    • 停止的消息可以复制、重新生成、删除
    • 实时状态反馈(发送中 → 已停止 → 可操作)

    状态管理增强

    • 新增 paused 消息状态
    • 新增 paused 流式事件类型
    • 完整的 AbortController 信号传递链
    • 流读取循环实时检查中止信号

    技术实现

    按钮事件修复

    • 修复点击事件绑定问题(从三元表达式改为函数调用)
    • 运行时动态判断状态,而非编译时
    // 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 更新显示"已停止"
    

    流读取中止检查

    while (true) {
      // 关键:每次读取前检查中止信号
      if (signal?.aborted) {
        console.log('检测到中止信号,停止读取流')
        reader.cancel()
        throw new DOMException('用户中止操作', 'AbortError')
      }
      
      const { done, value } = await reader.read()
      if (done) break
      
      // 处理数据...
    }
    

    错误处理优化

    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 修复

    Emoji 测试

    为验证发布脚本对 emoji 的处理(例如某些 emoji 属于 4 字节 unicode,可能触发服务器端 collation 问题),在此插入若干 emoji 供测试:

    • 表情类:
    • 物品/动作:
    • 动物/自然:
    • 标志/符号:️

    示例行(包含中文和 emoji):

    测试:本行包含中文与 emoji,目的是验证脚本对 emoji 的过滤与回退逻辑。示例 emoji: ️

    • 修复按钮点击无响应问题(事件绑定错误)
    • 修复停止后仍显示"发送中..."状态
    • 修复停止后消息列表不更新
    • 修复 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 - 快速验证清单

    升级指南

    # 拉取最新代码
    git pull origin main
    
    # 安装依赖
    cd web && npm install
    
    # 启动开发服务器
    npm run dev
    
    # 测试停止功能
    # 1. 发送消息
    # 2. 在 AI 回复时点击"停止"
    # 3. 验证显示"已停止"标签
    # 4. 验证可以继续对话
    

    验收标准

    • 按钮点击有明显反应
    • 流输出在 100ms 内停止
    • 显示"已停止"而非"失败"
    • 保留已生成内容
    • 停止后可立即继续对话
    • 可对停止的消息进行操作
    • 无意外错误日志

    下一步计划

    • 停止后自动保存草稿
    • 停止历史记录统计
    • 批量停止多个会话
    • 停止原因记录(用户主动/超时/错误)
    • 性能监控和优化

    v1.0.3 - 完美的停止体验,让对话更可控!

    Downloads