需求:1.加入了用户积分表;2.加入了指令积分扣除功能;3.加入了积分获得与扣除注解。

This commit is contained in:
liuwei
2025-04-09 11:54:03 +08:00
parent 9b8e0c3558
commit dba9c31504
31 changed files with 1435 additions and 527 deletions

View File

@@ -8,8 +8,9 @@ from wcferry import Wcf
from message_util import MessageUtil
from plugin_common.message_plugin_interface import MessagePluginInterface
from plugin_common.plugin_interface import PluginStatus
from plugins.stats_collector.decorators import plugin_stats_decorator
from robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
from utils.decorator.plugin_decorators import plugin_stats_decorator
from utils.robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
from utils.decorator.points_decorator import plugin_points_cost
class BeautyLegPlugin(MessagePluginInterface):
@@ -90,6 +91,7 @@ class BeautyLegPlugin(MessagePluginInterface):
return command in self._commands
@plugin_stats_decorator(plugin_name="美腿图片")
@plugin_points_cost(1, "美腿图片消耗积分")
def process_message(self, message: Dict[str, Any]) -> Tuple[bool, Optional[str]]:
"""处理消息"""
content = str(message.get("content", "")).strip()

View File

@@ -10,8 +10,9 @@ from wcferry import Wcf
from message_util import MessageUtil
from plugin_common.message_plugin_interface import MessagePluginInterface
from plugin_common.plugin_interface import PluginStatus
from plugins.stats_collector.decorators import plugin_stats_decorator
from robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
from utils.decorator.plugin_decorators import plugin_stats_decorator
from utils.robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
from utils.decorator.points_decorator import plugin_points_cost
from utils.media_downloader import MediaDownloader
@@ -103,6 +104,7 @@ class DifyPlugin(MessagePluginInterface):
return command in self._commands
@plugin_stats_decorator(plugin_name="Dify聊天")
@plugin_points_cost(2, "AI聊天消耗积分")
def process_message(self, message: Dict[str, Any]) -> Tuple[bool, Optional[str]]:
"""处理消息"""
content = str(message.get("content", "")).strip()

View File

@@ -6,12 +6,12 @@ import traceback
import requests
from typing import Dict, Any, List, Optional, Tuple
from wcferry import Wcf, WxMsg
from wcferry import Wcf
from plugin_common.message_plugin_interface import MessagePluginInterface
from plugin_common.plugin_interface import PluginStatus
from plugins.stats_collector.decorators import plugin_stats_decorator
from robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
from utils.decorator.plugin_decorators import plugin_stats_decorator
from utils.robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
class DouyinParserError(Exception):

View File

@@ -0,0 +1,5 @@
from .main import GameTaskPlugin
def get_plugin():
"""获取插件实例"""
return GameTaskPlugin()

View File

@@ -0,0 +1,8 @@
enable = true
command = ["game", "任务", "/t", "/a", "/s"]
command-format = """
🎮 游戏任务系统指令:
/s - 加入游戏
/t - 获取任务
/a <任务ID> <答案> - 提交答案
"""

552
plugins/game_task/main.py Normal file
View File

@@ -0,0 +1,552 @@
import random
import logging
from datetime import datetime
from typing import Dict, Any, List, Optional, Tuple
from wcferry import Wcf
from message_util import MessageUtil
from plugin_common.message_plugin_interface import MessagePluginInterface
from plugin_common.plugin_interface import PluginStatus
from utils.decorator.plugin_decorators import plugin_stats_decorator
from utils.robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
from utils.decorator.points_decorator import points_reward_decorator
from utils.ai.game_chatgpt_qa import game_question_json, game_answer_json
from db.connection import DBConnectionManager
from db.encyclopedia import EncyclopediaDB
class GameTaskPlugin(MessagePluginInterface):
"""游戏任务插件"""
@property
def name(self) -> str:
return "百科问答"
@property
def version(self) -> str:
return "1.0.0"
@property
def description(self) -> str:
return "百科问答游戏系统,支持问答积分"
@property
def author(self) -> str:
return "Trae AI"
@property
def command_prefix(self) -> Optional[str]:
return "" # 不需要前缀,直接匹配命令
@property
def commands(self) -> List[str]:
return self._commands
def __init__(self):
super().__init__()
def initialize(self, context: Dict[str, Any]) -> bool:
"""初始化插件"""
self.LOG = logging.getLogger(f"Plugin.{self.name}")
self.LOG.info(f"正在初始化 {self.name} 插件...")
# 保存上下文对象
self.wcf = context.get("wcf")
self.event_system = context.get("event_system")
self.message_util: MessageUtil = context.get("message_util")
# 初始化配置
self._commands = self._config.get("GameTask", {}).get("command",
["game", "任务", "/t", "/a", "/s", "/r", "/l", "/h"])
self.command_format = self._config.get("GameTask", {}).get("command-format", """
🎮 百科问答指令:
/s - 加入游戏
/t - 获取任务
/a <任务ID> <答案> - 提交答案
/r - 查看排行榜
/l - 查看活跃任务
/h - 查看未完成任务
""")
self.enable = self._config.get("GameTask", {}).get("enable", True)
# 初始化数据库连接
self.db_manager = DBConnectionManager.get_instance()
self.encyclopedia_db = EncyclopediaDB(self.db_manager)
# 注册定时任务
if self.event_system:
self.event_system.add_interval_job(
self.run_random_task_assignment,
hours=1,
id="game_task_random_assignment"
)
self.LOG.info(f"[{self.name}] 插件初始化完成,指令:{self._commands}")
return True
def start(self) -> bool:
"""启动插件"""
self.LOG.info(f"[{self.name}] 插件已启动")
self.status = PluginStatus.RUNNING
return True
def stop(self) -> bool:
"""停止插件"""
self.LOG.info(f"[{self.name}] 插件已停止")
self.status = PluginStatus.STOPPED
return True
def can_process(self, message: Dict[str, Any]) -> bool:
"""检查是否可以处理该消息"""
if not self.enable:
return False
content = str(message.get("content", "")).strip()
command = content.split(" ")[0]
return command in self._commands
def calculate_reward_points(self, message: Dict[str, Any], success: bool, response: str) -> int:
"""计算奖励积分"""
if not success:
return 0
return int(response)
@plugin_stats_decorator(plugin_name="百科问答")
def process_message(self, message: Dict[str, Any]) -> Tuple[bool, Optional[str]]:
"""处理消息"""
content = str(message.get("content", "")).strip()
command = content.split(" ")[0].lower()
sender = message.get("sender")
roomid = message.get("roomid", "")
wcf: Wcf = message.get("wcf")
gbm: GroupBotManager = message.get("gbm")
all_contacts = message.get("all_contacts", {})
self.LOG.info(f"插件执行: {self.name}{content}")
# 检查权限
if roomid and gbm.get_group_permission(roomid, Feature.TASK_GAME) == PermissionStatus.DISABLED:
return False, "没有权限"
try:
# 获取用户昵称
wx_nick_name = all_contacts.get(sender, sender)
if command == "/s":
self._handle_join_game(sender, roomid, wx_nick_name)
return True, "加入游戏成功"
elif command == "/t":
self._handle_get_task(sender, roomid)
return True, "获取任务成功"
elif command == "/a":
points = self._handle_submit_answer(content, sender, roomid)
return True, str(points)
elif command == "/r":
self._handle_show_rank(sender, roomid)
return True, "显示排行榜成功"
elif command == "/l":
self._handle_show_active_tasks(sender, roomid)
return True, "显示活跃任务成功"
elif command == "/h":
self._handle_list_uncompleted_tasks(sender, roomid)
return True, "列举未完成任务成功"
else:
self.message_util.send_text_msg(f"❌未知命令!\n{self.command_format}",
(roomid if roomid else sender), sender)
return False, "未知命令"
except Exception as e:
self.LOG.error(f"处理消息出错: {e}")
return False, f"处理出错: {e}"
def _handle_join_game(self, sender: str, roomid: str, wx_nick_name: str) -> None:
"""处理加入游戏请求"""
try:
# 检查并添加群聊
if not self.encyclopedia_db.check_group_exists(roomid):
self.encyclopedia_db.add_group(roomid)
self.message_util.send_text_msg(
f"🎉 群 {roomid} 已就位,准备开燥!",
(roomid if roomid else sender),
sender
)
# 检查并添加玩家
player = self.encyclopedia_db.get_player(sender, roomid)
if not player:
self.encyclopedia_db.add_player(sender, roomid, wx_nick_name)
self.message_util.send_text_msg(
f"🎉 哇塞,{wx_nick_name} 你来啦!\n"
f"🌟 群 {roomid} 瞬间燃爆!\n"
f"🎈 快来接任务,秀翻全场!指令: /t",
(roomid if roomid else sender),
sender
)
except Exception as e:
self.LOG.error(f"加入游戏出错: {e}")
self.message_util.send_text_msg(
f"😔 加入游戏出错,请稍后再试!",
(roomid if roomid else sender),
sender
)
def _handle_get_task(self, sender: str, roomid: str) -> None:
"""处理获取任务请求"""
try:
# 获取群内所有玩家
players = self.encyclopedia_db.get_all_players_in_group(roomid)
if not players:
self.message_util.send_text_msg(
f"😔 哎呀,群 {roomid} 静悄悄\n"
f"🌟 快拉小伙伴来嗨吧!",
(roomid if roomid else sender),
sender
)
return
player_dict = {p['player_id']: p['player_name'] for p in players}
if sender not in player_dict:
self.message_util.send_text_msg(
f"😅 嘿,你谁啊?\n"
f"🌟 先用 /s 报名,不然没法玩哦!",
(roomid if roomid else sender),
sender
)
return
task = game_question_json("请出题!")
category = task["category"]
question = task["question"]
answer = task["answer"]
score = int(task["score"])
description = task.get("description", "")
# 创建活跃任务
active_task_id = self.encyclopedia_db.create_active_task(
roomid, question, answer, score, description, sender
)
if not active_task_id:
self.message_util.send_text_msg(
f"😔 任务创建失败,请稍后再试!",
(roomid if roomid else sender),
sender
)
return
self.message_util.send_text_msg(
f"🎁 {player_dict[sender]},你的专属任务闪亮登场!\n"
f"🎀 任务ID: {active_task_id}\n"
f"🎈 问题:[{category}]{question}\n"
f"🌼 积分:{score}\n"
f"🌈 快上答案:/a {active_task_id} 答案",
(roomid if roomid else sender),
sender
)
except Exception as e:
self.LOG.error(f"获取任务出错: {e}")
self.message_util.send_text_msg(
f"😔 获取任务出错,请稍后再试!",
(roomid if roomid else sender),
sender
)
def calculate_game_points(self, message: Dict[str, Any], success: bool, response: str) -> int:
"""计算游戏积分"""
if not success:
return 0
try:
return int(response)
except (TypeError, ValueError):
return 0
@points_reward_decorator(calculate_game_points, "game", "百科答题奖励")
def _handle_submit_answer(self, content: str, sender: str, roomid: str) -> int:
"""处理提交答案请求"""
try:
parts = content.split(" ", 2)
if len(parts) < 3:
self.message_util.send_text_msg(
f"😅 喂,格式不对啊!\n"
f"🌟 正确姿势:/a [任务ID] [答案]\n"
f"🎈 比如:/a 1 钒",
(roomid if roomid else sender),
sender
)
return 0
task_id = parts[1]
answer = parts[2]
# 获取玩家信息
player = self.encyclopedia_db.get_player(sender, roomid)
if not player:
self.message_util.send_text_msg(
f"😅 嘿,你是路人甲吗?\n"
f"🌟 用 /s 先加入群 {roomid} 吧!",
(roomid if roomid else sender),
sender
)
return 0
player_name = player['player_name']
if not task_id.isdigit():
self.message_util.send_text_msg(
f"😅 喂任务ID得是数字好吗\n"
f"🌟 比如1\n"
f"🎈 别瞎搞,重新来!",
(roomid if roomid else sender),
sender
)
return 0
active_task_id = int(task_id)
# 获取任务信息
task_data = self.encyclopedia_db.get_task_by_id(roomid, active_task_id)
if not task_data:
self.message_util.send_text_msg(
f"😔 哎哟,任务 task_{active_task_id} 不翼而飞啦!\n"
f"🌼 可能被别人抢先一步咯!",
(roomid if roomid else sender),
sender
)
return 0
if task_data['status'] == 'completed':
self.message_util.send_text_msg(
f"😄 哈哈,你慢了一步!\n"
f"🌟 任务 task_{active_task_id} 已经完结\n"
f"🎈 快去抢新任务吧!",
(roomid if roomid else sender),
sender
)
return 0
question = task_data['question']
correct_answer_db = task_data['answer'].lower()
top_score = task_data['score']
holder_id = task_data['holder_id']
# 获取任务持有者信息
holder = self.encyclopedia_db.get_task_holder(roomid, holder_id)
holder_name = holder['player_name'] if holder else "未知玩家"
answer_json = {"question": question, "top_score": str(top_score), "answer": answer}
result = game_answer_json(answer_json)
points = int(result["score"])
description = result["description"]
is_correct = points > 0
# 记录答题历史
self.encyclopedia_db.add_task_history(
roomid, active_task_id, sender, answer, is_correct, points
)
if is_correct:
# 完成任务
self.encyclopedia_db.complete_task(active_task_id)
if sender == holder_id:
self.message_util.send_text_msg(
f"🎉 {player_name} 你是天才吗?\n"
f"🌟 任务:{question}\n"
f"🎈 答对啦,简直无敌!\n"
f"🌈 奖励:{points}\n"
f"🎀 彩蛋:{description}",
(roomid if roomid else sender),
sender
)
else:
self.message_util.send_text_msg(
f"🎉 {player_name} 抢答王上线!\n"
f"🌟 任务:{question}\n"
f"🎈 原主:{holder_name} 被你截胡啦!\n"
f"🌈 狂揽 {points} 分,太骚了!\n"
f"🎀 彩蛋:{description}",
(roomid if roomid else sender),
sender
)
else:
# 扣除积分
self.encyclopedia_db.update_player_points(sender, roomid, -1)
points = -1
self.message_util.send_text_msg(
f"😅 {player_name} 你这是要笑死我吗?\n"
f"🌼 任务:{question}\n"
f"🎈 你答:{answer}\n"
f"🌟 正确答案:{correct_answer_db}\n"
f"🌈 扣 1 分,别哭哦!\n"
f"🎀 提示:{description}\n"
f"🌟 任务ID: {active_task_id} 还能抢救一下!",
(roomid if roomid else sender),
sender
)
return points
except Exception as e:
self.LOG.error(f"提交答案出错: {e}")
self.message_util.send_text_msg(
f"😔 提交答案出错,请稍后再试!",
(roomid if roomid else sender),
sender
)
return 0
def _handle_show_rank(self, sender: str, roomid: str) -> None:
"""处理显示排行榜请求"""
try:
# 获取排行榜
ranks = self.encyclopedia_db.get_player_ranking(roomid, 10)
if not ranks:
self.message_util.send_text_msg(
f"😔 群 {roomid} 冷冷清清\n"
f"🌟 快来一起燥起来吧!",
(roomid if roomid else sender),
sender
)
return
rank_text = f"🎉 群 {roomid} 排行榜Top 10来啦\n"
for i, row in enumerate(ranks, 1):
rank_text += f"🐓 {i}. {row['player_name']}: {row['points']}\n"
self.message_util.send_text_msg(
rank_text,
(roomid if roomid else sender),
sender
)
except Exception as e:
self.LOG.error(f"显示排行榜出错: {e}")
self.message_util.send_text_msg(
f"😔 获取排行榜出错,请稍后再试!",
(roomid if roomid else sender),
sender
)
def _handle_show_active_tasks(self, sender: str, roomid: str) -> None:
"""处理显示活跃任务请求"""
try:
# 获取活跃任务
tasks = self.encyclopedia_db.get_active_tasks_in_group(roomid)
if not tasks:
self.message_util.send_text_msg(
f"😄 群 {roomid} 现在一片祥和\n"
f"🌟 没任务?快用 /t 搞一个!",
(roomid if roomid else sender),
sender
)
return
task_text = f"🎉 群 {roomid} 活跃任务速递:\n"
for task in tasks:
task_text += (
f"🌈 任务ID: task_{task['active_task_id']}\n"
f"🎀 问题:{task['question']}\n"
f"🌼 大佬:{task['player_name']}\n"
)
self.message_util.send_text_msg(
task_text,
(roomid if roomid else sender),
sender
)
except Exception as e:
self.LOG.error(f"显示活跃任务出错: {e}")
self.message_util.send_text_msg(
f"😔 获取活跃任务出错,请稍后再试!",
(roomid if roomid else sender),
sender
)
def _handle_list_uncompleted_tasks(self, sender: str, roomid: str) -> None:
"""处理列举未完成任务请求"""
try:
# 获取未完成任务
tasks = self.encyclopedia_db.get_active_tasks_in_group(roomid)
if not tasks:
self.message_util.send_text_msg(
f"😄 群 {roomid} 全员开挂?\n"
f"🌟 没未完成任务,快用 /t 再战!",
(roomid if roomid else sender),
sender
)
return
task_text = f"🎉 群 {roomid} 未完成任务大曝光:\n"
for task in tasks:
task_text += (
f"🌈 任务ID: task_{task['active_task_id']}\n"
f"🎀 问题:{task['question']}\n"
f"🌼 主人:{task['player_name']}\n"
)
self.message_util.send_text_msg(
task_text,
(roomid if roomid else sender),
sender
)
except Exception as e:
self.LOG.error(f"列举未完成任务出错: {e}")
self.message_util.send_text_msg(
f"😔 获取未完成任务出错,请稍后再试!",
(roomid if roomid else sender),
sender
)
def run_random_task_assignment(self) -> None:
"""定时任务整点触发排除23:00-08:00"""
current_hour = datetime.now().hour
if current_hour >= 23 or current_hour < 9:
self.LOG.info(f"当前时间 {current_hour}:00 在23:00-08:00区间跳过任务发放")
return
try:
# 获取所有群聊
groups = self.encyclopedia_db.get_all_groups()
for group in groups:
group_id = group['group_id']
# 获取群内所有玩家
players = self.encyclopedia_db.get_all_players_in_group(group_id)
if not players:
continue
# 随机选择一个玩家
holder = random.choice(players)
holder_id = holder['player_id']
holder_name = holder['player_name']
# 创建任务
task = game_question_json("请出题!")
category = task["category"]
question = task["question"]
answer = task["answer"]
score = int(task["score"])
description = task.get("description", "")
# 创建活跃任务
active_task_id = self.encyclopedia_db.create_active_task(
group_id, question, answer, score, description, holder_id
)
if active_task_id:
self.message_util.send_text_msg(
f"🎁 新任务来袭,够不够刺激?\n"
f"🎀 任务ID: {active_task_id}\n"
f"🌟 幸运鹅:{holder_name}\n"
f"🎈 问题:[{category}]{question}\n"
f"🌼 积分:{score}\n"
f"🌈 抢答格式:/a {active_task_id} 答案",
group_id
)
except Exception as e:
self.LOG.error(f"定时任务出错: {e}")

View File

@@ -3,11 +3,11 @@ import re
from datetime import datetime
from typing import Dict, Any, List, Optional, Tuple
from wcferry import Wcf, WxMsg
from wcferry import Wcf
from plugin_common.message_plugin_interface import MessagePluginInterface
from plugin_common.plugin_interface import PluginStatus
from robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
from utils.robot_cmd.robot_command import Feature, PermissionStatus
class GroupAddPlugin(MessagePluginInterface):

View File

@@ -3,12 +3,12 @@ import redis
import re
from typing import Dict, Any, List, Optional, Tuple
from wcferry import Wcf, WxMsg
from wcferry import Wcf
from plugin_common.message_plugin_interface import MessagePluginInterface
from plugin_common.plugin_interface import PluginStatus
from plugins.stats_collector.decorators import plugin_stats_decorator
from robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
from utils.decorator.plugin_decorators import plugin_stats_decorator
from utils.robot_cmd.robot_command import GroupBotManager
class GroupAutoInvitePlugin(MessagePluginInterface):

View File

@@ -2,13 +2,13 @@ import logging
import threading
import time
from datetime import datetime
from typing import Dict, Any, List, Optional, Set, Tuple
from typing import Dict, Any, List, Optional, Tuple
from wcferry import Wcf
from plugin_common.message_plugin_interface import MessagePluginInterface
from plugin_common.plugin_interface import PluginStatus
from robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
from utils.robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
from message_util import MessageUtil # 导入消息工具类

View File

@@ -4,8 +4,8 @@ from typing import Dict, Any, List, Tuple, Optional
from message_util import MessageUtil
from plugin_common.message_plugin_interface import MessagePluginInterface
from plugin_common.plugin_interface import PluginStatus
from plugins.stats_collector.decorators import plugin_stats_decorator
from robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
from utils.decorator.plugin_decorators import plugin_stats_decorator
from utils.robot_cmd.robot_command import GroupBotManager
from wcferry import Wcf

View File

@@ -3,19 +3,22 @@ import logging
import pytz
from typing import Dict, Any, List, Optional, Tuple
from wcferry import Wcf, WxMsg
from wcferry import Wcf
from db.connection import DBConnectionManager
from message_util import MessageUtil
from plugin_common.message_plugin_interface import MessagePluginInterface
from plugin_common.plugin_interface import PluginStatus
from plugins.stats_collector.decorators import plugin_stats_decorator
from robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
from utils.decorator.plugin_decorators import plugin_stats_decorator
from utils.robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
from db.sign_in import SignInDB
from db.sign_in_redis import SignInRedisDB
import random
import os
from utils.decorator.points_decorator import points_reward_decorator
class MessageSignPlugin(MessagePluginInterface):
"""签到插件"""
@@ -137,7 +140,47 @@ class MessageSignPlugin(MessagePluginInterface):
return command in self._commands
# 添加积分计算函数
def calculate_sign_in_points(self, message, success, response):
"""计算签到奖励积分
Args:
message: 消息内容
success: 处理结果
response: 响应内容
Returns:
int: 奖励积分数量
"""
sender = message.get("sender")
roomid = message.get("roomid", "")
# 获取当前时间,带有时区信息
current_time = datetime.now(tz=pytz.timezone(self.timezone))
today_start = current_time.replace(hour=0, minute=0, second=0, microsecond=0)
yesterday = today_start - timedelta(days=1)
# 获取用户的签到记录
user_record = self.get_user_record(sender, roomid)
# 计算连续签到天数
streak = 1
if user_record and user_record['sign_stat']:
last_sign_date = user_record['sign_stat'].replace(hour=0, minute=0, second=0, microsecond=0)
# 确保 sign_stat 和 today_start 是同一时区对象
if isinstance(last_sign_date, datetime) and last_sign_date.tzinfo is None:
last_sign_date = pytz.timezone(self.timezone).localize(last_sign_date)
if last_sign_date == yesterday:
streak = user_record['signin_streak'] + 1
# 计算积分
points = self.calculate_points(streak)
return points
# 修改process_message方法使用装饰器
@plugin_stats_decorator(plugin_name="签到系统")
@points_reward_decorator(calculate_sign_in_points, "checkin", "每日签到奖励")
def process_message(self, message: Dict[str, Any]) -> Tuple[bool, Optional[str]]:
"""处理消息"""
content = str(message.get("content", "")).strip()
@@ -156,31 +199,27 @@ class MessageSignPlugin(MessagePluginInterface):
try:
# 获取当前时间,带有时区信息
current_time = datetime.now(tz=pytz.timezone(self.timezone))
# 获取当天零点的时间
today_start = current_time.replace(hour=0, minute=0, second=0, microsecond=0)
# 获取昨天的时间
yesterday = today_start - timedelta(days=1)
# 获取用户的签到记录
user_record = self.get_user_record(sender, roomid)
wx_nick_name = all_contacts.get(sender, sender)
# 判断用户是否已经签到过
if user_record and user_record.get('sign_stat'):
sign_stat = user_record['sign_stat']
# 确保 sign_stat 和 today_start 是同一时区对象
if isinstance(sign_stat, datetime) and sign_stat.tzinfo is None:
sign_stat = pytz.timezone(self.timezone).localize(sign_stat)
# 如果 sign_stat 已经大于或等于今天的零点,则认为用户已经签到过了
if sign_stat >= today_start:
self.message_util.send_text_msg(f"您今天已经签到过了!当前积分:{user_record['points']}",
(roomid if roomid else sender), sender)
return True, "已签到"
streak = 0
streak_broken = False
old_streak = 1
@@ -200,28 +239,29 @@ class MessageSignPlugin(MessagePluginInterface):
streak_broken = True
else:
streak = 1
today_signin_rank = self.get_today_signin_count(roomid) + 1
self.today_signin_count[roomid] = today_signin_rank
self.sign_in_redis.save_signin_count(roomid, today_signin_rank)
points_to_add = self.calculate_points(streak)
# 使用数据库操作类更新或创建签到记录
# 注意:不再在这里计算和添加积分,由装饰器处理
points_to_add = self.calculate_points(streak)
if user_record:
self.sign_in_db.update_sign_record(
sender, roomid, wx_nick_name,
points_to_add, current_time, streak
points_to_add, # 不在这里添加积分,由装饰器处理
current_time, streak
)
else:
self.sign_in_db.create_sign_record(
sender, roomid, wx_nick_name,
points_to_add, current_time, streak
points_to_add, # 不在这里添加积分,由装饰器处理
current_time, streak
)
# 在签到成功后添加每日词汇
# 在输出信息中添加每日词汇
output = f"签到成功,加[{points_to_add}]分,第[{today_signin_rank}]个!"
output = f"签到成功,第[{today_signin_rank}]个!"
if streak_broken and old_streak > 0: # 只有在真的断签且之前有签到记录时才显示
output += f"断开了 {old_streak} 天连签!"
@@ -239,7 +279,7 @@ class MessageSignPlugin(MessagePluginInterface):
self.LOG.error(f"处理签到请求出错: {e}")
self.message_util.send_text_msg(f"签到出错:{e}",
(roomid if roomid else sender), sender)
return True, f"处理出错: {e}"
return False, f"处理出错: {e}"
def reset_today_count_if_needed(self):
"""检查并重置每日签到计数"""

View File

@@ -4,13 +4,14 @@ from typing import Dict, Any, Tuple, Optional, List
import requests
from message_storage.message_to_db import MessageStorage
from utils.wechat.message_to_db import MessageStorage
from utils.compress_chat_data import compress_chat_data
from plugin_common.message_plugin_interface import MessagePluginInterface
from plugin_common.plugin_interface import PluginStatus
from utils.decorator.points_decorator import plugin_points_cost
from utils.markdown_to_image import convert_md_str_to_image
from plugins.stats_collector.decorators import plugin_stats_decorator
from robot_cmd.robot_command import GroupBotManager, Feature, PermissionStatus
from utils.decorator.plugin_decorators import plugin_stats_decorator
from utils.robot_cmd.robot_command import GroupBotManager, Feature, PermissionStatus
class MessageSummaryPlugin(MessagePluginInterface):
@@ -73,6 +74,7 @@ class MessageSummaryPlugin(MessagePluginInterface):
return True
@plugin_stats_decorator(plugin_name="群聊总结")
@plugin_points_cost(10, "群聊总结消耗积分")
def process_message(self, message: Dict[str, Any]) -> Tuple[bool, Optional[str]]:
"""处理消息"""
try:

View File

@@ -7,8 +7,9 @@ from wcferry import Wcf
from plugin_common.message_plugin_interface import MessagePluginInterface
from plugin_common.plugin_interface import PluginStatus
from plugins.stats_collector.decorators import plugin_stats_decorator
from robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
from utils.decorator.plugin_decorators import plugin_stats_decorator
from utils.robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
from utils.decorator.points_decorator import plugin_points_cost
class MusicPlugin(MessagePluginInterface):
@@ -81,6 +82,7 @@ class MusicPlugin(MessagePluginInterface):
return command in self._commands
@plugin_stats_decorator(plugin_name="音乐点播")
@plugin_points_cost(1, "音乐点播消耗积分")
def process_message(self, message: Dict[str, Any]) -> Tuple[bool, Optional[str]]:
"""处理消息"""
content = str(message.get("content", "")).strip()

View File

@@ -6,7 +6,7 @@ from plugin_common.message_plugin_interface import MessagePluginInterface
from plugin_common.plugin_interface import PluginStatus
from plugin_common.plugin_registry import PluginRegistry
from plugin_common.plugin_manager import PluginManager
from robot_cmd.robot_command import GroupBotManager
from utils.robot_cmd.robot_command import GroupBotManager
class PluginManagerPlugin(MessagePluginInterface):

View File

@@ -1,7 +1,5 @@
import logging
import re
import os
import toml
from datetime import datetime
from typing import Dict, Any, List, Optional, Tuple
import xml.etree.ElementTree as ET
@@ -11,8 +9,8 @@ from wcferry import Wcf
from db.connection import DBConnectionManager
from plugin_common.message_plugin_interface import MessagePluginInterface
from plugin_common.plugin_interface import PluginStatus
from plugins.stats_collector.decorators import plugin_stats_decorator
from robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
from utils.decorator.plugin_decorators import plugin_stats_decorator
from utils.robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
import mysql.connector.pooling

View File

@@ -1,120 +0,0 @@
import functools
import time
import traceback
import logging
from datetime import datetime
from typing import Callable, Dict, Any, Tuple
from db.stats_db import StatsDBOperator
from db.connection import DBConnectionManager
def plugin_stats_decorator(plugin_name: str) -> Callable:
"""插件统计装饰器
Args:
plugin_name: 插件名称
Returns:
装饰器函数
"""
# 获取日志记录器
logger = logging.getLogger(f"StatsCollector.{plugin_name}")
logger.debug(f"为插件 '{plugin_name}' 应用统计装饰器")
def decorator(func: Callable) -> Callable:
logger.debug(f"装饰 '{plugin_name}'{func.__name__} 方法")
@functools.wraps(func)
def wrapper(self, message: Dict[str, Any]) -> Tuple[bool, str]:
# 获取数据库连接
try:
logger.debug(f"[{plugin_name}] 开始处理消息")
db_manager = DBConnectionManager.get_instance()
stats_db = StatsDBOperator(db_manager)
# 提取消息信息
content = message.get("content", "")
sender = message.get("sender", "")
roomid = message.get("roomid", "")
# 提取指令部分(假设指令是第一个单词或空格前的部分)
command = content.strip().split(' ')[0] if content else ""
logger.debug(f"[{plugin_name}] 消息内容: '{content}', 指令: '{command}', 发送者: {sender}, 群ID: {roomid}")
# 记录开始时间
start_time = time.time()
logger.debug(f"[{plugin_name}] 开始执行时间: {datetime.fromtimestamp(start_time).strftime('%Y-%m-%d %H:%M:%S.%f')}")
try:
# 调用原始方法
logger.debug(f"[{plugin_name}] 调用原始方法 {func.__name__}")
success, response = func(self, message)
# 计算执行时间(毫秒)
end_time = time.time()
process_time_ms = (end_time - start_time) * 1000
logger.debug(f"[{plugin_name}] 执行完成,耗时: {process_time_ms:.2f}ms, 结果: {success}, 响应: {response}")
# 记录插件调用
logger.debug(f"[{plugin_name}] 记录插件调用统计")
stats_db.record_plugin_call(
plugin_name=plugin_name,
command=command, # 使用提取的指令而不是完整内容
user_id=sender,
group_id=roomid,
success=success,
process_time_ms=process_time_ms
)
logger.info(f"[{plugin_name}] 成功记录插件调用: {command}, 耗时: {process_time_ms:.2f}ms")
return success, response
except Exception as e:
# 计算执行时间(毫秒)
end_time = time.time()
process_time_ms = (end_time - start_time) * 1000
# 记录错误
error_message = str(e)
stack_trace = traceback.format_exc()
logger.error(f"[{plugin_name}] 执行出错: {error_message}")
logger.debug(f"[{plugin_name}] 错误堆栈: {stack_trace}")
try:
# 记录插件调用(失败)
logger.debug(f"[{plugin_name}] 记录插件调用失败统计")
stats_db.record_plugin_call(
plugin_name=plugin_name,
command=command, # 使用提取的指令而不是完整内容
user_id=sender,
group_id=roomid,
success=False,
process_time_ms=process_time_ms
)
# 记录错误详情
logger.debug(f"[{plugin_name}] 记录错误详情")
stats_db.record_error(
plugin_name=plugin_name,
command=command, # 使用提取的指令而不是完整内容
user_id=sender,
group_id=roomid,
error_message=error_message,
stack_trace=stack_trace
)
logger.info(f"[{plugin_name}] 成功记录插件错误: {command}, 错误: {error_message}")
except Exception as db_error:
logger.error(f"[{plugin_name}] 记录插件统计数据失败: {db_error}")
# 重新抛出异常,让上层处理
raise
except Exception as outer_error:
logger.error(f"[{plugin_name}] 装饰器外层错误: {outer_error}")
logger.error(traceback.format_exc())
# 确保原始函数仍然被调用,即使装饰器出错
return func(self, message)
return wrapper
return decorator

View File

@@ -6,7 +6,7 @@ from typing import Dict, Any, List, Optional, Tuple
from plugin_common.message_plugin_interface import MessagePluginInterface
from plugin_common.plugin_interface import PluginStatus
from robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
from utils.robot_cmd.robot_command import Feature, PermissionStatus
# 动态导入win_click.py

View File

@@ -7,8 +7,9 @@ from wcferry import Wcf
from plugin_common.message_plugin_interface import MessagePluginInterface
from plugin_common.plugin_interface import PluginStatus
from plugins.stats_collector.decorators import plugin_stats_decorator
from robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
from utils.decorator.plugin_decorators import plugin_stats_decorator
from utils.robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
from utils.decorator.points_decorator import plugin_points_cost
class VideoPlugin(MessagePluginInterface):
@@ -88,6 +89,7 @@ class VideoPlugin(MessagePluginInterface):
return command in self._commands
@plugin_stats_decorator(plugin_name="视频插件")
@plugin_points_cost(1, "视频插件消耗积分")
def process_message(self, message: Dict[str, Any]) -> Tuple[bool, Optional[str]]:
"""处理消息"""
content = str(message.get("content", "")).strip()

View File

@@ -8,8 +8,9 @@ from wcferry import Wcf
from message_util import MessageUtil
from plugin_common.message_plugin_interface import MessagePluginInterface
from plugin_common.plugin_interface import PluginStatus
from plugins.stats_collector.decorators import plugin_stats_decorator
from robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
from utils.decorator.plugin_decorators import plugin_stats_decorator
from utils.robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
from utils.decorator.points_decorator import plugin_points_cost
class VideoManPlugin(MessagePluginInterface):
@@ -89,6 +90,7 @@ class VideoManPlugin(MessagePluginInterface):
return command in self._commands
@plugin_stats_decorator(plugin_name="猛男视频")
@plugin_points_cost(1, "猛男视频消耗积分")
def process_message(self, message: Dict[str, Any]) -> Tuple[bool, Optional[str]]:
"""处理消息"""
content = str(message.get("content", "")).strip()

View File

@@ -7,8 +7,9 @@ from wcferry import Wcf
from plugin_common.message_plugin_interface import MessagePluginInterface
from plugin_common.plugin_interface import PluginStatus
from plugins.stats_collector.decorators import plugin_stats_decorator
from robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
from utils.decorator.plugin_decorators import plugin_stats_decorator
from utils.robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
from utils.decorator.points_decorator import plugin_points_cost
class XiurenImagePlugin(MessagePluginInterface):
@@ -87,6 +88,7 @@ class XiurenImagePlugin(MessagePluginInterface):
return command in self._commands
@plugin_stats_decorator(plugin_name="秀人图片")
@plugin_points_cost(1, "秀人图片消耗积分")
def process_message(self, message: Dict[str, Any]) -> Tuple[bool, Optional[str]]:
"""处理消息"""
content = str(message.get("content", "")).strip()