diff --git a/src/plugins/built_in/napcat_adapter_plugin/plugin.py b/src/plugins/built_in/napcat_adapter_plugin/plugin.py index 1c1138511..f2d43a6c3 100644 --- a/src/plugins/built_in/napcat_adapter_plugin/plugin.py +++ b/src/plugins/built_in/napcat_adapter_plugin/plugin.py @@ -388,26 +388,7 @@ class NapcatAdapterPlugin(BasePlugin): "supported_formats": ConfigField( type=list, default=["mp4", "avi", "mov", "mkv", "flv", "wmv", "webm"], description="支持的视频格式" ), - # 消息缓冲设置 - "enable_message_buffer": ConfigField(type=bool, default=True, description="是否启用消息缓冲合并功能"), - "message_buffer_enable_group": ConfigField(type=bool, default=True, description="是否启用群聊消息缓冲合并"), - "message_buffer_enable_private": ConfigField( - type=bool, default=True, description="是否启用私聊消息缓冲合并" - ), - "message_buffer_interval": ConfigField( - type=float, default=3.0, description="消息合并间隔时间(秒),在此时间内的连续消息将被合并" - ), - "message_buffer_initial_delay": ConfigField( - type=float, default=0.5, description="消息缓冲初始延迟(秒),收到第一条消息后等待此时间开始合并" - ), - "message_buffer_max_components": ConfigField( - type=int, default=50, description="单个会话最大缓冲消息组件数量,超过此数量将强制合并" - ), - "message_buffer_block_prefixes": ConfigField( - type=list, - default=["/", "!", "!", ".", "。", "#", "%"], - description="消息缓冲屏蔽前缀,以这些前缀开头的消息不会被缓冲", - ), + # 消息缓冲功能已移除 }, } diff --git a/src/plugins/built_in/napcat_adapter_plugin/src/message_buffer.py b/src/plugins/built_in/napcat_adapter_plugin/src/message_buffer.py deleted file mode 100644 index 2bfe9078d..000000000 --- a/src/plugins/built_in/napcat_adapter_plugin/src/message_buffer.py +++ /dev/null @@ -1,322 +0,0 @@ -import asyncio -import time -from typing import Dict, List, Any, Optional -from dataclasses import dataclass, field - -from src.common.logger import get_logger - -logger = get_logger("napcat_adapter") - -from src.plugin_system.apis import config_api -from .recv_handler import RealMessageType - - -@dataclass -class TextMessage: - """文本消息""" - - text: str - timestamp: float = field(default_factory=time.time) - - -@dataclass -class BufferedSession: - """缓冲会话数据""" - - session_id: str - messages: List[TextMessage] = field(default_factory=list) - timer_task: Optional[asyncio.Task] = None - delay_task: Optional[asyncio.Task] = None - original_event: Any = None - created_at: float = field(default_factory=time.time) - - -class SimpleMessageBuffer: - def __init__(self, merge_callback=None): - """ - 初始化消息缓冲器 - - Args: - merge_callback: 消息合并后的回调函数,接收(session_id, merged_text, original_event)参数 - """ - self.buffer_pool: Dict[str, BufferedSession] = {} - self.lock = asyncio.Lock() - self.merge_callback = merge_callback - self._shutdown = False - self.plugin_config = None - - def set_plugin_config(self, plugin_config: dict): - """设置插件配置""" - self.plugin_config = plugin_config - - def get_session_id(self, event_data: Dict[str, Any]) -> str: - """根据事件数据生成会话ID""" - message_type = event_data.get("message_type", "unknown") - user_id = event_data.get("user_id", "unknown") - - if message_type == "private": - return f"private_{user_id}" - elif message_type == "group": - group_id = event_data.get("group_id", "unknown") - return f"group_{group_id}_{user_id}" - else: - return f"{message_type}_{user_id}" - - def extract_text_from_message(self, message: List[Dict[str, Any]]) -> Optional[str]: - """从OneBot消息中提取纯文本,如果包含非文本内容则返回None""" - text_parts = [] - has_non_text = False - - logger.debug(f"正在提取消息文本,消息段数量: {len(message)}") - - for msg_seg in message: - msg_type = msg_seg.get("type", "") - logger.debug(f"处理消息段类型: {msg_type}") - - if msg_type == RealMessageType.text: - text = msg_seg.get("data", {}).get("text", "").strip() - if text: - text_parts.append(text) - logger.debug(f"提取到文本: {text[:50]}...") - else: - # 发现非文本消息段,标记为包含非文本内容 - has_non_text = True - logger.debug(f"发现非文本消息段: {msg_type},跳过缓冲") - - # 如果包含非文本内容,则不进行缓冲 - if has_non_text: - logger.debug("消息包含非文本内容,不进行缓冲") - return None - - if text_parts: - combined_text = " ".join(text_parts).strip() - logger.debug(f"成功提取纯文本: {combined_text[:50]}...") - return combined_text - - logger.debug("没有找到有效的文本内容") - return None - - def should_skip_message(self, text: str) -> bool: - """判断消息是否应该跳过缓冲""" - if not text or not text.strip(): - return True - - # 检查屏蔽前缀 - block_prefixes = tuple( - config_api.get_plugin_config(self.plugin_config, "features.message_buffer_block_prefixes", []) - ) - - text = text.strip() - if text.startswith(block_prefixes): - logger.debug(f"消息以屏蔽前缀开头,跳过缓冲: {text[:20]}...") - return True - - return False - - async def add_text_message( - self, event_data: Dict[str, Any], message: List[Dict[str, Any]], original_event: Any = None - ) -> bool: - """ - 添加文本消息到缓冲区 - - Args: - event_data: 事件数据 - message: OneBot消息数组 - original_event: 原始事件对象 - - Returns: - 是否成功添加到缓冲区 - """ - if self._shutdown: - return False - - # 检查是否启用消息缓冲 - if not config_api.get_plugin_config(self.plugin_config, "features.enable_message_buffer", False): - return False - - # 检查是否启用对应类型的缓冲 - message_type = event_data.get("message_type", "") - if message_type == "group" and not config_api.get_plugin_config( - self.plugin_config, "features.message_buffer_enable_group", False - ): - return False - elif message_type == "private" and not config_api.get_plugin_config( - self.plugin_config, "features.message_buffer_enable_private", False - ): - return False - - # 提取文本 - text = self.extract_text_from_message(message) - if not text: - return False - - # 检查是否应该跳过 - if self.should_skip_message(text): - return False - - session_id = self.get_session_id(event_data) - - async with self.lock: - # 获取或创建会话 - if session_id not in self.buffer_pool: - self.buffer_pool[session_id] = BufferedSession(session_id=session_id, original_event=original_event) - - session = self.buffer_pool[session_id] - - # 检查是否超过最大组件数量 - if len(session.messages) >= config_api.get_plugin_config( - self.plugin_config, "features.message_buffer_max_components", 5 - ): - logger.debug(f"会话 {session_id} 消息数量达到上限,强制合并") - asyncio.create_task(self._force_merge_session(session_id)) - self.buffer_pool[session_id] = BufferedSession(session_id=session_id, original_event=original_event) - session = self.buffer_pool[session_id] - - # 添加文本消息 - session.messages.append(TextMessage(text=text)) - session.original_event = original_event # 更新事件 - - # 取消之前的定时器 - await self._cancel_session_timers(session) - - # 设置新的延迟任务 - session.delay_task = asyncio.create_task(self._wait_and_start_merge(session_id)) - - logger.debug(f"文本消息已添加到缓冲器 {session_id}: {text[:50]}...") - return True - - async def _cancel_session_timers(self, session: BufferedSession): - """取消会话的所有定时器""" - for task_name in ["timer_task", "delay_task"]: - task = getattr(session, task_name) - if task and not task.done(): - task.cancel() - try: - await task - except asyncio.CancelledError: - pass - setattr(session, task_name, None) - - async def _wait_and_start_merge(self, session_id: str): - """等待初始延迟后开始合并定时器""" - initial_delay = config_api.get_plugin_config(self.plugin_config, "features.message_buffer_initial_delay", 0.5) - await asyncio.sleep(initial_delay) - - async with self.lock: - session = self.buffer_pool.get(session_id) - if session and session.messages: - # 取消旧的定时器 - if session.timer_task and not session.timer_task.done(): - session.timer_task.cancel() - try: - await session.timer_task - except asyncio.CancelledError: - pass - - # 设置合并定时器 - session.timer_task = asyncio.create_task(self._wait_and_merge(session_id)) - - async def _wait_and_merge(self, session_id: str): - """等待合并间隔后执行合并""" - interval = config_api.get_plugin_config(self.plugin_config, "features.message_buffer_interval", 2.0) - await asyncio.sleep(interval) - await self._merge_session(session_id) - - async def _force_merge_session(self, session_id: str): - """强制合并会话(不等待定时器)""" - await self._merge_session(session_id, force=True) - - async def _merge_session(self, session_id: str, force: bool = False): - """合并会话中的消息""" - async with self.lock: - session = self.buffer_pool.get(session_id) - if not session or not session.messages: - self.buffer_pool.pop(session_id, None) - return - - try: - # 合并文本消息 - text_parts = [] - for msg in session.messages: - if msg.text.strip(): - text_parts.append(msg.text.strip()) - - if not text_parts: - self.buffer_pool.pop(session_id, None) - return - - merged_text = ",".join(text_parts) # 使用中文逗号连接 - message_count = len(session.messages) - - logger.debug(f"合并会话 {session_id} 的 {message_count} 条文本消息: {merged_text[:100]}...") - - # 调用回调函数 - if self.merge_callback: - try: - if asyncio.iscoroutinefunction(self.merge_callback): - await self.merge_callback(session_id, merged_text, session.original_event) - else: - self.merge_callback(session_id, merged_text, session.original_event) - except Exception as e: - logger.error(f"消息合并回调执行失败: {e}") - - except Exception as e: - logger.error(f"合并会话 {session_id} 时出错: {e}") - finally: - # 清理会话 - await self._cancel_session_timers(session) - self.buffer_pool.pop(session_id, None) - - async def flush_session(self, session_id: str): - """强制刷新指定会话的缓冲区""" - await self._force_merge_session(session_id) - - async def flush_all(self): - """强制刷新所有会话的缓冲区""" - session_ids = list(self.buffer_pool.keys()) - for session_id in session_ids: - await self._force_merge_session(session_id) - - async def get_buffer_stats(self) -> Dict[str, Any]: - """获取缓冲区统计信息""" - async with self.lock: - stats = {"total_sessions": len(self.buffer_pool), "sessions": {}} - - for session_id, session in self.buffer_pool.items(): - stats["sessions"][session_id] = { - "message_count": len(session.messages), - "created_at": session.created_at, - "age": time.time() - session.created_at, - } - - return stats - - async def clear_expired_sessions(self, max_age: float = 300.0): - """清理过期的会话""" - current_time = time.time() - expired_sessions = [] - - async with self.lock: - for session_id, session in self.buffer_pool.items(): - if current_time - session.created_at > max_age: - expired_sessions.append(session_id) - - for session_id in expired_sessions: - logger.debug(f"清理过期会话: {session_id}") - await self._force_merge_session(session_id) - - async def shutdown(self): - """关闭消息缓冲器""" - self._shutdown = True - logger.debug("正在关闭简化消息缓冲器...") - - # 刷新所有缓冲区 - await self.flush_all() - - # 确保所有任务都被取消 - async with self.lock: - for session in list(self.buffer_pool.values()): - await self._cancel_session_timers(session) - self.buffer_pool.clear() - - logger.debug("简化消息缓冲器已关闭") diff --git a/src/plugins/built_in/napcat_adapter_plugin/src/recv_handler/message_handler.py b/src/plugins/built_in/napcat_adapter_plugin/src/recv_handler/message_handler.py index 88eb48abc..ab0dac46b 100644 --- a/src/plugins/built_in/napcat_adapter_plugin/src/recv_handler/message_handler.py +++ b/src/plugins/built_in/napcat_adapter_plugin/src/recv_handler/message_handler.py @@ -6,7 +6,6 @@ from ...CONSTS import PLUGIN_NAME logger = get_logger("napcat_adapter") from src.plugin_system.apis import config_api -from ..message_buffer import SimpleMessageBuffer from ..utils import ( get_group_info, get_member_info, @@ -48,20 +47,18 @@ class MessageHandler: self.server_connection: Server.ServerConnection = None self.bot_id_list: Dict[int, bool] = {} self.plugin_config = None - # 初始化简化消息缓冲器,传入回调函数 - self.message_buffer = SimpleMessageBuffer(merge_callback=self._send_buffered_message) + # 消息缓冲功能已移除 def set_plugin_config(self, plugin_config: dict): """设置插件配置""" self.plugin_config = plugin_config - # 将配置传递给消息缓冲器 - if self.message_buffer: - self.message_buffer.set_plugin_config(plugin_config) + # 消息缓冲功能已移除 async def shutdown(self): """关闭消息处理器,清理资源""" - if self.message_buffer: - await self.message_buffer.shutdown() + # 消息缓冲功能已移除 + + # 消息缓冲功能已移除 async def set_server_connection(self, server_connection: Server.ServerConnection) -> None: """设置Napcat连接""" @@ -305,42 +302,7 @@ class MessageHandler: logger.warning("处理后消息内容为空") return None - # 检查是否需要使用消息缓冲 - enable_message_buffer = config_api.get_plugin_config(self.plugin_config, "features.enable_message_buffer", True) - if enable_message_buffer: - # 检查消息类型是否启用缓冲 - message_type = raw_message.get("message_type") - should_use_buffer = False - - if message_type == "group" and config_api.get_plugin_config( - self.plugin_config, "features.message_buffer_enable_group", True - ): - should_use_buffer = True - elif message_type == "private" and config_api.get_plugin_config( - self.plugin_config, "features.message_buffer_enable_private", True - ): - should_use_buffer = True - - if should_use_buffer: - logger.debug(f"尝试缓冲消息,消息类型: {message_type}, 用户: {user_info.user_id}") - - # 尝试添加到缓冲器 - buffered = await self.message_buffer.add_text_message( - event_data={ - "message_type": message_type, - "user_id": user_info.user_id, - "group_id": group_info.group_id if group_info else None, - }, - message=raw_message.get("message", []), - original_event={"message_info": message_info, "raw_message": raw_message}, - ) - - if buffered: - logger.debug(f"✅ 文本消息已成功缓冲: {user_info.user_id}") - return None # 缓冲成功,不立即发送 - # 如果缓冲失败(消息包含非文本元素),走正常处理流程 - logger.debug(f"❌ 消息缓冲失败,包含非文本元素,走正常处理流程: {user_info.user_id}") - # 缓冲失败时继续执行后面的正常处理流程,不要直接返回 + # 消息缓冲功能已移除,直接处理消息 logger.debug(f"准备发送消息到MaiBot,消息段数量: {len(seg_message)}") for i, seg in enumerate(seg_message): @@ -746,7 +708,6 @@ class MessageHandler: reply_message = [Seg(type="text", data="(获取发言内容失败)")] sender_info: dict = message_detail.get("sender") sender_nickname: str = sender_info.get("nickname") - sender_id: str = sender_info.get("user_id") seg_message: List[Seg] = [] if not sender_nickname: logger.warning("无法获取被引用的人的昵称,返回默认值") @@ -1060,54 +1021,7 @@ class MessageHandler: return None return response_data.get("messages") - async def _send_buffered_message(self, session_id: str, merged_text: str, original_event: Dict[str, Any]): - """发送缓冲的合并消息""" - try: - # 从原始事件数据中提取信息 - message_info = original_event.get("message_info") - raw_message = original_event.get("raw_message") - - if not message_info or not raw_message: - logger.error("缓冲消息缺少必要信息") - return - - # 创建合并后的消息段 - 将合并的文本转换为Seg格式 - from maim_message import Seg - - merged_seg = Seg(type="text", data=merged_text) - submit_seg = Seg(type="seglist", data=[merged_seg]) - - # 创建新的消息ID - import time - - new_message_id = f"buffered-{message_info.message_id}-{int(time.time() * 1000)}" - - # 更新消息信息 - from maim_message import BaseMessageInfo, MessageBase - - buffered_message_info = BaseMessageInfo( - platform=message_info.platform, - message_id=new_message_id, - time=time.time(), - user_info=message_info.user_info, - group_info=message_info.group_info, - template_info=message_info.template_info, - format_info=message_info.format_info, - additional_config=message_info.additional_config, - ) - - # 创建MessageBase - message_base = MessageBase( - message_info=buffered_message_info, - message_segment=submit_seg, - raw_message=raw_message.get("raw_message", ""), - ) - - logger.debug(f"发送缓冲合并消息到Maibot处理: {session_id}") - await message_send_instance.message_send(message_base) - - except Exception as e: - logger.error(f"发送缓冲消息失败: {e}", exc_info=True) + # 消息缓冲功能已移除 message_handler = MessageHandler() diff --git a/src/plugins/built_in/napcat_adapter_plugin/src/send_handler.py b/src/plugins/built_in/napcat_adapter_plugin/src/send_handler.py index d9eff74d8..a6960a212 100644 --- a/src/plugins/built_in/napcat_adapter_plugin/src/send_handler.py +++ b/src/plugins/built_in/napcat_adapter_plugin/src/send_handler.py @@ -296,13 +296,7 @@ class SendHandler: return reply_seg try: - # 检查是否为缓冲消息ID(格式:buffered-{original_id}-{timestamp}) - if id.startswith("buffered-"): - # 从缓冲消息ID中提取原始消息ID - original_id = id.split("-")[1] - msg_info_response = await self.send_message_to_napcat("get_msg", {"message_id": int(original_id)}) - else: - msg_info_response = await self.send_message_to_napcat("get_msg", {"message_id": id}) + msg_info_response = await self.send_message_to_napcat("get_msg", {"message_id": id}) replied_user_id = None if msg_info_response and msg_info_response.get("status") == "ok": diff --git a/src/plugins/built_in/napcat_adapter_plugin/template/features_template.toml b/src/plugins/built_in/napcat_adapter_plugin/template/features_template.toml deleted file mode 100644 index 679267ab2..000000000 --- a/src/plugins/built_in/napcat_adapter_plugin/template/features_template.toml +++ /dev/null @@ -1,43 +0,0 @@ -# 权限配置文件 -# 此文件用于管理群聊和私聊的黑白名单设置,以及聊天相关功能 -# 支持热重载,修改后会自动生效 - -# 群聊权限设置 -group_list_type = "whitelist" # 群聊列表类型:whitelist(白名单)或 blacklist(黑名单) -group_list = [] # 群聊ID列表 -# 当 group_list_type 为 whitelist 时,只有列表中的群聊可以使用机器人 -# 当 group_list_type 为 blacklist 时,列表中的群聊无法使用机器人 -# 示例:group_list = [123456789, 987654321] - -# 私聊权限设置 -private_list_type = "whitelist" # 私聊列表类型:whitelist(白名单)或 blacklist(黑名单) -private_list = [] # 用户ID列表 -# 当 private_list_type 为 whitelist 时,只有列表中的用户可以私聊机器人 -# 当 private_list_type 为 blacklist 时,列表中的用户无法私聊机器人 -# 示例:private_list = [123456789, 987654321] - -# 全局禁止设置 -ban_user_id = [] # 全局禁止用户ID列表,这些用户无法在任何地方使用机器人 -ban_qq_bot = false # 是否屏蔽QQ官方机器人消息 - -# 聊天功能设置 -enable_poke = true # 是否启用戳一戳功能 -ignore_non_self_poke = false # 是否无视不是针对自己的戳一戳 -poke_debounce_seconds = 3 # 戳一戳防抖时间(秒),在指定时间内第二次针对机器人的戳一戳将被忽略 -enable_reply_at = true # 是否启用引用回复时艾特用户的功能 -reply_at_rate = 0.5 # 引用回复时艾特用户的几率 (0.0 ~ 1.0) - -# 视频处理设置 -enable_video_analysis = true # 是否启用视频识别功能 -max_video_size_mb = 100 # 视频文件最大大小限制(MB) -download_timeout = 60 # 视频下载超时时间(秒) -supported_formats = ["mp4", "avi", "mov", "mkv", "flv", "wmv", "webm"] # 支持的视频格式 - -# 消息缓冲设置 -enable_message_buffer = true # 是否启用消息缓冲合并功能 -message_buffer_enable_group = true # 是否启用群聊消息缓冲合并 -message_buffer_enable_private = true # 是否启用私聊消息缓冲合并 -message_buffer_interval = 3.0 # 消息合并间隔时间(秒),在此时间内的连续消息将被合并 -message_buffer_initial_delay = 0.5 # 消息缓冲初始延迟(秒),收到第一条消息后等待此时间开始合并 -message_buffer_max_components = 50 # 单个会话最大缓冲消息组件数量,超过此数量将强制合并 -message_buffer_block_prefixes = ["/"] # 消息缓冲屏蔽前缀,以这些前缀开头的消息不会被缓冲 \ No newline at end of file diff --git a/src/plugins/built_in/napcat_adapter_plugin/template/template_config.toml b/src/plugins/built_in/napcat_adapter_plugin/template/template_config.toml deleted file mode 100644 index a06906ad3..000000000 --- a/src/plugins/built_in/napcat_adapter_plugin/template/template_config.toml +++ /dev/null @@ -1,29 +0,0 @@ -[inner] -version = "0.2.1" # 版本号 -# 请勿修改版本号,除非你知道自己在做什么 - -[nickname] # 现在没用 -nickname = "" - -[napcat_server] # Napcat连接的ws服务设置 -mode = "reverse" # 连接模式:reverse=反向连接(作为服务器), forward=正向连接(作为客户端) -host = "localhost" # 主机地址 -port = 8095 # 端口号 -url = "" # 正向连接时的完整WebSocket URL,如 ws://localhost:8080/ws (仅在forward模式下使用) -access_token = "" # WebSocket 连接的访问令牌,用于身份验证(可选) -heartbeat_interval = 30 # 心跳间隔时间(按秒计) - -[maibot_server] # 连接麦麦的ws服务设置 -host = "localhost" # 麦麦在.env文件中设置的主机地址,即HOST字段 -port = 8000 # 麦麦在.env文件中设置的端口,即PORT字段 - -[voice] # 发送语音设置 -use_tts = false # 是否使用tts语音(请确保你配置了tts并有对应的adapter) - -[slicing] # WebSocket消息切片设置 -max_frame_size = 64 # WebSocket帧的最大大小,单位为字节,默认64KB -delay_ms = 10 # 切片发送间隔时间,单位为毫秒 - -[debug] -level = "INFO" # 日志等级(DEBUG, INFO, WARNING, ERROR, CRITICAL) -