feature:加入了群成员变化监控功能,提醒群成员,有人退出了群聊

This commit is contained in:
liuwei
2025-02-18 17:57:29 +08:00
parent 6c8147cb17
commit 48a36d42d4
3 changed files with 276 additions and 6 deletions

View File

@@ -0,0 +1,93 @@
import redis
# 创建 Redis 连接
r = redis.StrictRedis(host='192.168.2.32', port=6379, db=0, decode_responses=True)
# Redis 中存储群组映射的前缀
mapping_prefix = "group:group_mapping:"
# 添加群组ID到指定key
def add_mapping(key, group_id):
if r.sismember(mapping_prefix + key, group_id):
print(f"Group ID {group_id} already exists for key {key}.")
else:
r.sadd(mapping_prefix + key, group_id)
print(f"Added: {key} -> {group_id}")
# 删除指定key下的某个群组ID
def del_mapping(key, group_id):
if r.sismember(mapping_prefix + key, group_id):
r.srem(mapping_prefix + key, group_id)
print(f"Deleted: {key} -> {group_id}")
else:
print(f"Group ID {group_id} not found for key {key}.")
# 获取指定key下的所有群组ID
def get_group_ids(key):
group_ids = r.smembers(mapping_prefix + key)
if group_ids:
print(f"Group IDs for {key}: {', '.join(group_ids)}")
else:
print(f"Key '{key}' has no associated group IDs.")
# 获取指定key的第一个群组ID
def get_first_group_id(key):
group_ids = r.smembers(mapping_prefix + key)
if group_ids:
first_group_id = next(iter(group_ids)) # 获取集合中的第一个元素
print(f"First Group ID for {key}: {first_group_id}")
else:
print(f"Key '{key}' has no associated group IDs.")
# 处理命令行输入
def process_command(command):
command_parts = command.split()
if len(command_parts) == 0:
print("Invalid command.")
return
cmd = command_parts[0]
if cmd == "add" and len(command_parts) == 3:
key = command_parts[1]
group_id = command_parts[2]
add_mapping(key, group_id)
elif cmd == "del" and len(command_parts) == 3:
key = command_parts[1]
group_id = command_parts[2]
del_mapping(key, group_id)
elif cmd == "get" and len(command_parts) == 2:
key = command_parts[1]
get_group_ids(key)
elif cmd == "get_first" and len(command_parts) == 2:
key = command_parts[1]
get_first_group_id(key)
else:
print("Unknown command or wrong number of arguments.")
# 主函数
def main():
print("群自动邀请系统已启动。")
print(
"输入 'add key group_id' 来添加群组ID'del key group_id' 来删除,'get key' 来查询所有群组ID'get_first key' 来查询第一个群组ID。")
while True:
command = input("请输入命令:")
if command.lower() == "exit":
print("退出系统。")
break
process_command(command)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,158 @@
import redis
import xml.etree.ElementTree as ET
from wcferry import Wcf
class GroupMemberChange:
def __init__(self, wcf: Wcf):
self.wcf = wcf # 假设 wcf 对象在此类中初始化
self.r = redis.Redis(host='192.168.2.32', port=6379, db=0, decode_responses=True)
# 初始化本地缓存
self.local_membercount = None
self.local_members = {}
def get_current_members(self, group_id):
""" 获取当前群成员信息 """
print(f"Fetching current members for group_id: {group_id}")
members = self.wcf.get_chatroom_members(group_id) # 假设返回的数据格式是 {wxid1: 昵称1, wxid2: 昵称2, ...}
print(f"Current members: {members}")
return members
def get_previous_data_from_redis(self, group_id):
""" 从 Redis 获取上次的数据 """
membercount_key = f"group:group_member_count:{group_id}"
members_key = f"group:group_members:{group_id}"
# 读取 Redis 中的数据
print(f"Fetching previous data from Redis for group_id: {group_id}")
membercount_previous = self.r.get(membercount_key)
members_previous = self.r.hgetall(members_key) # 获取上次的成员信息
print(f"Previous membercount: {membercount_previous}, Previous members: {members_previous}")
return membercount_previous, members_previous
def process_message(self, group_id, xml_data_current):
""" 处理消息并更新 Redis """
print(f"Processing message for group_id: {group_id}")
root_current = ET.fromstring(xml_data_current)
membercount_current = root_current.find('membercount').text
print(f"Current membercount: {membercount_current}")
result = [] # 初始化文案列表
# 如果本地没有缓存数据,则从 Redis 获取
if self.local_membercount is None or not self.local_members:
print("No local data, fetching from Redis")
membercount_previous, members_previous = self.get_previous_data_from_redis(group_id)
# 如果没有上次的数据,说明是第一次处理,直接存储本次数据
if membercount_previous is None or not members_previous:
print("First time processing, saving current data to Redis")
members_current = self.get_current_members(group_id)
self.r.set(f"group:group_member_count:{group_id}", membercount_current)
self.r.hmset(f"group:group_members:{group_id}", members_current) # 存储当前成员信息
# 更新本地缓存
self.local_membercount = membercount_current
self.local_members = members_current
result.append("$NO_CHANGE$")
return "\n".join(result)
else:
# 使用本地缓存的数据进行比较
print("Using local data for comparison")
membercount_previous = self.local_membercount
members_previous = self.local_members
# 比较 membercount 是否发生变化
if membercount_current != membercount_previous:
print(f"Membercount changed: {membercount_previous} -> {membercount_current}")
result.append(f"membercount has changed: {membercount_previous} -> {membercount_current}")
members_current = self.get_current_members(group_id)
# 比较成员,仅使用 wxid 进行比较
members_current_set = set(members_current.keys())
members_previous_set = set(members_previous.keys())
added_members = members_current_set - members_previous_set
removed_members = members_previous_set - members_current_set
# 添加变化成员的文案
for wxid in added_members:
nickname = members_current[wxid]
print(f"Detected member added: {nickname} ({wxid})")
result.append(f"检测到 {nickname}{wxid})加入群聊")
for wxid in removed_members:
nickname = members_previous[wxid]
print(f"Detected member removed: {nickname} ({wxid})")
result.append(f"检测到 {nickname}{wxid})退出群聊")
# 更新本地缓存
print(f"Updating local cache with current membercount and members")
self.local_membercount = membercount_current
self.local_members = members_current
# 更新 Redis 数据
print(f"Updating Redis with current membercount and members")
self.r.set(f"group:group_member_count:{group_id}", membercount_current)
self.r.hmset(f"group:group_members:{group_id}", members_current)
else:
print("No change detected in membercount")
result.append("$NO_CHANGE$")
# 返回拼接后的结果
return "\n".join(result)
def main():
group_id = "room123"
xml_data_current = """
<msgsource>
<pua>1</pua>
<eggIncluded>1</eggIncluded>
<silence>1</silence>
<membercount>118</membercount>
<members>
<member>
<wxid>wxid1</wxid>
<nickname>昵称1</nickname>
</member>
<member>
<wxid>wxid2</wxid>
<nickname>昵称2</nickname>
</member>
<member>
<wxid>wxid3</wxid>
<nickname>昵称3</nickname>
</member>
</members>
<signature>V1_5V25+oDw|v1_5V25+oDw</signature>
<tmp_node>
<publisher-id />
</tmp_node>
<sec_msg_node>
<alnode>
<fr>1</fr>
</alnode>
</sec_msg_node>
</msgsource>
"""
# 创建 YourClass 实例
your_instance = YourClass()
# 调用 process_message 方法来处理当前数据并获取变化文案
result = your_instance.process_message(group_id, xml_data_current)
# 判断是否没有变化
if "NO_CHANGE" in result:
print("没有变化,跳过处理")
else:
print("检测到变化,进行相关处理")
print(result) # 输出具体的变化文案
if __name__ == "__main__":
main()

View File

@@ -24,6 +24,8 @@ from base.func_xinghuo_web import XinghuoWeb
from base.func_claude import Claude
from configuration import Config
from constants import ChatType
from group_auto.group_auto_invite import get_first_group_id
from group_auto.group_member_change import GroupMemberChange
from robot_cmd.robot_command import GroupBotManager
from job_mgmt import Job
from robot_cmd.robot_command import Feature
@@ -51,6 +53,7 @@ class Robot(Job):
self.groups = {} # 存储按group_id分组的消息列表每个group_id最多保留10条消息
GroupBotManager.load_local_cache()
self.gbm = GroupBotManager()
self.gmc = GroupMemberChange(wcf)
if ChatType.is_in_chat_types(chat_type):
if chat_type == ChatType.TIGER_BOT.value and TigerBot.value_check(self.config.TIGERBOT):
self.chat = TigerBot(self.config.TIGERBOT)
@@ -138,25 +141,32 @@ class Robot(Job):
else: # 接了 ChatGPT智能回复
# 去除@的人和空格等字符
q = re.sub(r"@.*?[\u2005|\s]", "", msg.content).replace(" ", "")
# 使用正则表达式匹配加群指令
pattern = r'#加群:\[(.*?)\]' # 匹配 #加群:[<任何内容>]
match = re.match(pattern, q)
# 所有人员都可以要求他撤回刚刚的信息
if q == '撤回':
self.revoke_messages(msg.roomid)
return True
if q == "今日百度新闻":
if q == "#今日百度新闻":
self.newsBaiduReport((msg.roomid if msg.from_group() else msg.sender))
return True
elif q in ["nbc", "cnn", "abc", "fox", "bbc"]:
self.newsEnReport(q, (msg.roomid if msg.from_group() else msg.sender))
return True
elif q == '/总结':
elif q == '#总结':
self.message_summary_robot((msg.roomid if msg.from_group() else msg.sender))
return True
elif q == '4K':
# 如果正则匹配到时加群指令则从库中提取第一个群ID
elif match:
try:
self.LOG.info(f"邀请加入4K群{msg.sender}")
self.wcf.invite_chatroom_members('45317011307@chatroom', msg.sender)
group_id = get_first_group_id(match.group(1))
self.LOG.info(f"邀请加入{match.group(1)}{msg.sender}")
self.wcf.invite_chatroom_members(group_id, msg.sender)
except Exception as e:
self.LOG.error(f"邀请加入4K群出错:{e}")
self.LOG.error(f"邀请加入群出错:{e}")
return True
else:
# 如果是群消息并且群没开启AI则不处理该动作
@@ -214,6 +224,15 @@ class Robot(Job):
except Exception as e:
self.LOG.error(f"revoke_receive_message error: {e}")
try:
result = self.gmc.process_message(msg.roomid, msg.xml)
# 判断是否没有变化
if "$NO_CHANGE$" not in result:
self.LOG.info(f"检测到群成员变化,进行相关内容输出:{result}")
self.sendTextMsg(result, msg.roomid)
except Exception as e:
self.LOG.error(f"group_member_change error: {e}")
if msg.is_at(self.wxid): # 被@
self.toAt(msg)