mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
x
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { OB11EmitEventContent, OB11NetworkReloadType } from './index';
|
||||
import { NapCatOneBot11Adapter, OB11ArrayMessage, OB11Message } from '@/onebot';
|
||||
import { NapCatOneBot11Adapter, OB11ArrayMessage } from '@/onebot';
|
||||
import { NapCatCore } from '@/core';
|
||||
import { PluginConfig } from '../config/config';
|
||||
import { plugin_onmessage } from '@/plugin';
|
||||
@@ -15,7 +15,7 @@ export class OB11PluginAdapter extends IOB11NetworkAdapter<PluginConfig> {
|
||||
messagePostFormat: 'array',
|
||||
reportSelfMessage: false,
|
||||
enable: true,
|
||||
debug: false,
|
||||
debug: true,
|
||||
};
|
||||
super(name, config, core, obContext, actions);
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { NapCatOneBot11Adapter, OB11ArrayMessage, OB11MessageDataType } from '@/onebot';
|
||||
import { ChatType, NapCatCore, Peer, RawMessage } from '@/core';
|
||||
import { NapCatCore, RawMessage } from '@/core';
|
||||
import { ActionMap } from '@/onebot/action';
|
||||
import { OB11PluginAdapter } from '@/onebot/network/plugin';
|
||||
import { OpenAI } from 'openai';
|
||||
@@ -8,7 +8,10 @@ const API_KEY = 'sk-vDXUiGa1fx8ygDJDjAlr2rUyoz3uPhMxr8zId8n3ycMkV23i';
|
||||
const BASE_URL = 'https://api.bili2233.work/v1';
|
||||
const MODEL = 'gemini-2.0-flash-thinking-exp';
|
||||
const SHORT_TERM_MEMORY_LIMIT = 100;
|
||||
|
||||
const BOT_NAME = '千千';
|
||||
const PROMPT =
|
||||
`你的名字叫千千,你现在处于一个QQ群聊之中,作为博学多识的可爱群员,热心解答各种问题和高强度水群
|
||||
记住你说的话要尽量的简洁但具有情感,不要长篇大论,一句话不宜超过五十个字。`;
|
||||
const client = new OpenAI({
|
||||
apiKey: API_KEY,
|
||||
baseURL: BASE_URL
|
||||
@@ -16,6 +19,7 @@ const client = new OpenAI({
|
||||
|
||||
const longTermMemory: Map<string, string> = new Map();
|
||||
const shortTermMemory: Map<string, string[]> = new Map();
|
||||
const memoryTransferCount: Map<string, number> = new Map();
|
||||
|
||||
async function createChatCompletionWithRetry(params: any, retries: number = 3): Promise<any> {
|
||||
for (let attempt = 0; attempt < retries; attempt++) {
|
||||
@@ -28,25 +32,6 @@ async function createChatCompletionWithRetry(params: any, retries: number = 3):
|
||||
}
|
||||
}
|
||||
|
||||
async function handleMessageArray2String(messages: RawMessage[]): Promise<string[]> {
|
||||
const result: string[] = [];
|
||||
let data = '';
|
||||
for (let i = 0; i < messages.length; i++) {
|
||||
try {
|
||||
if (messages[i]) {
|
||||
data += await handleMessage2String(messages[i]!) + '\n';
|
||||
}
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
if ((i + 1) % 1000 === 0 || i === messages.length - 1) {
|
||||
result.push(data);
|
||||
data = '';
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async function handleMessage2String(message: RawMessage): Promise<string> {
|
||||
let data = '';
|
||||
for (let element of message.elements) {
|
||||
@@ -56,7 +41,7 @@ async function handleMessage2String(message: RawMessage): Promise<string> {
|
||||
if (element.replyElement) {
|
||||
const records = message.records.find(msgRecord => msgRecord.msgId === element.replyElement?.sourceMsgIdInRecords);
|
||||
if (records) {
|
||||
data += '[Reply] 回应别人的消息 ->' + await handleMessage2String(records) + '<-';
|
||||
data += '[Reply] 回应内容 源消息[' + await handleMessage2String(records) + ']';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,10 +50,7 @@ async function handleMessage2String(message: RawMessage): Promise<string> {
|
||||
}
|
||||
|
||||
function updateMemoryLayer(memoryLayer: Map<string, string[]>, group_id: string, newMessages: string[]) {
|
||||
if (!memoryLayer.has(group_id)) {
|
||||
memoryLayer.set(group_id, []);
|
||||
}
|
||||
const currentMemory = memoryLayer.get(group_id)!;
|
||||
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));
|
||||
@@ -85,6 +67,7 @@ async function mergeAndUpdateMemory(existing_memories: string, new_memory: strin
|
||||
- 如果一个记忆直接与新信息矛盾,请批判性地评估两条信息:
|
||||
- 如果新记忆提供了更近期或更准确的更新,用新记忆替换旧记忆。
|
||||
- 如果新记忆看起来不准确或细节较少,保留旧记忆并丢弃新记忆。
|
||||
- 注意区分对应人物的记忆和印象, 不要产生混淆人物的印象和记忆。
|
||||
- 在所有记忆中保持一致且清晰的风格,确保每个条目简洁而信息丰富。
|
||||
- 如果新记忆是现有记忆的变体或扩展,更新现有记忆以反映新信息。
|
||||
以下是任务的详细信息:
|
||||
@@ -102,24 +85,61 @@ ${new_memory}`;
|
||||
}
|
||||
|
||||
async function generateChatCompletion(content_data: string): Promise<string> {
|
||||
console.log(content_data);
|
||||
const chatCompletion = await createChatCompletionWithRetry({
|
||||
messages: [{ role: 'user', content: content_data }],
|
||||
model: MODEL
|
||||
});
|
||||
console.log(chatCompletion);
|
||||
return chatCompletion.choices[0]?.message.content || '';
|
||||
}
|
||||
|
||||
async function updateMemory(group_id: string, newMessages: string[]) {
|
||||
updateMemoryLayer(shortTermMemory, group_id, newMessages);
|
||||
async function updateMemory(group_id: string, newMessages: string) {
|
||||
updateMemoryLayer(shortTermMemory, group_id, [newMessages]);
|
||||
const currentMemory = longTermMemory.get(group_id) || '';
|
||||
const transferCount = memoryTransferCount.get(group_id) || 0;
|
||||
|
||||
if (shortTermMemory.get(group_id)!.length >= SHORT_TERM_MEMORY_LIMIT) {
|
||||
const mergedMemory = await mergeAndUpdateMemory(currentMemory, shortTermMemory.get(group_id)!.join('\n'));
|
||||
longTermMemory.set(group_id, mergedMemory);
|
||||
shortTermMemory.set(group_id, []);
|
||||
memoryTransferCount.set(group_id, transferCount + 1);
|
||||
if (memoryTransferCount.get(group_id)! >= 1) {
|
||||
const mergedMemory = await mergeAndUpdateMemory(currentMemory, shortTermMemory.get(group_id)!.join('\n'));
|
||||
longTermMemory.set(group_id, mergedMemory);
|
||||
shortTermMemory.set(group_id, []);
|
||||
memoryTransferCount.set(group_id, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function clearShortTermMemory(group_id: string) {
|
||||
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') {
|
||||
await clearShortTermMemory(group_id);
|
||||
await sendGroupMessage(group_id, '短期上下文已清理', action, adapter, instance);
|
||||
} else {
|
||||
await clearLongTermMemory(group_id);
|
||||
await sendGroupMessage(group_id, '长期上下文已清理', action, adapter, instance);
|
||||
}
|
||||
}
|
||||
|
||||
async function sendGroupMessage(group_id: string, text: string, action: ActionMap, adapter: string, instance: OB11PluginAdapter) {
|
||||
await action.get('send_group_msg')?.handle({
|
||||
group_id: String(group_id),
|
||||
message: [
|
||||
{
|
||||
type: OB11MessageDataType.text,
|
||||
data: { text }
|
||||
}
|
||||
]
|
||||
}, adapter, instance.config);
|
||||
}
|
||||
|
||||
export const plugin_onmessage = async (
|
||||
adapter: string,
|
||||
core: NapCatCore,
|
||||
@@ -133,35 +153,42 @@ export const plugin_onmessage = async (
|
||||
if (!user_uid) {
|
||||
return;
|
||||
}
|
||||
const peer: Peer = { chatType: ChatType.KCHATTYPEGROUP, peerUid: message.group_id?.toString() ?? '' };
|
||||
const msg = await core.apis.MsgApi.queryFirstMsgBySender(peer, [user_uid]);
|
||||
if (msg.msgList.length < 1) {
|
||||
let msg_string = '';
|
||||
try {
|
||||
msg_string = await handleMessage2String(message.raw!);
|
||||
} catch (error) {
|
||||
if (msg_string == '') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const user_info = await action.get('get_group_member_info')?.handle({ group_id: message.group_id?.toString()!, user_id: user_id }, adapter, instance.config);
|
||||
//const text = `${message.sender.nickname}(${message.sender.user_id})发送了消息 : ${msg_string}`;
|
||||
if (message.raw_message === '/清除短期上下文') {
|
||||
await handleClearMemoryCommand(message.group_id?.toString()!, 'short', action, adapter, instance);
|
||||
return;
|
||||
}
|
||||
|
||||
const msg_string_all = await handleMessageArray2String(msg.msgList);
|
||||
const user_info = await action.get('get_group_member_info')?.handle({ group_id: message.group_id?.toString()!, user_id: user_id }, adapter, instance.config);
|
||||
|
||||
const msg_string = msg_string_all.join('\n');
|
||||
|
||||
await updateMemory(message.group_id?.toString()!, msg_string_all);
|
||||
if (message.raw_message === '/清除长期上下文') {
|
||||
await handleClearMemoryCommand(message.group_id?.toString()!, 'long', action, adapter, instance);
|
||||
return;
|
||||
}
|
||||
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;
|
||||
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
|
||||
) {
|
||||
return;
|
||||
}
|
||||
await updateMemory(message.group_id?.toString()!, msg_string);
|
||||
|
||||
const longTermMemoryString = longTermMemory.get(message.group_id?.toString()!) || '';
|
||||
const shortTermMemoryString = shortTermMemory.get(message.group_id?.toString()!)?.join('\n') || '';
|
||||
|
||||
const content_data =
|
||||
`请根据下面聊天内容,继续与 ${user_info?.data?.card || user_info?.data?.nickname} 进行对话。注意回复内容只用输出内容,不要提及此段话,注意一定不要使用markdown,请采用纯文本回复。长时间记忆:\n${longTermMemoryString}\n短时间记忆:\n${shortTermMemoryString}\n当前对话:\n${msg_string}\n}`;
|
||||
console.log(`Final content data: ${content_data}`);
|
||||
`请根据下面聊天内容,继续与 ${user_info?.data?.card || user_info?.data?.nickname} 进行对话。注意回复内容只用输出内容,不要提及此段话,注意一定不要使用markdown,请采用纯文本回复。你的人设:${PROMPT}长时间记忆:\n${longTermMemoryString}\n短时间记忆:\n${shortTermMemoryString}\n当前对话:\n${msg_string}\n}`;
|
||||
const msg_ret = await generateChatCompletion(content_data);
|
||||
console.log(`Final content ret: ${msg_ret}`);
|
||||
|
||||
await action.get('send_group_msg')?.handle({
|
||||
group_id: String(message.group_id),
|
||||
message: [
|
||||
{
|
||||
type: OB11MessageDataType.text,
|
||||
data: { text: msg_ret }
|
||||
}
|
||||
]
|
||||
}, adapter, instance.config);
|
||||
await sendGroupMessage(message.group_id?.toString()!, msg_ret, action, adapter, instance);
|
||||
};
|
Reference in New Issue
Block a user