重构消息处理并用DatabaseMessages替换MessageRecv
-更新PlusCommand以使用DatabaseMessages而不是MessageRecv。 -将消息处理逻辑重构到一个新模块message_processor.py中,以处理消息段并从消息字典中创建DatabaseMessages。 -删除了已弃用的MessageRecv类及其相关逻辑。 -调整了各种插件以适应新的DatabaseMessages结构。 -增强了消息处理功能中的错误处理和日志记录。
This commit is contained in:
@@ -9,10 +9,10 @@ from maim_message import UserInfo
|
||||
from src.chat.antipromptinjector import initialize_anti_injector
|
||||
from src.chat.message_manager import message_manager
|
||||
from src.chat.message_receive.chat_stream import ChatStream, get_chat_manager
|
||||
from src.chat.message_receive.message import MessageRecv
|
||||
from src.chat.message_receive.storage import MessageStorage
|
||||
from src.chat.utils.prompt import create_prompt_async, global_prompt_manager
|
||||
from src.chat.utils.utils import is_mentioned_bot_in_message
|
||||
from src.common.data_models.database_data_model import DatabaseMessages
|
||||
from src.common.logger import get_logger
|
||||
from src.config.config import global_config
|
||||
from src.mood.mood_manager import mood_manager # 导入情绪管理器
|
||||
@@ -105,10 +105,10 @@ class ChatBot:
|
||||
|
||||
self._started = True
|
||||
|
||||
async def _process_plus_commands(self, message: MessageRecv):
|
||||
async def _process_plus_commands(self, message: DatabaseMessages, chat: ChatStream):
|
||||
"""独立处理PlusCommand系统"""
|
||||
try:
|
||||
text = message.processed_plain_text
|
||||
text = message.processed_plain_text or ""
|
||||
|
||||
# 获取配置的命令前缀
|
||||
from src.config.config import global_config
|
||||
@@ -166,10 +166,10 @@ class ChatBot:
|
||||
|
||||
# 检查命令是否被禁用
|
||||
if (
|
||||
message.chat_stream
|
||||
and message.chat_stream.stream_id
|
||||
chat
|
||||
and chat.stream_id
|
||||
and plus_command_name
|
||||
in global_announcement_manager.get_disabled_chat_commands(message.chat_stream.stream_id)
|
||||
in global_announcement_manager.get_disabled_chat_commands(chat.stream_id)
|
||||
):
|
||||
logger.info("用户禁用的PlusCommand,跳过处理")
|
||||
return False, None, True
|
||||
@@ -181,11 +181,14 @@ class ChatBot:
|
||||
|
||||
# 创建PlusCommand实例
|
||||
plus_command_instance = plus_command_class(message, plugin_config)
|
||||
|
||||
# 为插件实例设置 chat_stream 运行时属性
|
||||
setattr(plus_command_instance, "chat_stream", chat)
|
||||
|
||||
try:
|
||||
# 检查聊天类型限制
|
||||
if not plus_command_instance.is_chat_type_allowed():
|
||||
is_group = message.message_info.group_info
|
||||
is_group = chat.group_info is not None
|
||||
logger.info(
|
||||
f"PlusCommand {plus_command_class.__name__} 不支持当前聊天类型: {'群聊' if is_group else '私聊'}"
|
||||
)
|
||||
@@ -225,11 +228,11 @@ class ChatBot:
|
||||
logger.error(f"处理PlusCommand时出错: {e}")
|
||||
return False, None, True # 出错时继续处理消息
|
||||
|
||||
async def _process_commands_with_new_system(self, message: MessageRecv):
|
||||
async def _process_commands_with_new_system(self, message: DatabaseMessages, chat: ChatStream):
|
||||
# sourcery skip: use-named-expression
|
||||
"""使用新插件系统处理命令"""
|
||||
try:
|
||||
text = message.processed_plain_text
|
||||
text = message.processed_plain_text or ""
|
||||
|
||||
# 使用新的组件注册中心查找命令
|
||||
command_result = component_registry.find_command_by_text(text)
|
||||
@@ -238,10 +241,10 @@ class ChatBot:
|
||||
plugin_name = command_info.plugin_name
|
||||
command_name = command_info.name
|
||||
if (
|
||||
message.chat_stream
|
||||
and message.chat_stream.stream_id
|
||||
chat
|
||||
and chat.stream_id
|
||||
and command_name
|
||||
in global_announcement_manager.get_disabled_chat_commands(message.chat_stream.stream_id)
|
||||
in global_announcement_manager.get_disabled_chat_commands(chat.stream_id)
|
||||
):
|
||||
logger.info("用户禁用的命令,跳过处理")
|
||||
return False, None, True
|
||||
@@ -254,11 +257,14 @@ class ChatBot:
|
||||
# 创建命令实例
|
||||
command_instance: BaseCommand = command_class(message, plugin_config)
|
||||
command_instance.set_matched_groups(matched_groups)
|
||||
|
||||
# 为插件实例设置 chat_stream 运行时属性
|
||||
setattr(command_instance, "chat_stream", chat)
|
||||
|
||||
try:
|
||||
# 检查聊天类型限制
|
||||
if not command_instance.is_chat_type_allowed():
|
||||
is_group = message.message_info.group_info
|
||||
is_group = chat.group_info is not None
|
||||
logger.info(
|
||||
f"命令 {command_class.__name__} 不支持当前聊天类型: {'群聊' if is_group else '私聊'}"
|
||||
)
|
||||
@@ -295,13 +301,20 @@ class ChatBot:
|
||||
logger.error(f"处理命令时出错: {e}")
|
||||
return False, None, True # 出错时继续处理消息
|
||||
|
||||
async def handle_notice_message(self, message: MessageRecv):
|
||||
async def handle_notice_message(self, message: DatabaseMessages):
|
||||
"""处理notice消息
|
||||
|
||||
notice消息是系统事件通知(如禁言、戳一戳等),具有以下特点:
|
||||
1. 默认不触发聊天流程,只记录
|
||||
2. 可通过配置开启触发聊天流程
|
||||
3. 会在提示词中展示
|
||||
|
||||
Args:
|
||||
message: DatabaseMessages 对象
|
||||
|
||||
Returns:
|
||||
bool: True表示notice已完整处理(需要存储并终止后续流程)
|
||||
False表示不是notice或notice需要继续处理(触发聊天流程)
|
||||
"""
|
||||
# 检查是否是notice消息
|
||||
if message.is_notify:
|
||||
@@ -309,53 +322,42 @@ class ChatBot:
|
||||
|
||||
# 根据配置决定是否触发聊天流程
|
||||
if not global_config.notice.enable_notice_trigger_chat:
|
||||
logger.debug("notice消息不触发聊天流程(配置已关闭)")
|
||||
return True # 返回True表示已处理,不继续后续流程
|
||||
logger.debug("notice消息不触发聊天流程(配置已关闭),将存储后终止")
|
||||
return True # 返回True:需要在调用处存储并终止
|
||||
else:
|
||||
logger.debug("notice消息触发聊天流程(配置已开启)")
|
||||
return False # 返回False表示继续处理,触发聊天流程
|
||||
logger.debug("notice消息触发聊天流程(配置已开启),继续处理")
|
||||
return False # 返回False:继续正常流程,作为普通消息处理
|
||||
|
||||
# 兼容旧的notice判断方式
|
||||
if message.message_info.message_id == "notice":
|
||||
message.is_notify = True
|
||||
if message.message_id == "notice":
|
||||
# 为 DatabaseMessages 设置 is_notify 运行时属性
|
||||
from src.chat.message_receive.message_processor import set_db_message_runtime_attr
|
||||
set_db_message_runtime_attr(message, "is_notify", True)
|
||||
logger.info("旧格式notice消息")
|
||||
|
||||
# 同样根据配置决定
|
||||
if not global_config.notice.enable_notice_trigger_chat:
|
||||
return True
|
||||
logger.debug("旧格式notice消息不触发聊天流程,将存储后终止")
|
||||
return True # 需要存储并终止
|
||||
else:
|
||||
return False
|
||||
logger.debug("旧格式notice消息触发聊天流程,继续处理")
|
||||
return False # 继续正常流程
|
||||
|
||||
# 处理适配器响应消息
|
||||
if hasattr(message, "message_segment") and message.message_segment:
|
||||
if message.message_segment.type == "adapter_response":
|
||||
await self.handle_adapter_response(message)
|
||||
return True
|
||||
elif message.message_segment.type == "adapter_command":
|
||||
# 适配器命令消息不需要进一步处理
|
||||
logger.debug("收到适配器命令消息,跳过后续处理")
|
||||
return True
|
||||
# DatabaseMessages 不再有 message_segment,适配器响应处理已在消息处理阶段完成
|
||||
# 这里保留逻辑以防万一,但实际上不会再执行到
|
||||
return False # 不是notice消息,继续正常流程
|
||||
|
||||
return False
|
||||
|
||||
async def handle_adapter_response(self, message: MessageRecv):
|
||||
"""处理适配器命令响应"""
|
||||
async def handle_adapter_response(self, message: DatabaseMessages):
|
||||
"""处理适配器命令响应
|
||||
|
||||
注意: 此方法目前未被调用,但保留以备将来使用
|
||||
"""
|
||||
try:
|
||||
from src.plugin_system.apis.send_api import put_adapter_response
|
||||
|
||||
seg_data = message.message_segment.data
|
||||
if isinstance(seg_data, dict):
|
||||
request_id = seg_data.get("request_id")
|
||||
response_data = seg_data.get("response")
|
||||
else:
|
||||
request_id = None
|
||||
response_data = None
|
||||
|
||||
if request_id and response_data:
|
||||
logger.debug(f"收到适配器响应: request_id={request_id}")
|
||||
put_adapter_response(request_id, response_data)
|
||||
else:
|
||||
logger.warning("适配器响应消息格式不正确")
|
||||
# DatabaseMessages 使用 message_segments 字段存储消息段
|
||||
# 注意: 这可能需要根据实际使用情况进行调整
|
||||
logger.warning("handle_adapter_response 方法被调用,但目前未实现对 DatabaseMessages 的支持")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"处理适配器响应时出错: {e}")
|
||||
@@ -381,9 +383,6 @@ class ChatBot:
|
||||
await self._ensure_started()
|
||||
|
||||
# 控制握手等消息可能缺少 message_info,这里直接跳过避免 KeyError
|
||||
if not isinstance(message_data, dict):
|
||||
logger.warning(f"收到无法解析的消息类型: {type(message_data)},已跳过")
|
||||
return
|
||||
message_info = message_data.get("message_info")
|
||||
if not isinstance(message_info, dict):
|
||||
logger.debug(
|
||||
@@ -392,8 +391,6 @@ class ChatBot:
|
||||
)
|
||||
return
|
||||
|
||||
platform = message_info.get("platform")
|
||||
|
||||
if message_info.get("group_info") is not None:
|
||||
message_info["group_info"]["group_id"] = str(
|
||||
message_info["group_info"]["group_id"]
|
||||
@@ -404,74 +401,94 @@ class ChatBot:
|
||||
)
|
||||
# print(message_data)
|
||||
# logger.debug(str(message_data))
|
||||
message = MessageRecv(message_data)
|
||||
|
||||
group_info = message.message_info.group_info
|
||||
user_info = message.message_info.user_info
|
||||
if message.message_info.additional_config:
|
||||
sent_message = message.message_info.additional_config.get("echo", False)
|
||||
|
||||
# 先提取基础信息检查是否是自身消息上报
|
||||
from maim_message import BaseMessageInfo
|
||||
temp_message_info = BaseMessageInfo.from_dict(message_data.get("message_info", {}))
|
||||
if temp_message_info.additional_config:
|
||||
sent_message = temp_message_info.additional_config.get("echo", False)
|
||||
if sent_message: # 这一段只是为了在一切处理前劫持上报的自身消息,用于更新message_id,需要ada支持上报事件,实际测试中不会对正常使用造成任何问题
|
||||
await MessageStorage.update_message(message)
|
||||
# 直接使用消息字典更新,不再需要创建 MessageRecv
|
||||
await MessageStorage.update_message(message_data)
|
||||
return
|
||||
|
||||
group_info = temp_message_info.group_info
|
||||
user_info = temp_message_info.user_info
|
||||
|
||||
get_chat_manager().register_message(message)
|
||||
|
||||
# 获取或创建聊天流
|
||||
chat = await get_chat_manager().get_or_create_stream(
|
||||
platform=message.message_info.platform, # type: ignore
|
||||
platform=temp_message_info.platform, # type: ignore
|
||||
user_info=user_info, # type: ignore
|
||||
group_info=group_info,
|
||||
)
|
||||
|
||||
message.update_chat_stream(chat)
|
||||
|
||||
# 处理消息内容,生成纯文本
|
||||
await message.process()
|
||||
|
||||
# 使用新的消息处理器直接生成 DatabaseMessages
|
||||
from src.chat.message_receive.message_processor import process_message_from_dict
|
||||
message = await process_message_from_dict(
|
||||
message_dict=message_data,
|
||||
stream_id=chat.stream_id,
|
||||
platform=chat.platform
|
||||
)
|
||||
|
||||
# 填充聊天流时间信息
|
||||
message.chat_info.create_time = chat.create_time
|
||||
message.chat_info.last_active_time = chat.last_active_time
|
||||
|
||||
# 注册消息到聊天管理器
|
||||
get_chat_manager().register_message(message)
|
||||
|
||||
# 检测是否提及机器人
|
||||
message.is_mentioned, _ = is_mentioned_bot_in_message(message)
|
||||
|
||||
# 在这里打印[所见]日志,确保在所有处理和过滤之前记录
|
||||
chat_name = chat.group_info.group_name if chat.group_info else "私聊"
|
||||
if message.message_info.user_info:
|
||||
logger.info(
|
||||
f"[{chat_name}]{message.message_info.user_info.user_nickname}:{message.processed_plain_text}\u001b[0m"
|
||||
)
|
||||
user_nickname = message.user_info.user_nickname if message.user_info else "未知用户"
|
||||
logger.info(
|
||||
f"[{chat_name}]{user_nickname}:{message.processed_plain_text}\u001b[0m"
|
||||
)
|
||||
|
||||
# 在此添加硬编码过滤,防止回复图片处理失败的消息
|
||||
failure_keywords = ["[表情包(描述生成失败)]", "[图片(描述生成失败)]"]
|
||||
if any(keyword in message.processed_plain_text for keyword in failure_keywords):
|
||||
logger.info(f"[硬编码过滤] 检测到媒体内容处理失败({message.processed_plain_text}),消息被静默处理。")
|
||||
processed_text = message.processed_plain_text or ""
|
||||
if any(keyword in processed_text for keyword in failure_keywords):
|
||||
logger.info(f"[硬编码过滤] 检测到媒体内容处理失败({processed_text}),消息被静默处理。")
|
||||
return
|
||||
|
||||
# 处理notice消息
|
||||
# notice_handled=True: 表示notice不触发聊天,需要在此存储并终止
|
||||
# notice_handled=False: 表示notice触发聊天或不是notice,继续正常流程
|
||||
notice_handled = await self.handle_notice_message(message)
|
||||
if notice_handled:
|
||||
# notice消息已处理,使用统一的转换方法
|
||||
# notice消息不触发聊天流程,在此进行存储和记录后终止
|
||||
try:
|
||||
# 直接转换为 DatabaseMessages
|
||||
db_message = message.to_database_message()
|
||||
|
||||
# message 已经是 DatabaseMessages,直接使用
|
||||
# 添加到message_manager(这会将notice添加到全局notice管理器)
|
||||
await message_manager.add_message(message.chat_stream.stream_id, db_message)
|
||||
logger.info(f"✅ Notice消息已添加到message_manager: type={message.notice_type}, stream={message.chat_stream.stream_id}")
|
||||
await message_manager.add_message(chat.stream_id, message)
|
||||
logger.info(f"✅ Notice消息已添加到message_manager: type={message.notice_type}, stream={chat.stream_id}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Notice消息添加到message_manager失败: {e}", exc_info=True)
|
||||
|
||||
# 存储后直接返回
|
||||
await MessageStorage.store_message(message, chat)
|
||||
logger.debug("notice消息已存储,跳过后续处理")
|
||||
# 存储notice消息到数据库(需要更新 storage.py 支持 DatabaseMessages)
|
||||
# 暂时跳过存储,等待更新 storage.py
|
||||
logger.debug("notice消息已添加到message_manager(存储功能待更新)")
|
||||
return
|
||||
|
||||
# 如果notice_handled=False,则继续执行后续流程
|
||||
# 对于启用触发聊天的notice,会在后续的正常流程中被存储和处理
|
||||
|
||||
# 过滤检查
|
||||
# DatabaseMessages 使用 display_message 作为原始消息表示
|
||||
raw_text = message.display_message or message.processed_plain_text or ""
|
||||
if _check_ban_words(message.processed_plain_text, chat, user_info) or _check_ban_regex( # type: ignore
|
||||
message.raw_message, # type: ignore
|
||||
raw_text,
|
||||
chat,
|
||||
user_info, # type: ignore
|
||||
):
|
||||
return
|
||||
|
||||
# 命令处理 - 首先尝试PlusCommand独立处理
|
||||
is_plus_command, plus_cmd_result, plus_continue_process = await self._process_plus_commands(message)
|
||||
is_plus_command, plus_cmd_result, plus_continue_process = await self._process_plus_commands(message, chat)
|
||||
|
||||
# 如果是PlusCommand且不需要继续处理,则直接返回
|
||||
if is_plus_command and not plus_continue_process:
|
||||
@@ -481,7 +498,7 @@ class ChatBot:
|
||||
|
||||
# 如果不是PlusCommand,尝试传统的BaseCommand处理
|
||||
if not is_plus_command:
|
||||
is_command, cmd_result, continue_process = await self._process_commands_with_new_system(message)
|
||||
is_command, cmd_result, continue_process = await self._process_commands_with_new_system(message, chat)
|
||||
|
||||
# 如果是命令且不需要继续处理,则直接返回
|
||||
if is_command and not continue_process:
|
||||
@@ -493,24 +510,14 @@ class ChatBot:
|
||||
if result and not result.all_continue_process():
|
||||
raise UserWarning(f"插件{result.get_summary().get('stopped_handlers', '')}于消息到达时取消了消息处理")
|
||||
|
||||
# TODO:暂不可用
|
||||
# TODO:暂不可用 - DatabaseMessages 不再有 message_info.template_info
|
||||
# 确认从接口发来的message是否有自定义的prompt模板信息
|
||||
if message.message_info.template_info and not message.message_info.template_info.template_default:
|
||||
template_group_name: str | None = message.message_info.template_info.template_name # type: ignore
|
||||
template_items = message.message_info.template_info.template_items
|
||||
async with global_prompt_manager.async_message_scope(template_group_name):
|
||||
if isinstance(template_items, dict):
|
||||
for k in template_items.keys():
|
||||
await create_prompt_async(template_items[k], k)
|
||||
logger.debug(f"注册{template_items[k]},{k}")
|
||||
else:
|
||||
template_group_name = None
|
||||
# 这个功能需要在 adapter 层通过 additional_config 传递
|
||||
template_group_name = None
|
||||
|
||||
async def preprocess():
|
||||
# 使用统一的转换方法创建数据库消息对象
|
||||
db_message = message.to_database_message()
|
||||
|
||||
group_info = getattr(message.chat_stream, "group_info", None)
|
||||
# message 已经是 DatabaseMessages,直接使用
|
||||
group_info = chat.group_info
|
||||
|
||||
# 先交给消息管理器处理,计算兴趣度等衍生数据
|
||||
try:
|
||||
@@ -527,31 +534,15 @@ class ChatBot:
|
||||
should_process_in_manager = False
|
||||
|
||||
if should_process_in_manager:
|
||||
await message_manager.add_message(message.chat_stream.stream_id, db_message)
|
||||
logger.debug(f"消息已添加到消息管理器: {message.chat_stream.stream_id}")
|
||||
await message_manager.add_message(chat.stream_id, message)
|
||||
logger.debug(f"消息已添加到消息管理器: {chat.stream_id}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"消息添加到消息管理器失败: {e}")
|
||||
|
||||
# 将兴趣度结果同步回原始消息,便于后续流程使用
|
||||
message.interest_value = getattr(db_message, "interest_value", getattr(message, "interest_value", 0.0))
|
||||
setattr(
|
||||
message,
|
||||
"should_reply",
|
||||
getattr(db_message, "should_reply", getattr(message, "should_reply", False)),
|
||||
)
|
||||
setattr(message, "should_act", getattr(db_message, "should_act", getattr(message, "should_act", False)))
|
||||
|
||||
# 存储消息到数据库,只进行一次写入
|
||||
try:
|
||||
await MessageStorage.store_message(message, message.chat_stream)
|
||||
logger.debug(
|
||||
"消息已存储到数据库: %s (interest=%.3f, should_reply=%s, should_act=%s)",
|
||||
message.message_info.message_id,
|
||||
getattr(message, "interest_value", -1.0),
|
||||
getattr(message, "should_reply", None),
|
||||
getattr(message, "should_act", None),
|
||||
)
|
||||
await MessageStorage.store_message(message, chat)
|
||||
except Exception as e:
|
||||
logger.error(f"存储消息到数据库失败: {e}")
|
||||
traceback.print_exc()
|
||||
@@ -560,13 +551,13 @@ class ChatBot:
|
||||
try:
|
||||
if global_config.mood.enable_mood:
|
||||
# 获取兴趣度用于情绪更新
|
||||
interest_rate = getattr(message, "interest_value", 0.0)
|
||||
interest_rate = message.interest_value
|
||||
if interest_rate is None:
|
||||
interest_rate = 0.0
|
||||
logger.debug(f"开始更新情绪状态,兴趣度: {interest_rate:.2f}")
|
||||
|
||||
# 获取当前聊天的情绪对象并更新情绪状态
|
||||
chat_mood = mood_manager.get_mood_by_chat_id(message.chat_stream.stream_id)
|
||||
chat_mood = mood_manager.get_mood_by_chat_id(chat.stream_id)
|
||||
await chat_mood.update_mood_by_message(message, interest_rate)
|
||||
logger.debug("情绪状态更新完成")
|
||||
except Exception as e:
|
||||
|
||||
Reference in New Issue
Block a user