203 lines
No EOL
7.6 KiB
Python
203 lines
No EOL
7.6 KiB
Python
import logging
|
||
import time
|
||
from collections import deque, defaultdict
|
||
from dataclasses import dataclass
|
||
|
||
from aiogram import BaseMiddleware, Router
|
||
from aiogram.types import Message
|
||
from typing import Dict, Callable, Awaitable, Any
|
||
|
||
router = Router()
|
||
|
||
# 根据某只狐狐自己发的计算公式试图重构了这部分
|
||
# 这个代码的目的是计算用户的欠打度,因为他的公式是用 AI 生成的,所以我也用 AI 生成了这个代码
|
||
# AI 太好用了你们知道吗.jpg
|
||
# 然后限于条件(比如我没有模型可以拿来分类)对公式进行了一部分精简,比如去除了发情度和理性度的计算,加大了对于别人 /打 的惩罚力度
|
||
@dataclass
|
||
class UserMetrics:
|
||
"""用户指标数据类"""
|
||
cai_count: int = 0 # 卖菜度发言数
|
||
xm_count: int = 0 # 羡慕度发言数
|
||
nsfw_count: int = 0 # NSFW度发言数
|
||
antisocial_count: int = 0 # 反社会度发言数
|
||
total_count: int = 0 # 总发言数
|
||
neutral_count: int = 0 # 中性发言数(用于水群频率)
|
||
|
||
|
||
class RikkiMiddleware(BaseMiddleware):
|
||
def __init__(self, target_user_id: str = "5545347637"):
|
||
# 存储每个用户的触发几率,初始值在40-50%之间
|
||
self.user_probabilities: Dict[str, float] = {}
|
||
# 触发关键词
|
||
self.xm_keywords = ["啃", "羡慕", "xm", "xmsl", "羡慕死了", "我菜"]
|
||
self.cai_keywords = ["菜", "菜了", "菜死了", "我菜", "废物"]
|
||
self.nsfw_keywords = ["kig", "电你", "被电", "⚡", "tk", "打", "🌿我"]
|
||
|
||
self.target_user_id = target_user_id
|
||
|
||
# 权重配置
|
||
self.weights = {
|
||
'w_v': 20, # 卖菜度权重
|
||
'w_m': 15, # 羡慕度权重
|
||
'w_n': 30, # NSFW度权重
|
||
'w_a': 30, # 反社会度权重
|
||
'lambda': 1, # 水群缓冲系数
|
||
}
|
||
|
||
# 放大系数
|
||
self.amplifiers = {
|
||
'alpha_v': 2.5, # 卖菜度放大系数
|
||
'beta_m': 2.0, # 羡慕度放大系数
|
||
'gamma_n': 5.0, # NSFW度放大系数
|
||
'alpha_a': 5.0, # 反社会度放大系数
|
||
}
|
||
|
||
# 用户数据存储
|
||
self.user_metrics: Dict[str, UserMetrics] = defaultdict(UserMetrics)
|
||
self.user_message_times: Dict[str, deque] = defaultdict(lambda: deque())
|
||
self.has_sent_warning: Dict[str, bool] = defaultdict(bool)
|
||
|
||
|
||
def record_message(self, user_id: str) -> None:
|
||
"""记录用户发送消息的时间"""
|
||
current_time = time.time()
|
||
user_messages = self.user_message_times[user_id]
|
||
|
||
# 添加当前时间戳
|
||
user_messages.append(current_time)
|
||
|
||
# 清理24小时前的记录
|
||
cutoff_time = current_time - 24 * 60 * 60 # 24小时前
|
||
while user_messages and user_messages[0] < cutoff_time:
|
||
user_messages.popleft()
|
||
|
||
def get_24h_message_count(self, user_id: str) -> int:
|
||
"""获取用户24小时内的发言次数"""
|
||
current_time = time.time()
|
||
cutoff_time = current_time - 24 * 60 * 60
|
||
|
||
# 清理过期记录
|
||
user_messages = self.user_message_times[user_id]
|
||
while user_messages and user_messages[0] < cutoff_time:
|
||
user_messages.popleft()
|
||
|
||
return len(user_messages)
|
||
|
||
def classify_message(self, message: str, user_id: str) -> None:
|
||
"""分析消息内容并更新用户指标"""
|
||
metrics = self.user_metrics[user_id]
|
||
metrics.total_count += 1
|
||
|
||
message_lower = message.lower()
|
||
classified = False
|
||
|
||
# 检查各类关键词
|
||
for keyword in self.cai_keywords:
|
||
if keyword in message_lower:
|
||
metrics.cai_count += 1
|
||
classified = True
|
||
break
|
||
|
||
for keyword in self.xm_keywords:
|
||
if keyword in message_lower:
|
||
metrics.xm_count += 1
|
||
classified = True
|
||
break
|
||
|
||
for keyword in self.nsfw_keywords:
|
||
if keyword in message_lower:
|
||
metrics.nsfw_count += 1
|
||
classified = True
|
||
break
|
||
|
||
# 如果没有匹配任何特征关键词,算作中性发言
|
||
if not classified:
|
||
metrics.neutral_count += 1
|
||
|
||
def calculate_qianda_score(self, user_id: str) -> float:
|
||
"""计算用户欠打度"""
|
||
if user_id != self.target_user_id:
|
||
return 0.0
|
||
|
||
metrics = self.user_metrics[user_id]
|
||
|
||
if metrics.total_count == 0:
|
||
return 0.0
|
||
|
||
# 计算各项指标 [0,1]
|
||
v = min(1, self.amplifiers['alpha_v'] * (metrics.cai_count / metrics.total_count))
|
||
m = min(1, self.amplifiers['beta_m'] * (metrics.xm_count / metrics.total_count))
|
||
n = min(1, self.amplifiers['gamma_n'] * (metrics.nsfw_count / metrics.total_count))
|
||
a = min(1, self.amplifiers['alpha_a'] * (metrics.antisocial_count / metrics.total_count))
|
||
|
||
# 计算水群频率缓冲因子 W
|
||
# N 是24小时内中性发言次数,K设为7
|
||
k = 7
|
||
import math
|
||
neutral_24h = min(metrics.neutral_count, self.get_24h_message_count(user_id))
|
||
w = min(max(0, 1 - math.log(neutral_24h + 1) / k), 1)
|
||
|
||
# 应用欠打度公式
|
||
base_score = (
|
||
v * self.weights['w_v'] +
|
||
m * self.weights['w_m'] +
|
||
n * self.weights['w_n'] +
|
||
a * self.weights['w_a']
|
||
)
|
||
|
||
water_factor = 1 + self.weights['lambda'] * (1 - w)
|
||
|
||
final_score = min(100, base_score * water_factor)
|
||
|
||
return final_score
|
||
|
||
|
||
async def __call__(
|
||
self,
|
||
handler: Callable[[Message, Dict[str, Any]], Awaitable[Any]],
|
||
event: Message,
|
||
data: Dict[str, Any]) -> Any:
|
||
"""
|
||
处理消息的主要方法
|
||
"""
|
||
if not event.text:
|
||
return await handler(event, data)
|
||
|
||
user_id = str(event.from_user.id)
|
||
if event.chat.type in ['group', 'supergroup'] and user_id == self.target_user_id:
|
||
self.classify_message(event.text, user_id)
|
||
score = self.calculate_qianda_score(user_id)
|
||
logging.debug(f"当前欠打度: {score:.2f}%")
|
||
|
||
# 警告阈值:80%
|
||
if score >= 80.0 and not self.has_sent_warning[user_id]:
|
||
self.has_sent_warning[user_id] = True
|
||
await event.reply("泥欠打了")
|
||
|
||
# 检查是否触发
|
||
if score >= 100.0:
|
||
# 重置数据
|
||
self.user_metrics[user_id] = UserMetrics()
|
||
self.has_sent_warning[user_id] = False
|
||
await event.reply("/打")
|
||
|
||
if event.text and event.text.startswith('/打') and event.reply_to_message and str(
|
||
event.reply_to_message.from_user.id) == self.target_user_id:
|
||
# 增加反社会度作为惩罚
|
||
metrics = self.user_metrics[self.target_user_id]
|
||
metrics.antisocial_count += 2 # 被打时额外增加反社会度
|
||
score = self.calculate_qianda_score(user_id)
|
||
logging.debug("当前欠打的几率是{}".format(score))
|
||
|
||
return await handler(event, data)
|
||
|
||
def get_user_status(self, user_id: str) -> str:
|
||
"""获取用户当前几率状态(用于调试)"""
|
||
score = self.calculate_qianda_score(user_id)
|
||
metrics = self.user_metrics[user_id]
|
||
|
||
return (f"欠打度: {score:.2f}%\n"
|
||
f"卖菜: {metrics.cai_count}, 羡慕: {metrics.xm_count}, "
|
||
f"NSFW: {metrics.nsfw_count},"
|
||
f"反社会: {metrics.antisocial_count}, 中性: {metrics.neutral_count}\n"
|
||
f"总发言: {metrics.total_count}") |