From 6c9b99afcf628d4669416decc14ce051173a3e56 Mon Sep 17 00:00:00 2001 From: liuwei Date: Wed, 28 May 2025 15:33:23 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=81=94=E7=B3=BB=E4=BA=BA?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=EF=BC=8C=E8=A7=A3=E5=86=B3=E6=80=BB=E7=BB=93?= =?UTF-8?q?=E6=97=B6=E4=BD=BF=E7=94=A8=E4=BA=86=E5=85=B6=E4=BB=96=E7=BE=A4?= =?UTF-8?q?=E7=9A=84=E5=A4=87=E6=B3=A8=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- configuration.py | 17 ++---------- constants.py | 27 ------------------ db/contacts_db.py | 43 +++++++++++++++++++---------- plugins/group_member_change/main.py | 5 +++- plugins/message_summary/main.py | 10 +++++-- robot.py | 20 ++++++++------ utils/wechat/contact_manager.py | 41 +++++++++++++++++++++++++-- 7 files changed, 91 insertions(+), 72 deletions(-) delete mode 100644 constants.py diff --git a/configuration.py b/configuration.py index d95faf3..77309c9 100644 --- a/configuration.py +++ b/configuration.py @@ -3,7 +3,6 @@ import logging.config import os -import shutil import yaml @@ -14,26 +13,14 @@ class Config(object): def _load_config(self) -> dict: pwd = os.path.dirname(os.path.abspath(__file__)) - try: - with open(f"{pwd}/config.yaml", "rb") as fp: - yconfig = yaml.safe_load(fp) - except FileNotFoundError: - shutil.copyfile(f"{pwd}/config.yaml.template", f"{pwd}/config.yaml") - with open(f"{pwd}/config.yaml", "rb") as fp: - yconfig = yaml.safe_load(fp) - + with open(f"{pwd}/config.yaml", "rb") as fp: + yconfig = yaml.safe_load(fp) return yconfig def reload(self) -> None: yconfig = self._load_config() logging.config.dictConfig(yconfig["logging"]) - self.CHATGPT = yconfig.get("chatgpt", {}) - self.TIGERBOT = yconfig.get("tigerbot", {}) - self.XINGHUO_WEB = yconfig.get("xinghuo_web", {}) - self.CHATGLM = yconfig.get("chatglm", {}) - self.BardAssistant = yconfig.get("bard", {}) - self.ZhiPu = yconfig.get("zhipu", {}) self.CLAUDE = yconfig.get("claude", {}) self.DEEPSEEK = yconfig.get("deepseek", {}) self.DOUBAO = yconfig.get("doubao", {}) diff --git a/constants.py b/constants.py deleted file mode 100644 index a5404fa..0000000 --- a/constants.py +++ /dev/null @@ -1,27 +0,0 @@ -from enum import IntEnum, unique - - -@unique -class ChatType(IntEnum): - # UnKnown = 0 # 未知, 即未设置 - TIGER_BOT = 1 # TigerBot - CHATGPT = 2 # ChatGPT - XINGHUO_WEB = 3 # 讯飞星火 - CHATGLM = 4 # ChatGLM - BardAssistant = 5 # Google Bard - ZhiPu = 6 # ZhiPu - CLAUDE = 7 # CLAUDE - DOUBAO = 8 # doubao - - @staticmethod - def is_in_chat_types(chat_type: int) -> bool: - if chat_type in [ChatType.TIGER_BOT.value, ChatType.CHATGPT.value, - ChatType.XINGHUO_WEB.value, ChatType.CHATGLM.value, - ChatType.BardAssistant.value, ChatType.ZhiPu.value, ChatType.CLAUDE.value, - ChatType.DOUBAO.value]: - return True - return False - - @staticmethod - def help_hint() -> str: - return str({member.value: member.name for member in ChatType}).replace('{', '').replace('}', '') diff --git a/db/contacts_db.py b/db/contacts_db.py index a1d3e49..480a2a0 100644 --- a/db/contacts_db.py +++ b/db/contacts_db.py @@ -12,7 +12,6 @@ from db.base import BaseDBOperator from db.connection import DBConnectionManager - class ContactsDBOperator(BaseDBOperator): """微信联系人数据库操作类""" @@ -153,8 +152,8 @@ class ContactsDBOperator(BaseDBOperator): 'small_head_img_url': contact.get('SmallHeadImgUrl', ''), 'description': '', # 可根据需要补充 'card_img_url': '', # 可根据需要补充 - 'label_list': '', # 可根据需要补充 - 'phone_num_list': '',# 可根据需要补充 + 'label_list': '', # 可根据需要补充 + 'phone_num_list': '', # 可根据需要补充 'type': contact_type } @@ -289,9 +288,9 @@ class ContactsDBOperator(BaseDBOperator): SELECT chatroom_id as user_name, nick_name, remark as remark FROM t_chatrooms """ - + results = self.execute_query(sql) - + contacts_dict = {} for result in results: user_name = result.get('user_name') @@ -338,6 +337,7 @@ class ContactsDBOperator(BaseDBOperator): except Exception as e: self.LOG.error(f"获取所有联系人名称映射失败: {e}") return {} + def save_chatroom_member_simple(self, chatroom_id: str, member_details: List[Dict]) -> bool: """ 保存群成员简要信息到数据库,兼容不同数据结构 @@ -405,6 +405,7 @@ class ContactsDBOperator(BaseDBOperator): except Exception as e: self.LOG.error(f"保存群 {chatroom_id} 成员信息失败: {e}") return False + def save_chatroom_member_detail(self, chatroom_id: str, member_details: List[Dict]) -> bool: """保存群成员详细信息到数据库 @@ -540,7 +541,8 @@ class ContactsDBOperator(BaseDBOperator): 'chat_room_owner': chatroom_data.get('ChatRoomOwner', ''), 'small_head_img_url': chatroom_data.get('SmallHeadImgUrl', ''), # 成员列表可选存储为JSON字符串 - 'member_list': json.dumps(chatroom_data.get('NewChatroomData', {}).get('ChatRoomMember', []), ensure_ascii=False) + 'member_list': json.dumps(chatroom_data.get('NewChatroomData', {}).get('ChatRoomMember', []), + ensure_ascii=False) } fields = ', '.join(data.keys()) @@ -598,7 +600,7 @@ class ContactsDBOperator(BaseDBOperator): self.LOG.error(f"删除群聊{chatroom_id}信息失败: {e}") return False - #新增获取群列表接口 + # 新增获取群列表接口 def get_chatroom_list(self) -> List[dict]: """获取群列表""" try: @@ -612,7 +614,7 @@ class ContactsDBOperator(BaseDBOperator): self.LOG.error(f"获取群列表失败: {e}") return [] - #新增获取群成员列表接口 + # 新增获取群成员列表接口 def get_chatroom_member_list(self, chatroom_id: str) -> List[dict]: """获取群成员列表""" try: @@ -623,7 +625,18 @@ class ContactsDBOperator(BaseDBOperator): self.LOG.error(f"获取群{chatroom_id}成员列表失败: {e}") return [] - #新增获取群成员信息接口 + # 获取群成员的昵称信息 + def get_chatroom_member_list_name_all(self) -> List[dict]: + """获取群成员列表""" + try: + sql = "SELECT chatroom_id,wxid, COALESCE(NULLIF(display_name,''), nick_name, wxid) as nick_name FROM t_chatroom_member" + results = self.execute_query(sql) + return results + except Exception as e: + self.LOG.error(f"获取群成员列表失败: {e}") + return [] + + # 新增获取群成员信息接口 def get_chatroom_member_info(self, chatroom_id: str, wxid: str) -> Optional[dict]: """获取群成员信息""" try: @@ -634,7 +647,7 @@ class ContactsDBOperator(BaseDBOperator): self.LOG.error(f"获取群{chatroom_id}成员{wxid}信息失败: {e}") return None - #新增群信息删除功能 + # 新增群信息删除功能 def delete_chatroom_all_info(self, chatroom_id: str) -> bool: """删除群成员信息""" try: @@ -649,7 +662,7 @@ class ContactsDBOperator(BaseDBOperator): self.LOG.error(f"删除群{chatroom_id}信息失败: {e}") return False - #新增删除所有联系人功能 + # 新增删除所有联系人功能 def delete_all_contacts(self) -> bool: """删除所有联系人信息""" try: @@ -660,8 +673,8 @@ class ContactsDBOperator(BaseDBOperator): except Exception as e: self.LOG.error(f"删除所有联系人信息失败: {e}") return False - - #新增获取所有联系人头像信息接口 + + # 新增获取所有联系人头像信息接口 def get_all_contacts_avatar(self) -> Dict[str, str]: """获取所有联系人头像信息""" try: @@ -676,9 +689,9 @@ class ContactsDBOperator(BaseDBOperator): FROM t_chatrooms """ results = self.execute_query(sql) - #返回DICT + # 返回DICT results = {result['user_name']: result['small_head_img_url'] for result in results} return results except Exception as e: self.LOG.error(f"获取所有联系人头像信息失败: {e}") - return [] \ No newline at end of file + return [] diff --git a/plugins/group_member_change/main.py b/plugins/group_member_change/main.py index 3bd7c00..5a2ad06 100644 --- a/plugins/group_member_change/main.py +++ b/plugins/group_member_change/main.py @@ -6,6 +6,7 @@ import xml.etree.ElementTree as ET from base.plugin_common.message_plugin_interface import MessagePluginInterface from base.plugin_common.plugin_interface import PluginStatus from utils.robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager +from utils.wechat.contact_manager import ContactManager from wechat_ipad import WechatAPIClient @@ -118,10 +119,12 @@ class GroupMemberChangePlugin(MessagePluginInterface): now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") member_wxids = [wxid] - await bot.send_at_message(roomid, f"👏欢迎 {nickname} 加入群聊!🎉", member_wxids) members = await bot.get_chatroom_member_detail(wxid, roomid) head_url = members.get("SmallHeadImgUrl") or members.get("BigHeadImgUrl") or "" + # 更新联系人信息 + ContactManager.get_instance().update_head_image(wxid, head_url) + ContactManager.get_instance().update_group_members(roomid, wxid, nickname) xml_content = f""" diff --git a/plugins/message_summary/main.py b/plugins/message_summary/main.py index 6a504cf..3b369cf 100644 --- a/plugins/message_summary/main.py +++ b/plugins/message_summary/main.py @@ -9,6 +9,7 @@ import requests from utils.revoke.message_auto_revoke import MessageAutoRevoke from utils.string_utils import remove_trailing_content +from utils.wechat.contact_manager import ContactManager from utils.wechat.message_to_db import MessageStorage from utils.compress_chat_data import compress_chat_data from base.plugin_common.message_plugin_interface import MessagePluginInterface @@ -109,8 +110,9 @@ class MessageSummaryPlugin(MessagePluginInterface): return False, None # 从消息历史中获取群聊记录 all_contacts: dict = message.get("all_contacts") + group_members: dict = ContactManager.get_instance().get_group_members() - chat_content = self.message_storage.get_messages(group_id, all_contacts) + chat_content = self.message_storage.get_messages(group_id, group_members) if len(chat_content) < 100: return False, None @@ -141,11 +143,13 @@ class MessageSummaryPlugin(MessagePluginInterface): await self.bot.send_image_message(group_id, Path(image_path)) else: - client_msg_id, create_time, new_msg_id = await self.bot.send_text_message(group_id, "❌ 生成总结图片失败") + client_msg_id, create_time, new_msg_id = await self.bot.send_text_message(group_id, + "❌ 生成总结图片失败") self.revoke.add_message_to_revoke(group_id, client_msg_id, create_time, new_msg_id, 5) except Exception as e: self.LOG.error(f"异步生成总结失败: {e}") - client_msg_id, create_time, new_msg_id = await self.bot.send_text_message(group_id, f"❌ 生成总结失败: {str(e)}") + client_msg_id, create_time, new_msg_id = await self.bot.send_text_message(group_id, + f"❌ 生成总结失败: {str(e)}") self.revoke.add_message_to_revoke(group_id, client_msg_id, create_time, new_msg_id, 5) def _sanitize_group_name(self, group_name: str) -> str: diff --git a/robot.py b/robot.py index adfb226..056686a 100644 --- a/robot.py +++ b/robot.py @@ -185,7 +185,8 @@ class Robot: self.allContacts = self.get_all_contacts() friends = await self.ipad_bot.get_contract_list() self.head_images = self.get_all_head_images() - self.contact_manager.set_contacts(self.allContacts, friends, self.head_images) + self.all_chatroom_members = self.contacts_db.get_chatroom_member_list_name_all() + self.contact_manager.set_contacts(self.allContacts, friends, self.head_images, self.all_chatroom_members) self.message_storage = MessageStorage(self.ipad_bot) @@ -361,10 +362,6 @@ class Robot: try: # self.LOG.debug(f"message: {message}") # 消息已经是WxMessage对象,直接使用其属性和方法 - from_user = message.sender - to_user = message.to_user - content = message.content - msg_type = message.msg_type # 判断是否为群消息 is_group = message.from_group() @@ -409,7 +406,9 @@ class Robot: self.head_images[wxid] = small_head_img_url friends = await self.ipad_bot.get_contract_list() - self.contact_manager.set_contacts(self.allContacts, friends, self.head_images) + self.all_chatroom_members = self.contacts_db.get_chatroom_member_list_name_all() + self.contact_manager.set_contacts(self.allContacts, friends, self.head_images, + self.all_chatroom_members) self.LOG.info(f"已更新群 {group_id} 的成员信息") except Exception as e: self.LOG.error(f"获取群成员信息失败: {e}") @@ -459,7 +458,7 @@ class Robot: """刷新联系人信息""" self.allContacts = self.get_all_contacts() friends = await self.ipad_bot.get_contract_list() - self.contact_manager.refresh_contacts(self.allContacts,friends) + self.contact_manager.refresh_contacts(self.allContacts, friends) self.LOG.info("联系人信息已刷新") async def send_group_txt_message(self, msg: str, feature: Feature): @@ -609,8 +608,11 @@ class Robot: self.allContacts[wxid] = nick_name self.head_images[wxid] = small_head_img_url - friends = await self.ipad_bot.get_contract_list() - self.contact_manager.set_contacts(self.allContacts, friends, self.head_images) + friends = await self.ipad_bot.get_contractlist() + + self.all_chatroom_members = self.contacts_db.get_chatroom_member_list_name_all() + self.contact_manager.set_contacts(self.allContacts, friends, self.head_images, + self.all_chatroom_members) self.LOG.info(f"已更新群 {group_id} 的成员信息") else: self.LOG.error(f"获取群 {group_id} 信息失败,证明用户无该群信息,删除群的相关资料。") diff --git a/utils/wechat/contact_manager.py b/utils/wechat/contact_manager.py index 8cc51ea..5036e73 100644 --- a/utils/wechat/contact_manager.py +++ b/utils/wechat/contact_manager.py @@ -21,6 +21,7 @@ class ContactManager: _initialized = False _logger = logger _friends: List[str] = [] + _group_members: List[Dict] = [] _group_contacts_friends: Dict[str, Dict[str, str]] = {} # 定义公共好友列表 _PUBLIC_FRIENDS = { @@ -51,7 +52,8 @@ class ContactManager: cls._instance = ContactManager() return cls._instance - def set_contacts(self, contacts: Dict[str, str], friends: List[str], head_imgs: Dict[str, str]) -> None: + def set_contacts(self, contacts: Dict[str, str], friends: List[str], head_imgs: Dict[str, str], + chatroom_members: List[dict]) -> None: """设置联系人字典 Args: @@ -66,10 +68,12 @@ class ContactManager: "province": cnt.get("province", ""), "city": cnt.get("city", ""), "gender": gender} + chatroom_members: 所有的群成员昵称信息 """ self._contacts = contacts self._friends = friends self._head_images = head_imgs + self._group_members = chatroom_members self._logger.info(f"联系人信息已更新,共 {len(contacts)} 个联系人") # 分类联系人 self._classify_contacts() @@ -91,6 +95,12 @@ class ContactManager: # 判断是否为群组(wxid以@chatroom结尾) elif wxid.endswith('@chatroom'): self._group_contacts[wxid] = nickname + # 获取群成员信息: + for friend in self._group_members: + if friend.get('chatroom_id') == wxid: + self._group_contacts_friends[wxid].update( + {friend.get('wxid'): friend.get('nick_name', friend.get('wxid'))}) + else: # 判断 frinds 在contacts 里面,将在里面的用户分在 if wxid in self._friends: @@ -170,6 +180,18 @@ class ContactManager: """ return self._head_images.get(wxid, "") + def update_head_image(self, wxid: str, head_image: str) -> bool: + """根据微信ID更新头像 + + Args: + wxid: 微信ID + head_image:头像地址 + Returns: + 对应的头像,如果不存在这返回"" + """ + self._head_images.update({wxid: head_image}) + return True + def get_group_name(self, roomid: str, wxid: str) -> str: """ Args: @@ -192,6 +214,18 @@ class ContactManager: """ return self._group_contacts_friends.get(roomid, {}) + def update_group_members(self, roomid: str, wxid: str, nick_name: str) -> bool: + """更新指定群的成员列表 + + Args: + roomid: 群ID + + Returns: + 群成员字典,格式为 {"wxid": "NickName"} + """ + self._group_contacts_friends[roomid].update({wxid: nick_name}) + return True + def update_contact(self, wxid: str, nickname: str) -> None: """更新单个联系人信息 @@ -208,7 +242,10 @@ class ContactManager: elif wxid.endswith('@chatroom'): self._group_contacts[wxid] = nickname # 需要获取群成员昵称信息; 从数据库里面提取。 - # self._group_contacts_friends[wxid] = {} + for friend in self._group_members: + if friend.get('chatroom_id') == wxid: + self._group_contacts_friends[wxid].update( + {friend.get('wxid'): friend.get('nick_name', friend.get('wxid'))}) else: if wxid in self._friends: self._personal_contacts[wxid] = nickname