1.加入了指令;

2.判断接收人从redis+本地缓存中提取;
3.做本地缓存与redis实时同步;
This commit is contained in:
liuwei
2025-02-17 13:02:01 +08:00
parent cf01ed97f7
commit af2ef96c3e
4 changed files with 294 additions and 26 deletions

243
group_auto/robot_command.py Normal file
View File

@@ -0,0 +1,243 @@
# 群清单管理
# 群功能管理
# 0.加入或者关闭群机器人 #启用群机器人 #关闭群机器人
# 1.每日新闻自动播报 #启用每日新闻播报 #关闭每日新闻播报
# 2.每日群发言总结 #启用群发言 #关闭群发言
# 3.群AI能力 #启用群AI #关闭群AI
# 4.群总结能力 #启用群总结 #关闭群总结
# 5.sehuatang PDF能力 #启用pdf #关闭pdf
import redis
import json
from enum import Enum
# 连接到本地 Redis 服务
r = redis.StrictRedis(host='192.168.2.32', port=6379, db=0, decode_responses=True)
class PermissionStatus(Enum):
"""权限状态枚举"""
ENABLED = "enabled"
DISABLED = "disabled"
class Feature(Enum):
"""功能权限枚举,带序号"""
ROBOT = 1, "群机器人"
DAILY_NEWS = 2, "每日新闻自动播报"
DAILY_SUMMARY = 3, "每日群发言总结"
AI_CAPABILITY = 4, "群AI能力"
SUMMARY_CAPABILITY = 5, "群总结能力"
PDF_CAPABILITY = 6, "sehuatang PDF能力"
EPIC = 7, "EPIC自动播报"
def __new__(cls, value, description):
obj = object.__new__(cls)
obj._value_ = value
obj.description = description # 添加描述
return obj
def __str__(self):
return self.description
class GroupBotManager:
"""群机器人管理,支持本地缓存"""
# 本地缓存
local_cache = {
"group_permissions": {}, # 用于缓存群组功能权限
"group_list": set() # 用于缓存 group:list
}
@staticmethod
def load_local_cache():
"""从 Redis 加载数据到本地缓存"""
group_list = r.smembers("group:list")
GroupBotManager.local_cache["group_list"] = set(group_list)
# 加载群组权限
for group_id in GroupBotManager.local_cache["group_list"]:
key = f'group:{group_id}:permissions'
GroupBotManager.local_cache["group_permissions"][group_id] = {}
for feature in Feature:
status_value = r.hget(key, feature.name)
if status_value:
GroupBotManager.local_cache["group_permissions"][group_id][feature] = PermissionStatus(status_value)
else:
GroupBotManager.local_cache["group_permissions"][group_id][feature] = PermissionStatus.DISABLED
@staticmethod
def save_to_redis():
"""将本地缓存保存回 Redis"""
# 保存 group:list 到 Redis
r.sadd("group:list", *GroupBotManager.local_cache["group_list"])
# 保存每个群组的权限到 Redis
for group_id, permissions in GroupBotManager.local_cache["group_permissions"].items():
key = f'group:{group_id}:permissions'
for feature, status in permissions.items():
r.hset(key, feature.name, status.value)
@staticmethod
def set_group_permission(group_id, feature: Feature, status: PermissionStatus):
"""设置群组功能权限并更新本地缓存"""
# 更新本地缓存
if group_id not in GroupBotManager.local_cache["group_permissions"]:
GroupBotManager.local_cache["group_permissions"][group_id] = {}
GroupBotManager.local_cache["group_permissions"][group_id][feature] = status
# 同步到 Redis
key = f'group:{group_id}:permissions'
r.hset(key, feature.name, status.value)
@staticmethod
def get_group_permission(group_id, feature: Feature):
"""获取群组某个功能的权限状态"""
# 先从本地缓存获取
if group_id in GroupBotManager.local_cache["group_permissions"]:
return GroupBotManager.local_cache["group_permissions"][group_id].get(feature, PermissionStatus.DISABLED)
else:
return PermissionStatus.DISABLED
@staticmethod
def handle_command(group_id, command_str):
"""统一处理群功能指令"""
# 命令解析
command_parts = command_str.strip().split("-")
# 如果是MENU指令返回功能列表
if command_str.strip().upper() == "MENU":
return GroupBotManager.display_menu()
# 如果是GROUP_LIST指令返回 group:list 清单
if command_str.strip().upper() == "GROUP_LIST":
return GroupBotManager.get_group_list()
if len(command_parts) < 2:
return "无效命令,格式应为:功能-操作 或 序号-操作"
feature_str = command_parts[0]
action = command_parts[1]
# 如果第一个参数是序号,则转化为对应的功能
if feature_str.isdigit():
feature_num = int(feature_str)
try:
feature = Feature(feature_num) # 使用枚举序号查找功能
except ValueError:
return "无效的功能序号"
else:
try:
feature = Feature[feature_str] # 通过枚举名称获取功能枚举
except KeyError:
return "无效功能名称"
# 处理群机器人的启用和关闭(特别操作:更新 group:list
if feature == Feature.ROBOT:
if action == "启用":
GroupBotManager.set_group_permission(group_id, feature, PermissionStatus.ENABLED)
# 启用群机器人时,将 group_id 加入 group:list
GroupBotManager.local_cache["group_list"].add(group_id)
# 同步到 Redis
r.sadd("group:list", group_id)
return f"群机器人已启用,群组 {group_id} 已加入 group:list"
elif action == "关闭":
GroupBotManager.set_group_permission(group_id, feature, PermissionStatus.DISABLED)
# 关闭群机器人时,从 group:list 中删除 group_id
GroupBotManager.local_cache["group_list"].remove(group_id)
# 同步到 Redis
r.srem("group:list", group_id)
return f"群机器人已关闭,群组 {group_id} 已从 group:list 移除"
else:
return "无效操作,仅支持启用或关闭"
# 先检查群机器人权限
robot_status = GroupBotManager.get_group_permission(group_id, Feature.ROBOT)
if robot_status != PermissionStatus.ENABLED and feature != Feature.ROBOT:
return "群机器人未启用,无法执行其他功能操作"
# 根据不同的操作启用或禁用功能
if action == "启用":
GroupBotManager.set_group_permission(group_id, feature, PermissionStatus.ENABLED)
return f"{feature.description} 已启用"
elif action == "关闭":
GroupBotManager.set_group_permission(group_id, feature, PermissionStatus.DISABLED)
return f"{feature.description} 已关闭"
else:
return "无效操作,仅支持启用或关闭"
@staticmethod
def list_group_permissions(group_id):
"""列出群组所有功能及其状态"""
permissions = {}
for feature in Feature:
status = GroupBotManager.get_group_permission(group_id, feature)
permissions[feature] = status if status else PermissionStatus.DISABLED # 默认为禁用状态
return permissions
@staticmethod
def display_menu():
"""显示所有功能列表及其当前状态"""
menu = []
for feature in Feature:
menu.append(f"{feature.value}. {feature.description}")
return "\n".join(menu)
@staticmethod
def get_group_list():
"""返回所有启用了群机器人的群组清单,格式为集合"""
return list(GroupBotManager.local_cache["group_list"])
# 示例命令
def simulate_commands():
# 加载本地缓存
GroupBotManager.load_local_cache()
group_id = "12345"
# 启用群机器人
print(GroupBotManager.handle_command(group_id, "ROBOT-启用"))
# 启用每日新闻自动播报
print(GroupBotManager.handle_command(group_id, "2-启用")) # 使用序号启用每日新闻自动播报
# 关闭群AI能力
print(GroupBotManager.handle_command(group_id, "4-关闭")) # 使用序号关闭群AI能力
# 启用群总结能力
print(GroupBotManager.handle_command(group_id, "5-启用")) # 使用序号启用群总结能力
# 关闭Sehuatang PDF能力
print(GroupBotManager.handle_command(group_id, "6-关闭")) # 使用序号关闭Sehuatang PDF能力
# 查看当前群组的功能权限
print(GroupBotManager.get_group_permission(group_id, Feature.ROBOT))
print(GroupBotManager.get_group_permission(group_id, Feature.DAILY_NEWS))
print(GroupBotManager.get_group_permission(group_id, Feature.AI_CAPABILITY))
print(GroupBotManager.get_group_permission(group_id, Feature.SUMMARY_CAPABILITY))
print(GroupBotManager.get_group_permission(group_id, Feature.PDF_CAPABILITY))
# 查看群组所有功能和状态
permissions = GroupBotManager.list_group_permissions(group_id)
for feature, status in permissions.items():
print(f"{feature.description} (序号: {feature.value}): {status.value}")
# 查看 group:list 中的群组
print("当前启用群机器人的群组:", GroupBotManager.get_group_list())
# 查看菜单功能列表
print("功能列表:")
print(GroupBotManager.handle_command(group_id, "MENU"))
# 查看 group:list 清单
print("群组清单:")
print(GroupBotManager.handle_command(group_id, "GROUP_LIST"))
# 保存到 Redis
GroupBotManager.save_to_redis()
# 执行模拟命令
simulate_commands()

View File

@@ -50,22 +50,20 @@ def main(chat_type: int):
# robot.onEveryTime("07:00", weather_report, robot=robot)
# 每天 8:30 发送新闻
robot.onEveryTime("08:30", robot.newsBaiduReport)
robot.onEveryTime("08:30", robot.newsBaiduReportAuto)
# 每天 16:30 提醒发日报周报月报
# robot.onEveryTime("10:30", ReportReminder.remind, robot=robot)
# epic
robot.onEveryTime("10:30", robot.sendEpicFreeGames)
# message report 1:数据自动从redis 转到sqllite
robot.onEveryTime("00:30", robot.messageCountToDB)
# 从db中提取并发送给相关群
robot.onEveryTime("09:30", robot.generateAndSendRanking)
#sehuatang
robot.onEveryTime("15:00",robot.generateSehuatangPdf)
# sehuatang
robot.onEveryTime("15:00", robot.generateSehuatangPdf)
# 让机器人一直跑
robot.keepRunningAndBlockProcess()

View File

@@ -23,7 +23,9 @@ from base.func_xinghuo_web import XinghuoWeb
from base.func_claude import Claude
from configuration import Config
from constants import ChatType
from group_auto.robot_command import GroupBotManager
from job_mgmt import Job
from group_auto.robot_command import Feature
__version__ = "39.2.4.0"
@@ -44,7 +46,8 @@ class Robot(Job):
self.LOG = logging.getLogger("Robot")
self.wxid = self.wcf.get_self_wxid()
self.allContacts = self.getAllContacts()
GroupBotManager.load_local_cache()
self.gbm = GroupBotManager()
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)
@@ -127,6 +130,12 @@ class Robot(Job):
def toChitchat(self, msg: WxMsg) -> bool:
"""闲聊,接入 ChatGPT
"""
# 如果聊天内容来自自己,则进行指令判断
if msg.from_self() and msg.from_group():
command_str = re.sub(r"@.*?[\u2005|\s]", "", msg.content).replace(" ", "")
rsp = GroupBotManager.handle_command(msg.roomid, command_str)
self.sendTextMsg(rsp, msg.roomid, msg.sender)
return True
if not self.chat: # 没接 ChatGPT固定回复
rsp = "你@我干嘛?"
else: # 接了 ChatGPT智能回复
@@ -140,6 +149,7 @@ class Robot(Job):
elif q == '/总结':
self.message_summary_robot((msg.roomid if msg.from_group() else msg.sender))
return True
# 群管理自动加入,减少服务重启管理
else:
rsp = self.chat.get_answer(q, (msg.roomid if msg.from_group() else msg.sender))
@@ -301,18 +311,40 @@ class Robot(Job):
self.allContacts[msg.sender] = nickName[0]
self.sendTextMsg(f"Hi {nickName[0]},我自动通过了你的好友请求。", msg.sender)
def send_group_txt_message(self, msg: str, feature: Feature):
try:
receivers = self.gbm.get_group_list()
if not receivers:
return
for r in receivers:
if self.gbm.get_group_permission(r, feature):
self.sendTextMsg(msg, r)
except Exception as e:
self.LOG.error(f"send_group_txt_message:{feature.description} error{e}")
def send_group_file_message(self, path: str, feature: Feature):
try:
receivers = self.gbm.get_group_list()
if not receivers:
return
for r in receivers:
if self.gbm.get_group_permission(r, feature):
self.wcf.send_file(path, r)
except Exception as e:
self.LOG.error(f"send_group_file_message:{feature.description} error{e}")
# ============================================== 业务内容==========================================================
def newsBaiduReportAuto(self) -> None:
try:
news = News().get_baidu_news()
self.send_group_txt_message(news, Feature.DAILY_NEWS)
except Exception as e:
self.LOG.error(f"newsBaiduReportAuto error{e}")
def newsBaiduReport(self, sender: str = None) -> None:
try:
news = News().get_baidu_news()
# news = (
# f"请根据新闻标题,按照新闻的类型(财经、彩票、房产、股票、家居、教育、科技、社会、时尚、时政、体育、星座、游戏、娱乐)进行分类;内容前加入当前日期和星期几" \
# "内容格式如下:" \
# "### 分类1" \
# "1.#标题1" \
# "2.#标题2" \
# "分类之间使用--号进行分割,无内容则忽略该分组") + news
# rsp = self.chat.get_answer(news)
self.sendTextMsg(news, sender)
except Exception as e:
self.LOG.error(f"newsBaiduReport error{e}")
@@ -326,13 +358,9 @@ class Robot(Job):
def sendEpicFreeGames(self):
try:
receivers = self.config.NEWS
if not receivers:
return
if is_friday():
games = get_free()
for r in receivers:
self.sendTextMsg(games, r)
self.send_group_txt_message(games, Feature.EPIC)
except Exception as e:
self.LOG.error(f"sendEpicFreeGames error{e}")
@@ -344,11 +372,12 @@ class Robot(Job):
def generateAndSendRanking(self):
try:
receivers = self.config.NEWS
receivers = self.gbm.get_group_list()
if not receivers:
return
for r in receivers:
self.sendTextMsg(generate_and_send_ranking(r, self.allContacts), r)
if self.gbm.get_group_permission(r, Feature.DAILY_SUMMARY):
self.sendTextMsg(generate_and_send_ranking(r, self.allContacts), r)
except Exception as e:
self.LOG.error(f"SendRanking error{e}")
@@ -356,7 +385,7 @@ class Robot(Job):
try:
path = pdf_file_path()
# 暂时只发4K群
self.wcf.send_file(path, "45317011307@chatroom")
self.send_group_file_message(path, Feature.PDF_CAPABILITY)
except Exception as e:
self.LOG.error(f"generateSehuatangPdf error{e}")

View File

@@ -74,7 +74,6 @@ def fetch_and_create_pdf(url):
# 获取今天的日期
today = datetime.now().strftime('%Y-%m-%d')
# 注册中文字体
pdfmetrics.registerFont(TTFont('SamHei', 'fonts/simhei.ttf')) # 设置中文字体路径
styles = getSampleStyleSheet()
@@ -170,7 +169,6 @@ def fetch_and_create_pdf(url):
# 生成PDF
doc.build(content)
# 获取PDF文件的绝对路径
absolute_pdf_path = os.path.abspath(pdf_filename)
print(f"PDF saved as {absolute_pdf_path}")
@@ -202,12 +200,12 @@ def add_pdf_encryption(pdf_file, password="4000"):
print(f"PDF加密成功密码为: {password}")
def pdf_file_path():
url = 'https://www.sehuatang.net/forum.php?mod=forumdisplay&fid=103&filter=typeid&typeid=481'
pdf_path = fetch_and_create_pdf(url)
print(f"返回的PDF文件路径{pdf_path}")
return pdf_path
if __name__ == "__main__":
pdf_file_path()