1
This commit is contained in:
@@ -128,7 +128,7 @@ import {
|
||||
formatChatMessage,
|
||||
formatMessageTime
|
||||
} from '@/http/api/assistant.js'
|
||||
import { createPetAssistantSSE } from '@/utils/sse.js'
|
||||
import { createPetAssistantWebSocket } from '@/utils/websocket.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
@@ -192,6 +192,9 @@ export default {
|
||||
// 开始AI思考
|
||||
this.isThinking = true
|
||||
|
||||
// 用于存储当前AI消息的引用
|
||||
let currentAiMessage = null
|
||||
|
||||
// 确保DOM更新后再滚动到思考状态
|
||||
this.$nextTick(() => {
|
||||
this.forceScrollToBottom()
|
||||
@@ -205,11 +208,14 @@ export default {
|
||||
})
|
||||
|
||||
try {
|
||||
// 使用SSE流式响应
|
||||
// 使用WebSocket流式响应
|
||||
const response = await this.handleStreamResponse({
|
||||
message: userInput,
|
||||
temperature: 0.7,
|
||||
maxTokens: 1000
|
||||
}, (aiMessage) => {
|
||||
// 保存AI消息引用,用于fallback时更新
|
||||
currentAiMessage = aiMessage
|
||||
})
|
||||
|
||||
// 检查是否包含敏感词
|
||||
@@ -235,17 +241,25 @@ export default {
|
||||
})
|
||||
|
||||
if (fallbackResponse && fallbackResponse.data) {
|
||||
const aiMessage = {
|
||||
type: 'ai',
|
||||
content: fallbackResponse.data.message || fallbackResponse.data.content || '抱歉,我现在无法回答您的问题。',
|
||||
time: this.getCurrentTime(),
|
||||
isSensitive: fallbackResponse.data.isSensitive || false,
|
||||
tokenCount: fallbackResponse.data.tokenCount || 0,
|
||||
responseTime: fallbackResponse.data.responseTime || 0
|
||||
// 更新已存在的AI消息,而不是创建新的
|
||||
if (currentAiMessage) {
|
||||
currentAiMessage.content = fallbackResponse.data.message || fallbackResponse.data.content || '抱歉,我现在无法回答您的问题。'
|
||||
currentAiMessage.isSensitive = fallbackResponse.data.isSensitive || false
|
||||
currentAiMessage.tokenCount = fallbackResponse.data.tokenCount || 0
|
||||
currentAiMessage.responseTime = fallbackResponse.data.responseTime || 0
|
||||
} else {
|
||||
// 如果没有AI消息引用,创建新的(兜底逻辑)
|
||||
const aiMessage = {
|
||||
type: 'ai',
|
||||
content: fallbackResponse.data.message || fallbackResponse.data.content || '抱歉,我现在无法回答您的问题。',
|
||||
time: this.getCurrentTime(),
|
||||
isSensitive: fallbackResponse.data.isSensitive || false,
|
||||
tokenCount: fallbackResponse.data.tokenCount || 0,
|
||||
responseTime: fallbackResponse.data.responseTime || 0
|
||||
}
|
||||
this.messageList.push(aiMessage)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 检查敏感词
|
||||
if (fallbackResponse.data.isSensitive) {
|
||||
uni.showToast({
|
||||
@@ -255,14 +269,13 @@ export default {
|
||||
})
|
||||
}
|
||||
|
||||
this.messageList.push(aiMessage)
|
||||
this.forceScrollToBottom()
|
||||
} else {
|
||||
this.handleApiError('API响应格式异常')
|
||||
this.handleApiError('API响应格式异常', currentAiMessage)
|
||||
}
|
||||
} catch (fallbackError) {
|
||||
console.error('普通请求也失败:', fallbackError)
|
||||
this.handleApiError(fallbackError.message || '网络请求失败')
|
||||
this.handleApiError(fallbackError.message || '网络请求失败', currentAiMessage)
|
||||
}
|
||||
} finally {
|
||||
// 确保思考状态结束(防止异常情况)
|
||||
@@ -273,17 +286,26 @@ export default {
|
||||
/**
|
||||
* 处理API错误
|
||||
* @param {string} errorMessage 错误信息
|
||||
* @param {Object} existingAiMessage 已存在的AI消息对象(可选)
|
||||
*/
|
||||
handleApiError(errorMessage) {
|
||||
const errorMessage_display = {
|
||||
type: 'ai',
|
||||
content: `抱歉,我遇到了一些问题:${errorMessage}\n\n请稍后再试,或者检查网络连接。`,
|
||||
time: this.getCurrentTime(),
|
||||
isError: true
|
||||
handleApiError(errorMessage, existingAiMessage = null) {
|
||||
const errorContent = `抱歉,我遇到了一些问题:${errorMessage}\n\n请稍后再试,或者检查网络连接。`
|
||||
|
||||
if (existingAiMessage) {
|
||||
// 更新已存在的AI消息
|
||||
existingAiMessage.content = errorContent
|
||||
existingAiMessage.isError = true
|
||||
} else {
|
||||
// 创建新的错误消息(兜底逻辑)
|
||||
const errorMessage_display = {
|
||||
type: 'ai',
|
||||
content: errorContent,
|
||||
time: this.getCurrentTime(),
|
||||
isError: true
|
||||
}
|
||||
this.messageList.push(errorMessage_display)
|
||||
}
|
||||
|
||||
// 直接添加错误消息
|
||||
this.messageList.push(errorMessage_display)
|
||||
this.forceScrollToBottom()
|
||||
},
|
||||
|
||||
@@ -291,28 +313,43 @@ export default {
|
||||
* 加载聊天历史记录
|
||||
*/
|
||||
async loadChatHistory() {
|
||||
console.log('开始加载聊天历史记录...')
|
||||
try {
|
||||
const response = await getAssistantHistory({
|
||||
page: 1,
|
||||
pageSize: 50
|
||||
pageSize: 20
|
||||
})
|
||||
|
||||
if (response && response.data && response.data.list && response.data.list.length > 0) {
|
||||
console.log('历史记录API响应:', response)
|
||||
|
||||
if (response && Array.isArray(response) && response.length > 0) {
|
||||
// 格式化并设置历史消息
|
||||
const historyMessages = response.data.list.map(msg => formatChatMessage(msg))
|
||||
const historyMessages = response.map(msg => formatChatMessage(msg))
|
||||
console.log('格式化后的历史消息:', historyMessages)
|
||||
this.messageList = historyMessages
|
||||
|
||||
// 滚动到底部
|
||||
this.$nextTick(() => {
|
||||
this.scrollToBottom()
|
||||
})
|
||||
|
||||
console.log('历史记录加载成功,共', historyMessages.length, '条消息')
|
||||
} else {
|
||||
// 没有历史记录,保持空列表
|
||||
console.log('没有历史记录或数据格式异常:', response)
|
||||
this.messageList = []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载历史记录失败:', error)
|
||||
// 静默处理,保持空列表
|
||||
|
||||
// 显示用户友好的错误提示
|
||||
uni.showToast({
|
||||
title: '加载历史记录失败',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
})
|
||||
|
||||
// 保持空列表
|
||||
this.messageList = []
|
||||
}
|
||||
},
|
||||
@@ -360,11 +397,12 @@ export default {
|
||||
|
||||
|
||||
/**
|
||||
* 处理SSE流式响应
|
||||
* 处理WebSocket流式响应
|
||||
* @param {Object} messageData 消息数据
|
||||
* @param {Function} onAiMessageCreated 创建AI消息后的回调函数
|
||||
* @returns {Promise} 返回流式响应处理结果
|
||||
*/
|
||||
async handleStreamResponse(messageData) {
|
||||
async handleStreamResponse(messageData, onAiMessageCreated) {
|
||||
// 创建AI消息对象
|
||||
const aiMessage = {
|
||||
type: 'ai',
|
||||
@@ -378,14 +416,23 @@ export default {
|
||||
// 添加到消息列表
|
||||
this.messageList.push(aiMessage)
|
||||
|
||||
// 使用SSE工具类处理流式响应
|
||||
return createPetAssistantSSE(messageData, {
|
||||
// 通知调用者AI消息已创建
|
||||
if (onAiMessageCreated) {
|
||||
onAiMessageCreated(aiMessage)
|
||||
}
|
||||
|
||||
// 使用WebSocket工具类处理流式响应
|
||||
return createPetAssistantWebSocket(messageData, {
|
||||
onChunk: (chunk) => {
|
||||
// 实时更新消息内容
|
||||
console.log('收到WebSocket流式数据块:', chunk)
|
||||
// 实时更新消息内容,实现打字机效果
|
||||
aiMessage.content = chunk.totalContent
|
||||
// 强制触发视图更新
|
||||
this.$forceUpdate()
|
||||
this.forceScrollToBottom()
|
||||
},
|
||||
onComplete: (result) => {
|
||||
console.log('WebSocket流式响应完成:', result)
|
||||
// 更新消息的元数据
|
||||
if (result.data.isSensitive !== undefined) {
|
||||
aiMessage.isSensitive = result.data.isSensitive
|
||||
@@ -396,9 +443,17 @@ export default {
|
||||
if (result.data.responseTime !== undefined) {
|
||||
aiMessage.responseTime = result.data.responseTime
|
||||
}
|
||||
// 强制触发视图更新
|
||||
this.$forceUpdate()
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error('SSE流式响应失败:', error)
|
||||
console.error('WebSocket流式响应失败:', error)
|
||||
// 显示错误提示
|
||||
uni.showToast({
|
||||
title: '消息发送失败',
|
||||
icon: 'error',
|
||||
duration: 2000
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user