mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
x
This commit is contained in:
@@ -3,26 +3,29 @@ import { NapCatCore } from '@/core';
|
|||||||
import { ActionMap } from '@/onebot/action';
|
import { ActionMap } from '@/onebot/action';
|
||||||
import { OB11PluginAdapter } from '@/onebot/network/plugin';
|
import { OB11PluginAdapter } from '@/onebot/network/plugin';
|
||||||
import { OpenAI } from 'openai';
|
import { OpenAI } from 'openai';
|
||||||
|
import { ChatCompletionContentPart, ChatCompletionMessageParam } from 'openai/resources';
|
||||||
|
import { Mutex } from 'async-mutex';
|
||||||
|
|
||||||
const API_KEY = 'sk-vDXUiGa1fx8ygDJDjAlr2rUyoz3uPhMxr8zId8n3ycMkV23i';
|
const API_KEY = 'sk-vDXUiGa1fx8ygDJDjAlr2rUyoz3uPhMxr8zId8n3ycMkV23i';
|
||||||
const BASE_URL = 'https://api.bili2233.work/v1';
|
const BASE_URL = 'https://api.bili2233.work/v1';
|
||||||
const MODEL = 'gemini-2.0-flash-thinking-exp';
|
const MODEL = 'gemini-2.0-flash-thinking-exp';
|
||||||
const SHORT_TERM_MEMORY_LIMIT = 100;
|
const SHORT_TERM_MEMORY_LIMIT = 100;
|
||||||
const BOT_NAME = '千千';
|
const BOT_NAME = '千千';
|
||||||
const PROMPT =
|
const BOT_ADMIN = '1627126029';
|
||||||
`你的名字叫千千,你现在处于一个QQ群聊之中,作为博学多识的可爱群员,热心解答各种问题和高强度水群
|
const PROMPT = `你的名字叫千千,你现在处于一个QQ群聊之中,作为博学多识的可爱群员,不要故意装可爱卖萌,而是更自然,注意少使用标点符号,热心解答各种问题和高强度水群
|
||||||
记住你说的话要尽量的简洁但具有情感,不要长篇大论,一句话不宜超过五十个字。`;
|
记住你说的话要尽量的简洁但具有情感,不要长篇大论,一句话不宜超过五十个字但实际回复可以超过。`;
|
||||||
const CQCODE = `增加一下能力通过不同昵称和QQ进行区分哦,注意理清回复消息的人物, At人直接发送 [CQ:at,qq=1234] 这样可以直接at某个人喵这 回复消息需要发送[CQ:reply,id=xxx]这种格式叫CQ码,发送图片等操作你可以从聊天记录中学习哦, 如果聊天记录的image CQ码 maface类型你可以直接复制使用`
|
const CQCODE = `增加一下能力通过不同昵称和QQ进行区分哦,注意理清回复消息的人物, At人直接发送 [CQ:at,qq=1234] 这样可以直接at某个人喵这 回复消息需要发送[CQ:reply,id=xxx]这种格式叫CQ码,发送图片等操作你可以从聊天记录中学习哦, 如果聊天记录的image CQ码 maface类型你可以直接复制使用`;
|
||||||
const client = new OpenAI({
|
const client = new OpenAI({
|
||||||
apiKey: API_KEY,
|
apiKey: API_KEY,
|
||||||
baseURL: BASE_URL
|
baseURL: BASE_URL
|
||||||
});
|
});
|
||||||
|
|
||||||
const longTermMemory: Map<string, string> = new Map();
|
const longTermMemory: Map<string, string> = new Map();
|
||||||
const shortTermMemory: Map<string, string[]> = new Map();
|
const shortTermMemory: Map<string, Array<ChatCompletionContentPart>[]> = new Map();
|
||||||
const memoryTransferCount: Map<string, number> = new Map();
|
const MemoryCount: Map<string, number> = new Map();
|
||||||
//聊天热度
|
const chatHot: Map<string, { count: number, usetime: number, usecount: number }> = new Map();
|
||||||
const chatHot: Map<string, number> = new Map();
|
const chatHotMutex = new Mutex();
|
||||||
|
const memMutex = new Mutex();
|
||||||
|
|
||||||
async function createChatCompletionWithRetry(params: any, retries: number = 3): Promise<any> {
|
async function createChatCompletionWithRetry(params: any, retries: number = 3): Promise<any> {
|
||||||
for (let attempt = 0; attempt < retries; attempt++) {
|
for (let attempt = 0; attempt < retries; attempt++) {
|
||||||
@@ -35,7 +38,8 @@ async function createChatCompletionWithRetry(params: any, retries: number = 3):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function msg2string(adapter: string, msg: OB11MessageData[], group_id: string, action: ActionMap, plugin: OB11PluginAdapter): Promise<string> {
|
async function messageToOpenAi(adapter: string, msg: OB11MessageData[], groupId: string, action: ActionMap, plugin: OB11PluginAdapter, message: OB11ArrayMessage) {
|
||||||
|
const msgArray: Array<ChatCompletionContentPart> = [];
|
||||||
let ret = '';
|
let ret = '';
|
||||||
for (const m of msg) {
|
for (const m of msg) {
|
||||||
if (m.type === 'reply') {
|
if (m.type === 'reply') {
|
||||||
@@ -44,28 +48,28 @@ async function msg2string(adapter: string, msg: OB11MessageData[], group_id: str
|
|||||||
ret += m.data.text;
|
ret += m.data.text;
|
||||||
} else if (m.type === 'at') {
|
} else if (m.type === 'at') {
|
||||||
const memberInfo = await action.get('get_group_member_info')
|
const memberInfo = await action.get('get_group_member_info')
|
||||||
?.handle({ group_id: group_id, user_id: m.data.qq }, adapter, plugin.config);
|
?.handle({ group_id: groupId, user_id: m.data.qq }, adapter, plugin.config);
|
||||||
ret += `[CQ:at=${m.data.qq},name=${memberInfo?.data?.nickname}]`;
|
ret += `[CQ:at=${m.data.qq},name=${memberInfo?.data?.nickname}]`;
|
||||||
} else if (m.type === 'image') {
|
} else if (m.type === 'image') {
|
||||||
ret += '[CQ:image,file=' + m.data.url + ']';
|
ret += `[CQ:image,file=${m.data.url}]`;
|
||||||
|
msgArray.push({
|
||||||
|
type: 'image_url',
|
||||||
|
image_url: {
|
||||||
|
url: m.data.url?.replace('https://', 'http://') || ''
|
||||||
|
}
|
||||||
|
});
|
||||||
} else if (m.type === 'face') {
|
} else if (m.type === 'face') {
|
||||||
ret += '[CQ:face,id=' + m.data.id + ']';
|
ret += '[CQ:face,id=' + m.data.id + ']';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
msgArray.push({
|
||||||
|
type: 'text',
|
||||||
|
text: `${message.sender.nickname}(${message.sender.user_id})发送了消息(消息id:${message.message_id}) :` + ret
|
||||||
|
});
|
||||||
|
return msgArray.reverse();
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateMemoryLayer(memoryLayer: Map<string, string[]>, group_id: string, newMessages: string[]) {
|
async function mergeAndUpdateMemory(existingMemories: Array<ChatCompletionContentPart>[], newMemory: Array<ChatCompletionContentPart>[]): Promise<string> {
|
||||||
const currentMemory = memoryLayer.get(group_id) || [];
|
|
||||||
currentMemory.push(...newMessages);
|
|
||||||
if (currentMemory.length > SHORT_TERM_MEMORY_LIMIT) {
|
|
||||||
memoryLayer.set(group_id, currentMemory.slice(-SHORT_TERM_MEMORY_LIMIT));
|
|
||||||
} else {
|
|
||||||
memoryLayer.set(group_id, currentMemory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function mergeAndUpdateMemory(existing_memories: string, new_memory: string): Promise<string> {
|
|
||||||
const prompt = `
|
const prompt = `
|
||||||
你是合并、更新和组织记忆的专家。当提供现有记忆和新信息时,你的任务是合并和更新记忆列表,以反映最准确和最新的信息。你还会得到每个现有记忆与新信息的匹配分数。确保利用这些信息做出明智的决定,决定哪些记忆需要更新或合并。
|
你是合并、更新和组织记忆的专家。当提供现有记忆和新信息时,你的任务是合并和更新记忆列表,以反映最准确和最新的信息。你还会得到每个现有记忆与新信息的匹配分数。确保利用这些信息做出明智的决定,决定哪些记忆需要更新或合并。
|
||||||
指南:
|
指南:
|
||||||
@@ -76,110 +80,163 @@ async function mergeAndUpdateMemory(existing_memories: string, new_memory: strin
|
|||||||
- 注意区分对应人物的记忆和印象, 不要产生混淆人物的印象和记忆。
|
- 注意区分对应人物的记忆和印象, 不要产生混淆人物的印象和记忆。
|
||||||
- 在所有记忆中保持一致且清晰的风格,确保每个条目简洁而信息丰富。
|
- 在所有记忆中保持一致且清晰的风格,确保每个条目简洁而信息丰富。
|
||||||
- 如果新记忆是现有记忆的变体或扩展,更新现有记忆以反映新信息。
|
- 如果新记忆是现有记忆的变体或扩展,更新现有记忆以反映新信息。
|
||||||
以下是任务的详细信息:
|
`;
|
||||||
- 现有记忆:
|
|
||||||
${existing_memories}
|
|
||||||
- 新记忆:
|
|
||||||
${new_memory}`;
|
|
||||||
|
|
||||||
const completion = await createChatCompletionWithRetry({
|
const completion = await createChatCompletionWithRetry({
|
||||||
messages: [{ role: 'user', content: prompt }],
|
messages: await toSingleRole([
|
||||||
|
{ role: 'user', content: [{ type: 'text', text: prompt }] },
|
||||||
|
{ role: 'user', content: [{ type: 'text', text: '接下来是旧记忆' }] },
|
||||||
|
...(existingMemories.map(msg => ({ role: 'user', content: msg.filter(e => e.type === 'text') }))),
|
||||||
|
{ role: 'user', content: [{ type: 'text', text: '接下来是新记忆' }] },
|
||||||
|
...(newMemory.map(msg => ({ role: 'user', content: msg.filter(e => e.type === 'text') })))]),
|
||||||
model: MODEL
|
model: MODEL
|
||||||
});
|
});
|
||||||
|
|
||||||
return completion.choices[0]?.message.content || '';
|
return completion.choices[0]?.message.content || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
async function generateChatCompletion(content_data: string, url_image?: string[]): Promise<string> {
|
async function generateChatCompletion(contentData: Array<ChatCompletionMessageParam>): Promise<string> {
|
||||||
const messages: any = {
|
|
||||||
role: 'user', content: [{
|
|
||||||
type: 'text',
|
|
||||||
text: content_data
|
|
||||||
}]
|
|
||||||
};
|
|
||||||
if (url_image && url_image.length > 0) {
|
|
||||||
url_image.forEach(url => {
|
|
||||||
messages.content.push({
|
|
||||||
type: 'image_url',
|
|
||||||
image_url: {
|
|
||||||
url: url.replace('https://', 'http://')
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
console.log(JSON.stringify(messages, null, 2));
|
|
||||||
const chatCompletion = await createChatCompletionWithRetry({
|
const chatCompletion = await createChatCompletionWithRetry({
|
||||||
messages: [messages],
|
messages: contentData,
|
||||||
model: MODEL
|
model: MODEL
|
||||||
});
|
});
|
||||||
return chatCompletion.choices[0]?.message.content || '';
|
return chatCompletion.choices[0]?.message.content || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateMemory(group_id: string, newMessages: string) {
|
async function updateMemory(groupId: string, newMessages: Array<ChatCompletionContentPart>[], core: NapCatCore) {
|
||||||
updateMemoryLayer(shortTermMemory, group_id, [newMessages]);
|
const currentMemory = shortTermMemory.get(groupId) || [];
|
||||||
const currentMemory = longTermMemory.get(group_id) || '';
|
const memCount = await memMutex.runExclusive(() => {
|
||||||
const transferCount = memoryTransferCount.get(group_id) || 0;
|
const memCount = MemoryCount.get(groupId) || 0;
|
||||||
|
MemoryCount.set(groupId, memCount + 1);
|
||||||
if (shortTermMemory.get(group_id)!.length >= SHORT_TERM_MEMORY_LIMIT) {
|
return memCount + 1;
|
||||||
memoryTransferCount.set(group_id, transferCount + 1);
|
});
|
||||||
if (memoryTransferCount.get(group_id)! >= 1) {
|
console.log('memCount', memCount);
|
||||||
const mergedMemory = await mergeAndUpdateMemory(currentMemory, shortTermMemory.get(group_id)!.join('\n'));
|
currentMemory.push(...newMessages);
|
||||||
longTermMemory.set(group_id, mergedMemory);
|
if (memCount > SHORT_TERM_MEMORY_LIMIT) {
|
||||||
shortTermMemory.set(group_id, []);
|
await memMutex.runExclusive(async () => {
|
||||||
memoryTransferCount.set(group_id, 0);
|
const containsBotName = currentMemory.some(messages => messages.some(msg => msg.type === 'text' && msg.text.includes(core.selfInfo.uin)));
|
||||||
}
|
if (containsBotName) {
|
||||||
|
const mergedMemory = await mergeAndUpdateMemory(currentMemory, newMessages);
|
||||||
|
longTermMemory.set(groupId, mergedMemory);
|
||||||
|
}
|
||||||
|
shortTermMemory.set(groupId, currentMemory.slice(-SHORT_TERM_MEMORY_LIMIT));
|
||||||
|
MemoryCount.set(groupId, 0);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
shortTermMemory.set(groupId, currentMemory);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function clearShortTermMemory(group_id: string) {
|
async function clearMemory(groupId: string, type: 'short' | 'long') {
|
||||||
shortTermMemory.set(group_id, []);
|
|
||||||
memoryTransferCount.set(group_id, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function clearLongTermMemory(group_id: string) {
|
|
||||||
longTermMemory.set(group_id, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleClearMemoryCommand(group_id: string, type: 'short' | 'long', action: ActionMap, adapter: string, instance: OB11PluginAdapter) {
|
|
||||||
if (type === 'short') {
|
if (type === 'short') {
|
||||||
await clearShortTermMemory(group_id);
|
shortTermMemory.set(groupId, []);
|
||||||
await sendGroupMessage(group_id, '短期上下文已清理', action, adapter, instance);
|
|
||||||
} else {
|
} else {
|
||||||
await clearLongTermMemory(group_id);
|
longTermMemory.set(groupId, '');
|
||||||
await sendGroupMessage(group_id, '长期上下文已清理', action, adapter, instance);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function sendGroupMessage(group_id: string, text: string, action: ActionMap, adapter: string, instance: OB11PluginAdapter) {
|
async function handleClearMemoryCommand(groupId: string, type: 'short' | 'long', action: ActionMap, adapter: string, instance: OB11PluginAdapter) {
|
||||||
|
await clearMemory(groupId, type);
|
||||||
|
const message = type === 'short' ? '短期上下文已清理' : '长期上下文已清理';
|
||||||
|
await sendGroupMessage(groupId, message, action, adapter, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendGroupMessage(groupId: string, text: string, action: ActionMap, adapter: string, instance: OB11PluginAdapter) {
|
||||||
return await action.get('send_group_msg')?.handle({
|
return await action.get('send_group_msg')?.handle({
|
||||||
group_id: String(group_id),
|
group_id: String(groupId),
|
||||||
message: text
|
message: text
|
||||||
}, adapter, instance.config);
|
}, adapter, instance.config);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleMessage(message: OB11ArrayMessage, adapter: string, action: ActionMap, instance: OB11PluginAdapter): Promise<string> {
|
async function handleMessage(message: OB11ArrayMessage, adapter: string, action: ActionMap, instance: OB11PluginAdapter) {
|
||||||
let msg_string = '';
|
return await messageToOpenAi(adapter, message.message, message.group_id?.toString()!, action, instance, message);
|
||||||
try {
|
|
||||||
msg_string += `${message.sender.nickname}(${message.sender.user_id})发送了消息(消息id:${message.message_id}) :`
|
|
||||||
msg_string += await msg2string(adapter, message.message, message.group_id?.toString()!, action, instance);
|
|
||||||
} catch (error) {
|
|
||||||
if (msg_string == '') {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return msg_string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleChatResponse(message: OB11ArrayMessage, msg_string: string, adapter: string, action: ActionMap, instance: OB11PluginAdapter, _core: NapCatCore) {
|
async function toSingleRole(msg: Array<any>) {
|
||||||
const longTermMemoryString = longTermMemory.get(message.group_id?.toString()!) || '';
|
let ret = { role: 'user', content: new Array<ChatCompletionContentPart>() };
|
||||||
const shortTermMemoryString = shortTermMemory.get(message.group_id?.toString()!)?.join('\n') || '';
|
for (const m of msg) {
|
||||||
const user_info = await action.get('get_group_member_info')?.handle({ group_id: message.group_id?.toString()!, user_id: message.sender.user_id }, adapter, instance.config);
|
ret.content.push(...m.content as any)
|
||||||
const content_data =
|
}
|
||||||
`请根据下面聊天内容,继续与 ${user_info?.data?.card || user_info?.data?.nickname} 进行对话。${CQCODE},注意回复内容只用输出内容,不要提及此段话,注意一定不要使用markdown,请采用纯文本回复。你的人设:${PROMPT}长时间记忆:\n${longTermMemoryString}\n短时间记忆:\n${shortTermMemoryString}\n当前对话:\n${msg_string}\n}`;
|
console.log(JSON.stringify(ret, null, 2));
|
||||||
const msg_ret = await generateChatCompletion(content_data, message.message.filter(e => e.type === 'image').map(e => e.data.url!));
|
return [ret] as Array<ChatCompletionMessageParam>;
|
||||||
let msg = await sendGroupMessage(message.group_id?.toString()!, msg_ret, action, adapter, instance);
|
}
|
||||||
chatHot.set(message.group_id?.toString()!, (chatHot.get(message.group_id?.toString()!) || 0) + 3);
|
|
||||||
return msg?.data?.message_id;
|
async function handleChatResponse(message: OB11ArrayMessage, msgArray: Array<ChatCompletionContentPart>, adapter: string, action: ActionMap, instance: OB11PluginAdapter, _core: NapCatCore, reply?: Array<ChatCompletionContentPart>) {
|
||||||
|
const group_id = message.group_id?.toString()!;
|
||||||
|
const longTermMemoryList = longTermMemory.get(group_id) || '';
|
||||||
|
let shortTermMemoryList = shortTermMemory.get(group_id);
|
||||||
|
if (!shortTermMemoryList) {
|
||||||
|
let MemoryShort: Array<ChatCompletionContentPart>[] = [];
|
||||||
|
shortTermMemory.set(group_id, MemoryShort);
|
||||||
|
shortTermMemoryList = MemoryShort;
|
||||||
|
}
|
||||||
|
const prompt = `请根据下面聊天内容,继续与 ${message?.sender?.card || message?.sender?.nickname} 进行对话。${CQCODE},注意回复内容只用输出内容,不要提及此段话,注意一定不要使用markdown,请采用纯文本回复。你的人设:${PROMPT}`
|
||||||
|
let data = shortTermMemoryList.map(msg => ({ role: 'user' as const, content: msg.filter(e => e.type === 'text') }));
|
||||||
|
let contentData: Array<ChatCompletionMessageParam> = await toSingleRole([
|
||||||
|
{ role: 'user', content: [{ type: 'text', text: prompt }] },
|
||||||
|
{ role: 'user', content: [{ type: 'text', text: '接下来是长时间记忆' }] },
|
||||||
|
{ role: 'user', content: [{ type: 'text', text: longTermMemoryList }] },
|
||||||
|
{ role: 'user', content: [{ type: 'text', text: '接下来是短时间记忆' }] },
|
||||||
|
...data,
|
||||||
|
{ role: 'user', content: [{ type: 'text' as const, text: '接下来是本次引用消息' }] },
|
||||||
|
...(reply ? [{ role: 'user' as const, content: reply }] : []),
|
||||||
|
{ role: 'user', content: [{ type: 'text' as const, text: '接下来是当前对话' }] },
|
||||||
|
{ role: 'user', content: msgArray }
|
||||||
|
]);
|
||||||
|
const msgRet = await generateChatCompletion(contentData);
|
||||||
|
const sentMsg = await sendGroupMessage(group_id, msgRet, action, adapter, instance);
|
||||||
|
return { id: sentMsg?.data?.message_id, text: msgRet };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function shouldRespond(message: OB11ArrayMessage, core: NapCatCore, oriMsg: any, currentHot: number, msgArray: Array<ChatCompletionContentPart>, reply?: Array<ChatCompletionContentPart>): Promise<boolean> {
|
||||||
|
if (
|
||||||
|
!message.raw_message.startsWith(BOT_NAME) &&
|
||||||
|
!message.message.find(e => e.type == 'at' && e.data.qq == core.selfInfo.uin) &&
|
||||||
|
oriMsg?.sender.user_id.toString() !== core.selfInfo.uin
|
||||||
|
) {
|
||||||
|
if (currentHot > 0) {
|
||||||
|
if (msgArray.length > 0) {
|
||||||
|
const longTermMemoryList = longTermMemory.get(message.group_id?.toString()!) || '';
|
||||||
|
let shortTermMemoryList = shortTermMemory.get(message.group_id?.toString()!);
|
||||||
|
let prompt = `请根据在群内聊天与 ${message.sender.card || message.sender?.nickname} 发送的聊天消息推测本次消息是否应该回应。自身无关的话题和图片不要回复,尤其减少对图片消息的回复可能性, 注意回复内容只用输出2 - 3个字, 一定注意不想回复请回应不回复三个字即可, 想回复回应回复即可, 你的人设:${PROMPT}`;
|
||||||
|
if (!shortTermMemoryList) {
|
||||||
|
let MemoryShort: Array<ChatCompletionContentPart>[] = [];
|
||||||
|
shortTermMemory.set(message.group_id?.toString()!, MemoryShort);
|
||||||
|
shortTermMemoryList = MemoryShort;
|
||||||
|
}
|
||||||
|
const contentData: Array<ChatCompletionMessageParam> = await toSingleRole([
|
||||||
|
{ role: 'user', content: [{ type: 'text', text: prompt }] },
|
||||||
|
{ role: 'user', content: [{ type: 'text', text: '接下来是长时间记忆' }] },
|
||||||
|
{ role: 'user', content: [{ type: 'text', text: longTermMemoryList }] },
|
||||||
|
{ role: 'user', content: [{ type: 'text', text: '接下来是短时间记忆' }] },
|
||||||
|
|
||||||
|
...(shortTermMemoryList.map(msg => ({ role: 'user' as const, content: msg.filter(e => e.type === 'text') }))),
|
||||||
|
{ role: 'user', content: [{ type: 'text' as const, text: '接下来是本次引用消息' }] },
|
||||||
|
...(reply ? [{ role: 'user' as const, content: reply }] : []),
|
||||||
|
{ role: 'user', content: [{ type: 'text' as const, text: '接下来是当前对话' }] },
|
||||||
|
{ role: 'user', content: msgArray }
|
||||||
|
]);
|
||||||
|
const msgRet = await generateChatCompletion(contentData);
|
||||||
|
if (msgRet.indexOf('不回复') !== -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleClearMemory(message: OB11ArrayMessage, action: ActionMap, adapter: string, instance: OB11PluginAdapter) {
|
||||||
|
if (message.raw_message === '/清除短期上下文' && message.sender.user_id.toString() === BOT_ADMIN) {
|
||||||
|
await handleClearMemoryCommand(message.group_id?.toString()!, 'short', action, adapter, instance);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.raw_message === '/清除长期上下文' && message.sender.user_id.toString() === BOT_ADMIN) {
|
||||||
|
await handleClearMemoryCommand(message.group_id?.toString()!, 'long', action, adapter, instance);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const plugin_onmessage = async (
|
export const plugin_onmessage = async (
|
||||||
@@ -190,47 +247,47 @@ export const plugin_onmessage = async (
|
|||||||
action: ActionMap,
|
action: ActionMap,
|
||||||
instance: OB11PluginAdapter
|
instance: OB11PluginAdapter
|
||||||
) => {
|
) => {
|
||||||
const current_hot = chatHot.get(message.group_id?.toString()!) || 0;
|
const currentHot = await chatHotMutex.runExclusive(async () => {
|
||||||
const orimsgid = message.message.find(e => e.type == 'reply')?.data.id;
|
const group_id = message.group_id?.toString()!;
|
||||||
const orimsg = orimsgid ? await action.get('get_msg')?._handle({ message_id: orimsgid }, adapter, instance.config) : undefined;
|
const chatHotData = chatHot.get(group_id);
|
||||||
|
const currentTime = Date.now();
|
||||||
if (message.raw_message === '/清除短期上下文') {
|
if (chatHotData) {
|
||||||
await handleClearMemoryCommand(message.group_id?.toString()!, 'short', action, adapter, instance);
|
if (currentTime - chatHotData.usetime > 30000) {
|
||||||
return;
|
chatHot.set(group_id, { count: chatHotData.count, usetime: currentTime, usecount: 0 });
|
||||||
}
|
} else if (chatHotData.usecount > 2) {
|
||||||
|
chatHot.set(group_id, { count: 0, usetime: currentTime, usecount: 0 });
|
||||||
if (message.raw_message === '/清除长期上下文') {
|
|
||||||
await handleClearMemoryCommand(message.group_id?.toString()!, 'long', action, adapter, instance);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
!message.raw_message.startsWith(BOT_NAME) &&
|
|
||||||
!message.message.find(e => e.type == 'at' && e.data.qq == core.selfInfo.uin) &&
|
|
||||||
orimsg?.sender.user_id.toString() !== core.selfInfo.uin
|
|
||||||
) {
|
|
||||||
if (current_hot > 0) {
|
|
||||||
const msg_string = await handleMessage(message, adapter, action, instance);
|
|
||||||
if (msg_string) {
|
|
||||||
const longTermMemoryString = longTermMemory.get(message.group_id?.toString()!) || '';
|
|
||||||
const shortTermMemoryString = shortTermMemory.get(message.group_id?.toString()!)?.join('\n') || '';
|
|
||||||
const user_info = await action.get('get_group_member_info')?.handle({ group_id: message.group_id?.toString()!, user_id: message.sender.user_id }, adapter, instance.config);
|
|
||||||
const content_data =
|
|
||||||
`请根据在群内聊天与 ${user_info?.data?.card || user_info?.data?.nickname} 发送的聊天消息推测本次消息是否应该回应。${CQCODE},注意回复内容只用输出内容,一定注意不想回复请回应不回复三个字即可,想回复回应回复即可,你的人设:${PROMPT}长时间记忆:\n${longTermMemoryString}\n短时间记忆:\n${shortTermMemoryString}\n当前对话:\n${msg_string}\n}`
|
|
||||||
const msg_ret = await generateChatCompletion(content_data, message.message.filter(e => e.type === 'image').map(e => e.data.url!));
|
|
||||||
if (msg_ret.indexOf('不回复') == -1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return;
|
chatHot.set(group_id, { count: 0, usetime: currentTime, usecount: 0 });
|
||||||
}
|
}
|
||||||
|
return chatHot.get(group_id)!;
|
||||||
|
});
|
||||||
|
console.log('currentHot', currentHot);
|
||||||
|
const oriMsgId = message.message.find(e => e.type == 'reply')?.data.id;
|
||||||
|
const oriMsg = (oriMsgId ? await action.get('get_msg')?._handle({ message_id: oriMsgId }, adapter, instance.config) : undefined) as OB11ArrayMessage | undefined;
|
||||||
|
const msgArray = await handleMessage(message, adapter, action, instance);
|
||||||
|
if (!msgArray) return;
|
||||||
|
await updateMemory(message.group_id?.toString()!, [msgArray], core);
|
||||||
|
|
||||||
|
if (await handleClearMemory(message, action, adapter, instance)) return;
|
||||||
|
|
||||||
|
const oriMsgOpenai = oriMsg ? await handleMessage(oriMsg, adapter, action, instance) : undefined;
|
||||||
|
|
||||||
|
if (await shouldRespond(message, core, oriMsg, currentHot?.count || 0, msgArray, oriMsgOpenai)) {
|
||||||
|
const sentMsg = await handleChatResponse(message, msgArray, adapter, action, instance, core, oriMsgOpenai);
|
||||||
|
await updateMemory(message.group_id?.toString()!, [[{
|
||||||
|
type: 'text',
|
||||||
|
text: `我(群昵称: 乔千)(${core.selfInfo.uin})发送了消息(消息id: ${sentMsg.id}) : ` + sentMsg.text
|
||||||
|
}]], core);
|
||||||
|
await chatHotMutex.runExclusive(() => {
|
||||||
|
const currentTime = Date.now();
|
||||||
|
const group_id = message.group_id?.toString()!;
|
||||||
|
if (currentTime - currentHot.usetime < 40000) {
|
||||||
|
chatHot.set(group_id, { count: currentHot.count + 1, usetime: currentHot.usetime, usecount: currentHot.usecount + 1 });
|
||||||
|
} else {
|
||||||
|
chatHot.set(group_id, { count: 0, usetime: currentTime, usecount: 0 });
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const msg_string = await handleMessage(message, adapter, action, instance);
|
|
||||||
if (!msg_string) return;
|
|
||||||
|
|
||||||
await updateMemory(message.group_id?.toString()!, msg_string);
|
|
||||||
let sended_msg = await handleChatResponse(message, msg_string, adapter, action, instance, core);
|
|
||||||
await updateMemory(message.group_id?.toString()!, `乔千(${core.selfInfo.uin})发送了消息(消息id:${sended_msg}) :` + msg_string);
|
|
||||||
};
|
};
|
Reference in New Issue
Block a user