优化联系人信息,解决总结时使用了其他群的备注信息
This commit is contained in:
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
import logging.config
|
import logging.config
|
||||||
import os
|
import os
|
||||||
import shutil
|
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
@@ -14,26 +13,14 @@ class Config(object):
|
|||||||
|
|
||||||
def _load_config(self) -> dict:
|
def _load_config(self) -> dict:
|
||||||
pwd = os.path.dirname(os.path.abspath(__file__))
|
pwd = os.path.dirname(os.path.abspath(__file__))
|
||||||
try:
|
|
||||||
with open(f"{pwd}/config.yaml", "rb") as fp:
|
with open(f"{pwd}/config.yaml", "rb") as fp:
|
||||||
yconfig = yaml.safe_load(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)
|
|
||||||
|
|
||||||
return yconfig
|
return yconfig
|
||||||
|
|
||||||
def reload(self) -> None:
|
def reload(self) -> None:
|
||||||
yconfig = self._load_config()
|
yconfig = self._load_config()
|
||||||
logging.config.dictConfig(yconfig["logging"])
|
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.CLAUDE = yconfig.get("claude", {})
|
||||||
self.DEEPSEEK = yconfig.get("deepseek", {})
|
self.DEEPSEEK = yconfig.get("deepseek", {})
|
||||||
self.DOUBAO = yconfig.get("doubao", {})
|
self.DOUBAO = yconfig.get("doubao", {})
|
||||||
|
|||||||
27
constants.py
27
constants.py
@@ -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('}', '')
|
|
||||||
@@ -12,7 +12,6 @@ from db.base import BaseDBOperator
|
|||||||
from db.connection import DBConnectionManager
|
from db.connection import DBConnectionManager
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ContactsDBOperator(BaseDBOperator):
|
class ContactsDBOperator(BaseDBOperator):
|
||||||
"""微信联系人数据库操作类"""
|
"""微信联系人数据库操作类"""
|
||||||
|
|
||||||
@@ -338,6 +337,7 @@ class ContactsDBOperator(BaseDBOperator):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.LOG.error(f"获取所有联系人名称映射失败: {e}")
|
self.LOG.error(f"获取所有联系人名称映射失败: {e}")
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def save_chatroom_member_simple(self, chatroom_id: str, member_details: List[Dict]) -> bool:
|
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:
|
except Exception as e:
|
||||||
self.LOG.error(f"保存群 {chatroom_id} 成员信息失败: {e}")
|
self.LOG.error(f"保存群 {chatroom_id} 成员信息失败: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def save_chatroom_member_detail(self, chatroom_id: str, member_details: List[Dict]) -> bool:
|
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', ''),
|
'chat_room_owner': chatroom_data.get('ChatRoomOwner', ''),
|
||||||
'small_head_img_url': chatroom_data.get('SmallHeadImgUrl', ''),
|
'small_head_img_url': chatroom_data.get('SmallHeadImgUrl', ''),
|
||||||
# 成员列表可选存储为JSON字符串
|
# 成员列表可选存储为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())
|
fields = ', '.join(data.keys())
|
||||||
@@ -623,6 +625,17 @@ class ContactsDBOperator(BaseDBOperator):
|
|||||||
self.LOG.error(f"获取群{chatroom_id}成员列表失败: {e}")
|
self.LOG.error(f"获取群{chatroom_id}成员列表失败: {e}")
|
||||||
return []
|
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]:
|
def get_chatroom_member_info(self, chatroom_id: str, wxid: str) -> Optional[dict]:
|
||||||
"""获取群成员信息"""
|
"""获取群成员信息"""
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import xml.etree.ElementTree as ET
|
|||||||
from base.plugin_common.message_plugin_interface import MessagePluginInterface
|
from base.plugin_common.message_plugin_interface import MessagePluginInterface
|
||||||
from base.plugin_common.plugin_interface import PluginStatus
|
from base.plugin_common.plugin_interface import PluginStatus
|
||||||
from utils.robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
|
from utils.robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
|
||||||
|
from utils.wechat.contact_manager import ContactManager
|
||||||
from wechat_ipad import WechatAPIClient
|
from wechat_ipad import WechatAPIClient
|
||||||
|
|
||||||
|
|
||||||
@@ -118,10 +119,12 @@ class GroupMemberChangePlugin(MessagePluginInterface):
|
|||||||
|
|
||||||
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
member_wxids = [wxid]
|
member_wxids = [wxid]
|
||||||
|
|
||||||
await bot.send_at_message(roomid, f"👏欢迎 {nickname} 加入群聊!🎉", member_wxids)
|
await bot.send_at_message(roomid, f"👏欢迎 {nickname} 加入群聊!🎉", member_wxids)
|
||||||
members = await bot.get_chatroom_member_detail(wxid, roomid)
|
members = await bot.get_chatroom_member_detail(wxid, roomid)
|
||||||
head_url = members.get("SmallHeadImgUrl") or members.get("BigHeadImgUrl") or ""
|
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"""
|
xml_content = f"""
|
||||||
<appmsg appid="" sdkver="1">
|
<appmsg appid="" sdkver="1">
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import requests
|
|||||||
|
|
||||||
from utils.revoke.message_auto_revoke import MessageAutoRevoke
|
from utils.revoke.message_auto_revoke import MessageAutoRevoke
|
||||||
from utils.string_utils import remove_trailing_content
|
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.wechat.message_to_db import MessageStorage
|
||||||
from utils.compress_chat_data import compress_chat_data
|
from utils.compress_chat_data import compress_chat_data
|
||||||
from base.plugin_common.message_plugin_interface import MessagePluginInterface
|
from base.plugin_common.message_plugin_interface import MessagePluginInterface
|
||||||
@@ -109,8 +110,9 @@ class MessageSummaryPlugin(MessagePluginInterface):
|
|||||||
return False, None
|
return False, None
|
||||||
# 从消息历史中获取群聊记录
|
# 从消息历史中获取群聊记录
|
||||||
all_contacts: dict = message.get("all_contacts")
|
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:
|
if len(chat_content) < 100:
|
||||||
return False, None
|
return False, None
|
||||||
|
|
||||||
@@ -141,11 +143,13 @@ class MessageSummaryPlugin(MessagePluginInterface):
|
|||||||
await self.bot.send_image_message(group_id, Path(image_path))
|
await self.bot.send_image_message(group_id, Path(image_path))
|
||||||
else:
|
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)
|
self.revoke.add_message_to_revoke(group_id, client_msg_id, create_time, new_msg_id, 5)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.LOG.error(f"异步生成总结失败: {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)
|
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:
|
def _sanitize_group_name(self, group_name: str) -> str:
|
||||||
|
|||||||
18
robot.py
18
robot.py
@@ -185,7 +185,8 @@ class Robot:
|
|||||||
self.allContacts = self.get_all_contacts()
|
self.allContacts = self.get_all_contacts()
|
||||||
friends = await self.ipad_bot.get_contract_list()
|
friends = await self.ipad_bot.get_contract_list()
|
||||||
self.head_images = self.get_all_head_images()
|
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)
|
self.message_storage = MessageStorage(self.ipad_bot)
|
||||||
|
|
||||||
@@ -361,10 +362,6 @@ class Robot:
|
|||||||
try:
|
try:
|
||||||
# self.LOG.debug(f"message: {message}")
|
# self.LOG.debug(f"message: {message}")
|
||||||
# 消息已经是WxMessage对象,直接使用其属性和方法
|
# 消息已经是WxMessage对象,直接使用其属性和方法
|
||||||
from_user = message.sender
|
|
||||||
to_user = message.to_user
|
|
||||||
content = message.content
|
|
||||||
msg_type = message.msg_type
|
|
||||||
|
|
||||||
# 判断是否为群消息
|
# 判断是否为群消息
|
||||||
is_group = message.from_group()
|
is_group = message.from_group()
|
||||||
@@ -409,7 +406,9 @@ class Robot:
|
|||||||
self.head_images[wxid] = small_head_img_url
|
self.head_images[wxid] = small_head_img_url
|
||||||
|
|
||||||
friends = await self.ipad_bot.get_contract_list()
|
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} 的成员信息")
|
self.LOG.info(f"已更新群 {group_id} 的成员信息")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.LOG.error(f"获取群成员信息失败: {e}")
|
self.LOG.error(f"获取群成员信息失败: {e}")
|
||||||
@@ -609,8 +608,11 @@ class Robot:
|
|||||||
self.allContacts[wxid] = nick_name
|
self.allContacts[wxid] = nick_name
|
||||||
|
|
||||||
self.head_images[wxid] = small_head_img_url
|
self.head_images[wxid] = small_head_img_url
|
||||||
friends = await self.ipad_bot.get_contract_list()
|
friends = await self.ipad_bot.get_contractlist()
|
||||||
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} 的成员信息")
|
self.LOG.info(f"已更新群 {group_id} 的成员信息")
|
||||||
else:
|
else:
|
||||||
self.LOG.error(f"获取群 {group_id} 信息失败,证明用户无该群信息,删除群的相关资料。")
|
self.LOG.error(f"获取群 {group_id} 信息失败,证明用户无该群信息,删除群的相关资料。")
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ class ContactManager:
|
|||||||
_initialized = False
|
_initialized = False
|
||||||
_logger = logger
|
_logger = logger
|
||||||
_friends: List[str] = []
|
_friends: List[str] = []
|
||||||
|
_group_members: List[Dict] = []
|
||||||
_group_contacts_friends: Dict[str, Dict[str, str]] = {}
|
_group_contacts_friends: Dict[str, Dict[str, str]] = {}
|
||||||
# 定义公共好友列表
|
# 定义公共好友列表
|
||||||
_PUBLIC_FRIENDS = {
|
_PUBLIC_FRIENDS = {
|
||||||
@@ -51,7 +52,8 @@ class ContactManager:
|
|||||||
cls._instance = ContactManager()
|
cls._instance = ContactManager()
|
||||||
return cls._instance
|
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:
|
Args:
|
||||||
@@ -66,10 +68,12 @@ class ContactManager:
|
|||||||
"province": cnt.get("province", ""),
|
"province": cnt.get("province", ""),
|
||||||
"city": cnt.get("city", ""),
|
"city": cnt.get("city", ""),
|
||||||
"gender": gender}
|
"gender": gender}
|
||||||
|
chatroom_members: 所有的群成员昵称信息
|
||||||
"""
|
"""
|
||||||
self._contacts = contacts
|
self._contacts = contacts
|
||||||
self._friends = friends
|
self._friends = friends
|
||||||
self._head_images = head_imgs
|
self._head_images = head_imgs
|
||||||
|
self._group_members = chatroom_members
|
||||||
self._logger.info(f"联系人信息已更新,共 {len(contacts)} 个联系人")
|
self._logger.info(f"联系人信息已更新,共 {len(contacts)} 个联系人")
|
||||||
# 分类联系人
|
# 分类联系人
|
||||||
self._classify_contacts()
|
self._classify_contacts()
|
||||||
@@ -91,6 +95,12 @@ class ContactManager:
|
|||||||
# 判断是否为群组(wxid以@chatroom结尾)
|
# 判断是否为群组(wxid以@chatroom结尾)
|
||||||
elif wxid.endswith('@chatroom'):
|
elif wxid.endswith('@chatroom'):
|
||||||
self._group_contacts[wxid] = nickname
|
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:
|
else:
|
||||||
# 判断 frinds 在contacts 里面,将在里面的用户分在
|
# 判断 frinds 在contacts 里面,将在里面的用户分在
|
||||||
if wxid in self._friends:
|
if wxid in self._friends:
|
||||||
@@ -170,6 +180,18 @@ class ContactManager:
|
|||||||
"""
|
"""
|
||||||
return self._head_images.get(wxid, "")
|
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:
|
def get_group_name(self, roomid: str, wxid: str) -> str:
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
@@ -192,6 +214,18 @@ class ContactManager:
|
|||||||
"""
|
"""
|
||||||
return self._group_contacts_friends.get(roomid, {})
|
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:
|
def update_contact(self, wxid: str, nickname: str) -> None:
|
||||||
"""更新单个联系人信息
|
"""更新单个联系人信息
|
||||||
|
|
||||||
@@ -208,7 +242,10 @@ class ContactManager:
|
|||||||
elif wxid.endswith('@chatroom'):
|
elif wxid.endswith('@chatroom'):
|
||||||
self._group_contacts[wxid] = nickname
|
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:
|
else:
|
||||||
if wxid in self._friends:
|
if wxid in self._friends:
|
||||||
self._personal_contacts[wxid] = nickname
|
self._personal_contacts[wxid] = nickname
|
||||||
|
|||||||
Reference in New Issue
Block a user