diff --git a/src/AI/AI.ts b/src/AI/AI.ts index 3b73e46..2fb8331 100644 --- a/src/AI/AI.ts +++ b/src/AI/AI.ts @@ -28,13 +28,13 @@ export class AI { privilege: Privilege; // 下面是临时变量,用于处理消息 - stream: { + stream: { // 用于流式输出相关 id: string, reply: string, toolCallStatus: boolean } - bucket: { + bucket: { // 触发次数令牌桶 count: number, lastTime: number } diff --git a/src/AI/memory.ts b/src/AI/memory.ts index 369b986..fa9fb22 100644 --- a/src/AI/memory.ts +++ b/src/AI/memory.ts @@ -30,17 +30,19 @@ export interface MemoryInfo { export class Memory { persona: string; memoryMap: { [key: string]: MemoryInfo }; - shortMemory: string[]; + useShortMemory: boolean; + shortMemoryList: string[]; constructor() { this.persona = '无'; this.memoryMap = {}; - this.shortMemory = []; + this.useShortMemory = false; + this.shortMemoryList = []; } static reviver(value: any): Memory { const memory = new Memory(); - const validKeys = ['persona', 'memoryMap', 'shortMemory']; + const validKeys = ['persona', 'memoryMap', 'useShortMemory', 'shortMemory']; for (const k in value) { if (validKeys.includes(k)) { @@ -108,7 +110,7 @@ export class Memory { } clearShortMemory() { - this.shortMemory = []; + this.shortMemoryList = []; } limitMemory() { @@ -139,15 +141,26 @@ export class Memory { limitShortMemory() { const { shortMemoryLimit } = ConfigManager.memory; - if (this.shortMemory.length > shortMemoryLimit) { - this.shortMemory.splice(0, this.shortMemory.length - shortMemoryLimit); + if (this.shortMemoryList.length > shortMemoryLimit) { + this.shortMemoryList.splice(0, this.shortMemoryList.length - shortMemoryLimit); } } async updateShortMemory(ctx: seal.MsgContext, msg: seal.Message, ai: AI, sumMessages: Message[]) { - const { url, apiKey } = ConfigManager.request; + if (!this.useShortMemory) { + return; + } + + const { url: chatUrl, apiKey: chatApiKey } = ConfigManager.request; const { roleSettingTemplate, isPrefix, showNumber, showMsgId } = ConfigManager.message; - const { memoryBodyTemplate, memoryPromptTemplate } = ConfigManager.memory; + const { memoryUrl, memoryApiKey, memoryBodyTemplate, memoryPromptTemplate } = ConfigManager.memory; + + let url = chatUrl; + let apiKey = chatApiKey; + if (memoryUrl.trim()) { + url = memoryUrl; + apiKey = memoryApiKey; + } try { let [roleSettingIndex, _] = seal.vars.intGet(ctx, "$gSYSPROMPT"); @@ -217,7 +230,7 @@ export class Memory { }; - this.shortMemory.push(memoryData.content); + this.shortMemoryList.push(memoryData.content); this.limitShortMemory(); memoryData.memories.forEach(m => { diff --git a/src/config/config_backend.ts b/src/config/config_backend.ts index f48d1b6..53b5eee 100644 --- a/src/config/config_backend.ts +++ b/src/config/config_backend.ts @@ -8,9 +8,9 @@ export class BackendConfig { seal.ext.registerStringConfig(BackendConfig.ext, "流式输出", "http://localhost:3010", '自行搭建或使用他人提供的后端'); seal.ext.registerStringConfig(BackendConfig.ext, "图片转base64", "https://urltobase64.白鱼.chat", '可自行搭建'); - seal.ext.registerStringConfig(BackendConfig.ext, "联网搜索", "https://searxng.白鱼.chat", '可自行搭建'); - seal.ext.registerStringConfig(BackendConfig.ext, "网页读取", "https://webread.白鱼.chat", '可自行搭建'); - seal.ext.registerStringConfig(BackendConfig.ext, "用量图表", "http://error.白鱼.chat:3009", '可自行搭建'); + seal.ext.registerStringConfig(BackendConfig.ext, "联网搜索", "https://searxng.fishwhite.top", '可自行搭建'); + seal.ext.registerStringConfig(BackendConfig.ext, "网页读取", "https://webread.fishwhite.top", '可自行搭建'); + seal.ext.registerStringConfig(BackendConfig.ext, "用量图表", "http://localhost:3009", '可自行搭建'); } static get() { diff --git a/src/config/config_memory.ts b/src/config/config_memory.ts index 211bc0e..944a359 100644 --- a/src/config/config_memory.ts +++ b/src/config/config_memory.ts @@ -31,6 +31,8 @@ export class MemoryConfig { seal.ext.registerBoolConfig(MemoryConfig.ext, "是否启用短期记忆", true, ""); seal.ext.registerIntConfig(MemoryConfig.ext, "短期记忆上限", 10, ""); seal.ext.registerIntConfig(MemoryConfig.ext, "短期记忆总结轮数", 10, ""); + seal.ext.registerStringConfig(MemoryConfig.ext, "记忆总结 url地址", "", '为空时,默认使用对话接口'); + seal.ext.registerStringConfig(MemoryConfig.ext, "记忆总结 API Key", "你的API Key", '若使用对话接口无需填写'); seal.ext.registerTemplateConfig(MemoryConfig.ext, "记忆总结 body", [ `"model":"deepseek-chat"`, `"max_tokens":1024`, @@ -114,6 +116,8 @@ export class MemoryConfig { isShortMemory: seal.ext.getBoolConfig(MemoryConfig.ext, "是否启用短期记忆"), shortMemoryLimit: seal.ext.getIntConfig(MemoryConfig.ext, "短期记忆上限"), shortMemorySummaryRound: seal.ext.getIntConfig(MemoryConfig.ext, "短期记忆总结轮数"), + memoryUrl: seal.ext.getStringConfig(MemoryConfig.ext, "记忆总结 url地址"), + memoryApiKey: seal.ext.getStringConfig(MemoryConfig.ext, "记忆总结 API Key"), memoryBodyTemplate: seal.ext.getTemplateConfig(MemoryConfig.ext, "记忆总结 body"), memoryPromptTemplate: seal.ext.getTemplateConfig(MemoryConfig.ext, "记忆总结prompt模板") } diff --git a/src/index.ts b/src/index.ts index 3b5c6ad..aa58d79 100644 --- a/src/index.ts +++ b/src/index.ts @@ -369,6 +369,27 @@ function main() { const ai2 = AIManager.getAI(muid); const val2 = cmdArgs.getArgN(2); switch (val2) { + case 'status': { + let ai3 = ai; + if (cmdArgs.at.length > 0 && (cmdArgs.at.length !== 1 || cmdArgs.at[0].userId !== ctx.endPoint.userId)) { + ai3 = ai2; + } + + const { isMemory, isShortMemory } = ConfigManager.memory; + + const keywords = new Set(); + for (const key in ai3.memory.memoryMap) { + ai3.memory.memoryMap[key].keywords.forEach(kw => keywords.add(kw)); + } + + seal.replyToSender(ctx, msg, `${ai3.id} +长期记忆开启状态: ${isMemory ? '是' : '否'} +长期记忆条数: ${Object.keys(ai3.memory.memoryMap).length} +关键词库: ${Array.from(keywords).join('、')} +短期记忆开启状态: ${(isShortMemory && ai3.memory.useShortMemory) ? '是' : '否'} +短期记忆条数: ${ai3.memory.shortMemoryList.length}`); + return ret; + } case 'p': case 'private': { const val3 = cmdArgs.getArgN(3); @@ -398,11 +419,6 @@ function main() { } } } - case 'show': { - const s = ai2.memory.buildMemory(true, mctx.player.name, mctx.player.userId, '', ''); - seal.replyToSender(ctx, msg, s || '无'); - return ret; - } case 'del': { const idList = cmdArgs.args.slice(3); const kw = cmdArgs.kwargs.map(item => item.name); @@ -416,6 +432,11 @@ function main() { AIManager.saveAI(muid); return ret; } + case 'show': { + const s = ai2.memory.buildMemory(true, mctx.player.name, mctx.player.userId, '', ''); + seal.replyToSender(ctx, msg, s || '无'); + return ret; + } case 'clr': { ai2.memory.clearMemory(); seal.replyToSender(ctx, msg, '个人记忆已清除'); @@ -466,11 +487,6 @@ function main() { } } } - case 'show': { - const s = ai.memory.buildMemory(false, '', '', ctx.group.groupName, ctx.group.groupId); - seal.replyToSender(ctx, msg, s || '无'); - return ret; - } case 'del': { const idList = cmdArgs.args.slice(3); const kw = cmdArgs.kwargs.map(item => item.name); @@ -484,6 +500,11 @@ function main() { AIManager.saveAI(id); return ret; } + case 'show': { + const s = ai.memory.buildMemory(false, '', '', ctx.group.groupName, ctx.group.groupId); + seal.replyToSender(ctx, msg, s || '无'); + return ret; + } case 'clr': { ai.memory.clearMemory(); seal.replyToSender(ctx, msg, '群聊记忆已清除'); @@ -500,14 +521,26 @@ function main() { case 'short': { const val3 = cmdArgs.getArgN(3); switch (val3) { + case 'on': { + ai.memory.useShortMemory = true; + seal.replyToSender(ctx, msg, '短期记忆已开启'); + AIManager.saveAI(id); + return ret; + } + case 'off': { + ai.memory.useShortMemory = false; + seal.replyToSender(ctx, msg, '短期记忆已关闭'); + AIManager.saveAI(id); + return ret; + } case 'show': { - const s = ai.memory.shortMemory.map((item, index) => `${index + 1}. ${item}`).join('\n'); + const s = ai.memory.shortMemoryList.map((item, index) => `${index + 1}. ${item}`).join('\n'); seal.replyToSender(ctx, msg, s || '无'); return ret; } case 'clr': { ai.memory.clearShortMemory(); - seal.replyToSender(ctx, msg, '群聊记忆已清除'); + seal.replyToSender(ctx, msg, '短期记忆已清除'); AIManager.saveAI(id); return ret; } @@ -522,21 +555,21 @@ function main() { ai.context.summaryCounter = 0; ai.memory.updateShortMemory(ctx, msg, ai, ai.context.messages.slice(0, shortMemorySummaryRound)) .then(() => { - const s = ai.memory.shortMemory.map((item, index) => `${index + 1}. ${item}`).join('\n'); + const s = ai.memory.shortMemoryList.map((item, index) => `${index + 1}. ${item}`).join('\n'); seal.replyToSender(ctx, msg, s || '无'); }); return ret; } default: { seal.replyToSender(ctx, msg, `帮助: +【.ai memo status (@xxx)】查看记忆状态,@为查看个人记忆状态 【.ai memo [p/g] st <内容>】设置个人/群聊设定 【.ai memo [p/g] st clr】清除个人/群聊设定 -【.ai memo [p/g] show】展示个人/群聊记忆 【.ai memo [p/g] del --关键词1 --关键词2】删除个人/群聊记忆 -【.ai memo [p/g] clr】清除个人/群聊记忆 -【.ai memo s show】展示短期记忆 -【.ai memo s clr】清除短期记忆 -【.ai memo sum】总结短期记忆`); +【.ai memo [p/g/s] show】展示个人/群聊/短期记忆 +【.ai memo [p/g/s] clr】清除个人/群聊/短期记忆 +【.ai memo s [on/off]】开启/关闭短期记忆 +【.ai memo sum】立即总结一次短期记忆`); return ret; } } @@ -1141,7 +1174,7 @@ ${Object.keys(tool.info.function.parameters.properties).map(key => { cmdImage.name = 'img'; // 指令名字,可用中文 cmdImage.help = `盗图指南: 【.img draw [stl/lcl/save/all]】随机抽取偷的图片/本地图片/保存的图片/全部 -【.img stl (on/off)】偷图 开启/关闭 +【.img stl [on/off]】偷图 开启/关闭 【.img f [stl/save/all]】遗忘偷的图片/保存的图片/全部 【.img itt [图片/ran] (附加提示词)】图片转文字 【.img list [show/send]】展示保存的图片列表/展示并发送所有保存的图片 diff --git a/src/update.ts b/src/update.ts index 0298df5..2165dbd 100644 --- a/src/update.ts +++ b/src/update.ts @@ -1,8 +1,12 @@ // 版本更新日志,格式为 "版本号": "更新内容",版本号格式为 "x.y.z",按照时间顺序从新到旧排列。 export const updateInfo = { - "4.10.1": `- 修复了构建ctx时,isPrivate始终为0的问题 + "4.10.1": ` +- 可能修复了非指令无法响应的问题 +- 修复了构建ctx时,isPrivate始终为0的问题 - 新增保存图片功能 -- 重构了定时任务的执行`, +- 重构了定时任务的执行 +- 新增短期记忆单独控制开启 +- 新增memo status命令`, "4.10.0": `- 新增了全局待机模式配置项 - 修改了部分正则和部分默认配置项 - 修复了无法调用内置指令 diff --git a/src/utils/utils_message.ts b/src/utils/utils_message.ts index 47e5593..5ac1378 100644 --- a/src/utils/utils_message.ts +++ b/src/utils/utils_message.ts @@ -45,8 +45,8 @@ export function buildSystemMessage(ctx: seal.MsgContext, ai: AI): Message { // 短期记忆 let shortMemoryPrompt = ''; - if (isShortMemory) { - shortMemoryPrompt = ai.memory.shortMemory.map((item, index) => `${index + 1}. ${item}`).join('\n'); + if (isShortMemory && ai.memory.useShortMemory) { + shortMemoryPrompt = ai.memory.shortMemoryList.map((item, index) => `${index + 1}. ${item}`).join('\n'); } // 调用函数 @@ -72,7 +72,7 @@ export function buildSystemMessage(ctx: seal.MsgContext, ai: AI): Message { "可发送图片列表": sandableImagesPrompt, "开启长期记忆": isMemory && memoryPrompt, "记忆信息": memoryPrompt, - "开启短期记忆": isShortMemory && shortMemoryPrompt, + "开启短期记忆": isShortMemory && ai.memory.useShortMemory && shortMemoryPrompt, "短期记忆信息": shortMemoryPrompt, "开启工具函数提示词": isTool && usePromptEngineering, "函数列表": toolsPrompt