转换消息

pull/1195/head
UnCLAS-Prommer 2025-08-19 01:05:20 +08:00
parent 9379834171
commit 7a68ab0319
No known key found for this signature in database
3 changed files with 142 additions and 96 deletions

View File

@ -2,13 +2,14 @@ import time # 导入 time 模块以获取当前时间
import random import random
import re import re
from typing import List, Dict, Any, Tuple, Optional, Callable from typing import List, Dict, Any, Tuple, Optional, Callable, Union
from rich.traceback import install from rich.traceback import install
from src.config.config import global_config from src.config.config import global_config
from src.common.logger import get_logger from src.common.logger import get_logger
from src.common.message_repository import find_messages, count_messages from src.common.message_repository import find_messages, count_messages
from src.common.data_models.database_data_model import DatabaseMessages from src.common.data_models.database_data_model import DatabaseMessages
from src.common.data_models.message_data_model import MessageAndActionModel
from src.common.database.database_model import ActionRecords from src.common.database.database_model import ActionRecords
from src.common.database.database_model import Images from src.common.database.database_model import Images
from src.person_info.person_info import Person, get_person_id from src.person_info.person_info import Person, get_person_id
@ -394,7 +395,7 @@ def num_new_messages_since_with_users(
def _build_readable_messages_internal( def _build_readable_messages_internal(
messages: List[Dict[str, Any]], messages: List[MessageAndActionModel],
replace_bot_name: bool = True, replace_bot_name: bool = True,
merge_messages: bool = False, merge_messages: bool = False,
timestamp_mode: str = "relative", timestamp_mode: str = "relative",
@ -402,7 +403,7 @@ def _build_readable_messages_internal(
pic_id_mapping: Optional[Dict[str, str]] = None, pic_id_mapping: Optional[Dict[str, str]] = None,
pic_counter: int = 1, pic_counter: int = 1,
show_pic: bool = True, show_pic: bool = True,
message_id_list: Optional[List[Dict[str, Any]]] = None, message_id_list: Optional[List[DatabaseMessages]] = None,
) -> Tuple[str, List[Tuple[float, str, str]], Dict[str, str], int]: ) -> Tuple[str, List[Tuple[float, str, str]], Dict[str, str], int]:
""" """
内部辅助函数构建可读消息字符串和原始消息详情列表 内部辅助函数构建可读消息字符串和原始消息详情列表
@ -433,14 +434,15 @@ def _build_readable_messages_internal(
timestamp_to_id = {} timestamp_to_id = {}
if message_id_list: if message_id_list:
for item in message_id_list: for item in message_id_list:
message = item.get("message", {}) timestamp = item.time
timestamp = message.get("time")
if timestamp is not None: if timestamp is not None:
timestamp_to_id[timestamp] = item.get("id", "") timestamp_to_id[timestamp] = item.message_id
def process_pic_ids(content: str) -> str: def process_pic_ids(content: Optional[str]) -> str:
"""处理内容中的图片ID将其替换为[图片x]格式""" """处理内容中的图片ID将其替换为[图片x]格式"""
nonlocal current_pic_counter if content is None:
logger.warning("Content is None when processing pic IDs.")
raise ValueError("Content is None")
# 匹配 [picid:xxxxx] 格式 # 匹配 [picid:xxxxx] 格式
pic_pattern = r"\[picid:([^\]]+)\]" pic_pattern = r"\[picid:([^\]]+)\]"
@ -460,38 +462,23 @@ def _build_readable_messages_internal(
# 1 & 2: 获取发送者信息并提取消息组件 # 1 & 2: 获取发送者信息并提取消息组件
for msg in messages: for msg in messages:
# 检查是否是动作记录 # 检查是否是动作记录
if msg.get("is_action_record", False): if msg.is_action_record:
is_action = True is_action = True
timestamp: float = msg.get("time") # type: ignore timestamp: float = msg.time
content = msg.get("display_message", "") content = msg.display_message
# 对于动作记录也处理图片ID # 对于动作记录也处理图片ID
content = process_pic_ids(content) content = process_pic_ids(content)
message_details_raw.append((timestamp, global_config.bot.nickname, content, is_action)) message_details_raw.append((timestamp, global_config.bot.nickname, content, is_action))
continue continue
# 检查并修复缺少的user_info字段 platform = msg.user_platform
if "user_info" not in msg: user_id = msg.user_id
# 创建user_info字段
msg["user_info"] = {
"platform": msg.get("user_platform", ""),
"user_id": msg.get("user_id", ""),
"user_nickname": msg.get("user_nickname", ""),
"user_cardname": msg.get("user_cardname", ""),
}
user_info = msg.get("user_info", {}) user_nickname = msg.user_nickname
platform = user_info.get("platform") user_cardname = msg.user_cardname
user_id = user_info.get("user_id")
user_nickname = user_info.get("user_nickname") timestamp = msg.time
user_cardname = user_info.get("user_cardname") content = msg.display_message or msg.processed_plain_text or ""
timestamp: float = msg.get("time") # type: ignore
content: str
if msg.get("display_message"):
content = msg.get("display_message", "")
else:
content = msg.get("processed_plain_text", "") # 默认空字符串
if "" in content: if "" in content:
content = content.replace("", "") content = content.replace("", "")
@ -819,7 +806,7 @@ def build_readable_messages(
truncate: bool = False, truncate: bool = False,
show_actions: bool = False, show_actions: bool = False,
show_pic: bool = True, show_pic: bool = True,
message_id_list: Optional[List[Dict[str, Any]]] = None, message_id_list: Optional[List[DatabaseMessages]] = None,
) -> str: # sourcery skip: extract-method ) -> str: # sourcery skip: extract-method
""" """
将消息列表转换为可读的文本格式 将消息列表转换为可读的文本格式
@ -835,11 +822,24 @@ def build_readable_messages(
truncate: 是否截断长消息 truncate: 是否截断长消息
show_actions: 是否显示动作记录 show_actions: 是否显示动作记录
""" """
# WIP HERE and BELOW ----------------------------------------------
# 创建messages的深拷贝避免修改原始列表 # 创建messages的深拷贝避免修改原始列表
if not messages: if not messages:
return "" return ""
copy_messages = list(messages) copy_messages: List[MessageAndActionModel] = [
MessageAndActionModel(
msg.time,
msg.user_info.user_id,
msg.user_info.platform,
msg.user_info.user_nickname,
msg.user_info.user_cardname,
msg.processed_plain_text,
msg.display_message,
msg.chat_info.platform,
)
for msg in messages
]
if show_actions and copy_messages: if show_actions and copy_messages:
# 获取所有消息的时间范围 # 获取所有消息的时间范围
@ -847,7 +847,7 @@ def build_readable_messages(
max_time = max(msg.time or 0 for msg in copy_messages) max_time = max(msg.time or 0 for msg in copy_messages)
# 从第一条消息中获取chat_id # 从第一条消息中获取chat_id
chat_id = copy_messages[0].chat_id if copy_messages else None chat_id = messages[0].chat_id if messages else None
# 获取这个时间范围内的动作记录并匹配chat_id # 获取这个时间范围内的动作记录并匹配chat_id
actions_in_range = ( actions_in_range = (
@ -867,23 +867,24 @@ def build_readable_messages(
) )
# 合并两部分动作记录 # 合并两部分动作记录
actions = list(actions_in_range) + list(action_after_latest) actions: List[ActionRecords] = list(actions_in_range) + list(action_after_latest)
# 将动作记录转换为消息格式 # 将动作记录转换为消息格式
for action in actions: for action in actions:
# 只有当build_into_prompt为True时才添加动作记录 # 只有当build_into_prompt为True时才添加动作记录
if action.action_build_into_prompt: if action.action_build_into_prompt:
action_msg = { action_msg = MessageAndActionModel(
"time": action.time, time=float(action.time), # type: ignore
"user_id": global_config.bot.qq_account, # 使用机器人的QQ账号 user_id=global_config.bot.qq_account, # 使用机器人的QQ账号
"user_nickname": global_config.bot.nickname, # 使用机器人的昵称 user_platform=global_config.bot.platform, # 使用机器人的平台
"user_cardname": "", # 机器人没有群名片 user_nickname=global_config.bot.nickname, # 使用机器人的用户名
"processed_plain_text": f"{action.action_prompt_display}", user_cardname="", # 机器人没有群名片
"display_message": f"{action.action_prompt_display}", processed_plain_text=f"{action.action_prompt_display}",
"chat_info_platform": action.chat_info_platform, display_message=f"{action.action_prompt_display}",
"is_action_record": True, # 添加标识字段 chat_info_platform=str(action.chat_info_platform),
"action_name": action.action_name, # 保存动作名称 is_action_record=True, # 添加标识字段
} action_name=str(action.action_name), # 保存动作名称
)
copy_messages.append(action_msg) copy_messages.append(action_msg)
# 重新按时间排序 # 重新按时间排序

View File

@ -56,70 +56,99 @@ class DatabaseChatInfo(AbstractClassFlag):
@dataclass(init=False) @dataclass(init=False)
class DatabaseMessages(AbstractClassFlag): class DatabaseMessages(AbstractClassFlag):
message_id: str = field(default_factory=str) def __init__(
time: float = field(default_factory=float) self,
chat_id: str = field(default_factory=str) message_id: str = "",
reply_to: Optional[str] = None time: float = 0.0,
interest_value: Optional[float] = None chat_id: str = "",
reply_to: Optional[str] = None,
interest_value: Optional[float] = None,
key_words: Optional[str] = None,
key_words_lite: Optional[str] = None,
is_mentioned: Optional[bool] = None,
processed_plain_text: Optional[str] = None,
display_message: Optional[str] = None,
priority_mode: Optional[str] = None,
priority_info: Optional[str] = None,
additional_config: Optional[str] = None,
is_emoji: bool = False,
is_picid: bool = False,
is_command: bool = False,
is_notify: bool = False,
selected_expressions: Optional[str] = None,
user_id: str = "",
user_nickname: str = "",
user_cardname: Optional[str] = None,
user_platform: str = "",
chat_info_group_id: Optional[str] = None,
chat_info_group_name: Optional[str] = None,
chat_info_group_platform: Optional[str] = None,
chat_info_user_id: str = "",
chat_info_user_nickname: str = "",
chat_info_user_cardname: Optional[str] = None,
chat_info_user_platform: str = "",
chat_info_stream_id: str = "",
chat_info_platform: str = "",
chat_info_create_time: float = 0.0,
chat_info_last_active_time: float = 0.0,
**kwargs: Any,
):
self.message_id = message_id
self.time = time
self.chat_id = chat_id
self.reply_to = reply_to
self.interest_value = interest_value
key_words: Optional[str] = None self.key_words = key_words
key_words_lite: Optional[str] = None self.key_words_lite = key_words_lite
is_mentioned: Optional[bool] = None self.is_mentioned = is_mentioned
processed_plain_text: Optional[str] = None # 处理后的纯文本消息 self.processed_plain_text = processed_plain_text
display_message: Optional[str] = None # 显示的消息 self.display_message = display_message
priority_mode: Optional[str] = None self.priority_mode = priority_mode
priority_info: Optional[str] = None self.priority_info = priority_info
additional_config: Optional[str] = None self.additional_config = additional_config
is_emoji: bool = False self.is_emoji = is_emoji
is_picid: bool = False self.is_picid = is_picid
is_command: bool = False self.is_command = is_command
is_notify: bool = False self.is_notify = is_notify
selected_expressions: Optional[str] = None self.selected_expressions = selected_expressions
def __init__(self, **kwargs: Any): self.group_info: Optional[DatabaseGroupInfo] = None
defined = {f.name: f for f in fields(self.__class__)}
for name, f in defined.items():
if name in kwargs:
setattr(self, name, kwargs.pop(name))
elif f.default is not MISSING:
setattr(self, name, f.default)
else:
raise TypeError(f"缺失必需字段: {name}")
self.group_info = None
self.user_info = DatabaseUserInfo( self.user_info = DatabaseUserInfo(
user_id=kwargs.get("user_id"), # type: ignore user_id=user_id,
user_nickname=kwargs.get("user_nickname"), # type: ignore user_nickname=user_nickname,
user_cardname=kwargs.get("user_cardname"), # type: ignore user_cardname=user_cardname,
platform=kwargs.get("user_platform"), # type: ignore platform=user_platform,
) )
if kwargs.get("chat_info_group_id") and kwargs.get("chat_info_group_name"): if chat_info_group_id and chat_info_group_name:
self.group_info = DatabaseGroupInfo( self.group_info = DatabaseGroupInfo(
group_id=kwargs.get("chat_info_group_id"), # type: ignore group_id=chat_info_group_id,
group_name=kwargs.get("chat_info_group_name"), # type: ignore group_name=chat_info_group_name,
group_platform=kwargs.get("chat_info_group_platform"), # type: ignore group_platform=chat_info_group_platform,
) )
chat_user_info = DatabaseUserInfo(
user_id=kwargs.get("chat_info_user_id"), # type: ignore
user_nickname=kwargs.get("chat_info_user_nickname"), # type: ignore
user_cardname=kwargs.get("chat_info_user_cardname"), # type: ignore
platform=kwargs.get("chat_info_user_platform"), # type: ignore
)
self.chat_info = DatabaseChatInfo( self.chat_info = DatabaseChatInfo(
stream_id=kwargs.get("chat_info_stream_id"), # type: ignore stream_id=chat_info_stream_id,
platform=kwargs.get("chat_info_platform"), # type: ignore platform=chat_info_platform,
create_time=kwargs.get("chat_info_create_time"), # type: ignore create_time=chat_info_create_time,
last_active_time=kwargs.get("chat_info_last_active_time"), # type: ignore last_active_time=chat_info_last_active_time,
user_info=chat_user_info, user_info=DatabaseUserInfo(
user_id=chat_info_user_id,
user_nickname=chat_info_user_nickname,
user_cardname=chat_info_user_cardname,
platform=chat_info_user_platform,
),
group_info=self.group_info, group_info=self.group_info,
) )
if kwargs:
for key, value in kwargs.items():
setattr(self, key, value)
# def __post_init__(self): # def __post_init__(self):
# assert isinstance(self.message_id, str), "message_id must be a string" # assert isinstance(self.message_id, str), "message_id must be a string"
# assert isinstance(self.time, float), "time must be a float" # assert isinstance(self.time, float), "time must be a float"

View File

@ -0,0 +1,16 @@
from typing import Optional
from dataclasses import dataclass, field
@dataclass
class MessageAndActionModel:
time: float = field(default_factory=float)
user_id: str = field(default_factory=str)
user_platform: str = field(default_factory=str)
user_nickname: str = field(default_factory=str)
user_cardname: Optional[str] = None
processed_plain_text: Optional[str] = None
display_message: Optional[str] = None
chat_info_platform: str = field(default_factory=str)
is_action_record: bool = field(default=False)
action_name: Optional[str] = None