mirror of
https://github.com/Jerryplusy/crystelf-plugin.git
synced 2026-01-29 09:17:27 +00:00
241 lines
6.8 KiB
JavaScript
241 lines
6.8 KiB
JavaScript
import MemorySystem from "./memorySystem.js";
|
||
import configControl from "../config/configControl.js";
|
||
|
||
/**
|
||
* 响应处理器
|
||
* 处理AI返回的规范化响应
|
||
*/
|
||
class ResponseHandler {
|
||
constructor() {
|
||
this.memorySystem = MemorySystem;
|
||
}
|
||
|
||
/**
|
||
* 处理ai响应
|
||
* @param rawResponse ai原始回复
|
||
* @param userMessage 用户消息
|
||
* @param groupId 群聊id
|
||
* @param user_id 用户id
|
||
* @returns {Promise<[{type: string, data: string, at: boolean, quote: boolean, recall: number}]|Array|*[]>}
|
||
*/
|
||
async processResponse(rawResponse, userMessage, groupId,user_id) {
|
||
try {
|
||
// 检查是否是ReAct模式的响应
|
||
if (Array.isArray(rawResponse)) {
|
||
logger.info('[crystelf-ai] 处理ReAct模式响应');
|
||
return await this.processReActResponse(rawResponse, userMessage, groupId, user_id);
|
||
}
|
||
|
||
// 传统模式响应处理
|
||
const parsedResponse = this.parseAiResponse(rawResponse);
|
||
if (!parsedResponse.success) {
|
||
logger.error(`[crystelf-ai] 解析AI响应失败: ${parsedResponse.error}`);
|
||
return this.createErrorResponse(parsedResponse.error);
|
||
}
|
||
const messages = parsedResponse.messages;
|
||
const processedMessages = [];
|
||
for (const message of messages) {
|
||
const processedMessage = await this.processMessage(message, userMessage, groupId,user_id);
|
||
if (processedMessage) {
|
||
processedMessages.push(processedMessage);
|
||
}
|
||
}
|
||
if (processedMessages.length === 0) {
|
||
return this.createDefaultResponse();
|
||
}
|
||
return processedMessages;
|
||
} catch (error) {
|
||
logger.error(`[crystelf-ai] 处理响应失败: ${error.message}`);
|
||
return this.createErrorResponse('处理响应时发生错误');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 处理ReAct模式响应
|
||
* @param responses ReAct响应数组
|
||
* @param userMessage 用户消息
|
||
* @param groupId 群聊id
|
||
* @param user_id 用户id
|
||
* @returns {Promise<Array>} 处理后的消息数组
|
||
*/
|
||
async processReActResponse(responses, userMessage, groupId, user_id) {
|
||
const processedMessages = [];
|
||
|
||
for (const response of responses) {
|
||
// ReAct响应已经是标准格式,直接处理
|
||
const processedMessage = await this.processMessage(response, userMessage, groupId, user_id);
|
||
if (processedMessage) {
|
||
processedMessages.push(processedMessage);
|
||
}
|
||
}
|
||
|
||
if (processedMessages.length === 0) {
|
||
return this.createDefaultResponse();
|
||
}
|
||
|
||
return processedMessages;
|
||
}
|
||
|
||
parseAiResponse(response) {
|
||
try {
|
||
const cleanResponse = this.cleanResponseText(response);
|
||
const parsed = JSON.parse(cleanResponse);
|
||
if (Array.isArray(parsed)) {
|
||
return {
|
||
success: true,
|
||
messages: parsed
|
||
};
|
||
} else {
|
||
return {
|
||
success: true,
|
||
messages: [parsed]//处理模型降智返回对象的情况
|
||
};
|
||
}
|
||
} catch (error) {
|
||
logger.warn(`[crystelf-ai] AI返回非JSON格式: ${error.message}`);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 清理响应文本
|
||
* @param {string} text 原始文本
|
||
* @returns {string} 清理后的文本
|
||
*/
|
||
cleanResponseText(text) {
|
||
if (!text) return '';
|
||
let cleaned = text.replace(/```json\s*/g, '').replace(/```\s*/g, '');
|
||
cleaned = cleaned.trim();
|
||
return cleaned;
|
||
}
|
||
|
||
async processMessage(message, userMessage, groupId,userId) {
|
||
try {
|
||
if (!this.validateMessage(message)) {
|
||
logger.warn(`[crystelf-ai] 无效消息格式: ${JSON.stringify(message)}`);
|
||
return null;
|
||
}
|
||
switch (message.type) {
|
||
case 'memory':
|
||
await this.handleMemoryMessage(message, groupId,userId);
|
||
return null;
|
||
case 'image':
|
||
return this.handleImageMessage(message);
|
||
default:
|
||
return this.handleNormalMessage(message);
|
||
}
|
||
} catch (error) {
|
||
logger.error(`[crystelf-ai] 处理消息失败: ${error.message}`);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
validateMessage(message) {
|
||
if (!message || typeof message !== 'object') {
|
||
logger.info('[crystelf-ai] ai返回为空或不是对象')
|
||
return false;
|
||
}
|
||
if (!message.type) {
|
||
logger.info('[crystelf-ai] ai响应未包含type值')
|
||
return false;
|
||
}
|
||
const validTypes = [
|
||
'message', 'code', 'markdown', 'meme', 'at', 'poke','memory','image'
|
||
];
|
||
if (!validTypes.includes(message.type)) {
|
||
logger.info(`[crystelf-ai] ai返回未知的type类型:${message.type}`)
|
||
return false;
|
||
}return true;
|
||
}
|
||
|
||
/**
|
||
* 记忆消息
|
||
* @param message 记忆
|
||
* @param groupId 群聊id
|
||
* @param user_id 用户id
|
||
* @returns {Promise<void>}
|
||
*/
|
||
async handleMemoryMessage(message, groupId,user_id) {
|
||
try {
|
||
const memoryId = await this.memorySystem.addMemory(
|
||
groupId,
|
||
user_id,
|
||
message.data,
|
||
message.key || [],
|
||
message.timeout || 30
|
||
);
|
||
if (memoryId) {
|
||
logger.info(`[crystelf-ai] 存储记忆成功: ${memoryId}`);
|
||
}
|
||
} catch (error) {
|
||
logger.error(`[crystelf-ai] 存储记忆失败: ${error.message}`);
|
||
}
|
||
}
|
||
|
||
//普通消息
|
||
handleNormalMessage(message) {
|
||
// 设置默认值
|
||
let processedMessage = {
|
||
type: message.type,
|
||
data: message.data,
|
||
at: message.at || -1,
|
||
quote: message.quote || -1,
|
||
recall: message.recall || false
|
||
};
|
||
if (message.id) processedMessage.id = message.id;
|
||
if (message.seq) processedMessage.seq = message.seq;
|
||
if (message.num) processedMessage.num = message.num;
|
||
if (message.language) processedMessage.language = message.language;
|
||
return processedMessage;
|
||
}
|
||
|
||
/**
|
||
* 处理图像消息
|
||
* @param message 图像消息
|
||
* @returns {Object} 处理后的消息对象
|
||
*/
|
||
handleImageMessage(message) {
|
||
if (!message.data) {
|
||
logger.warn('[crystelf-ai] 图像消息缺少data字段');
|
||
return null;
|
||
}
|
||
|
||
let processedMessage = {
|
||
type: 'image',
|
||
data: message.data,
|
||
at: message.at || -1,
|
||
quote: message.quote || -1,
|
||
recall: message.recall || false
|
||
};
|
||
|
||
if (message.style) processedMessage.style = message.style;
|
||
if (message.quality) processedMessage.quality = message.quality;
|
||
if (message.size) processedMessage.size = message.size;
|
||
|
||
return processedMessage;
|
||
}
|
||
|
||
createErrorResponse(error) {
|
||
const nickName = configControl.get('profile')?.nickName;
|
||
return [{
|
||
type: 'message',
|
||
data: `${nickName}的服务器去火星开小差了..`,
|
||
at: -1,
|
||
quote: -1,
|
||
recall: true
|
||
}];
|
||
}
|
||
|
||
createDefaultResponse() {
|
||
const nickName = configControl.get('profile')?.nickName;
|
||
return [{
|
||
type: 'message',
|
||
data: `${nickName}的服务器去火星开小差了..`,
|
||
at: -1,
|
||
quote: -1,
|
||
recall: true
|
||
}];
|
||
}
|
||
}
|
||
|
||
export default new ResponseHandler();
|