需求:1.加入了用户积分表;2.加入了指令积分扣除功能;3.加入了积分获得与扣除注解。
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
from flask import Blueprint, render_template, jsonify, request, current_app
|
||||
from .auth import login_required
|
||||
import logging
|
||||
from robot_cmd.robot_command import GroupBotManager, Feature, PermissionStatus
|
||||
from utils.robot_cmd.robot_command import GroupBotManager, Feature, PermissionStatus
|
||||
from datetime import datetime
|
||||
|
||||
# 创建机器人管理蓝图
|
||||
|
||||
578
db/points_db.py
Normal file
578
db/points_db.py
Normal file
@@ -0,0 +1,578 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
积分系统数据库操作类
|
||||
"""
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from typing import Dict, List, Optional, Tuple, Any
|
||||
|
||||
from db.base import BaseDBOperator
|
||||
from db.connection import DBConnectionManager
|
||||
|
||||
|
||||
class PointSource(Enum):
|
||||
"""积分来源枚举"""
|
||||
CHECKIN = "checkin" # 签到
|
||||
GAME = "game" # 游戏
|
||||
ADMIN = "admin" # 管理员操作
|
||||
TRADE = "trade" # 积分交易
|
||||
PLUGIN = "plugin" # 插件使用
|
||||
OTHER = "other" # 其他
|
||||
|
||||
|
||||
class PointsDBOperator(BaseDBOperator):
|
||||
"""积分系统数据库操作类"""
|
||||
|
||||
def __init__(self, db_manager=None):
|
||||
"""初始化积分数据库操作类"""
|
||||
super().__init__(db_manager or DBConnectionManager.get_instance())
|
||||
self.logger = logging.getLogger("PointsDBOperator")
|
||||
|
||||
# 确保数据库表存在
|
||||
self._ensure_tables_exist()
|
||||
|
||||
def _ensure_tables_exist(self):
|
||||
"""确保积分相关的数据库表存在"""
|
||||
try:
|
||||
# 创建用户积分表
|
||||
self.execute_update("""
|
||||
CREATE TABLE IF NOT EXISTS t_user_points (
|
||||
id INTEGER PRIMARY KEY AUTO_INCREMENT,
|
||||
user_id VARCHAR(100) NOT NULL,
|
||||
group_id VARCHAR(100) NOT NULL,
|
||||
total_points INTEGER DEFAULT 0,
|
||||
checkin_points INTEGER DEFAULT 0,
|
||||
game_points INTEGER DEFAULT 0,
|
||||
other_points INTEGER DEFAULT 0,
|
||||
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE(user_id, group_id)
|
||||
) ENGINE=InnoDB CHARACTER SET utf8mb4;
|
||||
""")
|
||||
|
||||
# 创建积分交易记录表
|
||||
self.execute_update("""
|
||||
CREATE TABLE IF NOT EXISTS t_point_transactions (
|
||||
id INTEGER PRIMARY KEY AUTO_INCREMENT,
|
||||
user_id VARCHAR(100) NOT NULL,
|
||||
group_id VARCHAR(100) NOT NULL,
|
||||
transaction_type VARCHAR(20) NOT NULL,
|
||||
points INTEGER NOT NULL,
|
||||
source VARCHAR(50) NOT NULL,
|
||||
description TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB CHARACTER SET utf8mb4;
|
||||
""")
|
||||
|
||||
# 创建功能插件积分配置表
|
||||
self.execute_update("""
|
||||
CREATE TABLE IF NOT EXISTS t_plugin_point_config (
|
||||
id INTEGER PRIMARY KEY AUTO_INCREMENT,
|
||||
plugin_name VARCHAR(100) NOT NULL,
|
||||
points_required INTEGER DEFAULT 0,
|
||||
is_enabled BOOLEAN DEFAULT TRUE,
|
||||
description TEXT,
|
||||
UNIQUE(plugin_name)
|
||||
) ENGINE=InnoDB CHARACTER SET utf8mb4;
|
||||
""")
|
||||
|
||||
self.logger.info("积分系统数据库表检查/创建完成")
|
||||
except Exception as e:
|
||||
self.logger.error(f"创建积分系统数据库表失败: {e}")
|
||||
raise
|
||||
|
||||
def get_user_points(self, user_id: str, group_id: str) -> Dict:
|
||||
"""
|
||||
获取用户积分信息
|
||||
|
||||
Args:
|
||||
user_id: 用户ID
|
||||
group_id: 群组ID
|
||||
|
||||
Returns:
|
||||
包含用户积分信息的字典
|
||||
"""
|
||||
try:
|
||||
# 先尝试从新表获取
|
||||
result = self.execute_query("""
|
||||
SELECT * FROM t_user_points
|
||||
WHERE user_id = %s AND group_id = %s
|
||||
""", (user_id, group_id), fetch_one=True)
|
||||
|
||||
if result:
|
||||
return result
|
||||
|
||||
# 如果新表没有数据,尝试从旧表迁移数据
|
||||
return self._migrate_user_points(user_id, group_id)
|
||||
except Exception as e:
|
||||
self.logger.error(f"获取用户积分失败: {e}")
|
||||
return {
|
||||
"user_id": user_id,
|
||||
"group_id": group_id,
|
||||
"total_points": 0,
|
||||
"checkin_points": 0,
|
||||
"game_points": 0,
|
||||
"other_points": 0
|
||||
}
|
||||
|
||||
def _migrate_user_points(self, user_id: str, group_id: str) -> Dict:
|
||||
"""
|
||||
从旧表迁移用户积分数据到新表
|
||||
|
||||
Args:
|
||||
user_id: 用户ID
|
||||
group_id: 群组ID
|
||||
|
||||
Returns:
|
||||
包含用户积分信息的字典
|
||||
"""
|
||||
result = {
|
||||
"user_id": user_id,
|
||||
"group_id": group_id,
|
||||
"total_points": 0,
|
||||
"checkin_points": 0,
|
||||
"game_points": 0,
|
||||
"other_points": 0
|
||||
}
|
||||
|
||||
try:
|
||||
# 查询签到积分
|
||||
sign_result = self.execute_query("""
|
||||
SELECT points FROM t_sign_record
|
||||
WHERE wx_id = %s AND group_id = %s
|
||||
""", (user_id, group_id), fetch_one=True)
|
||||
|
||||
# 查询游戏积分
|
||||
game_result = self.execute_query("""
|
||||
SELECT points FROM t_encyclopedia_players
|
||||
WHERE player_id = %s AND group_id = %s
|
||||
""", (user_id, group_id), fetch_one=True)
|
||||
|
||||
# 合并积分
|
||||
checkin_points = sign_result["points"] if sign_result else 0
|
||||
game_points = game_result["points"] if game_result else 0
|
||||
total_points = checkin_points + game_points
|
||||
|
||||
# 更新结果
|
||||
result["checkin_points"] = checkin_points
|
||||
result["game_points"] = game_points
|
||||
result["total_points"] = total_points
|
||||
|
||||
# 插入到新表
|
||||
self.execute_update("""
|
||||
INSERT INTO t_user_points
|
||||
(user_id, group_id, total_points, checkin_points, game_points, other_points)
|
||||
VALUES (%s, %s, %s, %s, %s, %s)
|
||||
""", (user_id, group_id, total_points, checkin_points, game_points, 0))
|
||||
|
||||
# 获取插入后的完整记录
|
||||
return self.execute_query("""
|
||||
SELECT * FROM t_user_points
|
||||
WHERE user_id = %s AND group_id = %s
|
||||
""", (user_id, group_id), fetch_one=True) or result
|
||||
except Exception as e:
|
||||
self.logger.error(f"迁移用户积分失败: {e}")
|
||||
return result
|
||||
|
||||
def add_points(self, user_id: str, group_id: str, points: int,
|
||||
source: PointSource, description: str = None,
|
||||
user_name: str = None) -> Tuple[bool, Dict]:
|
||||
"""
|
||||
增加用户积分
|
||||
|
||||
Args:
|
||||
user_id: 用户ID
|
||||
group_id: 群组ID
|
||||
points: 积分数量
|
||||
source: 积分来源
|
||||
description: 描述
|
||||
user_name: 用户名称
|
||||
|
||||
Returns:
|
||||
(成功标志, 用户积分信息)
|
||||
"""
|
||||
if points <= 0:
|
||||
return False, {"error": "积分必须为正数"}
|
||||
|
||||
try:
|
||||
# 检查用户是否存在
|
||||
user_exists = self.execute_query("""
|
||||
SELECT * FROM t_user_points
|
||||
WHERE user_id = %s AND group_id = %s
|
||||
""", (user_id, group_id), fetch_one=True)
|
||||
|
||||
if not user_exists:
|
||||
# 如果用户不存在,先迁移或创建用户
|
||||
self._migrate_user_points(user_id, group_id)
|
||||
|
||||
# 更新积分
|
||||
source_field = f"{source.value}_points" if source.value in ["checkin", "game"] else "other_points"
|
||||
|
||||
self.execute_update(f"""
|
||||
UPDATE t_user_points
|
||||
SET total_points = total_points + %s,
|
||||
{source_field} = {source_field} + %s
|
||||
WHERE user_id = %s AND group_id = %s
|
||||
""", (points, points, user_id, group_id))
|
||||
|
||||
# 记录交易
|
||||
self.execute_update("""
|
||||
INSERT INTO t_point_transactions
|
||||
(user_id, group_id, transaction_type, points, source, description)
|
||||
VALUES (%s, %s, %s, %s, %s, %s)
|
||||
""", (user_id, group_id, "earn", points, source.value, description))
|
||||
|
||||
# 同时更新旧表,保持兼容
|
||||
if source == PointSource.CHECKIN:
|
||||
self.execute_update("""
|
||||
UPDATE t_sign_record
|
||||
SET points = points + %s
|
||||
WHERE wx_id = %s AND group_id = %s
|
||||
""", (points, user_id, group_id))
|
||||
elif source == PointSource.GAME:
|
||||
self.execute_update("""
|
||||
UPDATE t_encyclopedia_players
|
||||
SET points = points + %s
|
||||
WHERE player_id = %s AND group_id = %s
|
||||
""", (points, user_id, group_id))
|
||||
|
||||
# 获取更新后的积分信息
|
||||
updated_points = self.execute_query("""
|
||||
SELECT * FROM t_user_points
|
||||
WHERE user_id = %s AND group_id = %s
|
||||
""", (user_id, group_id), fetch_one=True)
|
||||
|
||||
return True, updated_points
|
||||
except Exception as e:
|
||||
self.logger.error(f"增加用户积分失败: {e}")
|
||||
return False, {"error": str(e)}
|
||||
|
||||
def deduct_points(self, user_id: str, group_id: str, points: int,
|
||||
source: PointSource, description: str = None) -> Tuple[bool, Dict]:
|
||||
"""
|
||||
扣除用户积分
|
||||
|
||||
Args:
|
||||
user_id: 用户ID
|
||||
group_id: 群组ID
|
||||
points: 积分数量
|
||||
source: 积分来源
|
||||
description: 描述
|
||||
|
||||
Returns:
|
||||
(成功标志, 用户积分信息)
|
||||
"""
|
||||
if points <= 0:
|
||||
return False, {"error": "积分必须为正数"}
|
||||
|
||||
try:
|
||||
# 检查用户是否存在及积分是否足够
|
||||
user_points = self.execute_query("""
|
||||
SELECT * FROM t_user_points
|
||||
WHERE user_id = %s AND group_id = %s
|
||||
""", (user_id, group_id), fetch_one=True)
|
||||
|
||||
if not user_points:
|
||||
# 如果用户不存在,先迁移或创建用户
|
||||
user_points = self._migrate_user_points(user_id, group_id)
|
||||
|
||||
if user_points["total_points"] < points:
|
||||
return False, {"error": "积分不足", "current_points": user_points["total_points"]}
|
||||
|
||||
# 更新积分
|
||||
self.execute_update("""
|
||||
UPDATE t_user_points
|
||||
SET total_points = total_points - %s
|
||||
WHERE user_id = %s AND group_id = %s
|
||||
""", (points, user_id, group_id))
|
||||
|
||||
# 记录交易
|
||||
self.execute_update("""
|
||||
INSERT INTO t_point_transactions
|
||||
(user_id, group_id, transaction_type, points, source, description)
|
||||
VALUES (%s, %s, %s, %s, %s, %s)
|
||||
""", (user_id, group_id, "spend", -points, source.value, description))
|
||||
|
||||
# 获取更新后的积分信息
|
||||
updated_points = self.execute_query("""
|
||||
SELECT * FROM t_user_points
|
||||
WHERE user_id = %s AND group_id = %s
|
||||
""", (user_id, group_id), fetch_one=True)
|
||||
|
||||
return True, updated_points
|
||||
except Exception as e:
|
||||
self.logger.error(f"扣除用户积分失败: {e}")
|
||||
return False, {"error": str(e)}
|
||||
|
||||
def transfer_points(self, from_user_id: str, to_user_id: str, group_id: str,
|
||||
points: int, description: str = None) -> Tuple[bool, Dict]:
|
||||
"""
|
||||
转移积分从一个用户到另一个用户
|
||||
|
||||
Args:
|
||||
from_user_id: 转出用户ID
|
||||
to_user_id: 转入用户ID
|
||||
group_id: 群组ID
|
||||
points: 积分数量
|
||||
description: 描述
|
||||
|
||||
Returns:
|
||||
(成功标志, 结果信息)
|
||||
"""
|
||||
if points <= 0:
|
||||
return False, {"error": "积分必须为正数"}
|
||||
|
||||
try:
|
||||
# 先扣除转出用户积分
|
||||
success, result = self.deduct_points(
|
||||
from_user_id, group_id, points,
|
||||
PointSource.TRADE, f"转账给用户 {to_user_id}: {description}"
|
||||
)
|
||||
|
||||
if not success:
|
||||
return False, result
|
||||
|
||||
# 再增加转入用户积分
|
||||
success, to_result = self.add_points(
|
||||
to_user_id, group_id, points,
|
||||
PointSource.TRADE, f"收到用户 {from_user_id} 的转账: {description}"
|
||||
)
|
||||
|
||||
if not success:
|
||||
# 如果增加失败,回滚扣除操作
|
||||
self.add_points(
|
||||
from_user_id, group_id, points,
|
||||
PointSource.TRADE, f"转账失败退回: {description}"
|
||||
)
|
||||
return False, to_result
|
||||
|
||||
return True, {
|
||||
"from_user": result,
|
||||
"to_user": to_result
|
||||
}
|
||||
except Exception as e:
|
||||
self.logger.error(f"转移用户积分失败: {e}")
|
||||
return False, {"error": str(e)}
|
||||
|
||||
def get_user_transactions(self, user_id: str, group_id: str, limit: int = 10) -> List[Dict]:
|
||||
"""
|
||||
获取用户积分交易记录
|
||||
|
||||
Args:
|
||||
user_id: 用户ID
|
||||
group_id: 群组ID
|
||||
limit: 记录数量限制
|
||||
|
||||
Returns:
|
||||
交易记录列表
|
||||
"""
|
||||
try:
|
||||
return self.execute_query("""
|
||||
SELECT * FROM t_point_transactions
|
||||
WHERE user_id = %s AND group_id = %s
|
||||
ORDER BY created_at DESC
|
||||
LIMIT %s
|
||||
""", (user_id, group_id, limit))
|
||||
except Exception as e:
|
||||
self.logger.error(f"获取用户交易记录失败: {e}")
|
||||
return []
|
||||
|
||||
def get_points_ranking(self, group_id: str, limit: int = 10) -> List[Dict]:
|
||||
"""
|
||||
获取群组积分排行榜
|
||||
|
||||
Args:
|
||||
group_id: 群组ID
|
||||
limit: 记录数量限制
|
||||
|
||||
Returns:
|
||||
排行榜列表
|
||||
"""
|
||||
try:
|
||||
return self.execute_query("""
|
||||
SELECT user_id, total_points, checkin_points, game_points, other_points
|
||||
FROM t_user_points
|
||||
WHERE group_id = %s
|
||||
ORDER BY total_points DESC
|
||||
LIMIT %s
|
||||
""", (group_id, limit))
|
||||
except Exception as e:
|
||||
self.logger.error(f"获取积分排行榜失败: {e}")
|
||||
return []
|
||||
|
||||
def get_plugin_config(self, plugin_name: str) -> Optional[Dict]:
|
||||
"""
|
||||
获取插件积分配置
|
||||
|
||||
Args:
|
||||
plugin_name: 插件名称
|
||||
|
||||
Returns:
|
||||
插件积分配置
|
||||
"""
|
||||
try:
|
||||
return self.execute_query("""
|
||||
SELECT * FROM t_plugin_point_config
|
||||
WHERE plugin_name = %s
|
||||
""", (plugin_name,), fetch_one=True)
|
||||
except Exception as e:
|
||||
self.logger.error(f"获取插件积分配置失败: {e}")
|
||||
return None
|
||||
|
||||
def set_plugin_config(self, plugin_name: str, points_required: int,
|
||||
is_enabled: bool = True, description: str = None) -> bool:
|
||||
"""
|
||||
设置插件积分配置
|
||||
|
||||
Args:
|
||||
plugin_name: 插件名称
|
||||
points_required: 所需积分
|
||||
is_enabled: 是否启用
|
||||
description: 描述
|
||||
|
||||
Returns:
|
||||
是否成功
|
||||
"""
|
||||
try:
|
||||
self.execute_update("""
|
||||
INSERT INTO t_plugin_point_config
|
||||
(plugin_name, points_required, is_enabled, description)
|
||||
VALUES (%s, %s, %s, %s)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
points_required = VALUES(points_required),
|
||||
is_enabled = VALUES(is_enabled),
|
||||
description = VALUES(description)
|
||||
""", (plugin_name, points_required, is_enabled, description))
|
||||
return True
|
||||
except Exception as e:
|
||||
self.logger.error(f"设置插件积分配置失败: {e}")
|
||||
return False
|
||||
|
||||
def get_all_plugin_configs(self) -> List[Dict]:
|
||||
"""
|
||||
获取所有插件积分配置
|
||||
|
||||
Returns:
|
||||
所有插件积分配置
|
||||
"""
|
||||
try:
|
||||
return self.execute_query("SELECT * FROM t_plugin_point_config")
|
||||
except Exception as e:
|
||||
self.logger.error(f"获取所有插件积分配置失败: {e}")
|
||||
return []
|
||||
|
||||
def check_plugin_points(self, user_id: str, group_id: str, plugin_name: str) -> Tuple[bool, Dict]:
|
||||
"""
|
||||
检查用户是否有足够积分使用插件
|
||||
|
||||
Args:
|
||||
user_id: 用户ID
|
||||
group_id: 群组ID
|
||||
plugin_name: 插件名称
|
||||
|
||||
Returns:
|
||||
(是否有足够积分, 结果信息)
|
||||
"""
|
||||
try:
|
||||
# 获取插件积分配置
|
||||
plugin_config = self.get_plugin_config(plugin_name)
|
||||
|
||||
# 如果插件未配置或未启用积分限制,直接返回成功
|
||||
if not plugin_config or not plugin_config["is_enabled"]:
|
||||
return True, {"message": "插件未配置积分限制"}
|
||||
|
||||
# 获取用户积分
|
||||
user_points = self.get_user_points(user_id, group_id)
|
||||
|
||||
# 检查积分是否足够
|
||||
if user_points["total_points"] < plugin_config["points_required"]:
|
||||
return False, {
|
||||
"error": "积分不足",
|
||||
"current_points": user_points["total_points"],
|
||||
"required_points": plugin_config["points_required"]
|
||||
}
|
||||
|
||||
return True, {
|
||||
"message": "积分充足",
|
||||
"current_points": user_points["total_points"],
|
||||
"required_points": plugin_config["points_required"]
|
||||
}
|
||||
except Exception as e:
|
||||
self.logger.error(f"检查插件积分失败: {e}")
|
||||
return True, {"error": str(e)} # 出错时默认允许使用
|
||||
|
||||
def use_plugin(self, user_id: str, group_id: str, plugin_name: str) -> Tuple[bool, Dict]:
|
||||
"""
|
||||
使用插件并扣除积分
|
||||
|
||||
Args:
|
||||
user_id: 用户ID
|
||||
group_id: 群组ID
|
||||
plugin_name: 插件名称
|
||||
|
||||
Returns:
|
||||
(是否成功, 结果信息)
|
||||
"""
|
||||
try:
|
||||
# 先检查积分是否足够
|
||||
can_use, result = self.check_plugin_points(user_id, group_id, plugin_name)
|
||||
|
||||
if not can_use:
|
||||
return False, result
|
||||
|
||||
# 如果插件未配置积分或不需要扣除积分,直接返回成功
|
||||
if "required_points" not in result or result["required_points"] <= 0:
|
||||
return True, {"message": "无需扣除积分"}
|
||||
|
||||
# 扣除积分
|
||||
return self.deduct_points(
|
||||
user_id, group_id, result["required_points"],
|
||||
PointSource.PLUGIN, f"使用插件: {plugin_name}"
|
||||
)
|
||||
except Exception as e:
|
||||
self.logger.error(f"使用插件扣除积分失败: {e}")
|
||||
return False, {"error": str(e)}
|
||||
|
||||
def get_user_points_stats(self, group_id: str) -> Dict[str, Any]:
|
||||
"""
|
||||
获取群组积分统计信息
|
||||
|
||||
Args:
|
||||
group_id: 群组ID
|
||||
|
||||
Returns:
|
||||
统计信息
|
||||
"""
|
||||
stats = {
|
||||
"total_users": 0,
|
||||
"total_points": 0,
|
||||
"avg_points": 0,
|
||||
"max_points": 0,
|
||||
"min_points": 0,
|
||||
"checkin_points_total": 0,
|
||||
"game_points_total": 0,
|
||||
"other_points_total": 0
|
||||
}
|
||||
|
||||
try:
|
||||
result = self.execute_query("""
|
||||
SELECT
|
||||
COUNT(*) as total_users,
|
||||
SUM(total_points) as total_points,
|
||||
AVG(total_points) as avg_points,
|
||||
MAX(total_points) as max_points,
|
||||
MIN(total_points) as min_points,
|
||||
SUM(checkin_points) as checkin_points_total,
|
||||
SUM(game_points) as game_points_total,
|
||||
SUM(other_points) as other_points_total
|
||||
FROM t_user_points
|
||||
WHERE group_id = %s
|
||||
""", (group_id,), fetch_one=True)
|
||||
|
||||
if result:
|
||||
stats.update({k: v or 0 for k, v in result.items()})
|
||||
|
||||
return stats
|
||||
except Exception as e:
|
||||
self.logger.error(f"获取群组积分统计信息失败: {e}")
|
||||
return stats
|
||||
@@ -1,427 +0,0 @@
|
||||
import random
|
||||
from datetime import datetime
|
||||
|
||||
from game_task.game_chatgpt_qa import game_question_json, game_answer_json
|
||||
from db.connection import DBConnectionManager
|
||||
from db.encyclopedia import EncyclopediaDB
|
||||
|
||||
# 获取数据库连接管理器的单例
|
||||
db_manager = DBConnectionManager.get_instance()
|
||||
encyclopedia_db = EncyclopediaDB(db_manager)
|
||||
|
||||
|
||||
# 添加群聊
|
||||
def add_group(group_id, player_id):
|
||||
try:
|
||||
result = encyclopedia_db.add_group(group_id)
|
||||
if result:
|
||||
message = f"🎉 群 {group_id} 已就位,准备开燥!"
|
||||
else:
|
||||
message = f"🌟 群 {group_id} 早就蓄势待发啦!"
|
||||
return {"message": message, "player_id": player_id}
|
||||
except Exception as e:
|
||||
print(f"添加群聊出错: {e}")
|
||||
message = f"🌟 群 {group_id} 早就蓄势待发啦!"
|
||||
return {"message": message, "player_id": player_id}
|
||||
|
||||
|
||||
# 获取所有群聊ID
|
||||
def get_group_ids():
|
||||
try:
|
||||
return encyclopedia_db.get_all_groups()
|
||||
except Exception as e:
|
||||
print(f"获取群聊ID出错: {e}")
|
||||
return []
|
||||
|
||||
|
||||
# 确保游戏启动(自动初始化群聊和玩家)
|
||||
def ensure_game_started(group_id, player_id, player_name="未知玩家"):
|
||||
try:
|
||||
# 检查并添加群聊
|
||||
if not encyclopedia_db.check_group_exists(group_id):
|
||||
add_group(group_id, player_id)
|
||||
|
||||
# 检查并添加玩家
|
||||
player = encyclopedia_db.get_player(player_id, group_id)
|
||||
if not player:
|
||||
encyclopedia_db.add_player(player_id, group_id, player_name)
|
||||
message = (
|
||||
f"🎉 哇塞,{player_name} 你来啦!\n"
|
||||
f"🌟 群 {group_id} 瞬间燃爆!\n"
|
||||
f"🎈 快来接任务,秀翻全场!指令: /t"
|
||||
)
|
||||
return {"message": message, "player_id": player_id}
|
||||
return {"message": None, "player_id": player_id}
|
||||
except Exception as e:
|
||||
print(f"确保游戏启动出错: {e}")
|
||||
return {"message": None, "player_id": player_id}
|
||||
|
||||
|
||||
# 随机分配任务
|
||||
def assign_random_task(group_id, player_id=None):
|
||||
try:
|
||||
# 获取群内所有玩家
|
||||
players = encyclopedia_db.get_all_players_in_group(group_id)
|
||||
|
||||
if not players:
|
||||
message = (
|
||||
f"😔 哎呀,群 {group_id} 静悄悄\n"
|
||||
f"🌟 快拉小伙伴来嗨吧!"
|
||||
)
|
||||
return {"message": message, "player_id": player_id}
|
||||
|
||||
if player_id:
|
||||
player_dict = {p['player_id']: p['player_name'] for p in players}
|
||||
if player_id not in player_dict:
|
||||
message = (
|
||||
f"😅 嘿,{player_id} 你谁啊?\n"
|
||||
f"🌟 先用 /s 报名,不然没法玩哦!"
|
||||
)
|
||||
return {"message": message, "player_id": player_id}
|
||||
holder_id = player_id
|
||||
holder_name = player_dict[player_id]
|
||||
else:
|
||||
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 = encyclopedia_db.create_active_task(
|
||||
group_id, question, answer, score, description, holder_id
|
||||
)
|
||||
|
||||
if not active_task_id:
|
||||
message = f"😔 任务创建失败,请稍后再试!"
|
||||
return {"message": message, "player_id": player_id}
|
||||
|
||||
if player_id:
|
||||
message = (
|
||||
f"🎁 {holder_name},你的专属任务闪亮登场!\n"
|
||||
f"🎀 任务ID: {active_task_id}\n"
|
||||
f"🎈 问题:[{category}]{question}\n"
|
||||
f"🌼 积分:{score}\n"
|
||||
f"🌈 快上答案:/a {active_task_id} 答案"
|
||||
)
|
||||
else:
|
||||
message = (
|
||||
f"🎁 新任务来袭,够不够刺激?\n"
|
||||
f"🎀 任务ID: {active_task_id}\n"
|
||||
f"🌟 幸运鹅:{holder_name}\n"
|
||||
f"🎈 问题:[{category}]{question}\n"
|
||||
f"🌼 积分:{score}\n"
|
||||
f"🌈 抢答格式:/a {active_task_id} 答案"
|
||||
)
|
||||
return {"message": message, "player_id": holder_id}
|
||||
except Exception as e:
|
||||
print(f"分配任务出错: {e}")
|
||||
message = f"😔 任务分配出错,请稍后再试!"
|
||||
return {"message": message, "player_id": player_id}
|
||||
|
||||
|
||||
# 提交答案并计分
|
||||
def submit_answer(group_id, player_id, task_id, answer):
|
||||
try:
|
||||
# 获取玩家信息
|
||||
player = encyclopedia_db.get_player(player_id, group_id)
|
||||
if not player:
|
||||
message = (
|
||||
f"😅 嘿,{player_id} 你是路人甲吗?\n"
|
||||
f"🌟 用 /s 先加入群 {group_id} 吧!"
|
||||
)
|
||||
return {"message": message, "player_id": player_id}
|
||||
|
||||
player_name = player['player_name']
|
||||
|
||||
if not task_id.isdigit():
|
||||
message = (
|
||||
f"😅 喂,任务ID得是数字好吗?\n"
|
||||
f"🌟 比如:1\n"
|
||||
f"🎈 别瞎搞,重新来!"
|
||||
)
|
||||
return {"message": message, "player_id": player_id}
|
||||
|
||||
active_task_id = int(task_id)
|
||||
|
||||
# 获取任务信息
|
||||
task_data = encyclopedia_db.get_task_by_id(group_id, active_task_id)
|
||||
|
||||
if not task_data:
|
||||
message = (
|
||||
f"😔 哎哟,任务 task_{active_task_id} 不翼而飞啦!\n"
|
||||
f"🌼 可能被别人抢先一步咯!"
|
||||
)
|
||||
return {"message": message, "player_id": player_id}
|
||||
|
||||
if task_data['status'] == 'completed':
|
||||
message = (
|
||||
f"😄 哈哈,你慢了一步!\n"
|
||||
f"🌟 任务 task_{active_task_id} 已经完结\n"
|
||||
f"🎈 快去抢新任务吧!"
|
||||
)
|
||||
return {"message": message, "player_id": player_id}
|
||||
|
||||
question = task_data['question']
|
||||
correct_answer_db = task_data['answer'].lower()
|
||||
top_score = task_data['score']
|
||||
holder_id = task_data['holder_id']
|
||||
|
||||
# 获取任务持有者信息
|
||||
holder = encyclopedia_db.get_task_holder(group_id, 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
|
||||
|
||||
if is_correct:
|
||||
# 更新玩家积分
|
||||
encyclopedia_db.update_player_points(player_id, group_id, points)
|
||||
|
||||
# 完成任务
|
||||
encyclopedia_db.complete_task(active_task_id)
|
||||
|
||||
if player_id == holder_id:
|
||||
message = (
|
||||
f"🎉 {player_name} 你是天才吗?\n"
|
||||
f"🌟 任务:{question}\n"
|
||||
f"🎈 答对啦,简直无敌!\n"
|
||||
f"🌈 奖励:{points} 分\n"
|
||||
f"🎀 彩蛋:{description}"
|
||||
)
|
||||
else:
|
||||
message = (
|
||||
f"🎉 {player_name} 抢答王上线!\n"
|
||||
f"🌟 任务:{question}\n"
|
||||
f"🎈 原主:{holder_name} 被你截胡啦!\n"
|
||||
f"🌈 狂揽 {points} 分,太骚了!\n"
|
||||
f"🎀 彩蛋:{description}"
|
||||
)
|
||||
else:
|
||||
# 扣除积分
|
||||
encyclopedia_db.update_player_points(player_id, group_id, -1)
|
||||
points = -1
|
||||
message = (
|
||||
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} 还能抢救一下!"
|
||||
)
|
||||
|
||||
# 添加任务历史记录
|
||||
encyclopedia_db.add_task_history(
|
||||
group_id, active_task_id, player_id, answer, is_correct, points
|
||||
)
|
||||
|
||||
return {"message": message, "player_id": player_id}
|
||||
except ValueError as e:
|
||||
print(f"submit_answer:{e}")
|
||||
message = (
|
||||
f"😅 喂,任务ID得是数字懂吗?\n"
|
||||
f"🌟 比如:1\n"
|
||||
f"🎈 重来,别皮!"
|
||||
)
|
||||
return {"message": message, "player_id": player_id}
|
||||
except Exception as e:
|
||||
print(f"submit_answer:{e}")
|
||||
message = (
|
||||
f"😅 出错了,任务ID得是数字哦!\n"
|
||||
f"🌟 比如:1\n"
|
||||
f"🎈 再试一次吧!"
|
||||
)
|
||||
return {"message": message, "player_id": player_id}
|
||||
|
||||
|
||||
# 显示排行榜
|
||||
def show_rank(group_id, player_id):
|
||||
try:
|
||||
# 获取排行榜
|
||||
ranks = encyclopedia_db.get_player_ranking(group_id, 10)
|
||||
|
||||
if not ranks:
|
||||
message = (
|
||||
f"😔 群 {group_id} 冷冷清清\n"
|
||||
f"🌟 快来一起燥起来吧!"
|
||||
)
|
||||
return {"message": message, "player_id": player_id}
|
||||
|
||||
rank_text = f"🎉 群 {group_id} 排行榜(Top 10)来啦!\n"
|
||||
for i, row in enumerate(ranks, 1):
|
||||
rank_text += f"🐓 {i}. {row['player_name']}: {row['points']} 分\n"
|
||||
return {"message": rank_text, "player_id": player_id}
|
||||
except Exception as e:
|
||||
print(f"显示排行榜出错: {e}")
|
||||
message = f"😔 获取排行榜出错,请稍后再试!"
|
||||
return {"message": message, "player_id": player_id}
|
||||
|
||||
|
||||
# 显示当前活跃任务
|
||||
def show_active_tasks(group_id, player_id):
|
||||
try:
|
||||
# 获取活跃任务
|
||||
tasks = encyclopedia_db.get_active_tasks_in_group(group_id)
|
||||
|
||||
if not tasks:
|
||||
message = (
|
||||
f"😄 群 {group_id} 现在一片祥和\n"
|
||||
f"🌟 没任务?快用 /t 搞一个!"
|
||||
)
|
||||
return {"message": message, "player_id": player_id}
|
||||
|
||||
task_text = f"🎉 群 {group_id} 活跃任务速递:\n"
|
||||
for task in tasks:
|
||||
task_text += (
|
||||
f"🌈 任务ID: task_{task['active_task_id']}\n"
|
||||
f"🎀 问题:{task['question']}\n"
|
||||
f"🌼 大佬:{task['player_name']}\n"
|
||||
)
|
||||
return {"message": task_text, "player_id": player_id}
|
||||
except Exception as e:
|
||||
print(f"显示活跃任务出错: {e}")
|
||||
message = f"😔 获取活跃任务出错,请稍后再试!"
|
||||
return {"message": message, "player_id": player_id}
|
||||
|
||||
|
||||
# 列举所有未完成任务
|
||||
def list_uncompleted_tasks(group_id, player_id):
|
||||
try:
|
||||
# 获取未完成任务
|
||||
tasks = encyclopedia_db.get_active_tasks_in_group(group_id)
|
||||
|
||||
if not tasks:
|
||||
message = (
|
||||
f"😄 群 {group_id} 全员开挂?\n"
|
||||
f"🌟 没未完成任务,快用 /t 再战!"
|
||||
)
|
||||
return {"message": message, "player_id": player_id}
|
||||
|
||||
task_text = f"🎉 群 {group_id} 未完成任务大曝光:\n"
|
||||
for task in tasks:
|
||||
task_text += (
|
||||
f"🌈 任务ID: task_{task['active_task_id']}\n"
|
||||
f"🎀 问题:{task['question']}\n"
|
||||
f"🌼 主人:{task['player_name']}\n"
|
||||
)
|
||||
return {"message": task_text, "player_id": player_id}
|
||||
except Exception as e:
|
||||
print(f"列举未完成任务出错: {e}")
|
||||
message = f"😔 获取未完成任务出错,请稍后再试!"
|
||||
return {"message": message, "player_id": player_id}
|
||||
|
||||
|
||||
# 定时任务:整点触发,排除23:00-08:00
|
||||
def run_random_task_assignment(group_id):
|
||||
current_hour = datetime.now().hour
|
||||
if current_hour >= 23 or current_hour < 9:
|
||||
message = (
|
||||
f"😴 现在 {current_hour}:00,小伙伴们都睡啦\n"
|
||||
f"🌙 9点到22点再来嗨吧!"
|
||||
)
|
||||
print(f"{datetime.now()} 群 {group_id} 当前时间 {current_hour}:00 在23:00-08:00区间,跳过任务发放")
|
||||
return {"message": message, "player_id": None}
|
||||
result = assign_random_task(group_id)
|
||||
print(f"{datetime.now()} {result['message']}")
|
||||
return result
|
||||
|
||||
|
||||
# 处理群聊消息
|
||||
def game_process_message(group_id, player_id, message, player_name="未知玩家"):
|
||||
init_result = ensure_game_started(group_id, player_id, player_name)
|
||||
init_message = init_result["message"]
|
||||
player_id = init_result["player_id"]
|
||||
|
||||
if message == "/s": # 可选:显式加入游戏
|
||||
if init_message:
|
||||
return {"message": init_message, "player_id": player_id}
|
||||
message = (
|
||||
f"😄 嘿,{player_name} 你来啦!\n"
|
||||
f"🌼 已加入群 {group_id} 的狂欢\n"
|
||||
f"🎶 快用 /t 开干吧!"
|
||||
)
|
||||
return {"message": message, "player_id": player_id}
|
||||
elif message == "/ts": # 查看活跃任务
|
||||
if init_message:
|
||||
message = init_message + "\n🌟 用 /ts 看看当前任务吧!"
|
||||
return {"message": message, "player_id": player_id}
|
||||
return show_active_tasks(group_id, player_id)
|
||||
elif message == "/l": # 列出未完成任务
|
||||
if init_message:
|
||||
message = init_message + "\n🌟 用 /l 查未完成任务哦!"
|
||||
return {"message": message, "player_id": player_id}
|
||||
return list_uncompleted_tasks(group_id, player_id)
|
||||
elif message.startswith("/a"): # 提交答案
|
||||
if init_message:
|
||||
message = init_message + "\n🌟 用 /a [任务ID] [答案] 放大招吧!"
|
||||
return {"message": message, "player_id": player_id}
|
||||
parts = message.split(" ", 2)
|
||||
if len(parts) < 3:
|
||||
message = (
|
||||
f"😅 喂,格式不对啊!\n"
|
||||
f"🌟 正确姿势:/a [任务ID] [答案]\n"
|
||||
f"🎈 比如:/a 1 钒"
|
||||
)
|
||||
return {"message": message, "player_id": player_id}
|
||||
task_id, answer = parts[1], parts[2]
|
||||
return submit_answer(group_id, player_id, task_id, answer)
|
||||
elif message == "/r": # 查看排行榜
|
||||
if init_message:
|
||||
message = init_message + "\n🌟 用 /r 看看谁是大佬!"
|
||||
return {"message": message, "player_id": player_id}
|
||||
return show_rank(group_id, player_id)
|
||||
elif message == "/ag": # 可选:手动添加群聊
|
||||
if init_message:
|
||||
return {"message": init_message, "player_id": player_id}
|
||||
return add_group(group_id, player_id)
|
||||
elif message == "/t": # 获取任务
|
||||
if init_message:
|
||||
message = init_message + "\n🌟 已为你准备好任务,快接招!"
|
||||
return {"message": message, "player_id": player_id}
|
||||
current_hour = datetime.now().hour
|
||||
if current_hour >= 23 or current_hour < 9:
|
||||
message = (
|
||||
f"😴 现在 {current_hour}:00\n"
|
||||
f"🌙 太晚啦,大家都睡了!\n"
|
||||
f"🌞 9点到22点再来嗨吧!"
|
||||
)
|
||||
return {"message": message, "player_id": player_id}
|
||||
return assign_random_task(group_id, player_id)
|
||||
else:
|
||||
message = (
|
||||
f"😄 嘿,二货!\n"
|
||||
f"🌟 指令玩错啦!\n"
|
||||
f"🎈 快试试这些:\n"
|
||||
f"🌈 /s - 加入狂欢(可选)\n"
|
||||
f"🎀 /ts - 看活跃任务\n"
|
||||
f"🌼 /l - 未完成任务\n"
|
||||
f"🌟 /a [任务ID] [答案] - 提交答案\n"
|
||||
f"🎈 /ag - 加群(可选)\n"
|
||||
f"🌈 /t - 抢任务\n"
|
||||
f"🎀 /r - 谁是大佬"
|
||||
)
|
||||
return {"message": message, "player_id": player_id}
|
||||
|
||||
|
||||
# 设置定时任务
|
||||
def setup_schedule():
|
||||
group_ids = get_group_ids()
|
||||
for gid in group_ids:
|
||||
run_random_task_assignment(group_id=gid)
|
||||
|
||||
|
||||
# 主程序
|
||||
if __name__ == "__main__":
|
||||
# 测试用例
|
||||
print(game_process_message("45317011307@chatroom", "Jyunere", "/t")) # 新用户获取任务
|
||||
print(game_process_message("45317011307@chatroom", "Jyunere", "/a 18 罗马斗兽场")) # 提交答案
|
||||
print(game_process_message("45317011307@chatroom", "Jyunere", "/r")) # 查看排行榜
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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):
|
||||
|
||||
5
plugins/game_task/__init__.py
Normal file
5
plugins/game_task/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from .main import GameTaskPlugin
|
||||
|
||||
def get_plugin():
|
||||
"""获取插件实例"""
|
||||
return GameTaskPlugin()
|
||||
8
plugins/game_task/config.toml
Normal file
8
plugins/game_task/config.toml
Normal 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
552
plugins/game_task/main.py
Normal 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}")
|
||||
@@ -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):
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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 # 导入消息工具类
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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):
|
||||
"""检查并重置每日签到计数"""
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
59
robot.py
59
robot.py
@@ -22,17 +22,16 @@ from base.func_xinghuo_web import XinghuoWeb
|
||||
from base.func_claude import Claude
|
||||
from configuration import Config
|
||||
from constants import ChatType
|
||||
from game_task.game_task_encyclopedia import game_process_message, get_group_ids, run_random_task_assignment
|
||||
from message_storage.message_to_db import MessageStorage
|
||||
from utils.wechat.message_to_db import MessageStorage
|
||||
from plugin_common.event_system import EventType, EventSystem
|
||||
from plugin_common.message_plugin_interface import MessagePluginInterface
|
||||
from plugin_common.plugin_interface import PluginStatus
|
||||
from plugin_common.plugin_manager import PluginManager
|
||||
from plugin_common.plugin_registry import PluginRegistry
|
||||
from robot_cmd.robot_command import GroupBotManager
|
||||
from utils.robot_cmd.robot_command import GroupBotManager
|
||||
from job_mgmt import Job
|
||||
from robot_cmd.robot_command import Feature
|
||||
from robot_cmd.robot_command import PermissionStatus
|
||||
from utils.robot_cmd.robot_command import Feature
|
||||
from utils.robot_cmd.robot_command import PermissionStatus
|
||||
|
||||
__version__ = "39.2.4.0"
|
||||
|
||||
@@ -243,26 +242,6 @@ class Robot(Job):
|
||||
except Exception as e:
|
||||
self.LOG.error(f"revoke_receive_message error: {e}")
|
||||
|
||||
# 兼容不@ 直接/触发指令,回答问题。
|
||||
try:
|
||||
if msg.content.startswith("/"):
|
||||
# 进行权限判断 加入权限,防止tokens浪费
|
||||
if self.gbm.get_group_permission(msg.roomid, Feature.TASK_GAME) == PermissionStatus.DISABLED:
|
||||
return
|
||||
else:
|
||||
# 因为内容中存在空格指令,所以不能使用
|
||||
self.LOG.info(f"msg.content:{msg.content}\n game_message: {msg.content}")
|
||||
resp = game_process_message(group_id=msg.roomid, player_id=msg.sender, message=msg.content,
|
||||
player_name=self.allContacts.get(msg.sender, msg.sender))
|
||||
message = resp["message"]
|
||||
player_id = resp["player_id"]
|
||||
print(f"消息: {message}")
|
||||
print(f"玩家ID: {player_id}")
|
||||
self.send_text_msg(message, msg.roomid, msg.sender)
|
||||
return
|
||||
except Exception as e:
|
||||
self.LOG.error(f"game_message_load error:{e}")
|
||||
|
||||
if msg.is_at(self.wxid): # 被@
|
||||
self.toAt(msg)
|
||||
return # 处理完群聊信息,后面就不需要处理了
|
||||
@@ -511,21 +490,21 @@ class Robot(Job):
|
||||
self.send_text_msg(output, r)
|
||||
except Exception as e:
|
||||
self.LOG.error(f"SendRanking error:{e}")
|
||||
|
||||
# 设置定时任务
|
||||
def game_auto_tasks(self):
|
||||
try:
|
||||
group_ids = get_group_ids()
|
||||
for gid in group_ids:
|
||||
if self.gbm.get_group_permission(gid, Feature.TASK_GAME) == PermissionStatus.ENABLED:
|
||||
rep = run_random_task_assignment(group_id=gid)
|
||||
message = rep["message"]
|
||||
player_id = rep["player_id"]
|
||||
print(f"消息: {message}")
|
||||
print(f"玩家ID: {player_id}")
|
||||
self.send_text_msg(message, gid, player_id)
|
||||
except Exception as e:
|
||||
self.LOG.error(f"message_summary_robot error:{e}")
|
||||
#
|
||||
# # 设置定时任务
|
||||
# def game_auto_tasks(self):
|
||||
# try:
|
||||
# group_ids = get_group_ids()
|
||||
# for gid in group_ids:
|
||||
# if self.gbm.get_group_permission(gid, Feature.TASK_GAME) == PermissionStatus.ENABLED:
|
||||
# rep = run_random_task_assignment(group_id=gid)
|
||||
# message = rep["message"]
|
||||
# player_id = rep["player_id"]
|
||||
# print(f"消息: {message}")
|
||||
# print(f"玩家ID: {player_id}")
|
||||
# self.send_text_msg(message, gid, player_id)
|
||||
# except Exception as e:
|
||||
# self.LOG.error(f"message_summary_robot error:{e}")
|
||||
|
||||
def xiu_ren_download_task(self):
|
||||
try:
|
||||
|
||||
164
utils/decorator/points_decorator.py
Normal file
164
utils/decorator/points_decorator.py
Normal file
@@ -0,0 +1,164 @@
|
||||
import functools
|
||||
import time
|
||||
import traceback
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Callable, Dict, Any, Tuple, Union
|
||||
|
||||
from db.connection import DBConnectionManager
|
||||
from db.points_db import PointsDBOperator, PointSource
|
||||
|
||||
|
||||
def points_reward_decorator(points_calculator: Union[int, Callable], source_type: str = "other",
|
||||
description: str = None):
|
||||
"""积分奖励装饰器
|
||||
|
||||
Args:
|
||||
points_calculator: 积分数量或计算函数,如果是函数,接收(self, message, success, response)参数并返回积分数量
|
||||
source_type: 积分来源类型 (checkin, game, other)
|
||||
description: 积分奖励描述
|
||||
|
||||
Returns:
|
||||
装饰器函数
|
||||
"""
|
||||
|
||||
def decorator(func: Callable) -> Callable:
|
||||
@functools.wraps(func)
|
||||
def wrapper(self, message: Dict[str, Any]) -> Tuple[bool, str]:
|
||||
# 调用原始方法
|
||||
success, response = func(self, message)
|
||||
|
||||
# 如果原始方法执行成功,奖励积分
|
||||
if success:
|
||||
try:
|
||||
# 获取消息信息
|
||||
sender = message.get("sender", "")
|
||||
roomid = message.get("roomid", "")
|
||||
|
||||
if sender and (roomid or sender):
|
||||
# 计算奖励积分数量
|
||||
if callable(points_calculator):
|
||||
# 如果是函数,调用函数计算积分
|
||||
points = points_calculator(self, message, success, response)
|
||||
if not points or points <= 0:
|
||||
# 如果计算结果为0或负数,不奖励积分
|
||||
return success, response
|
||||
else:
|
||||
# 如果是固定值,直接使用
|
||||
points = points_calculator
|
||||
|
||||
# 获取积分来源类型
|
||||
source = PointSource.CHECKIN
|
||||
if source_type.lower() == "game":
|
||||
source = PointSource.GAME
|
||||
elif source_type.lower() != "checkin":
|
||||
source = PointSource.OTHER
|
||||
|
||||
# 奖励积分
|
||||
db_manager = DBConnectionManager.get_instance()
|
||||
points_db = PointsDBOperator(db_manager)
|
||||
|
||||
# 如果description是函数,调用函数获取描述
|
||||
desc = description
|
||||
if callable(description):
|
||||
desc = description(self, message, success, response, points)
|
||||
|
||||
reward_success, reward_result = points_db.add_points(
|
||||
sender, roomid, points, source,
|
||||
desc or f"使用 {self.name if hasattr(self, 'name') else '功能'} 获得奖励"
|
||||
)
|
||||
|
||||
logger = logging.getLogger(f"PointsReward.{self.name if hasattr(self, 'name') else 'Unknown'}")
|
||||
if reward_success:
|
||||
logger.info(f"用户 {sender} 获得 {points} 积分奖励")
|
||||
|
||||
# 如果响应中没有提到积分,添加积分信息
|
||||
if "积分" not in response:
|
||||
response += f"\n\n🎁 恭喜获得 {points} 积分奖励!"
|
||||
else:
|
||||
logger.warning(f"用户 {sender} 积分奖励失败: {reward_result}")
|
||||
except Exception as e:
|
||||
logger = logging.getLogger("PointsReward")
|
||||
logger.error(f"奖励积分失败: {e}")
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
return success, response
|
||||
|
||||
return wrapper
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
def plugin_points_cost(points: int, description: str = None):
|
||||
"""插件积分消费装饰器
|
||||
|
||||
Args:
|
||||
points: 消费积分数量
|
||||
description: 积分消费描述
|
||||
|
||||
Returns:
|
||||
装饰器函数
|
||||
"""
|
||||
|
||||
def decorator(func: Callable) -> Callable:
|
||||
@functools.wraps(func)
|
||||
def wrapper(self, message: Dict[str, Any]) -> Tuple[bool, str]:
|
||||
try:
|
||||
# 获取消息信息
|
||||
sender = message.get("sender", "")
|
||||
roomid = message.get("roomid", "")
|
||||
|
||||
if not sender or not (roomid or sender):
|
||||
return func(self, message)
|
||||
|
||||
# 检查用户积分是否足够
|
||||
db_manager = DBConnectionManager.get_instance()
|
||||
points_db = PointsDBOperator(db_manager)
|
||||
|
||||
plugin_name = self.name if hasattr(self, 'name') else "未知插件"
|
||||
logger = logging.getLogger(f"PointsCost.{plugin_name}")
|
||||
|
||||
user_points = points_db.get_user_points(sender, roomid)
|
||||
if user_points["total_points"] < points:
|
||||
# 积分不足
|
||||
wcf = message.get("wcf")
|
||||
if wcf:
|
||||
wcf.send_text(
|
||||
f"❌ 积分不足,无法使用 {plugin_name} 功能\n"
|
||||
f"当前积分: {user_points['total_points']}\n"
|
||||
f"需要积分: {points}\n"
|
||||
f"还差 {points - user_points['total_points']} 积分",
|
||||
(roomid if roomid else sender), sender
|
||||
)
|
||||
logger.info(f"用户 {sender} 积分不足,无法使用功能")
|
||||
return False, "积分不足"
|
||||
|
||||
# 调用原始方法
|
||||
success, response = func(self, message)
|
||||
|
||||
# 如果原始方法执行成功,扣除积分
|
||||
if success:
|
||||
deduct_success, deduct_result = points_db.deduct_points(
|
||||
sender, roomid, points, PointSource.PLUGIN,
|
||||
description or f"使用 {plugin_name} 功能"
|
||||
)
|
||||
|
||||
if deduct_success:
|
||||
logger.info(f"用户 {sender} 使用功能扣除 {points} 积分")
|
||||
|
||||
# 如果响应中没有提到积分,添加积分信息
|
||||
if "积分" not in response:
|
||||
response += f"\n\n💰 已消费 {points} 积分"
|
||||
else:
|
||||
logger.warning(f"用户 {sender} 积分扣除失败: {deduct_result}")
|
||||
|
||||
return success, response
|
||||
except Exception as e:
|
||||
logger = logging.getLogger("PointsCost")
|
||||
logger.error(f"积分消费失败: {e}")
|
||||
logger.error(traceback.format_exc())
|
||||
return func(self, message)
|
||||
|
||||
return wrapper
|
||||
|
||||
return decorator
|
||||
@@ -3,9 +3,6 @@ import xml.etree.ElementTree as ET
|
||||
import logging
|
||||
import concurrent.futures # 添加线程池支持
|
||||
import os
|
||||
import hashlib
|
||||
import shutil
|
||||
|
||||
from wcferry import WxMsg, Wcf
|
||||
|
||||
from db.connection import DBConnectionManager
|
||||
@@ -3,7 +3,7 @@ import tomllib
|
||||
|
||||
from wcferry import WxMsg, Wcf
|
||||
|
||||
from robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
|
||||
from utils.robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
|
||||
from xiuren.random_pic import get_xiuren_pic
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user