This commit is contained in:
2025-08-17 22:38:36 +08:00
parent bab6bde04d
commit 6f2a12fab5

View File

@@ -167,7 +167,12 @@ export default {
retryCount: 0,
performanceMonitor: null,
memoryCheckInterval: null,
lastMemoryUsage: 0
lastMemoryUsage: 0,
// 请求监控
activeRequests: new Map(), // 存储活跃请求的信息
requestMonitorInterval: null,
maxRequestDuration: 60000 // 最大请求持续时间60秒
}
},
computed: {
@@ -217,6 +222,9 @@ export default {
// 启动性能监控
this.startPerformanceMonitoring()
// 启动请求监控
this.startRequestMonitoring()
// 确保DOM完全渲染后再初始化聊天
this.$nextTick(() => {
@@ -240,6 +248,9 @@ export default {
// 停止性能监控
this.stopPerformanceMonitoring()
// 停止请求监控
this.stopRequestMonitoring()
// 清理定时器
if (this.loadDebounceTimer) {
clearTimeout(this.loadDebounceTimer)
@@ -666,7 +677,7 @@ export default {
try {
// 创建流式聊天
const { stream, cancel } = createChatStream({
const { stream, cancel, requestId } = createChatStream({
conversationId: this.conversation_id || '',
prompt: userMessage,
user: this.user,
@@ -675,13 +686,58 @@ export default {
})
this.currentCancel = cancel
// 注册请求到监控系统
this.activeRequests.set(requestId, {
startTime: Date.now(),
type: 'sendMessage',
cancel: cancel,
userMessage: userMessage
})
// 添加额外的超时保护
const streamTimeout = setTimeout(() => {
if (cancel) {
cancel('流式响应超时')
}
aiMsg.content = '响应超时,请重新发送消息'
aiMsg.streamCompleted = true
this.sending = false
}, 45000) // 45秒超时保护
const response = await stream
clearTimeout(streamTimeout) // 清除超时保护
const { reader, decoder } = response
let buffer = ''
let lastUpdateTime = Date.now()
let noDataTimeout = null
while (true) {
// 设置无数据超时检测
if (noDataTimeout) {
clearTimeout(noDataTimeout)
}
noDataTimeout = setTimeout(() => {
if (cancel) {
cancel('数据流中断')
}
aiMsg.content = aiMsg.content === '正在思考...' ? '服务器响应中断,请重新发送' : aiMsg.content + '\n\n[响应中断]'
aiMsg.streamCompleted = true
}, 15000) // 15秒无数据则认为中断
const { done, value } = await reader.read()
// 清除无数据超时
if (noDataTimeout) {
clearTimeout(noDataTimeout)
noDataTimeout = null
}
if (done) break
// 更新最后接收数据时间
lastUpdateTime = Date.now()
buffer += decoder.decode(value, { stream: true })
const lines = buffer.split('\n')
@@ -720,6 +776,13 @@ export default {
// 标记流输出完成
aiMsg.streamCompleted = true
}
// 处理错误事件
if (data.event === 'error') {
aiMsg.content = data.message || '服务器处理出错,请重新发送'
aiMsg.streamCompleted = true
break
}
} catch (e) {
console.warn('JSON解析失败:', line, e)
}
@@ -727,15 +790,45 @@ export default {
}
} catch (error) {
console.error('发送消息失败:', error)
aiMsg.content = '抱歉,发送消息时出现错误,请稍后重试。'
// 清理所有定时器
if (streamTimeout) clearTimeout(streamTimeout)
if (noDataTimeout) clearTimeout(noDataTimeout)
// 根据错误类型显示不同的错误信息
let errorMessage = '发送消息失败'
if (error.message.includes('超时')) {
aiMsg.content = '网络连接超时,请检查网络后重试'
errorMessage = '网络连接超时'
} else if (error.message.includes('取消')) {
aiMsg.content = '请求已取消'
errorMessage = '请求已取消'
} else if (error.message.includes('网络')) {
aiMsg.content = '网络连接异常,请检查网络设置'
errorMessage = '网络连接异常'
} else if (error.message.includes('登录')) {
aiMsg.content = '登录已过期,请重新登录'
errorMessage = '登录已过期'
} else {
aiMsg.content = '抱歉,发送消息时出现错误,请稍后重试'
}
aiMsg.streamCompleted = true // 即使出错也标记为完成,显示操作区域
this.showToast('发送消息失败')
this.showToast(errorMessage, 'error')
} finally {
this.sending = false
this.currentCancel = null
// 清理所有定时器
if (streamTimeout) clearTimeout(streamTimeout)
if (noDataTimeout) clearTimeout(noDataTimeout)
// 从请求队列中移除当前请求
this.requestQueue = this.requestQueue.filter(id => id !== requestId)
// 从监控系统中移除请求
this.activeRequests.delete(requestId)
this.scrollToBottom(true) // 发送完成后使用平滑滚动
}
},
@@ -1018,6 +1111,69 @@ export default {
}
},
/**
* 启动请求监控
*/
startRequestMonitoring() {
if (this.requestMonitorInterval) {
clearInterval(this.requestMonitorInterval)
}
this.requestMonitorInterval = setInterval(() => {
this.checkActiveRequests()
}, 5000) // 每5秒检查一次
},
/**
* 停止请求监控
*/
stopRequestMonitoring() {
if (this.requestMonitorInterval) {
clearInterval(this.requestMonitorInterval)
this.requestMonitorInterval = null
}
// 取消所有活跃请求
this.activeRequests.forEach((request, requestId) => {
if (request.cancel) {
request.cancel('组件销毁')
}
})
this.activeRequests.clear()
},
/**
* 检查活跃请求
*/
checkActiveRequests() {
const now = Date.now()
const expiredRequests = []
this.activeRequests.forEach((request, requestId) => {
const duration = now - request.startTime
// 如果请求超过最大持续时间,标记为过期
if (duration > this.maxRequestDuration) {
expiredRequests.push({ requestId, request })
}
})
// 取消过期请求
expiredRequests.forEach(({ requestId, request }) => {
console.warn(`强制取消超时请求: ${request.type}, 持续时间: ${(Date.now() - request.startTime) / 1000}`)
if (request.cancel) {
request.cancel('请求超时被强制取消')
}
this.activeRequests.delete(requestId)
// 显示超时提示
this.showToast('请求超时已自动取消,请重试', 'warning')
})
},
/**
* 执行内存清理
*/