refactor(message-manager): 删除自适应流管理器并优化上下文加载
-从distribution_manager和message_manager中删除adaptive_stream_manager.py及其集成 -删除过时的message_recv_backup.py,因为MessageRecv已被DatabaseMessages完全替换 -在context_manager中添加异步历史初始化,以便在启动时从数据库加载消息 -优化default_generator以使用内存中的消息,而不是重复的数据库查询 -修复message.py中的回复消息段处理,以处理DatabaseMessages格式 -从chat_stream.py中删除deepcopy并改进context_manager初始化 -清理bot.py和适配器响应方法中未使用的通知处理 突破性变化:自适应流管理系统已被完全删除。所有消息处理现在都依赖于DatabaseMessages格式。上下文管理器现在在创建时从数据库异步初始化历史记录。
This commit is contained in:
@@ -301,67 +301,6 @@ class ChatBot:
|
||||
logger.error(f"处理命令时出错: {e}")
|
||||
return False, None, True # 出错时继续处理消息
|
||||
|
||||
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:
|
||||
logger.info(f"收到notice消息: {message.notice_type}")
|
||||
|
||||
# 根据配置决定是否触发聊天流程
|
||||
if not global_config.notice.enable_notice_trigger_chat:
|
||||
logger.debug("notice消息不触发聊天流程(配置已关闭),将存储后终止")
|
||||
return True # 返回True:需要在调用处存储并终止
|
||||
else:
|
||||
logger.debug("notice消息触发聊天流程(配置已开启),继续处理")
|
||||
return False # 返回False:继续正常流程,作为普通消息处理
|
||||
|
||||
# 兼容旧的notice判断方式
|
||||
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:
|
||||
logger.debug("旧格式notice消息不触发聊天流程,将存储后终止")
|
||||
return True # 需要存储并终止
|
||||
else:
|
||||
logger.debug("旧格式notice消息触发聊天流程,继续处理")
|
||||
return False # 继续正常流程
|
||||
|
||||
# DatabaseMessages 不再有 message_segment,适配器响应处理已在消息处理阶段完成
|
||||
# 这里保留逻辑以防万一,但实际上不会再执行到
|
||||
return False # 不是notice消息,继续正常流程
|
||||
|
||||
async def handle_adapter_response(self, message: DatabaseMessages):
|
||||
"""处理适配器命令响应
|
||||
|
||||
注意: 此方法目前未被调用,但保留以备将来使用
|
||||
"""
|
||||
try:
|
||||
from src.plugin_system.apis.send_api import put_adapter_response
|
||||
|
||||
# DatabaseMessages 使用 message_segments 字段存储消息段
|
||||
# 注意: 这可能需要根据实际使用情况进行调整
|
||||
logger.warning("handle_adapter_response 方法被调用,但目前未实现对 DatabaseMessages 的支持")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"处理适配器响应时出错: {e}")
|
||||
|
||||
async def message_process(self, message_data: dict[str, Any]) -> None:
|
||||
"""处理转化后的统一格式消息"""
|
||||
try:
|
||||
@@ -454,29 +393,6 @@ class ChatBot:
|
||||
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消息不触发聊天流程,在此进行存储和记录后终止
|
||||
try:
|
||||
# message 已经是 DatabaseMessages,直接使用
|
||||
# 添加到message_manager(这会将notice添加到全局notice管理器)
|
||||
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)
|
||||
|
||||
# 存储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 ""
|
||||
|
||||
@@ -62,36 +62,6 @@ class ChatStream:
|
||||
self._focus_energy = 0.5 # 内部存储的focus_energy值
|
||||
self.no_reply_consecutive = 0
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
"""自定义深拷贝方法,避免复制不可序列化的 asyncio.Task 对象"""
|
||||
import copy
|
||||
|
||||
# 创建新的实例
|
||||
new_stream = ChatStream(
|
||||
stream_id=self.stream_id,
|
||||
platform=self.platform,
|
||||
user_info=copy.deepcopy(self.user_info, memo),
|
||||
group_info=copy.deepcopy(self.group_info, memo),
|
||||
)
|
||||
|
||||
# 复制基本属性
|
||||
new_stream.create_time = self.create_time
|
||||
new_stream.last_active_time = self.last_active_time
|
||||
new_stream.sleep_pressure = self.sleep_pressure
|
||||
new_stream.saved = self.saved
|
||||
new_stream.base_interest_energy = self.base_interest_energy
|
||||
new_stream._focus_energy = self._focus_energy
|
||||
new_stream.no_reply_consecutive = self.no_reply_consecutive
|
||||
|
||||
# 复制 context_manager(包含 stream_context)
|
||||
new_stream.context_manager = copy.deepcopy(self.context_manager, memo)
|
||||
|
||||
# 清理 processing_task(如果存在)
|
||||
if hasattr(new_stream.context_manager.context, "processing_task"):
|
||||
new_stream.context_manager.context.processing_task = None
|
||||
|
||||
return new_stream
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
"""转换为字典格式"""
|
||||
return {
|
||||
@@ -461,7 +431,6 @@ class ChatManager:
|
||||
|
||||
# 更新用户信息和群组信息
|
||||
stream.update_active_time()
|
||||
stream = copy.deepcopy(stream) # 返回副本以避免外部修改影响缓存
|
||||
if user_info.platform and user_info.user_id:
|
||||
stream.user_info = user_info
|
||||
if group_info:
|
||||
@@ -530,7 +499,6 @@ class ChatManager:
|
||||
logger.error(f"获取或创建聊天流失败: {e}", exc_info=True)
|
||||
raise e
|
||||
|
||||
stream = copy.deepcopy(stream)
|
||||
from src.common.data_models.database_data_model import DatabaseMessages
|
||||
|
||||
if stream_id in self.last_messages and isinstance(self.last_messages[stream_id], DatabaseMessages):
|
||||
@@ -539,11 +507,12 @@ class ChatManager:
|
||||
logger.debug(f"聊天流 {stream_id} 不在最后消息列表中,可能是新创建的")
|
||||
|
||||
# 确保 ChatStream 有自己的 context_manager
|
||||
if not hasattr(stream, "context_manager"):
|
||||
if not hasattr(stream, "context_manager") or stream.context_manager is None:
|
||||
from src.chat.message_manager.context_manager import SingleStreamContextManager
|
||||
from src.common.data_models.message_manager_data_model import StreamContext
|
||||
from src.plugin_system.base.component_types import ChatMode, ChatType
|
||||
|
||||
logger.info(f"为 stream {stream_id} 创建新的 context_manager")
|
||||
stream.context_manager = SingleStreamContextManager(
|
||||
stream_id=stream_id,
|
||||
context=StreamContext(
|
||||
@@ -552,6 +521,8 @@ class ChatManager:
|
||||
chat_mode=ChatMode.NORMAL,
|
||||
),
|
||||
)
|
||||
else:
|
||||
logger.info(f"stream {stream_id} 已有 context_manager,跳过创建")
|
||||
|
||||
# 保存到内存和数据库
|
||||
self.streams[stream_id] = stream
|
||||
@@ -781,11 +752,12 @@ class ChatManager:
|
||||
# await stream.set_context(self.last_messages[stream.stream_id])
|
||||
|
||||
# 确保 ChatStream 有自己的 context_manager
|
||||
if not hasattr(stream, "context_manager"):
|
||||
if not hasattr(stream, "context_manager") or stream.context_manager is None:
|
||||
from src.chat.message_manager.context_manager import SingleStreamContextManager
|
||||
from src.common.data_models.message_manager_data_model import StreamContext
|
||||
from src.plugin_system.base.component_types import ChatMode, ChatType
|
||||
|
||||
logger.debug(f"为加载的 stream {stream.stream_id} 创建新的 context_manager")
|
||||
stream.context_manager = SingleStreamContextManager(
|
||||
stream_id=stream.stream_id,
|
||||
context=StreamContext(
|
||||
@@ -794,6 +766,8 @@ class ChatManager:
|
||||
chat_mode=ChatMode.NORMAL,
|
||||
),
|
||||
)
|
||||
else:
|
||||
logger.debug(f"加载的 stream {stream.stream_id} 已有 context_manager")
|
||||
except Exception as e:
|
||||
logger.error(f"从数据库加载所有聊天流失败 (SQLAlchemy): {e}", exc_info=True)
|
||||
|
||||
|
||||
@@ -160,7 +160,7 @@ class MessageProcessBase(Message):
|
||||
return "[表情,网卡了加载不出来]"
|
||||
elif seg.type == "voice":
|
||||
# 检查消息是否由机器人自己发送
|
||||
# 检查消息是否由机器人自己发送
|
||||
# self.message_info 来自 MessageBase,指当前消息的信息
|
||||
if self.message_info and self.message_info.user_info and str(self.message_info.user_info.user_id) == str(global_config.bot.qq_account):
|
||||
logger.info(f"检测到机器人自身发送的语音消息 (User ID: {self.message_info.user_info.user_id}),尝试从缓存获取文本。")
|
||||
if isinstance(seg.data, str):
|
||||
@@ -182,10 +182,24 @@ class MessageProcessBase(Message):
|
||||
return f"@{nickname}"
|
||||
return f"@{seg.data}" if isinstance(seg.data, str) else "@未知用户"
|
||||
elif seg.type == "reply":
|
||||
if self.reply and hasattr(self.reply, "processed_plain_text"):
|
||||
# print(f"self.reply.processed_plain_text: {self.reply.processed_plain_text}")
|
||||
# print(f"reply: {self.reply}")
|
||||
return f"[回复<{self.reply.message_info.user_info.user_nickname}({self.reply.message_info.user_info.user_id})> 的消息:{self.reply.processed_plain_text}]" # type: ignore
|
||||
# 处理回复消息段
|
||||
if self.reply:
|
||||
# 检查 reply 对象是否有必要的属性
|
||||
if hasattr(self.reply, "processed_plain_text") and self.reply.processed_plain_text:
|
||||
# DatabaseMessages 使用 user_info 而不是 message_info.user_info
|
||||
user_nickname = self.reply.user_info.user_nickname if self.reply.user_info else "未知用户"
|
||||
user_id = self.reply.user_info.user_id if self.reply.user_info else ""
|
||||
return f"[回复<{user_nickname}({user_id})> 的消息:{self.reply.processed_plain_text}]"
|
||||
else:
|
||||
# reply 对象存在但没有 processed_plain_text,返回简化的回复标识
|
||||
logger.debug(f"reply 消息段没有 processed_plain_text 属性,message_id: {getattr(self.reply, 'message_id', 'unknown')}")
|
||||
return "[回复消息]"
|
||||
else:
|
||||
# 没有 reply 对象,但有 reply 消息段(可能是机器人自己发送的消息)
|
||||
# 这种情况下 seg.data 应该包含被回复消息的 message_id
|
||||
if isinstance(seg.data, str):
|
||||
logger.debug(f"处理 reply 消息段,但 self.reply 为 None,reply_to message_id: {seg.data}")
|
||||
return f"[回复消息 {seg.data}]"
|
||||
return None
|
||||
else:
|
||||
return f"[{seg.type}:{seg.data!s}]"
|
||||
|
||||
@@ -79,13 +79,9 @@ async def process_message_from_dict(message_dict: dict[str, Any], stream_id: str
|
||||
group_name = group_info.group_name if group_info else None
|
||||
group_platform = group_info.platform if group_info else None
|
||||
|
||||
# 生成 chat_id
|
||||
if group_info and group_id:
|
||||
chat_id = f"{platform}_{group_id}"
|
||||
elif user_info and user_info.user_id:
|
||||
chat_id = f"{platform}_{user_info.user_id}_private"
|
||||
else:
|
||||
chat_id = stream_id
|
||||
# chat_id 应该直接使用 stream_id(与数据库存储格式一致)
|
||||
# stream_id 是通过 platform + user_id/group_id 的 SHA-256 哈希生成的
|
||||
chat_id = stream_id
|
||||
|
||||
# 准备 additional_config
|
||||
additional_config_str = _prepare_additional_config(message_info, is_notify, is_public_notice, notice_type)
|
||||
|
||||
@@ -1,434 +0,0 @@
|
||||
# MessageRecv 类备份 - 已从 message.py 中移除
|
||||
# 备份日期: 2025-10-31
|
||||
# 此类已被 DatabaseMessages 完全取代
|
||||
|
||||
# MessageRecv 类已被移除
|
||||
# 现在所有消息处理都使用 DatabaseMessages
|
||||
# 如果需要从消息字典创建 DatabaseMessages,请使用 message_processor.process_message_from_dict()
|
||||
#
|
||||
# 历史参考: MessageRecv 曾经是接收消息的包装类,现已被 DatabaseMessages 完全取代
|
||||
# 迁移完成日期: 2025-10-31
|
||||
|
||||
"""
|
||||
# 以下是已删除的 MessageRecv 类(保留作为参考)
|
||||
class MessageRecv:
|
||||
接收消息类 - DatabaseMessages 的轻量级包装器
|
||||
|
||||
这个类现在主要作为适配器层,处理外部消息格式并内部使用 DatabaseMessages。
|
||||
保留此类是为了向后兼容性和处理 message_segment 的异步逻辑。
|
||||
"""
|
||||
|
||||
def __init__(self, message_dict: dict[str, Any]):
|
||||
"""从MessageCQ的字典初始化
|
||||
|
||||
Args:
|
||||
message_dict: MessageCQ序列化后的字典
|
||||
"""
|
||||
# 保留原始消息信息用于某些场景
|
||||
self.message_info = BaseMessageInfo.from_dict(message_dict.get("message_info", {}))
|
||||
self.message_segment = Seg.from_dict(message_dict.get("message_segment", {}))
|
||||
self.raw_message = message_dict.get("raw_message")
|
||||
|
||||
# 处理状态(在process()之前临时使用)
|
||||
self._processing_state = {
|
||||
"is_emoji": False,
|
||||
"has_emoji": False,
|
||||
"is_picid": False,
|
||||
"has_picid": False,
|
||||
"is_voice": False,
|
||||
"is_video": False,
|
||||
"is_mentioned": None,
|
||||
"is_at": False,
|
||||
"priority_mode": "interest",
|
||||
"priority_info": None,
|
||||
}
|
||||
|
||||
self.chat_stream = None
|
||||
self.reply = None
|
||||
self.processed_plain_text = message_dict.get("processed_plain_text", "")
|
||||
|
||||
# 解析additional_config中的notice信息
|
||||
self.is_notify = False
|
||||
self.is_public_notice = False
|
||||
self.notice_type = None
|
||||
if self.message_info.additional_config and isinstance(self.message_info.additional_config, dict):
|
||||
self.is_notify = self.message_info.additional_config.get("is_notice", False)
|
||||
self.is_public_notice = self.message_info.additional_config.get("is_public_notice", False)
|
||||
self.notice_type = self.message_info.additional_config.get("notice_type")
|
||||
|
||||
# 兼容性属性 - 代理到 _processing_state
|
||||
@property
|
||||
def is_emoji(self) -> bool:
|
||||
return self._processing_state["is_emoji"]
|
||||
|
||||
@is_emoji.setter
|
||||
def is_emoji(self, value: bool):
|
||||
self._processing_state["is_emoji"] = value
|
||||
|
||||
@property
|
||||
def has_emoji(self) -> bool:
|
||||
return self._processing_state["has_emoji"]
|
||||
|
||||
@has_emoji.setter
|
||||
def has_emoji(self, value: bool):
|
||||
self._processing_state["has_emoji"] = value
|
||||
|
||||
@property
|
||||
def is_picid(self) -> bool:
|
||||
return self._processing_state["is_picid"]
|
||||
|
||||
@is_picid.setter
|
||||
def is_picid(self, value: bool):
|
||||
self._processing_state["is_picid"] = value
|
||||
|
||||
@property
|
||||
def has_picid(self) -> bool:
|
||||
return self._processing_state["has_picid"]
|
||||
|
||||
@has_picid.setter
|
||||
def has_picid(self, value: bool):
|
||||
self._processing_state["has_picid"] = value
|
||||
|
||||
@property
|
||||
def is_voice(self) -> bool:
|
||||
return self._processing_state["is_voice"]
|
||||
|
||||
@is_voice.setter
|
||||
def is_voice(self, value: bool):
|
||||
self._processing_state["is_voice"] = value
|
||||
|
||||
@property
|
||||
def is_video(self) -> bool:
|
||||
return self._processing_state["is_video"]
|
||||
|
||||
@is_video.setter
|
||||
def is_video(self, value: bool):
|
||||
self._processing_state["is_video"] = value
|
||||
|
||||
@property
|
||||
def is_mentioned(self):
|
||||
return self._processing_state["is_mentioned"]
|
||||
|
||||
@is_mentioned.setter
|
||||
def is_mentioned(self, value):
|
||||
self._processing_state["is_mentioned"] = value
|
||||
|
||||
@property
|
||||
def is_at(self) -> bool:
|
||||
return self._processing_state["is_at"]
|
||||
|
||||
@is_at.setter
|
||||
def is_at(self, value: bool):
|
||||
self._processing_state["is_at"] = value
|
||||
|
||||
@property
|
||||
def priority_mode(self) -> str:
|
||||
return self._processing_state["priority_mode"]
|
||||
|
||||
@priority_mode.setter
|
||||
def priority_mode(self, value: str):
|
||||
self._processing_state["priority_mode"] = value
|
||||
|
||||
@property
|
||||
def priority_info(self):
|
||||
return self._processing_state["priority_info"]
|
||||
|
||||
@priority_info.setter
|
||||
def priority_info(self, value):
|
||||
self._processing_state["priority_info"] = value
|
||||
|
||||
# 其他常用属性
|
||||
interest_value: float = 0.0
|
||||
is_command: bool = False
|
||||
memorized_times: int = 0
|
||||
|
||||
def __post_init__(self):
|
||||
"""dataclass 初始化后处理"""
|
||||
self.key_words = []
|
||||
self.key_words_lite = []
|
||||
|
||||
def update_chat_stream(self, chat_stream: "ChatStream"):
|
||||
self.chat_stream = chat_stream
|
||||
|
||||
def to_database_message(self) -> "DatabaseMessages":
|
||||
"""将 MessageRecv 转换为 DatabaseMessages 对象
|
||||
|
||||
Returns:
|
||||
DatabaseMessages: 数据库消息对象
|
||||
"""
|
||||
import time
|
||||
|
||||
message_info = self.message_info
|
||||
msg_user_info = getattr(message_info, "user_info", None)
|
||||
stream_user_info = getattr(self.chat_stream, "user_info", None) if self.chat_stream else None
|
||||
group_info = getattr(self.chat_stream, "group_info", None) if self.chat_stream else None
|
||||
|
||||
message_id = message_info.message_id or ""
|
||||
message_time = message_info.time if hasattr(message_info, "time") and message_info.time is not None else time.time()
|
||||
is_mentioned = None
|
||||
if isinstance(self.is_mentioned, bool):
|
||||
is_mentioned = self.is_mentioned
|
||||
elif isinstance(self.is_mentioned, int | float):
|
||||
is_mentioned = self.is_mentioned != 0
|
||||
|
||||
# 提取用户信息
|
||||
user_id = ""
|
||||
user_nickname = ""
|
||||
user_cardname = None
|
||||
user_platform = ""
|
||||
if msg_user_info:
|
||||
user_id = str(getattr(msg_user_info, "user_id", "") or "")
|
||||
user_nickname = getattr(msg_user_info, "user_nickname", "") or ""
|
||||
user_cardname = getattr(msg_user_info, "user_cardname", None)
|
||||
user_platform = getattr(msg_user_info, "platform", "") or ""
|
||||
elif stream_user_info:
|
||||
user_id = str(getattr(stream_user_info, "user_id", "") or "")
|
||||
user_nickname = getattr(stream_user_info, "user_nickname", "") or ""
|
||||
user_cardname = getattr(stream_user_info, "user_cardname", None)
|
||||
user_platform = getattr(stream_user_info, "platform", "") or ""
|
||||
|
||||
# 提取聊天流信息
|
||||
chat_user_id = str(getattr(stream_user_info, "user_id", "") or "") if stream_user_info else ""
|
||||
chat_user_nickname = getattr(stream_user_info, "user_nickname", "") or "" if stream_user_info else ""
|
||||
chat_user_cardname = getattr(stream_user_info, "user_cardname", None) if stream_user_info else None
|
||||
chat_user_platform = getattr(stream_user_info, "platform", "") or "" if stream_user_info else ""
|
||||
|
||||
group_id = getattr(group_info, "group_id", None) if group_info else None
|
||||
group_name = getattr(group_info, "group_name", None) if group_info else None
|
||||
group_platform = getattr(group_info, "platform", None) if group_info else None
|
||||
|
||||
# 准备 additional_config
|
||||
additional_config_str = None
|
||||
try:
|
||||
import orjson
|
||||
|
||||
additional_config_data = {}
|
||||
|
||||
# 首先获取adapter传递的additional_config
|
||||
if hasattr(message_info, 'additional_config') and message_info.additional_config:
|
||||
if isinstance(message_info.additional_config, dict):
|
||||
additional_config_data = message_info.additional_config.copy()
|
||||
elif isinstance(message_info.additional_config, str):
|
||||
try:
|
||||
additional_config_data = orjson.loads(message_info.additional_config)
|
||||
except Exception as e:
|
||||
logger.warning(f"无法解析 additional_config JSON: {e}")
|
||||
additional_config_data = {}
|
||||
|
||||
# 添加notice相关标志
|
||||
if self.is_notify:
|
||||
additional_config_data["is_notice"] = True
|
||||
additional_config_data["notice_type"] = self.notice_type or "unknown"
|
||||
additional_config_data["is_public_notice"] = bool(self.is_public_notice)
|
||||
|
||||
# 添加format_info到additional_config中
|
||||
if hasattr(message_info, 'format_info') and message_info.format_info:
|
||||
try:
|
||||
format_info_dict = message_info.format_info.to_dict()
|
||||
additional_config_data["format_info"] = format_info_dict
|
||||
logger.debug(f"[message.py] 嵌入 format_info 到 additional_config: {format_info_dict}")
|
||||
except Exception as e:
|
||||
logger.warning(f"将 format_info 转换为字典失败: {e}")
|
||||
|
||||
# 序列化为JSON字符串
|
||||
if additional_config_data:
|
||||
additional_config_str = orjson.dumps(additional_config_data).decode("utf-8")
|
||||
except Exception as e:
|
||||
logger.error(f"准备 additional_config 失败: {e}")
|
||||
|
||||
# 创建数据库消息对象
|
||||
db_message = DatabaseMessages(
|
||||
message_id=message_id,
|
||||
time=float(message_time),
|
||||
chat_id=self.chat_stream.stream_id if self.chat_stream else "",
|
||||
processed_plain_text=self.processed_plain_text,
|
||||
display_message=self.processed_plain_text,
|
||||
is_mentioned=is_mentioned,
|
||||
is_at=bool(self.is_at) if self.is_at is not None else None,
|
||||
is_emoji=bool(self.is_emoji),
|
||||
is_picid=bool(self.is_picid),
|
||||
is_command=bool(self.is_command),
|
||||
is_notify=bool(self.is_notify),
|
||||
is_public_notice=bool(self.is_public_notice),
|
||||
notice_type=self.notice_type,
|
||||
additional_config=additional_config_str,
|
||||
user_id=user_id,
|
||||
user_nickname=user_nickname,
|
||||
user_cardname=user_cardname,
|
||||
user_platform=user_platform,
|
||||
chat_info_stream_id=self.chat_stream.stream_id if self.chat_stream else "",
|
||||
chat_info_platform=self.chat_stream.platform if self.chat_stream else "",
|
||||
chat_info_create_time=float(self.chat_stream.create_time) if self.chat_stream else 0.0,
|
||||
chat_info_last_active_time=float(self.chat_stream.last_active_time) if self.chat_stream else 0.0,
|
||||
chat_info_user_id=chat_user_id,
|
||||
chat_info_user_nickname=chat_user_nickname,
|
||||
chat_info_user_cardname=chat_user_cardname,
|
||||
chat_info_user_platform=chat_user_platform,
|
||||
chat_info_group_id=group_id,
|
||||
chat_info_group_name=group_name,
|
||||
chat_info_group_platform=group_platform,
|
||||
)
|
||||
|
||||
# 同步兴趣度等衍生属性
|
||||
db_message.interest_value = getattr(self, "interest_value", 0.0)
|
||||
setattr(db_message, "should_reply", getattr(self, "should_reply", False))
|
||||
setattr(db_message, "should_act", getattr(self, "should_act", False))
|
||||
|
||||
return db_message
|
||||
|
||||
async def process(self) -> None:
|
||||
"""处理消息内容,生成纯文本和详细文本
|
||||
|
||||
这个方法必须在创建实例后显式调用,因为它包含异步操作。
|
||||
"""
|
||||
self.processed_plain_text = await self._process_message_segments(self.message_segment)
|
||||
|
||||
async def _process_single_segment(self, segment: Seg) -> str:
|
||||
"""处理单个消息段
|
||||
|
||||
Args:
|
||||
segment: 消息段
|
||||
|
||||
Returns:
|
||||
str: 处理后的文本
|
||||
"""
|
||||
try:
|
||||
if segment.type == "text":
|
||||
self.is_picid = False
|
||||
self.is_emoji = False
|
||||
self.is_video = False
|
||||
return segment.data # type: ignore
|
||||
elif segment.type == "at":
|
||||
self.is_picid = False
|
||||
self.is_emoji = False
|
||||
self.is_video = False
|
||||
# 处理at消息,格式为"昵称:QQ号"
|
||||
if isinstance(segment.data, str) and ":" in segment.data:
|
||||
nickname, qq_id = segment.data.split(":", 1)
|
||||
return f"@{nickname}"
|
||||
return f"@{segment.data}" if isinstance(segment.data, str) else "@未知用户"
|
||||
elif segment.type == "image":
|
||||
# 如果是base64图片数据
|
||||
if isinstance(segment.data, str):
|
||||
self.has_picid = True
|
||||
self.is_picid = True
|
||||
self.is_emoji = False
|
||||
self.is_video = False
|
||||
image_manager = get_image_manager()
|
||||
# print(f"segment.data: {segment.data}")
|
||||
_, processed_text = await image_manager.process_image(segment.data)
|
||||
return processed_text
|
||||
return "[发了一张图片,网卡了加载不出来]"
|
||||
elif segment.type == "emoji":
|
||||
self.has_emoji = True
|
||||
self.is_emoji = True
|
||||
self.is_picid = False
|
||||
self.is_voice = False
|
||||
self.is_video = False
|
||||
if isinstance(segment.data, str):
|
||||
return await get_image_manager().get_emoji_description(segment.data)
|
||||
return "[发了一个表情包,网卡了加载不出来]"
|
||||
elif segment.type == "voice":
|
||||
self.is_picid = False
|
||||
self.is_emoji = False
|
||||
self.is_voice = True
|
||||
self.is_video = False
|
||||
|
||||
# 检查消息是否由机器人自己发送
|
||||
if self.message_info and self.message_info.user_info and str(self.message_info.user_info.user_id) == str(global_config.bot.qq_account):
|
||||
logger.info(f"检测到机器人自身发送的语音消息 (User ID: {self.message_info.user_info.user_id}),尝试从缓存获取文本。")
|
||||
if isinstance(segment.data, str):
|
||||
cached_text = consume_self_voice_text(segment.data)
|
||||
if cached_text:
|
||||
logger.info(f"成功从缓存中获取语音文本: '{cached_text[:70]}...'")
|
||||
return f"[语音:{cached_text}]"
|
||||
else:
|
||||
logger.warning("机器人自身语音消息缓存未命中,将回退到标准语音识别。")
|
||||
|
||||
# 标准语音识别流程 (也作为缓存未命中的后备方案)
|
||||
if isinstance(segment.data, str):
|
||||
return await get_voice_text(segment.data)
|
||||
return "[发了一段语音,网卡了加载不出来]"
|
||||
elif segment.type == "mention_bot":
|
||||
self.is_picid = False
|
||||
self.is_emoji = False
|
||||
self.is_voice = False
|
||||
self.is_video = False
|
||||
self.is_mentioned = float(segment.data) # type: ignore
|
||||
return ""
|
||||
elif segment.type == "priority_info":
|
||||
self.is_picid = False
|
||||
self.is_emoji = False
|
||||
self.is_voice = False
|
||||
if isinstance(segment.data, dict):
|
||||
# 处理优先级信息
|
||||
self.priority_mode = "priority"
|
||||
self.priority_info = segment.data
|
||||
"""
|
||||
{
|
||||
'message_type': 'vip', # vip or normal
|
||||
'message_priority': 1.0, # 优先级,大为优先,float
|
||||
}
|
||||
"""
|
||||
return ""
|
||||
elif segment.type == "file":
|
||||
if isinstance(segment.data, dict):
|
||||
file_name = segment.data.get('name', '未知文件')
|
||||
file_size = segment.data.get('size', '未知大小')
|
||||
return f"[文件:{file_name} ({file_size}字节)]"
|
||||
return "[收到一个文件]"
|
||||
elif segment.type == "video":
|
||||
self.is_picid = False
|
||||
self.is_emoji = False
|
||||
self.is_voice = False
|
||||
self.is_video = True
|
||||
logger.info(f"接收到视频消息,数据类型: {type(segment.data)}")
|
||||
|
||||
# 检查视频分析功能是否可用
|
||||
if not is_video_analysis_available():
|
||||
logger.warning("⚠️ Rust视频处理模块不可用,跳过视频分析")
|
||||
return "[视频]"
|
||||
|
||||
if global_config.video_analysis.enable:
|
||||
logger.info("已启用视频识别,开始识别")
|
||||
if isinstance(segment.data, dict):
|
||||
try:
|
||||
# 从Adapter接收的视频数据
|
||||
video_base64 = segment.data.get("base64")
|
||||
filename = segment.data.get("filename", "video.mp4")
|
||||
|
||||
logger.info(f"视频文件名: {filename}")
|
||||
logger.info(f"Base64数据长度: {len(video_base64) if video_base64 else 0}")
|
||||
|
||||
if video_base64:
|
||||
# 解码base64视频数据
|
||||
video_bytes = base64.b64decode(video_base64)
|
||||
logger.info(f"解码后视频大小: {len(video_bytes)} 字节")
|
||||
|
||||
# 使用video analyzer分析视频
|
||||
video_analyzer = get_video_analyzer()
|
||||
result = await video_analyzer.analyze_video_from_bytes(
|
||||
video_bytes, filename, prompt=global_config.video_analysis.batch_analysis_prompt
|
||||
)
|
||||
|
||||
logger.info(f"视频分析结果: {result}")
|
||||
|
||||
# 返回视频分析结果
|
||||
summary = result.get("summary", "")
|
||||
if summary:
|
||||
return f"[视频内容] {summary}"
|
||||
else:
|
||||
return "[已收到视频,但分析失败]"
|
||||
else:
|
||||
logger.warning("视频消息中没有base64数据")
|
||||
return "[收到视频消息,但数据异常]"
|
||||
except Exception as e:
|
||||
logger.error(f"视频处理失败: {e!s}")
|
||||
import traceback
|
||||
|
||||
logger.error(f"错误详情: {traceback.format_exc()}")
|
||||
return "[收到视频,但处理时出现错误]"
|
||||
else:
|
||||
logger.warning(f"视频消息数据不是字典格式: {type(segment.data)}")
|
||||
return "[发了一个视频,但格式不支持]"
|
||||
else:
|
||||
Reference in New Issue
Block a user