From f5e71819494bca796057408ae1d3f45a929c3a2d Mon Sep 17 00:00:00 2001 From: meng_xi_pan <1903647908@qq.com> Date: Thu, 3 Apr 2025 23:06:54 +0800 Subject: [PATCH 01/16] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=BC=93=E5=AD=98?= =?UTF-8?q?=E5=99=A8=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/chat/message_buffer.py | 89 ++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/plugins/chat/message_buffer.py diff --git a/src/plugins/chat/message_buffer.py b/src/plugins/chat/message_buffer.py new file mode 100644 index 000000000..93a7d6487 --- /dev/null +++ b/src/plugins/chat/message_buffer.py @@ -0,0 +1,89 @@ +from ..person_info import person_info +from src.common.logger import get_module_logger +import asyncio +from dataclasses import dataclass +from .message import MessageRecv +import hashlib +from typing import List, Dict +from dataclasses import dataclass, field + +logger = get_module_logger("message_buffer") + +@dataclass +class CacheMessages: + message: MessageRecv + cache_determination: asyncio.Event = field(default_factory=asyncio.Event) # 判断缓冲是否产生结果 + result: str = "U" + + +class MassageBuffer: + def __init__(self): + self.buffer_pool: Dict[str, List[CacheMessages]] = {} + self.lock = asyncio.Lock() + + def get_person_id_(self, platform:str, user_id:str, group_id:str): + """获取唯一id""" + group_id = group_id or "私聊" + key = f"{platform}_{user_id}_{group_id}" + return hashlib.md5(key.encode()).hexdigest() + + async def start_caching_messages(self, message:MessageRecv): + """添加消息并重置缓冲计时器""" + person_id_ = self.get_person_id_(message.chat_info.platform, + message.chat_info.user_info.user_id, + message.chat_info.group_info.group_id) + async with self.lock: + # 清空该用户之前的未处理消息 + if person_id_ in self.buffer_pool: + for old_msg in self.buffer_pool[person_id_]: + if old_msg.result == "U": + old_msg.cache_determination.set() + old_msg.result = "F" # 标记旧消息为失败 + logger.debug(f"被新消息覆盖信息id: {message.message_id}") + + # 添加新消息 + cache_msg = CacheMessages(message=message, result="U") + self.buffer_pool[person_id_] = [cache_msg] # 只保留最新消息 + + # 启动3秒缓冲计时器 + asyncio.create_task(self._debounce_processor(person_id_, cache_msg)) + + async def _debounce_processor(self, person_id_:str, cache_msg:CacheMessages): + """等待3秒无新消息""" + await asyncio.sleep(3) + + async with self.lock: + # 检查消息是否仍未被覆盖 + if (person_id_ in self.buffer_pool and + cache_msg in self.buffer_pool[person_id_] and + cache_msg.result == "U"): + + cache_msg.result = "T" # 标记为成功处理 + cache_msg.cache_determination.set() + + + async def query_buffer_result(self, message:MessageRecv) -> bool: + """查询缓冲结果""" + person_id_ = self.get_person_id_(message.chat_info.platform, + message.chat_info.user_info.user_id, + message.chat_info.group_info.group_id) + + async with self.lock: + if person_id_ not in self.buffer_pool or not self.buffer_pool[person_id_]: + return False + + cache_msg = self.buffer_pool[person_id_][-1] # 获取最新消息 + if cache_msg.message.message_id != message.message_id: + return False + + try: + await asyncio.wait_for(cache_msg.cache_determination.wait(), timeout=10) + return cache_msg.result == "T" + except asyncio.TimeoutError: + logger.debug(f"查询超时消息id: {message.message_id}") + return False + + + + +message_buffer = MassageBuffer() \ No newline at end of file From 78b5ee81d664f43d38cda0fafc280f633976b74e Mon Sep 17 00:00:00 2001 From: meng_xi_pan <1903647908@qq.com> Date: Fri, 4 Apr 2025 09:48:19 +0800 Subject: [PATCH 02/16] =?UTF-8?q?=E5=BF=83=E6=B5=81=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=E5=AE=8C=E6=88=90=E7=BC=93=E5=86=B2=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/chat/message_buffer.py | 141 +++++++++++++----- .../think_flow_chat/think_flow_chat.py | 10 ++ src/plugins/person_info/person_info.py | 1 + 3 files changed, 112 insertions(+), 40 deletions(-) diff --git a/src/plugins/chat/message_buffer.py b/src/plugins/chat/message_buffer.py index 93a7d6487..4e9aa5582 100644 --- a/src/plugins/chat/message_buffer.py +++ b/src/plugins/chat/message_buffer.py @@ -1,11 +1,13 @@ -from ..person_info import person_info +from ..person_info.person_info import person_info_manager from src.common.logger import get_module_logger import asyncio from dataclasses import dataclass from .message import MessageRecv import hashlib -from typing import List, Dict +from typing import Dict from dataclasses import dataclass, field +from collections import OrderedDict +import random logger = get_module_logger("message_buffer") @@ -18,7 +20,7 @@ class CacheMessages: class MassageBuffer: def __init__(self): - self.buffer_pool: Dict[str, List[CacheMessages]] = {} + self.buffer_pool: Dict[str, OrderedDict[str, CacheMessages]] = {} self.lock = asyncio.Lock() def get_person_id_(self, platform:str, user_id:str, group_id:str): @@ -28,62 +30,121 @@ class MassageBuffer: return hashlib.md5(key.encode()).hexdigest() async def start_caching_messages(self, message:MessageRecv): - """添加消息并重置缓冲计时器""" - person_id_ = self.get_person_id_(message.chat_info.platform, - message.chat_info.user_info.user_id, - message.chat_info.group_info.group_id) + """添加消息,启动缓冲""" + person_id_ = self.get_person_id_(message.message_info.platform, + message.message_info.user_info.user_id, + message.message_info.group_info.group_id) + async with self.lock: - # 清空该用户之前的未处理消息 - if person_id_ in self.buffer_pool: - for old_msg in self.buffer_pool[person_id_]: - if old_msg.result == "U": - old_msg.cache_determination.set() - old_msg.result = "F" # 标记旧消息为失败 - logger.debug(f"被新消息覆盖信息id: {message.message_id}") + if person_id_ not in self.buffer_pool: + self.buffer_pool[person_id_] = OrderedDict() + + # 查找最近的处理成功消息(T) + last_T_msg = None + recent_F_count = 0 + for msg_id in reversed(self.buffer_pool[person_id_]): + msg = self.buffer_pool[person_id_][msg_id] + if msg.result == "T": + last_T_msg = msg + break + elif msg.result == "F": + recent_F_count += 1 + + # 判断条件:最近T之后有超过3条F + if (recent_F_count >= random.randint(3, 5)): + new_msg = CacheMessages(message=message, result="T") + new_msg.cache_determination.set() + self.buffer_pool[person_id_][message.message_info.message_id] = new_msg + logger.debug(f"快速处理消息(已堆积{recent_F_count}条F): {message.message_info.message_id}") + return + + # 标记该用户之前的未处理消息 + for msg_id, cache_msg in self.buffer_pool[person_id_].items(): + if cache_msg.result == "U": + cache_msg.result = "F" + cache_msg.cache_determination.set() + logger.debug(f"被新消息覆盖信息id: {message.message_info.message_id}") # 添加新消息 - cache_msg = CacheMessages(message=message, result="U") - self.buffer_pool[person_id_] = [cache_msg] # 只保留最新消息 + self.buffer_pool[person_id_][message.message_info.message_id] = CacheMessages(message=message) # 启动3秒缓冲计时器 - asyncio.create_task(self._debounce_processor(person_id_, cache_msg)) + person_id = person_info_manager.get_person_id(message.message_info.user_info.platform, + message.message_info.user_info.user_id) + asyncio.create_task(self._debounce_processor(person_id_, + message.message_info.message_id, + person_id)) - async def _debounce_processor(self, person_id_:str, cache_msg:CacheMessages): + async def _debounce_processor(self, person_id_: str, message_id: str, person_id: str): """等待3秒无新消息""" - await asyncio.sleep(3) + interval_time = await person_info_manager.get_value(person_id, "msg_interval") + if not isinstance(interval_time, (int, str)) or not str(interval_time).isdigit(): + logger.debug("debounce_processor无效的时间") + return + interval_time = max(0.5, int(interval_time) / 1000) + await asyncio.sleep(interval_time) async with self.lock: - # 检查消息是否仍未被覆盖 - if (person_id_ in self.buffer_pool and - cache_msg in self.buffer_pool[person_id_] and - cache_msg.result == "U"): - - cache_msg.result = "T" # 标记为成功处理 + if (person_id_ not in self.buffer_pool or + message_id not in self.buffer_pool[person_id_]): + logger.debug(f"消息异常被清理,msgid: {message_id}") + return + + cache_msg = self.buffer_pool[person_id_][message_id] + if cache_msg.result == "U": + cache_msg.result = "T" cache_msg.cache_determination.set() async def query_buffer_result(self, message:MessageRecv) -> bool: - """查询缓冲结果""" - person_id_ = self.get_person_id_(message.chat_info.platform, - message.chat_info.user_info.user_id, - message.chat_info.group_info.group_id) + """查询缓冲结果,并清理""" + person_id_ = self.get_person_id_(message.message_info.platform, + message.message_info.user_info.user_id, + message.message_info.group_info.group_id) + async with self.lock: - if person_id_ not in self.buffer_pool or not self.buffer_pool[person_id_]: - return False - - cache_msg = self.buffer_pool[person_id_][-1] # 获取最新消息 - if cache_msg.message.message_id != message.message_id: - return False - + user_msgs = self.buffer_pool.get(person_id_, {}) + cache_msg = user_msgs.get(message.message_info.message_id) + + if not cache_msg: + logger.debug(f"查询异常,消息不存在,msgid: {message.message_info.message_id}") + return False # 消息不存在或已清理 + try: await asyncio.wait_for(cache_msg.cache_determination.wait(), timeout=10) - return cache_msg.result == "T" + result = cache_msg.result == "T" + + if result: + async with self.lock: # 再次加锁 + # 清理所有早于当前消息的已处理消息, 收集所有早于当前消息的F消息的processed_plain_text + keep_msgs = OrderedDict() + combined_text = [] + found = False + for msg_id, msg in self.buffer_pool[person_id_].items(): + if msg_id == message.message_info.message_id: + found = True + combined_text.append(msg.message.processed_plain_text) + continue + if found: + keep_msgs[msg_id] = msg + elif msg.result == "F": + # 收集F消息的文本内容 + if hasattr(msg.message, 'processed_plain_text') and msg.message.processed_plain_text: + combined_text.append(msg.message.processed_plain_text) + elif msg.result == "U": + logger.debug(f"异常未处理信息id: {msg.message.message_info.message_id}") + + # 更新当前消息的processed_plain_text + if combined_text and combined_text[0] != message.processed_plain_text: + message.processed_plain_text = "".join(combined_text) + logger.debug(f"整合了{len(combined_text)-1}条F消息的内容到当前消息") + + self.buffer_pool[person_id_] = keep_msgs + return result except asyncio.TimeoutError: - logger.debug(f"查询超时消息id: {message.message_id}") + logger.debug(f"查询超时消息id: {message.message_info.message_id}") return False - - message_buffer = MassageBuffer() \ No newline at end of file diff --git a/src/plugins/chat_module/think_flow_chat/think_flow_chat.py b/src/plugins/chat_module/think_flow_chat/think_flow_chat.py index 87ea1575a..de034e25b 100644 --- a/src/plugins/chat_module/think_flow_chat/think_flow_chat.py +++ b/src/plugins/chat_module/think_flow_chat/think_flow_chat.py @@ -18,6 +18,7 @@ from src.heart_flow.heartflow import heartflow from src.common.logger import get_module_logger, CHAT_STYLE_CONFIG, LogConfig from ...chat.chat_stream import chat_manager from ...person_info.relationship_manager import relationship_manager +from ...chat.message_buffer import message_buffer # 定义日志配置 chat_config = LogConfig( @@ -161,6 +162,8 @@ class ThinkFlowChat: userinfo = message.message_info.user_info messageinfo = message.message_info + # 消息加入缓冲池 + await message_buffer.start_caching_messages(message) # 创建聊天流 chat = await chat_manager.get_or_create_stream( @@ -192,8 +195,15 @@ class ThinkFlowChat: timing_results["记忆激活"] = timer2 - timer1 logger.debug(f"记忆激活: {interested_rate}") + # 查询缓冲器结果,会整合前面跳过的消息,改变processed_plain_text + buffer_result = await message_buffer.query_buffer_result(message) + if not buffer_result: + logger.info(f"触发缓冲,已炸飞消息:{message.processed_plain_text}") + return + is_mentioned = is_mentioned_bot_in_message(message) + # 计算回复意愿 current_willing_old = willing_manager.get_willing(chat_stream=chat) # current_willing_new = (heartflow.get_subheartflow(chat.stream_id).current_state.willing - 5) / 4 diff --git a/src/plugins/person_info/person_info.py b/src/plugins/person_info/person_info.py index f940c0fca..3373366a0 100644 --- a/src/plugins/person_info/person_info.py +++ b/src/plugins/person_info/person_info.py @@ -30,6 +30,7 @@ person_info_default = { # "impression" : None, # "gender" : Unkown, "konw_time" : 0, + "msg_interval": 3000 } # 个人信息的各项与默认值在此定义,以下处理会自动创建/补全每一项 class PersonInfoManager: From 255d4ea575ef62a59b482a4ffc1b22aeccf72c08 Mon Sep 17 00:00:00 2001 From: meng_xi_pan <1903647908@qq.com> Date: Fri, 4 Apr 2025 13:26:46 +0800 Subject: [PATCH 03/16] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86=E4=B8=80?= =?UTF-8?q?=E4=BA=9Bbug=EF=BC=8C=E5=8C=85=E6=8B=AC=E7=BC=93=E5=86=B2?= =?UTF-8?q?=E5=99=A8=E5=AF=B9=E4=BA=8E=E6=B6=88=E6=81=AF=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E7=9A=84=E5=A4=84=E7=90=86=EF=BC=8Cpersoninfo=E7=9A=84?= =?UTF-8?q?=E6=8B=B7=E8=B4=9D=E9=97=AE=E9=A2=98=EF=BC=8C=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E4=BF=A1=E6=81=AF=E9=97=B4=E9=9A=94=E7=9A=84?= =?UTF-8?q?=E6=94=B6=E9=9B=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.py | 3 +- src/plugins/chat/message_buffer.py | 33 ++++++++++--- .../think_flow_chat/think_flow_chat.py | 7 ++- src/plugins/person_info/person_info.py | 47 +++++++++++++++++-- 4 files changed, 78 insertions(+), 12 deletions(-) diff --git a/src/main.py b/src/main.py index e3bbf38d1..932fbfcfe 100644 --- a/src/main.py +++ b/src/main.py @@ -56,8 +56,9 @@ class MainSystem: self.mood_manager.start_mood_update(update_interval=global_config.mood_update_interval) logger.success("情绪管理器启动成功") - # 检查并清除person_info冗余字段 + # 检查并清除person_info冗余字段,启动个人习惯推断 await person_info_manager.del_all_undefined_field() + # asyncio.create_task(person_info_manager.personal_habit_deduction()) # 启动愿望管理器 await willing_manager.ensure_started() diff --git a/src/plugins/chat/message_buffer.py b/src/plugins/chat/message_buffer.py index 4e9aa5582..9919e6cf7 100644 --- a/src/plugins/chat/message_buffer.py +++ b/src/plugins/chat/message_buffer.py @@ -3,11 +3,13 @@ from src.common.logger import get_module_logger import asyncio from dataclasses import dataclass from .message import MessageRecv +from ..message.message_base import BaseMessageInfo import hashlib from typing import Dict from dataclasses import dataclass, field from collections import OrderedDict import random +import time logger = get_module_logger("message_buffer") @@ -40,17 +42,15 @@ class MassageBuffer: self.buffer_pool[person_id_] = OrderedDict() # 查找最近的处理成功消息(T) - last_T_msg = None recent_F_count = 0 for msg_id in reversed(self.buffer_pool[person_id_]): msg = self.buffer_pool[person_id_][msg_id] if msg.result == "T": - last_T_msg = msg break elif msg.result == "F": recent_F_count += 1 - # 判断条件:最近T之后有超过3条F + # 判断条件:最近T之后有超过3-5条F if (recent_F_count >= random.randint(3, 5)): new_msg = CacheMessages(message=message, result="T") new_msg.cache_determination.set() @@ -63,7 +63,7 @@ class MassageBuffer: if cache_msg.result == "U": cache_msg.result = "F" cache_msg.cache_determination.set() - logger.debug(f"被新消息覆盖信息id: {message.message_info.message_id}") + logger.debug(f"被新消息覆盖信息id: {cache_msg.message.message_info.message_id}") # 添加新消息 self.buffer_pool[person_id_][message.message_info.message_id] = CacheMessages(message=message) @@ -71,6 +71,7 @@ class MassageBuffer: # 启动3秒缓冲计时器 person_id = person_info_manager.get_person_id(message.message_info.user_info.platform, message.message_info.user_info.user_id) + asyncio.create_task(self.save_message_interval(person_id, message.message_info)) asyncio.create_task(self._debounce_processor(person_id_, message.message_info.message_id, person_id)) @@ -121,22 +122,26 @@ class MassageBuffer: keep_msgs = OrderedDict() combined_text = [] found = False + is_text = False for msg_id, msg in self.buffer_pool[person_id_].items(): if msg_id == message.message_info.message_id: found = True + is_text = msg.message.message_segment.type == "text" combined_text.append(msg.message.processed_plain_text) continue if found: keep_msgs[msg_id] = msg elif msg.result == "F": # 收集F消息的文本内容 - if hasattr(msg.message, 'processed_plain_text') and msg.message.processed_plain_text: + if (hasattr(msg.message, 'processed_plain_text') + and msg.message.message_segment.type == "text" + and msg.message.processed_plain_text): combined_text.append(msg.message.processed_plain_text) elif msg.result == "U": logger.debug(f"异常未处理信息id: {msg.message.message_info.message_id}") # 更新当前消息的processed_plain_text - if combined_text and combined_text[0] != message.processed_plain_text: + if combined_text and combined_text[0] != message.processed_plain_text and is_text: message.processed_plain_text = "".join(combined_text) logger.debug(f"整合了{len(combined_text)-1}条F消息的内容到当前消息") @@ -145,6 +150,22 @@ class MassageBuffer: except asyncio.TimeoutError: logger.debug(f"查询超时消息id: {message.message_info.message_id}") return False + + async def save_message_interval(self, person_id:str, message:BaseMessageInfo): + message_interval_list = await person_info_manager.get_value(person_id, "msg_interval_list") + now_time_ms = int(round(time.time() * 1000)) + if len(message_interval_list) < 1000: + message_interval_list.append(now_time_ms) + else: + message_interval_list = message_interval_list.pop(0) + message_interval_list.append(now_time_ms) + data = { + "platform" : message.platform, + "user_id" : message.user_info.user_id, + "nickname" : message.user_info.user_nickname, + "konw_time" : int(time.time()) + } + await person_info_manager.update_one_field(person_id, "msg_interval_list", message_interval_list, data) message_buffer = MassageBuffer() \ No newline at end of file diff --git a/src/plugins/chat_module/think_flow_chat/think_flow_chat.py b/src/plugins/chat_module/think_flow_chat/think_flow_chat.py index de034e25b..8f5322e22 100644 --- a/src/plugins/chat_module/think_flow_chat/think_flow_chat.py +++ b/src/plugins/chat_module/think_flow_chat/think_flow_chat.py @@ -198,7 +198,12 @@ class ThinkFlowChat: # 查询缓冲器结果,会整合前面跳过的消息,改变processed_plain_text buffer_result = await message_buffer.query_buffer_result(message) if not buffer_result: - logger.info(f"触发缓冲,已炸飞消息:{message.processed_plain_text}") + if message.message_segment.type == "text": + logger.info(f"触发缓冲,已炸飞消息:{message.processed_plain_text}") + elif message.message_segment.type == "image": + logger.info(f"触发缓冲,已炸飞表情包/图片") + elif message.message_segment.type == "seglist": + logger.info(f"触发缓冲,已炸飞消息列") return is_mentioned = is_mentioned_bot_in_message(message) diff --git a/src/plugins/person_info/person_info.py b/src/plugins/person_info/person_info.py index 3373366a0..20ab2db8b 100644 --- a/src/plugins/person_info/person_info.py +++ b/src/plugins/person_info/person_info.py @@ -4,6 +4,7 @@ import copy import hashlib from typing import Any, Callable, Dict, TypeVar T = TypeVar('T') # 泛型类型 +import datetime """ PersonInfoManager 类方法功能摘要: @@ -15,6 +16,7 @@ PersonInfoManager 类方法功能摘要: 6. get_values - 批量获取字段值(任一字段无效则返回空字典) 7. del_all_undefined_field - 清理全集合中未定义的字段 8. get_specific_value_list - 根据指定条件,返回person_id,value字典 +9. personal_habit_deduction - 定时推断个人习惯 """ logger = get_module_logger("person_info") @@ -30,11 +32,13 @@ person_info_default = { # "impression" : None, # "gender" : Unkown, "konw_time" : 0, - "msg_interval": 3000 + "msg_interval": 3000, + "msg_interval_list": [] } # 个人信息的各项与默认值在此定义,以下处理会自动创建/补全每一项 class PersonInfoManager: def __init__(self): + self.start_time = datetime.datetime.now() if "person_info" not in db.list_collection_names(): db.create_collection("person_info") db.person_info.create_index("person_id", unique=True) @@ -109,8 +113,9 @@ class PersonInfoManager: if document and field_name in document: return document[field_name] else: - logger.debug(f"获取{person_id}的{field_name}失败,已返回默认值{person_info_default[field_name]}") - return person_info_default[field_name] + default_value = copy.deepcopy(person_info_default[field_name]) + logger.debug(f"获取{person_id}的{field_name}失败,已返回默认值{default_value}") + return default_value async def get_values(self, person_id: str, field_names: list) -> dict: """获取指定person_id文档的多个字段值,若不存在该字段,则返回该字段的全局默认值""" @@ -134,7 +139,10 @@ class PersonInfoManager: result = {} for field in field_names: - result[field] = document.get(field, person_info_default[field]) if document else person_info_default[field] + result[field] = copy.deepcopy( + document.get(field, person_info_default[field]) + if document else person_info_default[field] + ) return result @@ -210,5 +218,36 @@ class PersonInfoManager: except Exception as e: logger.error(f"数据库查询失败: {str(e)}", exc_info=True) return {} + + async def personal_habit_deduction(self): + """启动个人信息推断,每天根据一定条件推断一次""" + try: + logger.info(f"个人信息推断启动: {self.start_time.strftime('%Y-%m-%d %H:%M:%S')}") + # # 初始化日程 + # await self.check_and_create_today_schedule() + # self.print_schedule() + + # while True: + # # print(self.get_current_num_task(1, True)) + + # current_time = datetime.datetime.now() + + # # 检查是否需要重新生成日程(日期变化) + # if current_time.date() != self.start_time.date(): + # logger.info("检测到日期变化,重新生成日程") + # self.start_time = current_time + # await self.check_and_create_today_schedule() + # self.print_schedule() + + # # 执行当前活动 + # # mind_thinking = heartflow.current_state.current_mind + + # await self.move_doing() + + # await asyncio.sleep(self.schedule_doing_update_interval) + + except Exception as e: + logger.error(f"个人信息推断运行时出错: {str(e)}") + logger.exception("详细错误信息:") person_info_manager = PersonInfoManager() \ No newline at end of file From 87f3fc7b33daebcd3c9335a7a37a4c3794e2f79a Mon Sep 17 00:00:00 2001 From: meng_xi_pan <1903647908@qq.com> Date: Fri, 4 Apr 2025 14:22:26 +0800 Subject: [PATCH 04/16] =?UTF-8?q?=E6=9B=B4=E6=94=B9=E5=A4=84=E7=90=86?= =?UTF-8?q?=E4=B8=AA=E4=BA=BA=E5=A4=8D=E5=90=88=E6=B6=88=E6=81=AF=E7=9A=84?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/chat/message_buffer.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/plugins/chat/message_buffer.py b/src/plugins/chat/message_buffer.py index 9919e6cf7..a7be8abcd 100644 --- a/src/plugins/chat/message_buffer.py +++ b/src/plugins/chat/message_buffer.py @@ -122,11 +122,11 @@ class MassageBuffer: keep_msgs = OrderedDict() combined_text = [] found = False - is_text = False + type = "text" for msg_id, msg in self.buffer_pool[person_id_].items(): if msg_id == message.message_info.message_id: found = True - is_text = msg.message.message_segment.type == "text" + type = msg.message.message_segment.type combined_text.append(msg.message.processed_plain_text) continue if found: @@ -141,9 +141,15 @@ class MassageBuffer: logger.debug(f"异常未处理信息id: {msg.message.message_info.message_id}") # 更新当前消息的processed_plain_text - if combined_text and combined_text[0] != message.processed_plain_text and is_text: - message.processed_plain_text = "".join(combined_text) - logger.debug(f"整合了{len(combined_text)-1}条F消息的内容到当前消息") + if combined_text and combined_text[0] != message.processed_plain_text: + if type == "text": + message.processed_plain_text = "".join(combined_text) + logger.debug(f"整合了{len(combined_text)-1}条F消息的内容到当前消息") + elif type == "image": + combined_text.pop() + message.processed_plain_text = "".join(combined_text) + message.is_emoji = False + logger.debug(f"整合了{len(combined_text)-1}条F消息的内容,覆盖当前image消息") self.buffer_pool[person_id_] = keep_msgs return result From 2746072edbe5f4dbcb9fee11a813b49549a9618f Mon Sep 17 00:00:00 2001 From: meng_xi_pan <1903647908@qq.com> Date: Fri, 4 Apr 2025 16:54:58 +0800 Subject: [PATCH 05/16] =?UTF-8?q?=E5=AE=8C=E6=88=90=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E9=97=B4=E9=9A=94=E6=8E=A8=E6=96=AD=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.py | 2 +- src/plugins/chat/message_buffer.py | 2 +- src/plugins/person_info/person_info.py | 70 +++++++++++++++++++------- 3 files changed, 54 insertions(+), 20 deletions(-) diff --git a/src/main.py b/src/main.py index 932fbfcfe..9ab75f46a 100644 --- a/src/main.py +++ b/src/main.py @@ -58,7 +58,7 @@ class MainSystem: # 检查并清除person_info冗余字段,启动个人习惯推断 await person_info_manager.del_all_undefined_field() - # asyncio.create_task(person_info_manager.personal_habit_deduction()) + asyncio.create_task(person_info_manager.personal_habit_deduction()) # 启动愿望管理器 await willing_manager.ensure_started() diff --git a/src/plugins/chat/message_buffer.py b/src/plugins/chat/message_buffer.py index a7be8abcd..c1bac3b14 100644 --- a/src/plugins/chat/message_buffer.py +++ b/src/plugins/chat/message_buffer.py @@ -163,7 +163,7 @@ class MassageBuffer: if len(message_interval_list) < 1000: message_interval_list.append(now_time_ms) else: - message_interval_list = message_interval_list.pop(0) + message_interval_list.pop(0) message_interval_list.append(now_time_ms) data = { "platform" : message.platform, diff --git a/src/plugins/person_info/person_info.py b/src/plugins/person_info/person_info.py index 20ab2db8b..7df27b632 100644 --- a/src/plugins/person_info/person_info.py +++ b/src/plugins/person_info/person_info.py @@ -5,6 +5,11 @@ import hashlib from typing import Any, Callable, Dict, TypeVar T = TypeVar('T') # 泛型类型 import datetime +import asyncio +import numpy + +import matplotlib.pyplot as plt +from pathlib import Path """ PersonInfoManager 类方法功能摘要: @@ -38,7 +43,6 @@ person_info_default = { class PersonInfoManager: def __init__(self): - self.start_time = datetime.datetime.now() if "person_info" not in db.list_collection_names(): db.create_collection("person_info") db.person_info.create_index("person_id", unique=True) @@ -222,29 +226,59 @@ class PersonInfoManager: async def personal_habit_deduction(self): """启动个人信息推断,每天根据一定条件推断一次""" try: - logger.info(f"个人信息推断启动: {self.start_time.strftime('%Y-%m-%d %H:%M:%S')}") - # # 初始化日程 - # await self.check_and_create_today_schedule() - # self.print_schedule() + while(1): + await asyncio.sleep(60) + current_time = datetime.datetime.now() + logger.info(f"个人信息推断启动: {current_time.strftime('%Y-%m-%d %H:%M:%S')}") - # while True: - # # print(self.get_current_num_task(1, True)) + # "msg_interval"推断 + msg_interval_lists = await self.get_specific_value_list( + "msg_interval_list", + lambda x: isinstance(x, list) and len(x) >= 100 + ) + for person_id, msg_interval_list_ in msg_interval_lists.items(): + try: + time_interval = [] + for t1, t2 in zip(msg_interval_list_, msg_interval_list_[1:]): + delta = t2 - t1 + if delta < 6000: # 小于6秒 + time_interval.append(delta) - # current_time = datetime.datetime.now() + if len(time_interval) > 30: + time_interval.sort() - # # 检查是否需要重新生成日程(日期变化) - # if current_time.date() != self.start_time.date(): - # logger.info("检测到日期变化,重新生成日程") - # self.start_time = current_time - # await self.check_and_create_today_schedule() - # self.print_schedule() + # 画图(log) + log_dir = Path("logs/person_info") + log_dir.mkdir(parents=True, exist_ok=True) + plt.figure(figsize=(10, 6)) - # # 执行当前活动 - # # mind_thinking = heartflow.current_state.current_mind + plt.hist(time_interval, bins=30, density=True, alpha=0.5, color='g') - # await self.move_doing() + plt.grid(True, alpha=0.3) - # await asyncio.sleep(self.schedule_doing_update_interval) + plt.title(f"Message Interval Density (User: {person_id[:8]}...)") + plt.xlabel("Interval (ms)") + plt.ylabel("Density") + + img_path = log_dir / f"interval_density_{person_id[:8]}.png" + plt.savefig(img_path) + plt.close() + logger.info(f"已保存分布图到: {img_path}") + # 画图 + + filtered_intervals = [t for t in time_interval if t >= 500] + if len(filtered_intervals) > 25: + msg_interval = numpy.percentile(filtered_intervals, 90) + await self.update_one_field(person_id, "msg_interval", int(msg_interval)) + logger.debug(f"用户{person_id}的msg_interval已经被更新为{msg_interval}") + except Exception as e: + logger.debug(f"处理用户{person_id}msg_interval推断时出错: {str(e)}") + continue + + # 其他... + + logger.info(f"个人信息推断结束: {current_time.strftime('%Y-%m-%d %H:%M:%S')}") + await asyncio.sleep(86400) except Exception as e: logger.error(f"个人信息推断运行时出错: {str(e)}") From 280e488f713efca4c63eb036283801e92ef312f4 Mon Sep 17 00:00:00 2001 From: meng_xi_pan <1903647908@qq.com> Date: Fri, 4 Apr 2025 17:56:49 +0800 Subject: [PATCH 06/16] =?UTF-8?q?=E4=BC=98=E9=9B=85=E7=9A=84=E7=94=BB?= =?UTF-8?q?=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/person_info/person_info.py | 27 ++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/plugins/person_info/person_info.py b/src/plugins/person_info/person_info.py index 7df27b632..8f5949c5e 100644 --- a/src/plugins/person_info/person_info.py +++ b/src/plugins/person_info/person_info.py @@ -10,6 +10,7 @@ import numpy import matplotlib.pyplot as plt from pathlib import Path +import pandas as pd """ PersonInfoManager 类方法功能摘要: @@ -232,6 +233,7 @@ class PersonInfoManager: logger.info(f"个人信息推断启动: {current_time.strftime('%Y-%m-%d %H:%M:%S')}") # "msg_interval"推断 + msg_interval_map = False msg_interval_lists = await self.get_specific_value_list( "msg_interval_list", lambda x: isinstance(x, list) and len(x) >= 100 @@ -241,35 +243,42 @@ class PersonInfoManager: time_interval = [] for t1, t2 in zip(msg_interval_list_, msg_interval_list_[1:]): delta = t2 - t1 - if delta < 6000: # 小于6秒 + if delta < 6000 and delta > 0: # 小于6秒 time_interval.append(delta) if len(time_interval) > 30: time_interval.sort() # 画图(log) + msg_interval_map = True log_dir = Path("logs/person_info") log_dir.mkdir(parents=True, exist_ok=True) plt.figure(figsize=(10, 6)) - plt.hist(time_interval, bins=30, density=True, alpha=0.5, color='g') + time_series = pd.Series(time_interval) - plt.grid(True, alpha=0.3) + # 绘制直方图 + plt.hist(time_series, bins=50, density=True, alpha=0.4, color='pink', label='Histogram') - plt.title(f"Message Interval Density (User: {person_id[:8]}...)") + # 绘制KDE曲线(使用相同的实际数据) + time_series.plot(kind='kde', color='mediumpurple', linewidth=1, label='Density') + + plt.grid(True, alpha=0.2) + plt.xlim(0, 6000) + plt.title(f"Message Interval Distribution (User: {person_id[:8]}...)") plt.xlabel("Interval (ms)") plt.ylabel("Density") + plt.legend(framealpha=0.9, facecolor='white') - img_path = log_dir / f"interval_density_{person_id[:8]}.png" + img_path = log_dir / f"interval_distribution_{person_id[:8]}.png" plt.savefig(img_path) plt.close() - logger.info(f"已保存分布图到: {img_path}") # 画图 filtered_intervals = [t for t in time_interval if t >= 500] if len(filtered_intervals) > 25: - msg_interval = numpy.percentile(filtered_intervals, 90) - await self.update_one_field(person_id, "msg_interval", int(msg_interval)) + msg_interval = int(round(numpy.percentile(filtered_intervals, 90))) + await self.update_one_field(person_id, "msg_interval", msg_interval) logger.debug(f"用户{person_id}的msg_interval已经被更新为{msg_interval}") except Exception as e: logger.debug(f"处理用户{person_id}msg_interval推断时出错: {str(e)}") @@ -277,6 +286,8 @@ class PersonInfoManager: # 其他... + if msg_interval_map: + logger.info(f"已保存分布图到: logs/person_info") logger.info(f"个人信息推断结束: {current_time.strftime('%Y-%m-%d %H:%M:%S')}") await asyncio.sleep(86400) From 80759f3fa166891986612cd89e653940082209e2 Mon Sep 17 00:00:00 2001 From: meng_xi_pan <1903647908@qq.com> Date: Fri, 4 Apr 2025 18:00:12 +0800 Subject: [PATCH 07/16] =?UTF-8?q?=E9=80=82=E9=85=8D=E6=8E=A8=E7=90=86?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chat_module/reasoning_chat/reasoning_chat.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/plugins/chat_module/reasoning_chat/reasoning_chat.py b/src/plugins/chat_module/reasoning_chat/reasoning_chat.py index 0163a306e..677baac52 100644 --- a/src/plugins/chat_module/reasoning_chat/reasoning_chat.py +++ b/src/plugins/chat_module/reasoning_chat/reasoning_chat.py @@ -17,6 +17,7 @@ from ...message import UserInfo, Seg from src.common.logger import get_module_logger, CHAT_STYLE_CONFIG, LogConfig from ...chat.chat_stream import chat_manager from ...person_info.relationship_manager import relationship_manager +from ...chat.message_buffer import message_buffer # 定义日志配置 chat_config = LogConfig( @@ -143,6 +144,8 @@ class ReasoningChat: userinfo = message.message_info.user_info messageinfo = message.message_info + # 消息加入缓冲池 + await message_buffer.start_caching_messages(message) # logger.info("使用推理聊天模式") @@ -172,6 +175,17 @@ class ReasoningChat: timer2 = time.time() timing_results["记忆激活"] = timer2 - timer1 + # 查询缓冲器结果,会整合前面跳过的消息,改变processed_plain_text + buffer_result = await message_buffer.query_buffer_result(message) + if not buffer_result: + if message.message_segment.type == "text": + logger.info(f"触发缓冲,已炸飞消息:{message.processed_plain_text}") + elif message.message_segment.type == "image": + logger.info(f"触发缓冲,已炸飞表情包/图片") + elif message.message_segment.type == "seglist": + logger.info(f"触发缓冲,已炸飞消息列") + return + is_mentioned = is_mentioned_bot_in_message(message) # 计算回复意愿 From 132861d16b1de3c62e8e62474d7a8f4f564dff80 Mon Sep 17 00:00:00 2001 From: meng_xi_pan <1903647908@qq.com> Date: Fri, 4 Apr 2025 18:24:43 +0800 Subject: [PATCH 08/16] ruff --- src/plugins/chat/message_buffer.py | 8 ++++---- src/plugins/chat_module/reasoning_chat/reasoning_chat.py | 4 ++-- .../chat_module/think_flow_chat/think_flow_chat.py | 4 ++-- src/plugins/person_info/person_info.py | 3 +-- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/plugins/chat/message_buffer.py b/src/plugins/chat/message_buffer.py index c1bac3b14..d42fc9973 100644 --- a/src/plugins/chat/message_buffer.py +++ b/src/plugins/chat/message_buffer.py @@ -6,7 +6,7 @@ from .message import MessageRecv from ..message.message_base import BaseMessageInfo import hashlib from typing import Dict -from dataclasses import dataclass, field +from dataclasses import field from collections import OrderedDict import random import time @@ -20,7 +20,7 @@ class CacheMessages: result: str = "U" -class MassageBuffer: +class MessageBuffer: def __init__(self): self.buffer_pool: Dict[str, OrderedDict[str, CacheMessages]] = {} self.lock = asyncio.Lock() @@ -59,7 +59,7 @@ class MassageBuffer: return # 标记该用户之前的未处理消息 - for msg_id, cache_msg in self.buffer_pool[person_id_].items(): + for cache_msg in self.buffer_pool[person_id_].values: if cache_msg.result == "U": cache_msg.result = "F" cache_msg.cache_determination.set() @@ -174,4 +174,4 @@ class MassageBuffer: await person_info_manager.update_one_field(person_id, "msg_interval_list", message_interval_list, data) -message_buffer = MassageBuffer() \ No newline at end of file +message_buffer = MessageBuffer() \ No newline at end of file diff --git a/src/plugins/chat_module/reasoning_chat/reasoning_chat.py b/src/plugins/chat_module/reasoning_chat/reasoning_chat.py index 677baac52..13f055185 100644 --- a/src/plugins/chat_module/reasoning_chat/reasoning_chat.py +++ b/src/plugins/chat_module/reasoning_chat/reasoning_chat.py @@ -181,9 +181,9 @@ class ReasoningChat: if message.message_segment.type == "text": logger.info(f"触发缓冲,已炸飞消息:{message.processed_plain_text}") elif message.message_segment.type == "image": - logger.info(f"触发缓冲,已炸飞表情包/图片") + logger.info("触发缓冲,已炸飞表情包/图片") elif message.message_segment.type == "seglist": - logger.info(f"触发缓冲,已炸飞消息列") + logger.info("触发缓冲,已炸飞消息列") return is_mentioned = is_mentioned_bot_in_message(message) diff --git a/src/plugins/chat_module/think_flow_chat/think_flow_chat.py b/src/plugins/chat_module/think_flow_chat/think_flow_chat.py index 0f8d3298b..42e2b8e43 100644 --- a/src/plugins/chat_module/think_flow_chat/think_flow_chat.py +++ b/src/plugins/chat_module/think_flow_chat/think_flow_chat.py @@ -204,9 +204,9 @@ class ThinkFlowChat: if message.message_segment.type == "text": logger.info(f"触发缓冲,已炸飞消息:{message.processed_plain_text}") elif message.message_segment.type == "image": - logger.info(f"触发缓冲,已炸飞表情包/图片") + logger.info("触发缓冲,已炸飞表情包/图片") elif message.message_segment.type == "seglist": - logger.info(f"触发缓冲,已炸飞消息列") + logger.info("触发缓冲,已炸飞消息列") return is_mentioned = is_mentioned_bot_in_message(message) diff --git a/src/plugins/person_info/person_info.py b/src/plugins/person_info/person_info.py index 8f5949c5e..3cbccbe8a 100644 --- a/src/plugins/person_info/person_info.py +++ b/src/plugins/person_info/person_info.py @@ -3,15 +3,14 @@ from ...common.database import db import copy import hashlib from typing import Any, Callable, Dict, TypeVar -T = TypeVar('T') # 泛型类型 import datetime import asyncio import numpy - import matplotlib.pyplot as plt from pathlib import Path import pandas as pd + """ PersonInfoManager 类方法功能摘要: 1. get_person_id - 根据平台和用户ID生成MD5哈希的唯一person_id From 68014de2723f5df8e254d081437fe7576a7420ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=A6=E6=BA=AA=E7=95=94?= <130263765+na10xi27da@users.noreply.github.com> Date: Fri, 4 Apr 2025 18:27:10 +0800 Subject: [PATCH 09/16] ruff --- src/plugins/person_info/person_info.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/person_info/person_info.py b/src/plugins/person_info/person_info.py index 3cbccbe8a..9bb5408e4 100644 --- a/src/plugins/person_info/person_info.py +++ b/src/plugins/person_info/person_info.py @@ -2,7 +2,7 @@ from src.common.logger import get_module_logger from ...common.database import db import copy import hashlib -from typing import Any, Callable, Dict, TypeVar +from typing import Any, Callable, Dict import datetime import asyncio import numpy @@ -286,7 +286,7 @@ class PersonInfoManager: # 其他... if msg_interval_map: - logger.info(f"已保存分布图到: logs/person_info") + logger.info("已保存分布图到: logs/person_info") logger.info(f"个人信息推断结束: {current_time.strftime('%Y-%m-%d %H:%M:%S')}") await asyncio.sleep(86400) @@ -294,4 +294,4 @@ class PersonInfoManager: logger.error(f"个人信息推断运行时出错: {str(e)}") logger.exception("详细错误信息:") -person_info_manager = PersonInfoManager() \ No newline at end of file +person_info_manager = PersonInfoManager() From 9ba6c8dacd6c0f30112be241625976e692728c6e Mon Sep 17 00:00:00 2001 From: meng_xi_pan <1903647908@qq.com> Date: Fri, 4 Apr 2025 20:31:26 +0800 Subject: [PATCH 10/16] debug... --- src/plugins/chat/message_buffer.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plugins/chat/message_buffer.py b/src/plugins/chat/message_buffer.py index d42fc9973..e139a122b 100644 --- a/src/plugins/chat/message_buffer.py +++ b/src/plugins/chat/message_buffer.py @@ -1,12 +1,11 @@ from ..person_info.person_info import person_info_manager from src.common.logger import get_module_logger import asyncio -from dataclasses import dataclass +from dataclasses import dataclass, field from .message import MessageRecv from ..message.message_base import BaseMessageInfo import hashlib from typing import Dict -from dataclasses import field from collections import OrderedDict import random import time @@ -59,7 +58,7 @@ class MessageBuffer: return # 标记该用户之前的未处理消息 - for cache_msg in self.buffer_pool[person_id_].values: + for cache_msg in self.buffer_pool[person_id_].values(): if cache_msg.result == "U": cache_msg.result = "F" cache_msg.cache_determination.set() From 02643d729e1ad5d35e32247e4ab2a690f698f376 Mon Sep 17 00:00:00 2001 From: meng_xi_pan <1903647908@qq.com> Date: Sat, 5 Apr 2025 01:00:05 +0800 Subject: [PATCH 11/16] =?UTF-8?q?=E5=90=88=E5=B9=B6=E6=9D=A1=E4=BB=B6?= =?UTF-8?q?=E6=9B=B4=E4=B8=A5=E6=A0=BC=EF=BC=8C=E5=A2=9E=E5=8A=A0=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E9=80=89=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/chat/message_buffer.py | 17 ++++++++++++++--- src/plugins/config/config.py | 3 +++ src/plugins/person_info/person_info.py | 4 ++-- template/bot_config_template.toml | 3 ++- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/plugins/chat/message_buffer.py b/src/plugins/chat/message_buffer.py index e139a122b..ccfcf81cc 100644 --- a/src/plugins/chat/message_buffer.py +++ b/src/plugins/chat/message_buffer.py @@ -9,6 +9,7 @@ from typing import Dict from collections import OrderedDict import random import time +from ..config.config import global_config logger = get_module_logger("message_buffer") @@ -32,6 +33,11 @@ class MessageBuffer: async def start_caching_messages(self, message:MessageRecv): """添加消息,启动缓冲""" + if not global_config.message_buffer: + person_id = person_info_manager.get_person_id(message.message_info.user_info.platform, + message.message_info.user_info.user_id) + asyncio.create_task(self.save_message_interval(person_id, message.message_info)) + return person_id_ = self.get_person_id_(message.message_info.platform, message.message_info.user_info.user_id, message.message_info.group_info.group_id) @@ -98,6 +104,8 @@ class MessageBuffer: async def query_buffer_result(self, message:MessageRecv) -> bool: """查询缓冲结果,并清理""" + if not global_config.message_buffer: + return True person_id_ = self.get_person_id_(message.message_info.platform, message.message_info.user_info.user_id, message.message_info.group_info.group_id) @@ -122,6 +130,7 @@ class MessageBuffer: combined_text = [] found = False type = "text" + is_update = True for msg_id, msg in self.buffer_pool[person_id_].items(): if msg_id == message.message_info.message_id: found = True @@ -133,14 +142,16 @@ class MessageBuffer: elif msg.result == "F": # 收集F消息的文本内容 if (hasattr(msg.message, 'processed_plain_text') - and msg.message.message_segment.type == "text" and msg.message.processed_plain_text): - combined_text.append(msg.message.processed_plain_text) + if msg.message.message_segment.type == "text": + combined_text.append(msg.message.processed_plain_text) + elif msg.message.message_segment.type != "text": + is_update = False elif msg.result == "U": logger.debug(f"异常未处理信息id: {msg.message.message_info.message_id}") # 更新当前消息的processed_plain_text - if combined_text and combined_text[0] != message.processed_plain_text: + if combined_text and combined_text[0] != message.processed_plain_text and is_update: if type == "text": message.processed_plain_text = "".join(combined_text) logger.debug(f"整合了{len(combined_text)-1}条F消息的内容到当前消息") diff --git a/src/plugins/config/config.py b/src/plugins/config/config.py index 2422b0d1f..bf06b8947 100644 --- a/src/plugins/config/config.py +++ b/src/plugins/config/config.py @@ -159,6 +159,7 @@ class BotConfig: emoji_chance: float = 0.2 # 发送表情包的基础概率 thinking_timeout: int = 120 # 思考时间 max_response_length: int = 1024 # 最大回复长度 + message_buffer: bool = True # 消息缓冲器 ban_words = set() ban_msgs_regex = set() @@ -502,6 +503,8 @@ class BotConfig: if config.INNER_VERSION in SpecifierSet(">=0.0.11"): config.max_response_length = msg_config.get("max_response_length", config.max_response_length) + if config.INNER_VERSION in SpecifierSet(">=1.1.4"): + config.message_buffer = msg_config.get("message_buffer", config.message_buffer) def memory(parent: dict): memory_config = parent["memory"] diff --git a/src/plugins/person_info/person_info.py b/src/plugins/person_info/person_info.py index 9bb5408e4..543fdb3ee 100644 --- a/src/plugins/person_info/person_info.py +++ b/src/plugins/person_info/person_info.py @@ -242,7 +242,7 @@ class PersonInfoManager: time_interval = [] for t1, t2 in zip(msg_interval_list_, msg_interval_list_[1:]): delta = t2 - t1 - if delta < 6000 and delta > 0: # 小于6秒 + if delta < 8000 and delta > 0: # 小于8秒 time_interval.append(delta) if len(time_interval) > 30: @@ -263,7 +263,7 @@ class PersonInfoManager: time_series.plot(kind='kde', color='mediumpurple', linewidth=1, label='Density') plt.grid(True, alpha=0.2) - plt.xlim(0, 6000) + plt.xlim(0, 8000) plt.title(f"Message Interval Distribution (User: {person_id[:8]}...)") plt.xlabel("Interval (ms)") plt.ylabel("Density") diff --git a/template/bot_config_template.toml b/template/bot_config_template.toml index 7df6a6e8e..97a06b700 100644 --- a/template/bot_config_template.toml +++ b/template/bot_config_template.toml @@ -1,5 +1,5 @@ [inner] -version = "1.1.3" +version = "1.1.4" #以下是给开发人员阅读的,一般用户不需要阅读 @@ -72,6 +72,7 @@ max_context_size = 12 # 麦麦获得的上文数量,建议12,太短太长都 emoji_chance = 0.2 # 麦麦使用表情包的概率 thinking_timeout = 60 # 麦麦最长思考时间,超过这个时间的思考会放弃 max_response_length = 256 # 麦麦回答的最大token数 +message_buffer = true # 启用消息缓冲器? ban_words = [ # "403","张三" ] From aadd494151b1789bcbd48db98c35aa3548ea15e8 Mon Sep 17 00:00:00 2001 From: meng_xi_pan <1903647908@qq.com> Date: Sat, 5 Apr 2025 01:54:31 +0800 Subject: [PATCH 12/16] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/chat/message_buffer.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/plugins/chat/message_buffer.py b/src/plugins/chat/message_buffer.py index ccfcf81cc..e5f26e53e 100644 --- a/src/plugins/chat/message_buffer.py +++ b/src/plugins/chat/message_buffer.py @@ -46,6 +46,13 @@ class MessageBuffer: if person_id_ not in self.buffer_pool: self.buffer_pool[person_id_] = OrderedDict() + # 标记该用户之前的未处理消息 + for cache_msg in self.buffer_pool[person_id_].values(): + if cache_msg.result == "U": + cache_msg.result = "F" + cache_msg.cache_determination.set() + logger.debug(f"被新消息覆盖信息id: {cache_msg.message.message_info.message_id}") + # 查找最近的处理成功消息(T) recent_F_count = 0 for msg_id in reversed(self.buffer_pool[person_id_]): @@ -62,13 +69,6 @@ class MessageBuffer: self.buffer_pool[person_id_][message.message_info.message_id] = new_msg logger.debug(f"快速处理消息(已堆积{recent_F_count}条F): {message.message_info.message_id}") return - - # 标记该用户之前的未处理消息 - for cache_msg in self.buffer_pool[person_id_].values(): - if cache_msg.result == "U": - cache_msg.result = "F" - cache_msg.cache_determination.set() - logger.debug(f"被新消息覆盖信息id: {cache_msg.message.message_info.message_id}") # 添加新消息 self.buffer_pool[person_id_][message.message_info.message_id] = CacheMessages(message=message) @@ -93,7 +93,7 @@ class MessageBuffer: async with self.lock: if (person_id_ not in self.buffer_pool or message_id not in self.buffer_pool[person_id_]): - logger.debug(f"消息异常被清理,msgid: {message_id}") + logger.debug(f"消息已被清理,msgid: {message_id}") return cache_msg = self.buffer_pool[person_id_][message_id] From 81acf7afd7d9ba3efb92f86121a51b6869b42c04 Mon Sep 17 00:00:00 2001 From: meng_xi_pan <1903647908@qq.com> Date: Sat, 5 Apr 2025 02:09:10 +0800 Subject: [PATCH 13/16] =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E5=B0=8Fbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/chat/message_buffer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/chat/message_buffer.py b/src/plugins/chat/message_buffer.py index e5f26e53e..1d0291a1c 100644 --- a/src/plugins/chat/message_buffer.py +++ b/src/plugins/chat/message_buffer.py @@ -155,11 +155,11 @@ class MessageBuffer: if type == "text": message.processed_plain_text = "".join(combined_text) logger.debug(f"整合了{len(combined_text)-1}条F消息的内容到当前消息") - elif type == "image": + elif type == "emoji": combined_text.pop() message.processed_plain_text = "".join(combined_text) message.is_emoji = False - logger.debug(f"整合了{len(combined_text)-1}条F消息的内容,覆盖当前image消息") + logger.debug(f"整合了{len(combined_text)-1}条F消息的内容,覆盖当前emoji消息") self.buffer_pool[person_id_] = keep_msgs return result From 3f570a01dd4759f8e3a8bf6ac7ddd938d1cacdd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=A6=E6=BA=AA=E7=95=94?= <130263765+na10xi27da@users.noreply.github.com> Date: Sat, 5 Apr 2025 13:56:53 +0800 Subject: [PATCH 14/16] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E9=A1=B9=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- template/bot_config_template.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/template/bot_config_template.toml b/template/bot_config_template.toml index 97a06b700..bcb62ddc6 100644 --- a/template/bot_config_template.toml +++ b/template/bot_config_template.toml @@ -72,7 +72,7 @@ max_context_size = 12 # 麦麦获得的上文数量,建议12,太短太长都 emoji_chance = 0.2 # 麦麦使用表情包的概率 thinking_timeout = 60 # 麦麦最长思考时间,超过这个时间的思考会放弃 max_response_length = 256 # 麦麦回答的最大token数 -message_buffer = true # 启用消息缓冲器? +message_buffer = true # 启用消息缓冲器?启用此项以解决消息的拆分问题,但会使麦麦的回复延迟 ban_words = [ # "403","张三" ] @@ -237,4 +237,4 @@ pri_out = 1.26 name = "Qwen/Qwen2.5-32B-Instruct" provider = "SILICONFLOW" pri_in = 1.26 -pri_out = 1.26 \ No newline at end of file +pri_out = 1.26 From 848f5c53fc5c849ba0e77d45c55cfd2764eace65 Mon Sep 17 00:00:00 2001 From: meng_xi_pan <1903647908@qq.com> Date: Sat, 5 Apr 2025 20:39:06 +0800 Subject: [PATCH 15/16] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/person_info/person_info.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/person_info/person_info.py b/src/plugins/person_info/person_info.py index 543fdb3ee..0bf15e177 100644 --- a/src/plugins/person_info/person_info.py +++ b/src/plugins/person_info/person_info.py @@ -276,7 +276,7 @@ class PersonInfoManager: filtered_intervals = [t for t in time_interval if t >= 500] if len(filtered_intervals) > 25: - msg_interval = int(round(numpy.percentile(filtered_intervals, 90))) + msg_interval = int(round(numpy.percentile(filtered_intervals, 80))) await self.update_one_field(person_id, "msg_interval", msg_interval) logger.debug(f"用户{person_id}的msg_interval已经被更新为{msg_interval}") except Exception as e: From 1f1ab2697dda70865d62db910b3e59be2f631f34 Mon Sep 17 00:00:00 2001 From: meng_xi_pan <1903647908@qq.com> Date: Sat, 5 Apr 2025 21:20:29 +0800 Subject: [PATCH 16/16] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=80=E4=B8=AArelat?= =?UTF-8?q?ion=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/moods/moods.py | 2 +- src/plugins/person_info/relationship_manager.py | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/plugins/moods/moods.py b/src/plugins/moods/moods.py index 98fd61952..3d3feadf1 100644 --- a/src/plugins/moods/moods.py +++ b/src/plugins/moods/moods.py @@ -237,7 +237,7 @@ class MoodManager: old_arousal = self.current_mood.arousal old_mood = self.current_mood.text - valence_change *= relationship_manager.gain_coefficient[relationship_manager.positive_feedback_value] + valence_change = relationship_manager.feedback_to_mood(valence_change) # 应用情绪强度 valence_change *= intensity diff --git a/src/plugins/person_info/relationship_manager.py b/src/plugins/person_info/relationship_manager.py index 707dbbe51..9bbcf4e19 100644 --- a/src/plugins/person_info/relationship_manager.py +++ b/src/plugins/person_info/relationship_manager.py @@ -63,7 +63,15 @@ class RelationshipManager: value += value * mood_gain logger.info(f"当前relationship增益系数:{mood_gain:.3f}") return value - + + def feedback_to_mood(self, mood_value): + """对情绪的反馈""" + coefficient = self.gain_coefficient[abs(self.positive_feedback_value)] + if (mood_value > 0 and self.positive_feedback_value > 0 + or mood_value < 0 and self.positive_feedback_value < 0): + return mood_value*coefficient + else: + return mood_value/coefficient async def calculate_update_relationship_value(self, chat_stream: ChatStream, label: str, stance: str) -> None: """计算并变更关系值