1
This commit is contained in:
@@ -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')
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 执行内存清理
|
||||
*/
|
||||
|
Reference in New Issue
Block a user