feat: 实现聊天取消功能,提升用户交互体验

- 在教练页面中添加用户取消发送或终止回复的能力
- 更新发送按钮状态,支持发送和取消状态切换
- 在流式回复中显示取消按钮,允许用户中断助手的生成
- 增强请求管理,添加请求序列号和有效性验证,防止延迟响应影响用户体验
- 优化错误处理,区分用户主动取消和网络错误,提升系统稳定性
- 更新相关文档,详细描述取消功能的实现和用户体验设计
This commit is contained in:
richarjiang
2025-08-18 18:59:23 +08:00
parent 05a00236bc
commit d52981ab29
6 changed files with 1097 additions and 78 deletions

View File

@@ -0,0 +1,234 @@
# 完整取消功能解决方案
## 问题诊断
您遇到的问题确实需要前后端协作解决:
1. **客户端问题**: XMLHttpRequest.abort() 只能终止网络传输,无法停止服务端处理
2. **会话持久化问题**: 服务端可能已经开始处理并保存会话记录
3. **延迟响应问题**: 服务端处理完成后,响应仍会到达客户端
## 已实现的客户端增强方案
### 1. 请求序列号机制
```typescript
// 防止延迟响应影响当前状态
const requestSequenceRef = useRef<number>(0);
const activeRequestIdRef = useRef<string | null>(null);
function cancelCurrentRequest() {
// 增加序列号,使后续响应失效
requestSequenceRef.current += 1;
activeRequestIdRef.current = null;
// 中断网络请求
streamAbortRef.current?.abort();
// 清理状态和UI
setIsSending(false);
setIsStreaming(false);
// ...
}
```
### 2. 请求有效性验证
```typescript
const isRequestValid = () => {
return activeRequestIdRef.current === requestId &&
requestSequenceRef.current === currentSequence;
};
// 在所有回调中验证
const onChunk = (chunk: string) => {
if (!isRequestValid()) {
console.log('Ignoring chunk from invalidated request');
return;
}
// 处理chunk...
};
```
### 3. 延迟会话ID生成
```typescript
// 修改前立即生成会话ID
function ensureConversationId(): string {
const cid = `mobile-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
setConversationId(cid); // 立即设置
return cid;
}
// 修改后:延迟生成,只在请求成功时设置
function ensureConversationId(): string {
if (conversationId && conversationId.trim()) return conversationId;
return ''; // 返回空,让服务端生成
}
```
### 4. 请求追踪机制
```typescript
// 在 api.ts 中添加请求ID
const requestId = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
const requestHeaders = {
'Content-Type': 'application/json',
'X-Request-Id': requestId, // 用于服务端追踪
// ...
};
```
## 需要服务端配合的方案
### 方案1: 连接断开检测(推荐)
**原理**: 服务端检测客户端连接状态,断开时停止处理
```python
# 服务端伪代码
async def ai_chat_stream(request):
conversation_id = request.json.get('conversationId')
is_new_conversation = not conversation_id
try:
# 检查客户端连接
if await request.is_disconnected():
return
# 延迟创建会话记录
temp_conv_id = None
if is_new_conversation:
temp_conv_id = create_temp_conversation()
async for chunk in ai_generate_stream():
# 每次生成前检查连接
if await request.is_disconnected():
if temp_conv_id:
delete_temp_conversation(temp_conv_id)
return
yield chunk
# 只有成功完成才保存会话
if temp_conv_id:
save_permanent_conversation(temp_conv_id)
except ClientDisconnectedError:
if temp_conv_id:
delete_temp_conversation(temp_conv_id)
```
**优点**:
- 自动检测无需额外API
- 资源清理及时
- 实现相对简单
### 方案2: 主动取消端点(备选)
**原理**: 提供专门的取消API客户端主动通知
```python
@app.post("/api/ai-coach/cancel")
async def cancel_request(request):
request_id = request.json.get('requestId')
conversation_id = request.json.get('conversationId')
# 标记请求取消
cancel_request_processing(request_id)
# 清理临时会话
if is_temp_conversation(conversation_id):
delete_conversation(conversation_id)
return {"status": "cancelled"}
```
**客户端调用**:
```typescript
function cancelCurrentRequest() {
// 现有逻辑...
// 主动通知服务端
if (activeRequestIdRef.current) {
notifyServerCancel(conversationId, activeRequestIdRef.current);
}
}
async function notifyServerCancel(conversationId?: string, requestId?: string) {
try {
await api.post('/api/ai-coach/cancel', {
requestId,
conversationId
});
} catch (error) {
console.warn('Failed to notify server:', error);
}
}
```
## 数据库设计建议
```sql
-- 会话状态管理
CREATE TABLE conversations (
id VARCHAR(50) PRIMARY KEY,
user_id INT,
status ENUM('temp', 'active', 'cancelled') DEFAULT 'temp',
created_at TIMESTAMP,
confirmed_at TIMESTAMP NULL,
messages JSON,
INDEX idx_status_created (status, created_at)
);
-- 定期清理临时会话(防止内存泄漏)
-- 可以用定时任务或在新请求时清理
DELETE FROM conversations
WHERE status = 'temp'
AND created_at < NOW() - INTERVAL 10 MINUTE;
```
## 立即可用的解决方案
### 当前已实现(无需服务端修改)
客户端增强已经可以解决大部分问题:
1.**防止延迟响应**: 请求序列号机制
2.**严格状态管理**: 请求有效性验证
3.**延迟会话创建**: 避免空会话记录
4.**即时UI反馈**: 取消后立即清理界面
### 效果评估
**改进前**:
- 点击取消 → 网络中断 → 但服务端继续处理 → 稍后响应仍然到达
- 会话记录已创建且保留
**改进后**:
- 点击取消 → 序列号增加 → 界面立即清理 → 延迟响应被忽略
- 会话ID延迟生成减少空记录
### 推荐实施步骤
**第一阶段(立即可用)**:
1. ✅ 使用当前客户端增强方案
2. 测试取消功能的改善效果
**第二阶段(服务端配合)**:
1. 实现连接断开检测
2. 临时会话管理机制
3. 完善资源清理
**第三阶段(可选优化)**:
1. 主动取消通知端点
2. 数据库优化和定期清理
3. 监控和日志完善
## 测试验证
建议测试以下场景:
1. **快速取消**: 发送后立即点击取消
2. **生成中取消**: 在AI回复过程中取消
3. **网络异常**: 弱网环境下的取消行为
4. **连续操作**: 快速发送多条消息并取消
5. **状态恢复**: 取消后是否能正常发送新消息
通过这个完整方案,可以显著改善取消功能的用户体验,即使在服务端暂未配合的情况下,客户端增强也能解决大部分问题。