import { definePlugin } from 'kivibot' import OpenAI from "openai"; import path from 'path'; import fs from 'fs'; // 基础配置 const baseConfig = {   MAX_MESSAGES: 10,   TTS_URL: "http://127.0.0.1:5000/tts?text=",   OPENAI_CONFIG: {     baseURL: 'https://api.deepseek.com',     apiKey: ''   },   AI_MODEL: "deepseek-chat",   TRIGGER_WORD: "汐汐",   CONFIG_DIR: './config/',   PERSONA_DIR: './default/',   DEFAULT_PERSONA_FILE: 'default.json',   DIRECT_TRIGGER: "$", // 添加专业回复直接触发的前缀 }; interface Message {   时间: string;   角色: string;   内容: string; } interface GroupConfig {   tts: boolean;   persona: string; } const groupMessagesMap: Map = new Map(); const groupConfigMap: Map = new Map(); function loadGroupConfig(groupId: number): GroupConfig {   const configPath = path.join(__dirname, baseConfig.CONFIG_DIR, `${groupId}.json`);   if (fs.existsSync(configPath)) {     return JSON.parse(fs.readFileSync(configPath, 'utf-8'));   }   // 如果配置文件不存在,创建默认配置并保存   const defaultConfig: GroupConfig = { tts: true, persona: 'default' };   saveGroupConfig(groupId, defaultConfig);   return defaultConfig; } function saveGroupConfig(groupId: number, config: GroupConfig) {   const configDir = path.join(__dirname, baseConfig.CONFIG_DIR);   if (!fs.existsSync(configDir)) {     fs.mkdirSync(configDir, { recursive: true });   }   const configPath = path.join(configDir, `${groupId}.json`);   fs.writeFileSync(configPath, JSON.stringify(config, null, 2));   groupConfigMap.set(groupId, config); } function loadPersona(personaName: string) {   const personaPath = path.join(__dirname, baseConfig.PERSONA_DIR, `${personaName}.json`);   if (fs.existsSync(personaPath)) {     return JSON.parse(fs.readFileSync(personaPath, 'utf-8')).prompt;   }   return []; } function ensureDefaultPersonaExists() {   const defaultPersonaPath = path.join(__dirname, baseConfig.PERSONA_DIR, baseConfig.DEFAULT_PERSONA_FILE);   if (!fs.existsSync(defaultPersonaPath)) {     const defaultContent = {       "prompt": [         {           "content": "You are a helpful assistant",           "role": "system"         }       ]     };     fs.writeFileSync(defaultPersonaPath, JSON.stringify(defaultContent, null, 2));     console.log(`Created default persona file at ${defaultPersonaPath}`);   } } export default definePlugin({   name: 'asi',   version: '1.0.0',   setup(ctx) {     const openai = new OpenAI(baseConfig.OPENAI_CONFIG);     // 确保默认人格文件存在     ensureDefaultPersonaExists();     ctx.handle('message.group', async e => handleGroupMessage(ctx, e, openai));     ctx.handle('message.private', async e => handlePrivateMessage(ctx, e, openai));   }, }) async function handleGroupMessage(ctx, e, openai) {   const { group_id, time, sender, raw_message } = e;   const formattedTime = formatDate(new Date(time * 1000));   const senderName = sender.card || sender.nickname;   // 确保每个群都有配置   if (!groupConfigMap.has(group_id)) {     groupConfigMap.set(group_id, loadGroupConfig(group_id));   }   const groupConfig = groupConfigMap.get(group_id)!;   // 检查是否是管理员命令,并且发送者是群管理员或机器人管理员   if (raw_message.startsWith('#asi ') && (ctx.isAdmin(e) || ctx.isOwner(e))) {     handleAdminCommand(ctx, e, groupConfig);     return;   }   // 检查是否是直接触发   if (raw_message.startsWith(baseConfig.DIRECT_TRIGGER)) {     const directMessage = raw_message.slice(baseConfig.DIRECT_TRIGGER.length).trim();     await handleDirectMessage(ctx, e, openai, directMessage);     return;   }   updateGroupMessageLog(group_id, formattedTime, "user", senderName, raw_message);   if (raw_message.startsWith(baseConfig.TRIGGER_WORD) || e.atme) {     const groupMessages = getGroupMessages(group_id);     const contextMessages = groupMessages.map(msg => ({       role: msg.角色,       content: msg.内容.split(': ')[1] // 只取冒号后面的内容     }));         const persona = loadPersona(groupConfig.persona);     const messages = [...persona, ...contextMessages];         const assistantMessage = await getAIResponse(openai, messages);     // 添加类型检查     if (typeof assistantMessage !== 'string') {       console.error('AI 响应格式错误');       e.reply('抱歉,我遇到了一些问题。请稍后再试。');       return;     }     const replyContent = assistantMessage || '抱歉,我现在无法回答。';     if (groupConfig.tts) {       e.reply(ctx.oicq.segment.record(baseConfig.TTS_URL + replyContent) || 'error');     } else {       e.reply(replyContent);     }     updateGroupMessageLog(group_id, formatDate(new Date()), "assistant", "汐汐", replyContent);     console.log(`\n========== 群 ${group_id} 的内存数据 ==========`);     console.log(JSON.stringify(getGroupMessages(group_id), null, 2));     console.log('==========================================\n');   } } function handleAdminCommand(ctx, e, groupConfig: GroupConfig) {   const { group_id, raw_message } = e;     // 再次检查权限,以防万一   if (!ctx.isAdmin(e) && !ctx.isOwner(e)) {     e.reply('抱歉,您没有权限执行此命令。');     return;   }   const command = raw_message.split(' ')[1];   switch (command) {     case '帮助':       e.reply(`         #asi 帮助 - 显示此帮助信息         #asi nature - 设置人格 (例如: #asi nature bing)         #asi nature list - 列出可用的人格         #asi tts on/off - 开启/关闭语音回复       `);       break;     case 'nature':       const personaName = raw_message.split(' ')[2];       if (personaName === 'list') {         const personas = fs.readdirSync(path.join(__dirname, baseConfig.PERSONA_DIR))           .filter(file => file.endsWith('.json'))           .map(file => file.replace('.json', ''));         e.reply(`可用的人格: ${personas.join(', ')}`);       } else if (fs.existsSync(path.join(__dirname, baseConfig.PERSONA_DIR, `${personaName}.json`))) {         groupConfig.persona = personaName;         saveGroupConfig(group_id, groupConfig);         e.reply(`已将人格设置为 ${personaName}`);       } else {         e.reply('无效的人格名称');       }       break;     case 'tts':       const status = raw_message.split(' ')[2];       if (status === 'on' || status === 'off') {         groupConfig.tts = status === 'on';         saveGroupConfig(group_id, groupConfig);         e.reply(`语音回复已${groupConfig.tts ? '开启' : '关闭'}`);       } else {         e.reply('无效的 tts 状态,请使用 on 或 off');       }       break;     default:       e.reply('无效的命令,请使用 #asi 帮助 查看可用命令');   } } // 其他函数保持不变... async function handlePrivateMessage(ctx, e, openai) {   const { sender, raw_message } = e;     if (raw_message.startsWith('#')) return;   // 检查是否是直接触发   if (raw_message.startsWith(baseConfig.DIRECT_TRIGGER)) {     const directMessage = raw_message.slice(baseConfig.DIRECT_TRIGGER.length).trim();     await handleDirectMessage(ctx, e, openai, directMessage);     return;   }   // 原有的私聊处理逻辑   const persona = loadPersona('default');   const userMessage = { role: "user", content: raw_message };   const messages = [...persona, userMessage];     const assistantMessage = await getAIResponse(openai, messages);   // 添加类型检查   if (typeof assistantMessage !== 'string') {     console.error('AI 响应格式错误');     e.reply('抱歉,我遇到了一些问题。请稍后再试。');     return;   }   e.reply(assistantMessage || '抱歉,我现在无法回答。'); } async function handleDirectMessage(ctx, e, openai, message: string) {   const persona = loadPersona('default');   const userMessage = { role: "user", content: message };   const messages = [...persona, userMessage];     const assistantMessage = await getAIResponse(openai, messages);   if (typeof assistantMessage !== 'string') {     console.error('AI 响应格式错误');     e.reply('抱歉,我遇到了一些问题。请稍后再试。');     return;   }   const replyContent = assistantMessage || '抱歉,我现在无法回答。';   e.reply(replyContent); } function formatDate(date: Date): string {   const pad = (num: number) => String(num).padStart(2, '0');   return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`; } function updateGroupMessageLog(groupId: number, time: string, role: string, senderName: string, message: string) {   let messages = groupMessagesMap.get(groupId) || [];   messages.push({ 时间: time, 角色: role, 内容: `${senderName}: ${message}` });   if (messages.length > baseConfig.MAX_MESSAGES) {     messages = messages.slice(-baseConfig.MAX_MESSAGES);   }   groupMessagesMap.set(groupId, messages); } function getGroupMessages(groupId: number): Message[] {   return groupMessagesMap.get(groupId) || []; } async function getAIResponse(openai: OpenAI, messages: any[]): Promise {   try {     const completion = await openai.chat.completions.create({       messages,       model: baseConfig.AI_MODEL,     });     return completion.choices[0].message.content || '抱歉,我现在无法回答。';   } catch (error) {     console.error('获取 AI 响应时出错:', error);     return '抱歉,发生了一些错误。请稍后再试。';   } }