feat(chat): 统一消息格式信息处理逻辑
在多个消息处理模块中统一了 format_info 的处理方式,确保适配器支持的消息类型能够正确传递给 action_modifier: - 在 bot.py、chat_stream.py、optimized_chat_stream.py 中新增 _prepare_additional_config 方法 - 将 format_info 嵌入到 additional_config 中,确保数据库存储一致性 - 增强 action_modifier 中的适配器类型检查逻辑,添加更详细的错误日志 - 修复 storage.py 中的 additional_config 处理逻辑,避免覆盖原始配置 这些改进确保了 Action 能够正确检查适配器支持的消息类型,避免因缺少 format_info 导致的类型检查失败。
This commit is contained in:
@@ -659,6 +659,41 @@ class ChatBot:
|
||||
group_name = getattr(group_info, "group_name", None)
|
||||
group_platform = getattr(group_info, "platform", None)
|
||||
|
||||
# 准备 additional_config,将 format_info 嵌入其中
|
||||
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 = {}
|
||||
|
||||
# 然后添加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"[bot.py] 嵌入 format_info 到 additional_config: {format_info_dict}")
|
||||
except Exception as e:
|
||||
logger.warning(f"将 format_info 转换为字典失败: {e}")
|
||||
else:
|
||||
logger.warning(f"[bot.py] [问题] 消息缺少 format_info: message_id={message_id}")
|
||||
|
||||
# 序列化为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,
|
||||
@@ -674,6 +709,7 @@ class ChatBot:
|
||||
is_notify=bool(message.is_notify),
|
||||
is_public_notice=bool(message.is_public_notice),
|
||||
notice_type=message.notice_type,
|
||||
additional_config=additional_config_str,
|
||||
user_id=user_id,
|
||||
user_nickname=user_nickname,
|
||||
user_cardname=user_cardname,
|
||||
|
||||
@@ -213,8 +213,8 @@ class ChatStream:
|
||||
priority_info=json.dumps(getattr(message, "priority_info", None))
|
||||
if getattr(message, "priority_info", None)
|
||||
else None,
|
||||
# 额外配置
|
||||
additional_config=getattr(message_info, "additional_config", None),
|
||||
# 额外配置 - 需要将 format_info 嵌入到 additional_config 中
|
||||
additional_config=self._prepare_additional_config(message_info),
|
||||
# 用户信息
|
||||
user_id=str(getattr(user_info, "user_id", "")),
|
||||
user_nickname=getattr(user_info, "user_nickname", ""),
|
||||
@@ -253,8 +253,59 @@ class ChatStream:
|
||||
f"interest_value: {db_message.interest_value}"
|
||||
)
|
||||
|
||||
def _prepare_additional_config(self, message_info) -> str | None:
|
||||
"""
|
||||
准备 additional_config,将 format_info 嵌入其中
|
||||
|
||||
这个方法模仿 storage.py 中的逻辑,确保 DatabaseMessages 中的 additional_config
|
||||
包含 format_info,使得 action_modifier 能够正确获取适配器支持的消息类型
|
||||
|
||||
Args:
|
||||
message_info: BaseMessageInfo 对象
|
||||
|
||||
Returns:
|
||||
str | None: JSON 字符串格式的 additional_config,如果为空则返回 None
|
||||
"""
|
||||
import orjson
|
||||
|
||||
# 首先获取adapter传递的additional_config
|
||||
additional_config_data = {}
|
||||
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 = {}
|
||||
|
||||
# 然后添加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"嵌入 format_info 到 additional_config: {format_info_dict}")
|
||||
except Exception as e:
|
||||
logger.warning(f"将 format_info 转换为字典失败: {e}")
|
||||
else:
|
||||
logger.warning(f"[问题] 消息缺少 format_info: message_id={getattr(message_info, 'message_id', 'unknown')}")
|
||||
logger.warning("[问题] 这可能导致 Action 无法正确检查适配器支持的类型")
|
||||
|
||||
# 序列化为JSON字符串
|
||||
if additional_config_data:
|
||||
try:
|
||||
return orjson.dumps(additional_config_data).decode("utf-8")
|
||||
except Exception as e:
|
||||
logger.error(f"序列化 additional_config 失败: {e}")
|
||||
return None
|
||||
return None
|
||||
|
||||
def _safe_get_actions(self, message: "MessageRecv") -> list | None:
|
||||
"""安全获取消息的actions字段"""
|
||||
import json
|
||||
|
||||
try:
|
||||
actions = getattr(message, "actions", None)
|
||||
if actions is None:
|
||||
@@ -263,8 +314,6 @@ class ChatStream:
|
||||
# 如果是字符串,尝试解析为JSON
|
||||
if isinstance(actions, str):
|
||||
try:
|
||||
import json
|
||||
|
||||
actions = json.loads(actions)
|
||||
except json.JSONDecodeError:
|
||||
logger.warning(f"无法解析actions JSON字符串: {actions}")
|
||||
|
||||
@@ -230,7 +230,7 @@ class OptimizedChatStream:
|
||||
priority_info=json.dumps(getattr(message, "priority_info", None))
|
||||
if getattr(message, "priority_info", None)
|
||||
else None,
|
||||
additional_config=getattr(message_info, "additional_config", None),
|
||||
additional_config=self._prepare_additional_config(message_info),
|
||||
user_id=str(getattr(user_info, "user_id", "")),
|
||||
user_nickname=getattr(user_info, "user_nickname", ""),
|
||||
user_cardname=getattr(user_info, "user_cardname", None),
|
||||
@@ -342,8 +342,59 @@ class OptimizedChatStream:
|
||||
|
||||
return instance
|
||||
|
||||
def _prepare_additional_config(self, message_info) -> str | None:
|
||||
"""
|
||||
准备 additional_config,将 format_info 嵌入其中
|
||||
|
||||
这个方法模仿 storage.py 中的逻辑,确保 DatabaseMessages 中的 additional_config
|
||||
包含 format_info,使得 action_modifier 能够正确获取适配器支持的消息类型
|
||||
|
||||
Args:
|
||||
message_info: BaseMessageInfo 对象
|
||||
|
||||
Returns:
|
||||
str | None: JSON 字符串格式的 additional_config,如果为空则返回 None
|
||||
"""
|
||||
import orjson
|
||||
|
||||
# 首先获取adapter传递的additional_config
|
||||
additional_config_data = {}
|
||||
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 = {}
|
||||
|
||||
# 然后添加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"嵌入 format_info 到 additional_config: {format_info_dict}")
|
||||
except Exception as e:
|
||||
logger.warning(f"将 format_info 转换为字典失败: {e}")
|
||||
else:
|
||||
logger.warning(f"[问题] 消息缺少 format_info: message_id={getattr(message_info, 'message_id', 'unknown')}")
|
||||
logger.warning("[问题] 这可能导致 Action 无法正确检查适配器支持的类型")
|
||||
|
||||
# 序列化为JSON字符串
|
||||
if additional_config_data:
|
||||
try:
|
||||
return orjson.dumps(additional_config_data).decode("utf-8")
|
||||
except Exception as e:
|
||||
logger.error(f"序列化 additional_config 失败: {e}")
|
||||
return None
|
||||
return None
|
||||
|
||||
def _safe_get_actions(self, message: "MessageRecv") -> list | None:
|
||||
"""安全获取消息的actions字段"""
|
||||
import json
|
||||
|
||||
try:
|
||||
actions = getattr(message, "actions", None)
|
||||
if actions is None:
|
||||
@@ -351,8 +402,6 @@ class OptimizedChatStream:
|
||||
|
||||
if isinstance(actions, str):
|
||||
try:
|
||||
import json
|
||||
|
||||
actions = json.loads(actions)
|
||||
except json.JSONDecodeError:
|
||||
logger.warning(f"无法解析actions JSON字符串: {actions}")
|
||||
|
||||
@@ -100,16 +100,22 @@ class MessageStorage:
|
||||
priority_info_json = orjson.dumps(priority_info).decode("utf-8") if priority_info else None
|
||||
|
||||
# 准备additional_config,包含format_info和其他配置
|
||||
additional_config_data = {}
|
||||
additional_config_data = None
|
||||
|
||||
# 保存format_info到additional_config中
|
||||
# 首先获取adapter传递的additional_config
|
||||
if hasattr(message.message_info, 'additional_config') and message.message_info.additional_config:
|
||||
additional_config_data = message.message_info.additional_config.copy() # 避免修改原始对象
|
||||
else:
|
||||
additional_config_data = {}
|
||||
|
||||
# 然后添加format_info到additional_config中
|
||||
if hasattr(message.message_info, 'format_info') and message.message_info.format_info:
|
||||
format_info_dict = message.message_info.format_info.to_dict()
|
||||
additional_config_data["format_info"] = format_info_dict
|
||||
|
||||
# 合并adapter传递的其他additional_config
|
||||
if hasattr(message.message_info, 'additional_config') and message.message_info.additional_config:
|
||||
additional_config_data.update(message.message_info.additional_config)
|
||||
logger.debug(f"保存format_info: {format_info_dict}")
|
||||
else:
|
||||
logger.warning(f"[问题] 消息缺少format_info: message_id={getattr(message.message_info, 'message_id', 'unknown')}")
|
||||
logger.warning("[问题] 这可能导致Action无法正确检查适配器支持的类型")
|
||||
|
||||
# 序列化为JSON字符串以便存储
|
||||
additional_config_json = orjson.dumps(additional_config_data).decode("utf-8") if additional_config_data else None
|
||||
|
||||
@@ -223,12 +223,32 @@ class ActionModifier:
|
||||
list[str]: 支持的输出类型列表
|
||||
"""
|
||||
# 检查additional_config是否存在且不为空
|
||||
if (chat_context.current_message
|
||||
and hasattr(chat_context.current_message, "additional_config")
|
||||
and chat_context.current_message.additional_config):
|
||||
additional_config = None
|
||||
has_additional_config = False
|
||||
|
||||
# 先检查 current_message 是否存在
|
||||
if not chat_context.current_message:
|
||||
logger.warning(f"{self.log_prefix} [问题] chat_context.current_message 为 None,无法获取适配器支持的类型")
|
||||
return ["text", "emoji"] # 返回基础类型
|
||||
|
||||
if hasattr(chat_context.current_message, "additional_config"):
|
||||
additional_config = chat_context.current_message.additional_config
|
||||
|
||||
# 更准确的非空判断
|
||||
if additional_config is not None:
|
||||
if isinstance(additional_config, str) and additional_config.strip():
|
||||
has_additional_config = True
|
||||
elif isinstance(additional_config, dict):
|
||||
# 字典存在就可以,即使为空也可能有format_info字段
|
||||
has_additional_config = True
|
||||
else:
|
||||
logger.warning(f"{self.log_prefix} [问题] current_message 没有 additional_config 属性")
|
||||
|
||||
logger.debug(f"{self.log_prefix} [调试] has_additional_config: {has_additional_config}")
|
||||
|
||||
if has_additional_config:
|
||||
try:
|
||||
additional_config = chat_context.current_message.additional_config
|
||||
logger.debug(f"{self.log_prefix} [调试] 开始解析 additional_config")
|
||||
format_info = None
|
||||
|
||||
# 处理additional_config可能是字符串或字典的情况
|
||||
@@ -237,8 +257,7 @@ class ActionModifier:
|
||||
try:
|
||||
config = orjson.loads(additional_config)
|
||||
format_info = config.get("format_info")
|
||||
except (orjson.JSONDecodeError, AttributeError, TypeError):
|
||||
logger.debug("无法解析additional_config JSON字符串")
|
||||
except (orjson.JSONDecodeError, AttributeError, TypeError) as e:
|
||||
format_info = None
|
||||
|
||||
elif isinstance(additional_config, dict):
|
||||
@@ -247,7 +266,6 @@ class ActionModifier:
|
||||
|
||||
# 如果找到了format_info,从中提取支持的类型
|
||||
if format_info:
|
||||
# 优先检查accept_format字段
|
||||
if "accept_format" in format_info:
|
||||
accept_format = format_info["accept_format"]
|
||||
if isinstance(accept_format, str):
|
||||
@@ -258,11 +276,13 @@ class ActionModifier:
|
||||
accept_format = list(accept_format) if hasattr(accept_format, "__iter__") else []
|
||||
|
||||
# 合并基础类型和适配器特定类型
|
||||
return list(set(accept_format))
|
||||
result = list(set(accept_format))
|
||||
return result
|
||||
|
||||
# 备用检查content_format字段
|
||||
elif "content_format" in format_info:
|
||||
content_format = format_info["content_format"]
|
||||
logger.debug(f"{self.log_prefix} [调试] 找到 content_format: {content_format}")
|
||||
if isinstance(content_format, str):
|
||||
content_format = [content_format]
|
||||
elif isinstance(content_format, list):
|
||||
@@ -270,10 +290,25 @@ class ActionModifier:
|
||||
else:
|
||||
content_format = list(content_format) if hasattr(content_format, "__iter__") else []
|
||||
|
||||
return list(set(content_format))
|
||||
|
||||
result = list(set(content_format))
|
||||
return result
|
||||
else:
|
||||
logger.warning(f"{self.log_prefix} [问题] additional_config 中没有 format_info 字段")
|
||||
except Exception as e:
|
||||
logger.debug(f"解析适配器格式信息失败,使用默认支持类型: {e}")
|
||||
logger.error(f"{self.log_prefix} [问题] 解析适配器格式信息失败: {e}", exc_info=True)
|
||||
else:
|
||||
logger.warning(f"{self.log_prefix} [问题] additional_config 不存在或为空")
|
||||
|
||||
# 如果无法获取格式信息,返回默认支持的基础类型
|
||||
default_types = ["text", "emoji"]
|
||||
logger.warning(
|
||||
f"{self.log_prefix} [问题] 无法从适配器获取支持的消息类型,使用默认类型: {default_types}"
|
||||
)
|
||||
logger.warning(
|
||||
f"{self.log_prefix} [问题] 这可能导致某些 Action 被错误地过滤。"
|
||||
f"请检查适配器是否正确设置了 format_info。"
|
||||
)
|
||||
return default_types
|
||||
|
||||
|
||||
async def _get_deactivated_actions_by_type(
|
||||
|
||||
Reference in New Issue
Block a user