chore:把 message替换成 query
This commit is contained in:
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user