1. 新增多语言文案,适配AI智能体通用场景 2. 新增AI智能体页面路由常量与跳转逻辑 3. 改造AI聊天页面支持动态agent_id和页面标题 4. 升级AI服务层,支持多agent_id自动传递
760 lines
22 KiB
JavaScript
760 lines
22 KiB
JavaScript
import Config from './config.js'
|
||
import http from './http.js'
|
||
import store from '@/store/index.js'
|
||
import lang from './lang.js'
|
||
|
||
let currentConversationId = null;
|
||
|
||
// ====== AI Agent Generalization (customer service is the first agent) ======
|
||
// setAgentId updates currentAgentId; default is agent_aikefu.
|
||
// Any sendMessage / sendStreamMessage / getServiceConfig call passes agent_id automatically.
|
||
|
||
export const DEFAULT_AGENT_ID = 'agent_aikefu';
|
||
let currentAgentId = DEFAULT_AGENT_ID;
|
||
export const CONVERSATION_KEY = 'ai_conversation_id';
|
||
|
||
/**
|
||
* 获取域名配置参数(避免重复代码)
|
||
*/
|
||
function getDomainParams() {
|
||
return {
|
||
imgDomain: Config.imgDomain,
|
||
h5Domain: Config.h5Domain,
|
||
baseUrl: Config.baseUrl
|
||
};
|
||
}
|
||
|
||
// 初始化时从本地读取会话ID
|
||
try {
|
||
const saved = uni.getStorageSync(CONVERSATION_KEY);
|
||
if (saved) {
|
||
currentConversationId = saved;
|
||
}
|
||
} catch (e) {
|
||
console.warn('读取会话ID失败:', e);
|
||
}
|
||
|
||
const GUEST_ID_KEY = 'ai_guest_user_id';
|
||
|
||
/**
|
||
* 获取用户ID:已登录返回 memberId,未登录生成访客唯一标识并持久化
|
||
*/
|
||
function getUserId() {
|
||
const memberId = store.state.memberInfo?.id;
|
||
if (memberId) return memberId;
|
||
|
||
let guestId;
|
||
try {
|
||
guestId = uni.getStorageSync(GUEST_ID_KEY);
|
||
} catch (e) { /* ignore */ }
|
||
|
||
if (!guestId) {
|
||
guestId = 'guest_' + Date.now() + '_' + Math.random().toString(36).slice(2, 10);
|
||
try {
|
||
uni.setStorageSync(GUEST_ID_KEY, guestId);
|
||
} catch (e) { /* ignore */ }
|
||
}
|
||
return guestId;
|
||
}
|
||
|
||
/**
|
||
* 获取当前 AI Agent。
|
||
*/
|
||
function getAgentId() {
|
||
return currentAgentId || DEFAULT_AGENT_ID;
|
||
}
|
||
|
||
/**
|
||
* 设置当前 AI Agent。
|
||
*/
|
||
function setAgentId(agentId) {
|
||
if (agentId && typeof agentId === 'string') currentAgentId = agentId;
|
||
}
|
||
|
||
// #ifdef MP
|
||
// ================================
|
||
// WebSocket 长连接管理(微信小程序)
|
||
// ================================
|
||
let wsSocketTask = null;
|
||
let wsAuthenticated = false;
|
||
let wsConnected = false;
|
||
let wsConnectionPromise = null;
|
||
|
||
function getWsDomain() {
|
||
var match = Config.baseUrl.match(/^(?:https?:\/\/|wss?:\/\/)([^\/\s:?#]+(?::\d+)?)/);
|
||
return match ? match[1] : '';
|
||
}
|
||
|
||
function resetWsState() {
|
||
wsSocketTask = null;
|
||
wsAuthenticated = false;
|
||
wsConnected = false;
|
||
wsConnectionPromise = null;
|
||
}
|
||
|
||
/**
|
||
* 确保 WebSocket 已连接并认证,返回一个 Promise
|
||
* 连接建立后保持不断开,后续可复用
|
||
*/
|
||
function ensureWebSocketConnected() {
|
||
if (wsConnected && wsAuthenticated) {
|
||
return Promise.resolve();
|
||
}
|
||
if (wsConnectionPromise) {
|
||
return wsConnectionPromise;
|
||
}
|
||
|
||
wsConnectionPromise = new Promise(function(resolve, reject) {
|
||
var domain = getWsDomain();
|
||
if (!domain) {
|
||
wsConnectionPromise = null;
|
||
reject(new Error(lang.lang('aiService.wsDomainInvalid')));
|
||
return;
|
||
}
|
||
|
||
var wssUrl = 'wss://' + domain + '/ws/aikefu';
|
||
wsConnected = false;
|
||
wsAuthenticated = false;
|
||
wsSocketTask = wx.connectSocket({ url: wssUrl, header: {} });
|
||
|
||
// 获取认证参数(独立函数,不使用 this)
|
||
var _uniacid = uni.getStorageSync('uniacid') || Config.uniacid;
|
||
var _token = store.state.token || 'test_token';
|
||
var _userId = getUserId();
|
||
|
||
wsSocketTask.onOpen(function() {
|
||
wsConnected = true;
|
||
wsSocketTask.send({
|
||
data: JSON.stringify({
|
||
action: 'auth',
|
||
agent_id: getAgentId(),
|
||
uniacid: _uniacid,
|
||
token: _token,
|
||
user_id: _userId
|
||
})
|
||
});
|
||
});
|
||
|
||
wsSocketTask.onMessage(function(res) {
|
||
try {
|
||
var data = JSON.parse(res.data);
|
||
|
||
// Auth 响应
|
||
if (data.type === 'auth_success') {
|
||
wsAuthenticated = true;
|
||
resolve();
|
||
return;
|
||
}
|
||
if (data.type === 'auth_failed') {
|
||
wsAuthenticated = false;
|
||
wsConnectionPromise = null;
|
||
reject(new Error(lang.lang('aiService.wsAuthFailed')));
|
||
return;
|
||
}
|
||
|
||
// 以下为聊天消息响应,只在有活跃消息时处理
|
||
if (!wsMessageActive) return;
|
||
|
||
if (data.event === 'message') {
|
||
var text = data.answer || data.content || data.text || '';
|
||
// 兼容嵌套 data.data.content 格式
|
||
if (!text && data.data) {
|
||
text = data.data.content || data.data.answer || '';
|
||
}
|
||
wsMessageContent += text;
|
||
if (wsMessageOnChunk) wsMessageOnChunk(text);
|
||
} else if (data.event === 'message_end' || data.event === 'done') {
|
||
// 兼容两种结束信号:message_end(流结束)或 done(服务端完成)
|
||
// 兼容两种数据层级:conversation_id 可能在顶层或 data.data 中
|
||
var conversationId = data.conversation_id || (data.data && data.data.conversation_id) || '';
|
||
console.log('[AI WS] 流结束信号, event:', data.event, 'type:', data.type, 'conversationId:', conversationId, '当前内存:', currentConversationId);
|
||
// 保存会话ID(独立函数,不使用 this)
|
||
if (conversationId) {
|
||
if (conversationId !== currentConversationId) {
|
||
currentConversationId = conversationId;
|
||
try {
|
||
uni.setStorageSync(CONVERSATION_KEY, conversationId);
|
||
console.log('[AI WS] 会话ID已持久化到 storage:', conversationId);
|
||
} catch (e) {
|
||
console.error('保存会话ID失败:', e);
|
||
}
|
||
}
|
||
}
|
||
var content = wsMessageContent;
|
||
var convId = conversationId;
|
||
// 重置消息状态,但不断开连接
|
||
wsMessageActive = false;
|
||
wsMessageContent = '';
|
||
if (wsMessageOnComplete) wsMessageOnComplete({ content: content, conversation_id: convId });
|
||
if (wsMessageResolve) wsMessageResolve({ content: content, conversation_id: convId });
|
||
} else {
|
||
// 兜底日志:打印所有未识别的消息类型
|
||
console.log('[AI WS] 未识别的消息:', JSON.stringify(data).substring(0, 200));
|
||
}
|
||
} catch (e) {
|
||
console.error('WebSocket 消息解析失败:', e, '原始数据:', res.data);
|
||
}
|
||
});
|
||
|
||
wsSocketTask.onError(function(err) {
|
||
console.error('WebSocket 连接失败:', err);
|
||
var prevReject = wsMessageReject;
|
||
resetWsState();
|
||
resetWsMessageState();
|
||
if (prevReject) prevReject(new Error(lang.lang('aiService.wsConnectionFailed')));
|
||
reject(new Error(lang.lang('aiService.wsConnectionFailed')));
|
||
});
|
||
|
||
wsSocketTask.onClose(function() {
|
||
console.warn('WebSocket 连接已关闭');
|
||
var prevReject = wsMessageReject;
|
||
resetWsState();
|
||
resetWsMessageState();
|
||
if (prevReject) prevReject(new Error(lang.lang('aiService.wsConnectionClosed')));
|
||
});
|
||
});
|
||
|
||
return wsConnectionPromise;
|
||
}
|
||
|
||
// 当前消息的回调状态(只支持串行)
|
||
var wsMessageResolve = null;
|
||
var wsMessageReject = null;
|
||
var wsMessageOnChunk = null;
|
||
var wsMessageOnComplete = null;
|
||
var wsMessageContent = '';
|
||
var wsMessageActive = false;
|
||
|
||
function resetWsMessageState() {
|
||
wsMessageResolve = null;
|
||
wsMessageReject = null;
|
||
wsMessageOnChunk = null;
|
||
wsMessageOnComplete = null;
|
||
wsMessageContent = '';
|
||
wsMessageActive = false;
|
||
}
|
||
|
||
/**
|
||
* 断开 WebSocket 长连接
|
||
*/
|
||
function disconnectWebSocket() {
|
||
if (wsSocketTask) {
|
||
try { wsSocketTask.close(); } catch (e) { /* ignore */ }
|
||
}
|
||
resetWsState();
|
||
resetWsMessageState();
|
||
}
|
||
// #endif
|
||
|
||
export default {
|
||
/**
|
||
* 获取uniacid
|
||
* @returns {number} uniacid
|
||
*/
|
||
getUniacid() {
|
||
return uni.getStorageSync('uniacid') || Config.uniacid; // 从缓存中获取uniacid,或使用默认uniacid
|
||
},
|
||
|
||
/**
|
||
* 发送普通消息(blocking 模式)
|
||
*/
|
||
async sendMessage(message, options = {}) {
|
||
try {
|
||
const params = {
|
||
url: '/api/kefu/chat',
|
||
data: {
|
||
agent_id: getAgentId(),
|
||
user_id: getUserId(),
|
||
stream: false,
|
||
inputs: {},
|
||
query: message,
|
||
response_mode: 'blocking', // 强制 blocking
|
||
user: getUserId(),
|
||
conversation_id: this.getConversationId() || '',
|
||
...getDomainParams()
|
||
},
|
||
header: {
|
||
'Content-Type': 'application/json'
|
||
}
|
||
};
|
||
|
||
const response = await http.sendRequest({
|
||
...params,
|
||
async: false
|
||
});
|
||
|
||
const result = this.handleResponse(response);
|
||
if (result.conversationId) {
|
||
this.setConversationId(result.conversationId);
|
||
}
|
||
return result;
|
||
} catch (error) {
|
||
console.error('[AI Service] AiChat API请求失败,详细错误:', error);
|
||
console.error('[AI Service] 错误堆栈:', error.stack);
|
||
// 打印更多信息帮助调试
|
||
console.error('[AI Service] store 状态:', {
|
||
memberInfo: store.state.memberInfo,
|
||
uniacid: this.getUniacid(),
|
||
token: store.state.token
|
||
});
|
||
throw new Error(lang.lang('aiService.serviceUnavailable'));
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 流式消息入口(自动适配平台)
|
||
* 微信小程序:复用长连接 WebSocket
|
||
*/
|
||
async sendStreamMessage(message, onChunk, onComplete) {
|
||
// #ifdef MP
|
||
// 先确保连接已就绪
|
||
try {
|
||
await ensureWebSocketConnected();
|
||
} catch (e) {
|
||
if (onComplete) onComplete({ error: e.message });
|
||
throw e;
|
||
}
|
||
|
||
// 设置当前消息回调
|
||
wsMessageContent = '';
|
||
wsMessageActive = true;
|
||
wsMessageOnChunk = onChunk || null;
|
||
wsMessageOnComplete = onComplete || null;
|
||
|
||
return new Promise((resolve, reject) => {
|
||
wsMessageResolve = resolve;
|
||
wsMessageReject = reject;
|
||
|
||
wsSocketTask.send({
|
||
data: JSON.stringify({
|
||
action: 'chat',
|
||
agent_id: getAgentId(),
|
||
uniacid: this.getUniacid(),
|
||
query: message,
|
||
user_id: getUserId(),
|
||
conversation_id: this.getConversationId() || '',
|
||
...getDomainParams()
|
||
})
|
||
});
|
||
});
|
||
// #endif
|
||
},
|
||
/**
|
||
* HTTP 流式请求(仅 H5 使用)
|
||
*/
|
||
async sendHttpStream(message, onChunk, onComplete) {
|
||
// #ifdef H5
|
||
try {
|
||
const url = Config.baseUrl + `/api/kefu/chat`;
|
||
const response = await fetch(url, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Accept': 'text/event-stream',
|
||
},
|
||
body: JSON.stringify({
|
||
uniacid: this.getUniacid(),
|
||
token: store.state.token || 'test_token',
|
||
inputs: {},
|
||
query: message,
|
||
response_mode: 'streaming',
|
||
user_id: getUserId(),
|
||
conversation_id: this.getConversationId() || '',
|
||
...getDomainParams()
|
||
})
|
||
});
|
||
|
||
if (!response.ok || !response.body) {
|
||
throw new Error(lang.lang('aiService.invalidResponse'));
|
||
}
|
||
|
||
const reader = response.body.getReader();
|
||
const decoder = new TextDecoder('utf-8');
|
||
let buffer = '';
|
||
let content = '';
|
||
let conversationId = '';
|
||
|
||
while (true) {
|
||
const { done, value } = await reader.read();
|
||
if (done) break;
|
||
|
||
buffer += decoder.decode(value, { stream: true });
|
||
|
||
// 按行分割,保留不完整的最后一行
|
||
const lines = buffer.split('\n');
|
||
buffer = lines.pop() || ''; // 未完成的行留到下次
|
||
|
||
for (const line of lines) {
|
||
const trimmed = line.trim();
|
||
if (trimmed.startsWith('data:')) {
|
||
try {
|
||
const jsonStr = trimmed.slice(5).trim();
|
||
if (jsonStr && jsonStr !== '[DONE]') {
|
||
const data = JSON.parse(jsonStr);
|
||
if (data.event === 'message') {
|
||
var text = data.answer || data.text || '';
|
||
// 兼容嵌套 data.data 格式
|
||
if (!text && data.data) {
|
||
text = data.data.content || data.data.answer || '';
|
||
}
|
||
content += text;
|
||
if (onChunk) onChunk(text);
|
||
}
|
||
// 兼容两种层级:conversation_id 可能在顶层或 data.data 中
|
||
var cid = data.conversation_id || (data.data && data.data.conversation_id) || '';
|
||
if (cid) {
|
||
conversationId = cid;
|
||
}
|
||
if (data.event === 'message_end' || data.event === 'done') {
|
||
console.log('[AI SSE] 收到完成信号:', data.event, 'conversationId:', cid);
|
||
}
|
||
}
|
||
} catch (e) {
|
||
console.warn('解析失败:', e, line);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 处理最后残留的 buffer(如果有)
|
||
if (buffer.trim().startsWith('data:')) {
|
||
try {
|
||
const jsonStr = buffer.trim().slice(5);
|
||
if (jsonStr) {
|
||
const data = JSON.parse(jsonStr);
|
||
if (data.event === 'message') {
|
||
var text = data.answer || data.text || '';
|
||
if (!text && data.data) {
|
||
text = data.data.content || data.data.answer || '';
|
||
}
|
||
content += text;
|
||
if (onChunk) onChunk(text);
|
||
}
|
||
var cid = data.conversation_id || (data.data && data.data.conversation_id) || '';
|
||
if (cid) {
|
||
conversationId = cid;
|
||
}
|
||
}
|
||
} catch (e) {
|
||
console.warn('最后 buffer 解析失败:', e);
|
||
}
|
||
}
|
||
|
||
console.log('[AI SSE] 流完成, conversationId:', conversationId, 'content长度:', content.length);
|
||
if (onComplete) {
|
||
onComplete({ content, conversation_id: conversationId });
|
||
}
|
||
return { content, conversation_id: conversationId };
|
||
} catch (error) {
|
||
console.error('H5 流式请求失败:', error);
|
||
throw error;
|
||
}
|
||
// #endif
|
||
},
|
||
|
||
/**
|
||
* 处理API响应(统一格式)
|
||
*/
|
||
handleResponse(response) {
|
||
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 || lang.lang('aiService.serviceResponseError'));
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 获取当前会话ID
|
||
*/
|
||
getConversationId() {
|
||
return currentConversationId;
|
||
},
|
||
|
||
/**
|
||
* 设置并持久化会话ID
|
||
*/
|
||
setConversationId(id) {
|
||
if (id && id !== currentConversationId) {
|
||
currentConversationId = id;
|
||
try {
|
||
uni.setStorageSync(CONVERSATION_KEY, id);
|
||
} catch (e) {
|
||
console.error('保存会话ID失败:', e);
|
||
}
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 清除会话ID
|
||
*/
|
||
clearConversationId() {
|
||
currentConversationId = null;
|
||
try {
|
||
uni.removeStorageSync(CONVERSATION_KEY);
|
||
} catch (e) {
|
||
console.error('清除会话ID失败:', e);
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 生成新会话(如需)
|
||
*/
|
||
async generateConversationId() {
|
||
const params = {
|
||
url: '/api/kefu/createConversation',
|
||
data: {
|
||
agent_id: getAgentId(),
|
||
uniacid: this.getUniacid(),
|
||
token: store.state.token || 'test_token',
|
||
user_id: getUserId(),
|
||
member_id: getUserId(),
|
||
...getDomainParams()
|
||
},
|
||
header: {
|
||
'Content-Type': 'application/json'
|
||
}
|
||
};
|
||
const response = await http.sendRequest({
|
||
...params,
|
||
async: false
|
||
});
|
||
return this.handleResponse(response);
|
||
},
|
||
|
||
/**
|
||
* 获取服务状态
|
||
*/
|
||
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 ? lang.lang('aiService.statusNormal') : lang.lang('aiService.statusAbnormal')
|
||
};
|
||
} catch (error) {
|
||
return {
|
||
available: false,
|
||
reason: lang.lang('aiService.statusCheckFailed')
|
||
};
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 获取服务配置信息
|
||
*/
|
||
async getServiceConfig() {
|
||
try {
|
||
const params = {
|
||
url: '/api/kefu/info',
|
||
data: {
|
||
agent_id: getAgentId(),
|
||
uniacid: this.getUniacid(),
|
||
token: store.state.token || 'test_token',
|
||
user_id: getUserId(),
|
||
member_id: getUserId(),
|
||
locale: lang.getCurrentLocale()
|
||
},
|
||
header: {
|
||
'Content-Type': 'application/json'
|
||
}
|
||
};
|
||
const response = await http.sendRequest({
|
||
...params,
|
||
async: false,
|
||
});
|
||
console.log('[AI Service] getServiceConfig response:', JSON.stringify(response));
|
||
return response.data;
|
||
} catch (error) {
|
||
console.error('[AI Service] getServiceConfig error:', error);
|
||
return null;
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 清除会话历史(调用后端接口)
|
||
*/
|
||
async clearConversation(conversationId) {
|
||
try {
|
||
const response = await http.sendRequest({
|
||
url: '/api/kefu/clear-conversation',
|
||
data: {
|
||
agent_id: getAgentId(),
|
||
conversation_id: conversationId,
|
||
...getDomainParams()
|
||
},
|
||
async: false
|
||
});
|
||
return response.success;
|
||
} catch (error) {
|
||
console.error('清除会话失败:', error);
|
||
return false;
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 获取会话历史
|
||
*/
|
||
async getConversationHistory(params = {}) {
|
||
try {
|
||
if (!params.conversation_id) {
|
||
throw new Error(lang.lang('aiService.conversationIdRequired'));
|
||
}
|
||
console.log('[AI History] 请求历史, conversation_id:', params.conversation_id, 'limit:', params.limit);
|
||
const requestData = {
|
||
agent_id: params.agent_id || getAgentId(),
|
||
uniacid: params.uniacid || this.getUniacid(),
|
||
conversation_id: params.conversation_id,
|
||
user_id: params.user_id || getUserId(),
|
||
limit: params.limit || 20,
|
||
offset: params.offset || 0,
|
||
member_id: params.member_id || getUserId(),
|
||
token: params.token || '',
|
||
...getDomainParams()
|
||
};
|
||
const response = await http.sendRequest({
|
||
url: '/api/kefu/getHistory',
|
||
data: requestData,
|
||
header: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
async: false
|
||
});
|
||
if (response.code === 0 || response.success) {
|
||
return {
|
||
success: true,
|
||
data: response.data,
|
||
messages: response.data?.messages || [],
|
||
total: response.data?.total || 0,
|
||
page_info: response.data?.page_info || { limit: 20, offset: 0 }
|
||
};
|
||
} else {
|
||
throw new Error(response.message || lang.lang('aiService.getHistoryFailed'));
|
||
}
|
||
} catch (error) {
|
||
console.error('获取会话历史失败:', error);
|
||
throw new Error(error.message || lang.lang('aiService.getHistoryError'));
|
||
}
|
||
},
|
||
|
||
// ================================
|
||
// 以下方法仅用于 H5,小程序无效
|
||
// ================================
|
||
|
||
/**
|
||
* [H5 Only] EventSource 流式聊天(备用)
|
||
*/
|
||
chatWithEventSource(message, conversationId = '', onMessage, onComplete, onError) {
|
||
// #ifdef H5
|
||
if (window.currentEventSource) {
|
||
window.currentEventSource.close();
|
||
}
|
||
const paramsObj = {
|
||
agent_id: getAgentId(),
|
||
uniacid: this.getUniacid(),
|
||
user_id: getUserId(),
|
||
member_id: getUserId(),
|
||
token: store.state.token || 'test_token',
|
||
query: message,
|
||
conversation_id: conversationId || '',
|
||
stream: 'true',
|
||
...getDomainParams()
|
||
};
|
||
const params = new URLSearchParams(paramsObj);
|
||
const url = `${Config.baseUrl}/api/kefu/chat?${params.toString()}`;
|
||
try {
|
||
const eventSource = new EventSource(url);
|
||
window.currentEventSource = eventSource;
|
||
let aiMessage = '';
|
||
eventSource.onmessage = (event) => {
|
||
try {
|
||
const data = JSON.parse(event.data);
|
||
if (data.event === 'message') {
|
||
aiMessage += data.answer || '';
|
||
if (onMessage) onMessage(data.answer || '');
|
||
}
|
||
if (data.event === 'message_end') {
|
||
if (onComplete) onComplete({
|
||
conversation_id: data.conversation_id,
|
||
message: aiMessage
|
||
});
|
||
}
|
||
} catch (error) {
|
||
console.error('解析消息失败:', error);
|
||
}
|
||
};
|
||
eventSource.onerror = (error) => {
|
||
console.error('EventSource错误:', error);
|
||
if (onError) onError({ error: lang.lang('aiService.connectionFailed') });
|
||
window.currentEventSource = null;
|
||
};
|
||
return eventSource;
|
||
} catch (error) {
|
||
console.error('创建EventSource失败:', error);
|
||
if (onError) onError({ error: error.message });
|
||
return null;
|
||
}
|
||
// #endif
|
||
// #ifdef MP
|
||
console.warn('chatWithEventSource 不支持微信小程序');
|
||
return null;
|
||
// #endif
|
||
},
|
||
|
||
/**
|
||
* [H5 Only] Fetch 流式聊天(备用)
|
||
*/
|
||
async chatWithFetchStream(message, conversationId = '', onMessage, onComplete, onError) {
|
||
// #ifdef H5
|
||
// 实际逻辑已在 sendHttpStream 中实现,此处可复用或留空
|
||
return this.sendHttpStream(message, onMessage, (res) => {
|
||
onComplete?.({ message: res.content, conversation_id: res.conversation_id });
|
||
});
|
||
// #endif
|
||
// #ifdef MP
|
||
console.warn('chatWithFetchStream 不支持微信小程序');
|
||
return null;
|
||
// #endif
|
||
},
|
||
|
||
// #ifdef MP
|
||
/**
|
||
* [微信小程序] 断开 WebSocket 长连接(页面离开时调用)
|
||
*/
|
||
disconnectWebSocket() {
|
||
disconnectWebSocket();
|
||
},
|
||
// #endif
|
||
// #ifdef H5
|
||
disconnectWebSocket() {
|
||
// H5 无 WebSocket 长连接,无需操作
|
||
},
|
||
// #endif
|
||
|
||
/**
|
||
* Set current AI Agent (default aikefu; link system passes agent_id).
|
||
* @param {string} agentId
|
||
*/
|
||
setAgentId(agentId) {
|
||
setAgentId(agentId);
|
||
},
|
||
|
||
/**
|
||
* Get current AI Agent.
|
||
* @returns {string}
|
||
*/
|
||
getAgentId() {
|
||
return getAgentId();
|
||
},
|
||
};
|