1
This commit is contained in:
@@ -167,7 +167,12 @@ export default {
|
|||||||
retryCount: 0,
|
retryCount: 0,
|
||||||
performanceMonitor: null,
|
performanceMonitor: null,
|
||||||
memoryCheckInterval: null,
|
memoryCheckInterval: null,
|
||||||
lastMemoryUsage: 0
|
lastMemoryUsage: 0,
|
||||||
|
|
||||||
|
// 请求监控
|
||||||
|
activeRequests: new Map(), // 存储活跃请求的信息
|
||||||
|
requestMonitorInterval: null,
|
||||||
|
maxRequestDuration: 60000 // 最大请求持续时间60秒
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -218,6 +223,9 @@ export default {
|
|||||||
// 启动性能监控
|
// 启动性能监控
|
||||||
this.startPerformanceMonitoring()
|
this.startPerformanceMonitoring()
|
||||||
|
|
||||||
|
// 启动请求监控
|
||||||
|
this.startRequestMonitoring()
|
||||||
|
|
||||||
// 确保DOM完全渲染后再初始化聊天
|
// 确保DOM完全渲染后再初始化聊天
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
@@ -240,6 +248,9 @@ export default {
|
|||||||
// 停止性能监控
|
// 停止性能监控
|
||||||
this.stopPerformanceMonitoring()
|
this.stopPerformanceMonitoring()
|
||||||
|
|
||||||
|
// 停止请求监控
|
||||||
|
this.stopRequestMonitoring()
|
||||||
|
|
||||||
// 清理定时器
|
// 清理定时器
|
||||||
if (this.loadDebounceTimer) {
|
if (this.loadDebounceTimer) {
|
||||||
clearTimeout(this.loadDebounceTimer)
|
clearTimeout(this.loadDebounceTimer)
|
||||||
@@ -666,7 +677,7 @@ export default {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// 创建流式聊天
|
// 创建流式聊天
|
||||||
const { stream, cancel } = createChatStream({
|
const { stream, cancel, requestId } = createChatStream({
|
||||||
conversationId: this.conversation_id || '',
|
conversationId: this.conversation_id || '',
|
||||||
prompt: userMessage,
|
prompt: userMessage,
|
||||||
user: this.user,
|
user: this.user,
|
||||||
@@ -675,14 +686,59 @@ export default {
|
|||||||
})
|
})
|
||||||
|
|
||||||
this.currentCancel = cancel
|
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
|
const response = await stream
|
||||||
|
clearTimeout(streamTimeout) // 清除超时保护
|
||||||
|
|
||||||
const { reader, decoder } = response
|
const { reader, decoder } = response
|
||||||
let buffer = ''
|
let buffer = ''
|
||||||
|
let lastUpdateTime = Date.now()
|
||||||
|
let noDataTimeout = null
|
||||||
|
|
||||||
while (true) {
|
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()
|
const { done, value } = await reader.read()
|
||||||
|
|
||||||
|
// 清除无数据超时
|
||||||
|
if (noDataTimeout) {
|
||||||
|
clearTimeout(noDataTimeout)
|
||||||
|
noDataTimeout = null
|
||||||
|
}
|
||||||
|
|
||||||
if (done) break
|
if (done) break
|
||||||
|
|
||||||
|
// 更新最后接收数据时间
|
||||||
|
lastUpdateTime = Date.now()
|
||||||
|
|
||||||
buffer += decoder.decode(value, { stream: true })
|
buffer += decoder.decode(value, { stream: true })
|
||||||
const lines = buffer.split('\n')
|
const lines = buffer.split('\n')
|
||||||
buffer = lines.pop() || ''
|
buffer = lines.pop() || ''
|
||||||
@@ -720,6 +776,13 @@ export default {
|
|||||||
// 标记流输出完成
|
// 标记流输出完成
|
||||||
aiMsg.streamCompleted = true
|
aiMsg.streamCompleted = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理错误事件
|
||||||
|
if (data.event === 'error') {
|
||||||
|
aiMsg.content = data.message || '服务器处理出错,请重新发送'
|
||||||
|
aiMsg.streamCompleted = true
|
||||||
|
break
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('JSON解析失败:', line, e)
|
console.warn('JSON解析失败:', line, e)
|
||||||
}
|
}
|
||||||
@@ -727,15 +790,45 @@ export default {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('发送消息失败:', 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 // 即使出错也标记为完成,显示操作区域
|
aiMsg.streamCompleted = true // 即使出错也标记为完成,显示操作区域
|
||||||
this.showToast('发送消息失败')
|
this.showToast(errorMessage, 'error')
|
||||||
} finally {
|
} finally {
|
||||||
this.sending = false
|
this.sending = false
|
||||||
|
this.currentCancel = null
|
||||||
|
|
||||||
|
// 清理所有定时器
|
||||||
|
if (streamTimeout) clearTimeout(streamTimeout)
|
||||||
|
if (noDataTimeout) clearTimeout(noDataTimeout)
|
||||||
|
|
||||||
// 从请求队列中移除当前请求
|
// 从请求队列中移除当前请求
|
||||||
this.requestQueue = this.requestQueue.filter(id => id !== requestId)
|
this.requestQueue = this.requestQueue.filter(id => id !== requestId)
|
||||||
|
|
||||||
|
// 从监控系统中移除请求
|
||||||
|
this.activeRequests.delete(requestId)
|
||||||
|
|
||||||
this.scrollToBottom(true) // 发送完成后使用平滑滚动
|
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