chore:把 message替换成 query

This commit is contained in:
2025-12-11 09:42:28 +08:00
parent 2750d8012f
commit f0d3d1986f

View File

@@ -1,349 +1,250 @@
import http from './http.js' import http from './http.js'
import store from '@/store/index.js' import store from '@/store/index.js'
export default { export default {
/** /**
* 发送消息到Dify API * 发送消息到Dify API
* @param {string} message 用户消息内容 * @param {string} message 用户消息内容
* @param {Object} options 配置选项 * @param {Object} options 配置选项
* @returns {Promise} * @returns {Promise}
*/ */
async sendMessage(message, options = {}) { async sendMessage(message, options = {}) {
try { try {
// 获取AI配置 // 获取AI配置
const aiConfig = store.getters.globalAIKefuConfig const aiConfig = store.getters.globalAIKefuConfig
// const new_conversationId = await this.generateConversationId() // const new_conversationId = await this.generateConversationId()
// 构建Dify API请求参数 // 构建Dify API请求参数
const params = { const params = {
url: '/api/kefu/chat', // 后端代理接口 url: '/api/kefu/chat', // 后端代理接口
data: { data: {
message: message, // conversation_id: options.conversationId ?? new_conversationId,
// conversation_id: options.conversationId ?? new_conversationId, user_id: store.state.memberInfo?.id || 'anonymous',
user_id: store.state.memberInfo?.id || 'anonymous', stream: false,
stream: options.stream || false, // 是否流式响应 // Dify API参数
// Dify API参数 inputs: {},
inputs: {}, query: message,
query: message, response_mode: options.stream ? 'streaming' : 'blocking',
response_mode: options.stream ? 'streaming' : 'blocking', user: store.state.memberInfo?.id || 'anonymous'
user: store.state.memberInfo?.id || 'anonymous' },
}, header: {
header: { 'Content-Type': 'application/json'
'Content-Type': 'application/json' }
} }
}
// 发送请求
// 发送请求 const response = await http.sendRequest({
const response = await http.sendRequest({ ...params,
...params, async: false // 使用Promise方式
async: false // 使用Promise方式 })
})
return this.handleResponse(response, options)
return this.handleResponse(response, options)
} catch (error) {
} catch (error) { console.error('Dify API请求失败:', error)
console.error('Dify API请求失败:', error) throw new Error('AI服务暂时不可用请稍后重试')
throw new Error('AI服务暂时不可用请稍后重试') }
} },
},
/**
/** * 流式消息处理
* 流式消息处理 * @param {string} message 用户消息
* @param {string} message 用户消息 * @param {Function} onChunk 流式数据回调
* @param {Function} onChunk 流式数据回调 * @param {Function} onComplete 完成回调
* @param {Function} onComplete 完成回调 */
*/ async sendStreamMessage(message, onChunk, onComplete) {
async sendStreamMessage(message, onChunk, onComplete) { try {
try { // 使用HTTP流式请求
// 使用HTTP流式请求 return this.sendHttpStream(message, onChunk, onComplete)
return this.sendHttpStream(message, onChunk, onComplete)
} catch (error) {
} catch (error) { console.error('流式消息发送失败:', error)
console.error('流式消息发送失败:', error) throw error
throw error }
} },
},
/**
/** * HTTP流式请求
* WebSocket连接 */
*/ async sendHttpStream(message, onChunk, onComplete) {
connectWebSocket(message, onChunk, onComplete) { const params = {
return new Promise((resolve, reject) => { url: '/api/kefu/chat',
const aiConfig = store.getters.globalAIKefuConfig data: {
const wsUrl = aiConfig.difyWsUrl query: message,
conversation_id: this.generateConversationId(),
if (!wsUrl) { user_id: store.state.memberInfo?.id || 'anonymous',
reject(new Error('未配置WebSocket地址')) stream: true,
return uniacid: store.state.uniacid, // 保留必填参数
} },
header: {
// #ifdef H5 'Content-Type': 'application/json'
const ws = new WebSocket(wsUrl) }
}
ws.onopen = () => {
// 发送消息 // 使用fetch API进行流式请求H5环境
ws.send(JSON.stringify({ // #ifdef H5
message: message, try {
user_id: store.state.memberInfo?.id || 'anonymous', const response = await fetch(`/api/kefu/chat`, {
conversation_id: this.generateConversationId() method: 'POST',
})) headers: {
} 'Content-Type': 'application/json',
},
ws.onmessage = (event) => { body: JSON.stringify({
try { inputs: {},
const data = JSON.parse(event.data) query: message,
if (data.type === 'chunk' && onChunk) { response_mode: 'streaming',
onChunk(data.content) user: store.state.memberInfo?.id || 'anonymous'
} else if (data.type === 'complete' && onComplete) { })
onComplete(data.content) })
ws.close()
resolve(data.content) const reader = response.body.getReader()
} const decoder = new TextDecoder()
} catch (e) { let content = ''
console.error('WebSocket消息解析失败:', e)
} while (true) {
} const { done, value } = await reader.read()
if (done) break
ws.onerror = (error) => {
console.error('WebSocket连接错误:', error) const chunk = decoder.decode(value)
reject(error) const lines = chunk.split('\n')
}
for (const line of lines) {
ws.onclose = () => { if (line.startsWith('data: ')) {
console.log('WebSocket连接关闭') try {
} const data = JSON.parse(line.slice(6))
// #endif if (data.event === 'text_message' && data.text) {
content += data.text
// #ifdef MP-WEIXIN || APP-PLUS if (onChunk) onChunk(data.text)
// 小程序和APP使用uni.connectSocket }
uni.connectSocket({ } catch (e) {
url: wsUrl, // 忽略解析错误
success: () => { }
uni.onSocketOpen(() => { }
uni.sendSocketMessage({ }
data: JSON.stringify({ }
message: message,
user_id: store.state.memberInfo?.id || 'anonymous', if (onComplete) onComplete(content)
conversation_id: this.generateConversationId() return content
})
}) } catch (error) {
}) console.error('HTTP流式请求失败:', error)
throw error
uni.onSocketMessage((res) => { }
try { // #endif
const data = JSON.parse(res.data)
if (data.type === 'chunk' && onChunk) { // 非H5环境使用普通请求模拟流式效果
onChunk(data.content) // #ifndef H5
} else if (data.type === 'complete' && onComplete) { const response = await http.sendRequest({
onComplete(data.content) ...params,
uni.closeSocket() async: false
resolve(data.content) })
}
} catch (e) { // 模拟流式效果
console.error('WebSocket消息解析失败:', e) if (response.success && response.data) {
} const content = response.data
}) const chunkSize = 3
let index = 0
uni.onSocketError((error) => {
console.error('WebSocket连接错误:', error) const streamInterval = setInterval(() => {
reject(error) if (index < content.length) {
}) const chunk = content.substring(index, index + chunkSize)
}, index += chunkSize
fail: (error) => { if (onChunk) onChunk(chunk)
reject(error) } else {
} clearInterval(streamInterval)
}) if (onComplete) onComplete(content)
// #endif }
}) }, 100)
}, }
// #endif
/** },
* HTTP流式请求
*/ /**
async sendHttpStream(message, onChunk, onComplete) { * 处理API响应
const aiConfig = store.getters.globalAIKefuConfig */
handleResponse(response, options) {
const params = { if (response.code === 0 || response.success) {
url: '/api/kefu/chat-stream', return {
data: { success: true,
message: message, content: response.data?.answer || response.data?.content || response.data?.reply|| response.data,
conversation_id: this.generateConversationId(), conversationId: response.data?.conversation_id,
user_id: store.state.memberInfo?.id || 'anonymous', messageId: response.data?.message_id
stream: true }
}, } else {
header: { throw new Error(response.message || 'AI服务返回错误')
'Content-Type': 'application/json' }
} },
}
/**
if (aiConfig?.difyApiKey) { * 生成会话ID
params.header['Authorization'] = `Bearer ${aiConfig.difyApiKey}` */
} async generateConversationId() {
// 构建Dify API请求参数
// 使用fetch API进行流式请求H5环境 const params = {
// #ifdef H5 url: '/api/kefu/createConversation', // 后端代理接口
try { data: {
const response = await fetch(`/api/kefu/chat-messages`, { uniacid: store.state.uniacid,
method: 'POST', user_id: store.state.memberInfo?.id || 'anonymous',
headers: { member_id: store.state.memberInfo?.id || '',
'Content-Type': 'application/json', },
}, header: {
body: JSON.stringify({ 'Content-Type': 'application/json'
inputs: {}, }
query: message, }
response_mode: 'streaming',
user: store.state.memberInfo?.id || 'anonymous' // 发送请求
}) const response = await http.sendRequest({
}) ...params,
async: false // 使用Promise方式
const reader = response.body.getReader() })
const decoder = new TextDecoder()
let content = '' return this.handleResponse(response, options)
},
while (true) {
const { done, value } = await reader.read() /**
if (done) break * 获取AI服务状态
*/
const chunk = decoder.decode(value) async getServiceStatus() {
const lines = chunk.split('\n') try {
// 简单的健康检查
for (const line of lines) { const response = await http.sendRequest({
if (line.startsWith('data: ')) { url: '/api/kefu/health',
try { async: false,
const data = JSON.parse(line.slice(6)) data: {}
if (data.event === 'text_message' && data.text) { })
content += data.text
if (onChunk) onChunk(data.text) const available = [response?.data?.status, response?.data?.components?.ai_service_config?.status].filter(item => item === 'healthy').length > 0;
}
} catch (e) { return {
// 忽略解析错误 available,
} reason: available ? '服务正常' : '服务异常'
} }
}
} } catch (error) {
return {
if (onComplete) onComplete(content) available: false,
return content reason: '服务检查失败'
}
} catch (error) { }
console.error('HTTP流式请求失败:', error) },
throw error
} /**
// #endif * 清除会话历史
*/
// 非H5环境使用普通请求模拟流式效果 async clearConversation(conversationId) {
// #ifndef H5 try {
const response = await http.sendRequest({ const response = await http.sendRequest({
...params, url: '/api/kefu/clear-conversation',
async: false data: { conversation_id: conversationId },
}) async: false
})
// 模拟流式效果
if (response.success && response.data) { return response.success
const content = response.data
const chunkSize = 3 } catch (error) {
let index = 0 console.error('清除会话失败:', error)
return false
const streamInterval = setInterval(() => { }
if (index < content.length) { }
const chunk = content.substring(index, index + chunkSize)
index += chunkSize
if (onChunk) onChunk(chunk)
} else {
clearInterval(streamInterval)
if (onComplete) onComplete(content)
}
}, 100)
}
// #endif
},
/**
* 处理API响应
*/
handleResponse(response, options) {
if (response.code === 0 || response.success) {
return {
success: true,
content: response.data?.answer || response.data?.content || response.data?.reply|| response.data,
conversationId: response.data?.conversation_id,
messageId: response.data?.message_id
}
} else {
throw new Error(response.message || 'AI服务返回错误')
}
},
/**
* 生成会话ID
*/
async generateConversationId() {
// 构建Dify API请求参数
const params = {
url: '/api/kefu/createConversation', // 后端代理接口
data: {
uniacid: store.state.uniacid,
user_id: store.state.memberInfo?.id || 'anonymous',
member_id: store.state.memberInfo?.id || '',
},
header: {
'Content-Type': 'application/json'
}
}
// 发送请求
const response = await http.sendRequest({
...params,
async: false // 使用Promise方式
})
return this.handleResponse(response, options)
},
/**
* 获取AI服务状态
*/
async getServiceStatus() {
try {
// 简单的健康检查
const response = await http.sendRequest({
url: '/api/kefu/health',
async: false,
data: {}
})
const available = [response?.data?.status, response?.data?.components?.ai_service_config?.status].filter(item => item === 'healthy').length > 0;
return {
available,
reason: available ? '服务正常' : '服务异常'
}
} catch (error) {
return {
available: false,
reason: '服务检查失败'
}
}
},
/**
* 清除会话历史
*/
async clearConversation(conversationId) {
try {
const response = await http.sendRequest({
url: '/api/kefu/clear-conversation',
data: { conversation_id: conversationId },
async: false
})
return response.success
} catch (error) {
console.error('清除会话失败:', error)
return false
}
}
} }