feat: prefer qq group cards across messaging

pull/1334/head
magisk317 2025-10-29 18:10:03 +08:00
parent 4d5456ed4b
commit ae1a1d4a56
8 changed files with 58 additions and 22 deletions

View File

@ -81,12 +81,14 @@ class HeartFCMessageReceiver:
# if not processed_plain_text: # if not processed_plain_text:
# print(message) # print(message)
logger.info(f"[{mes_name}]{userinfo.user_nickname}:{processed_plain_text}") # type: ignore display_name = userinfo.user_cardname or userinfo.user_nickname # type: ignore
logger.info(f"[{mes_name}]{display_name}:{processed_plain_text}") # type: ignore
preferred_name = display_name or userinfo.user_nickname # type: ignore
_ = Person.register_person( _ = Person.register_person(
platform=message.message_info.platform, # type: ignore platform=message.message_info.platform, # type: ignore
user_id=message.message_info.user_info.user_id, # type: ignore user_id=message.message_info.user_info.user_id, # type: ignore
nickname=userinfo.user_nickname, # type: ignore nickname=preferred_name, # type: ignore
) )
except Exception as e: except Exception as e:

View File

@ -40,7 +40,8 @@ def _check_ban_words(text: str, userinfo: UserInfo, group_info: Optional[GroupIn
for word in global_config.message_receive.ban_words: for word in global_config.message_receive.ban_words:
if word in text: if word in text:
chat_name = group_info.group_name if group_info else "私聊" chat_name = group_info.group_name if group_info else "私聊"
logger.info(f"[{chat_name}]{userinfo.user_nickname}:{text}") display_name = userinfo.user_cardname or userinfo.user_nickname
logger.info(f"[{chat_name}]{display_name}:{text}")
logger.info(f"[过滤词识别]消息中含有{word}filtered") logger.info(f"[过滤词识别]消息中含有{word}filtered")
return True return True
return False return False
@ -64,7 +65,8 @@ def _check_ban_regex(text: str, userinfo: UserInfo, group_info: Optional[GroupIn
for pattern in global_config.message_receive.ban_msgs_regex: for pattern in global_config.message_receive.ban_msgs_regex:
if re.search(pattern, text): if re.search(pattern, text):
chat_name = group_info.group_name if group_info else "私聊" chat_name = group_info.group_name if group_info else "私聊"
logger.info(f"[{chat_name}]{userinfo.user_nickname}:{text}") display_name = userinfo.user_cardname or userinfo.user_nickname
logger.info(f"[{chat_name}]{display_name}:{text}")
logger.info(f"[正则表达式过滤]消息匹配到{pattern}filtered") logger.info(f"[正则表达式过滤]消息匹配到{pattern}filtered")
return True return True
return False return False
@ -206,6 +208,13 @@ class ChatBot:
group_info = message.message_info.group_info group_info = message.message_info.group_info
user_info = message.message_info.user_info user_info = message.message_info.user_info
if (
group_info
and user_info
and (not user_info.user_cardname or not str(user_info.user_cardname).strip())
):
user_info.user_cardname = user_info.user_nickname or ""
continue_flag, modified_message = await events_manager.handle_mai_events( continue_flag, modified_message = await events_manager.handle_mai_events(
EventType.ON_MESSAGE_PRE_PROCESS, message EventType.ON_MESSAGE_PRE_PROCESS, message
) )

View File

@ -313,8 +313,10 @@ class ChatManager:
if stream.group_info and stream.group_info.group_name: if stream.group_info and stream.group_info.group_name:
return stream.group_info.group_name return stream.group_info.group_name
elif stream.user_info and stream.user_info.user_nickname: elif stream.user_info:
return f"{stream.user_info.user_nickname}的私聊" display_name = stream.user_info.user_cardname or stream.user_info.user_nickname
if display_name:
return f"{display_name}的私聊"
else: else:
return None return None

View File

@ -283,7 +283,11 @@ class MessageProcessBase(Message):
if self.reply and hasattr(self.reply, "processed_plain_text"): if self.reply and hasattr(self.reply, "processed_plain_text"):
# print(f"self.reply.processed_plain_text: {self.reply.processed_plain_text}") # print(f"self.reply.processed_plain_text: {self.reply.processed_plain_text}")
# print(f"reply: {self.reply}") # 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 reply_user_info = self.reply.message_info.user_info # type: ignore
reply_name = reply_user_info.user_cardname or reply_user_info.user_nickname # type: ignore
return (
f"[回复<{reply_name}:{reply_user_info.user_id}> 的消息:{self.reply.processed_plain_text}]"
) # type: ignore
return "" return ""
else: else:
return f"[{segment.type}:{str(segment.data)}]" return f"[{segment.type}:{str(segment.data)}]"

View File

@ -413,7 +413,8 @@ def _build_readable_messages_internal(
if message.is_action_record: if message.is_action_record:
# 对于动作记录也处理图片ID # 对于动作记录也处理图片ID
content = process_pic_ids(message.display_message) content = process_pic_ids(message.display_message)
detailed_messages_raw.append((message.time, message.user_nickname, content, True)) action_name = message.user_cardname or message.user_nickname or "系统"
detailed_messages_raw.append((message.time, action_name, content, True))
continue continue
platform = message.user_platform platform = message.user_platform
@ -434,9 +435,9 @@ def _build_readable_messages_internal(
person = Person(platform=platform, user_id=user_id) person = Person(platform=platform, user_id=user_id)
# 根据 replace_bot_name 参数决定是否替换机器人名称 # 根据 replace_bot_name 参数决定是否替换机器人名称
person_name = ( preferred_display = user_cardname or user_nickname
person.person_name or f"{user_nickname}" or (f"昵称:{user_cardname}" if user_cardname else "某人") fallback_display = user_nickname or user_cardname or "某人"
) person_name = person.person_name or preferred_display or fallback_display
if replace_bot_name and ( if replace_bot_name and (
(platform == global_config.bot.platform and user_id == global_config.bot.qq_account) (platform == global_config.bot.platform and user_id == global_config.bot.qq_account)
or (platform == "telegram" and user_id == getattr(global_config.bot, "telegram_account", "")) or (platform == "telegram" and user_id == getattr(global_config.bot, "telegram_account", ""))

View File

@ -480,7 +480,7 @@ class StatisticOutputTask(AsyncTask):
elif message.user_id: # Fallback to sender's info for chat_id if not a group_info based chat elif message.user_id: # Fallback to sender's info for chat_id if not a group_info based chat
# This uses the message SENDER's ID as per original logic's fallback # This uses the message SENDER's ID as per original logic's fallback
chat_id = f"u{message.user_id}" # SENDER's user_id chat_id = f"u{message.user_id}" # SENDER's user_id
chat_name = message.user_nickname # SENDER's nickname chat_name = message.user_cardname or message.user_nickname # SENDER's display name
else: else:
# If neither group_id nor sender_id is available for chat identification # If neither group_id nor sender_id is available for chat identification
logger.warning( logger.warning(
@ -704,7 +704,7 @@ class StatisticOutputTask(AsyncTask):
if group_name and group_name.strip(): if group_name and group_name.strip():
return group_name.strip() return group_name.strip()
elif stream.user_info and hasattr(stream.user_info, "user_nickname"): elif stream.user_info and hasattr(stream.user_info, "user_nickname"):
user_name = stream.user_info.user_nickname user_name = stream.user_info.user_cardname or stream.user_info.user_nickname
if user_name and user_name.strip(): if user_name and user_name.strip():
return user_name.strip() return user_name.strip()
@ -1293,7 +1293,7 @@ class StatisticOutputTask(AsyncTask):
if message.chat_info_group_id: if message.chat_info_group_id:
chat_name = message.chat_info_group_name or f"{message.chat_info_group_id}" chat_name = message.chat_info_group_name or f"{message.chat_info_group_id}"
elif message.user_id: elif message.user_id:
chat_name = message.user_nickname or f"用户{message.user_id}" chat_name = (message.user_cardname or message.user_nickname) or f"用户{message.user_id}"
else: else:
continue continue

View File

@ -585,10 +585,11 @@ def get_chat_type_and_target_info(chat_id: str) -> Tuple[bool, Optional["TargetP
from src.common.data_models.info_data_model import TargetPersonInfo # 解决循环导入问题 from src.common.data_models.info_data_model import TargetPersonInfo # 解决循环导入问题
# Initialize target_info with basic info # Initialize target_info with basic info
display_name = user_info.user_cardname or user_info.user_nickname # type: ignore
target_info = TargetPersonInfo( target_info = TargetPersonInfo(
platform=platform, platform=platform,
user_id=user_id, user_id=user_id,
user_nickname=user_info.user_nickname, # type: ignore user_nickname=display_name, # type: ignore
person_id=None, person_id=None,
person_name=None, person_name=None,
) )
@ -597,7 +598,7 @@ def get_chat_type_and_target_info(chat_id: str) -> Tuple[bool, Optional["TargetP
try: try:
person = Person(platform=platform, user_id=user_id) person = Person(platform=platform, user_id=user_id)
if not person.is_known: if not person.is_known:
logger.warning(f"用户 {user_info.user_nickname} 尚未认识") logger.warning(f"用户 {display_name} 尚未认识")
# 如果用户尚未认识则返回False和None # 如果用户尚未认识则返回False和None
return False, None return False, None
if person.person_id: if person.person_id:

View File

@ -173,7 +173,11 @@ class Person:
Returns: Returns:
Person: 新注册的Person实例 Person: 新注册的Person实例
""" """
if not platform or not user_id or not nickname: display_name = (nickname or "").strip()
if not display_name:
display_name = f"用户{user_id}" if user_id else "未知用户"
if not platform or not user_id:
logger.error("注册用户失败platform、user_id 和 nickname 都是必需参数") logger.error("注册用户失败platform、user_id 和 nickname 都是必需参数")
return None return None
@ -181,8 +185,21 @@ class Person:
person_id = get_person_id(platform, user_id) person_id = get_person_id(platform, user_id)
if is_person_known(person_id=person_id): if is_person_known(person_id=person_id):
logger.debug(f"用户 {nickname} 已存在") person = Person(person_id=person_id)
return Person(person_id=person_id) if not person or not person.is_known:
return person
old_nickname = person.nickname or ""
old_person_name = person.person_name
if display_name != old_nickname:
person.nickname = display_name
if not old_person_name or old_person_name == old_nickname:
person.person_name = display_name
person.sync_to_database()
logger.debug(
f"更新用户 {person_id} 的昵称信息: '{old_nickname}' -> '{display_name}'"
)
return person
# 创建Person实例 # 创建Person实例
person = cls.__new__(cls) person = cls.__new__(cls)
@ -191,11 +208,11 @@ class Person:
person.person_id = person_id person.person_id = person_id
person.platform = platform person.platform = platform
person.user_id = user_id person.user_id = user_id
person.nickname = nickname person.nickname = display_name
# 初始化默认值 # 初始化默认值
person.is_known = True # 注册后立即标记为已认识 person.is_known = True # 注册后立即标记为已认识
person.person_name = nickname # 使用nickname作为初始person_name person.person_name = display_name # 使用nickname作为初始person_name
person.name_reason = "用户注册时设置的昵称" person.name_reason = "用户注册时设置的昵称"
person.know_times = 1 person.know_times = 1
person.know_since = time.time() person.know_since = time.time()
@ -205,7 +222,7 @@ class Person:
# 同步到数据库 # 同步到数据库
person.sync_to_database() person.sync_to_database()
logger.info(f"成功注册新用户:{person_id},平台:{platform},昵称:{nickname}") logger.info(f"成功注册新用户:{person_id},平台:{platform},昵称:{display_name}")
return person return person