feat: more accurate formula provided the fox itself
This commit is contained in:
parent
3a6426d7da
commit
3440ab6a96
3 changed files with 173 additions and 56 deletions
|
@ -25,6 +25,7 @@ from core.actions import handle_actions, handle_reverse_actions
|
||||||
from core.stats import handle_stats_command
|
from core.stats import handle_stats_command
|
||||||
from core.middleware.stats import MessageStatsMiddleware
|
from core.middleware.stats import MessageStatsMiddleware
|
||||||
from core.unpin import handle_unpin_channel_message
|
from core.unpin import handle_unpin_channel_message
|
||||||
|
from core.rikki_hit import handle_query_hit_command
|
||||||
|
|
||||||
TOKEN = getenv("BOT_TOKEN")
|
TOKEN = getenv("BOT_TOKEN")
|
||||||
|
|
||||||
|
@ -52,6 +53,7 @@ class TelegramAdapter:
|
||||||
router.message(Command('about'))(handle_about_command)
|
router.message(Command('about'))(handle_about_command)
|
||||||
router.message(Command('ping'))(handle_ping_command)
|
router.message(Command('ping'))(handle_ping_command)
|
||||||
router.message(Command('tips'))(handle_tips_command)
|
router.message(Command('tips'))(handle_tips_command)
|
||||||
|
router.message(Command('query_hit'))(handle_query_hit_command)
|
||||||
# bitflip 模块
|
# bitflip 模块
|
||||||
router.message(Command('bitflip'))(handle_bitflip_command)
|
router.message(Command('bitflip'))(handle_bitflip_command)
|
||||||
# promote 模块
|
# promote 模块
|
||||||
|
|
|
@ -1,94 +1,203 @@
|
||||||
import logging
|
import logging
|
||||||
import random
|
import time
|
||||||
|
from collections import deque, defaultdict
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
from aiogram import BaseMiddleware, Router
|
from aiogram import BaseMiddleware, Router
|
||||||
from aiogram.types import Message
|
from aiogram.types import Message
|
||||||
from typing import Dict, Optional, Callable, Awaitable, Any
|
from typing import Dict, Callable, Awaitable, Any
|
||||||
|
|
||||||
router = Router()
|
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):
|
class RikkiMiddleware(BaseMiddleware):
|
||||||
def __init__(self, target_user_id: str = "5545347637"):
|
def __init__(self, target_user_id: str = "5545347637"):
|
||||||
# 存储每个用户的触发几率,初始值在40-50%之间
|
# 存储每个用户的触发几率,初始值在40-50%之间
|
||||||
self.user_probabilities: Dict[str, float] = {}
|
self.user_probabilities: Dict[str, float] = {}
|
||||||
# 触发关键词
|
# 触发关键词
|
||||||
self.trigger_plus_keywords = ["啃","羡慕", "xm", "xmsl", "羡慕死了", "我菜"]
|
self.xm_keywords = ["啃", "羡慕", "xm", "xmsl", "羡慕死了", "我菜"]
|
||||||
self.trigger_plusplus_keywords = ["kig","电你","被电","⚡","tk","打"]
|
self.cai_keywords = ["菜", "菜了", "菜死了", "我菜", "废物"]
|
||||||
|
self.nsfw_keywords = ["kig", "电你", "被电", "⚡", "tk", "打", "🌿我"]
|
||||||
|
|
||||||
self.target_user_id = target_user_id
|
self.target_user_id = target_user_id
|
||||||
|
|
||||||
def get_user_probability(self, user_id: str) -> float:
|
# 权重配置
|
||||||
"""获取用户当前触发几率,如果不存在则初始化"""
|
self.weights = {
|
||||||
if user_id != self.target_user_id:
|
'w_v': 20, # 卖菜度权重
|
||||||
return 0.0 # 非目标用户返回默认值
|
'w_m': 15, # 羡慕度权重
|
||||||
if user_id not in self.user_probabilities:
|
'w_n': 30, # NSFW度权重
|
||||||
self.user_probabilities[user_id] = random.uniform(10.0, 40.0)
|
'w_a': 30, # 反社会度权重
|
||||||
return self.user_probabilities[user_id]
|
'lambda': 1, # 水群缓冲系数
|
||||||
|
}
|
||||||
|
|
||||||
def update_probability(self, user_id: str, message: str, hit_by_others = False) -> float:
|
# 放大系数
|
||||||
"""更新用户触发几率"""
|
self.amplifiers = {
|
||||||
if user_id != self.target_user_id:
|
'alpha_v': 2.5, # 卖菜度放大系数
|
||||||
return 0.0 # 非目标用户不更新
|
'beta_m': 2.0, # 羡慕度放大系数
|
||||||
current_prob = self.get_user_probability(user_id)
|
'gamma_n': 5.0, # NSFW度放大系数
|
||||||
|
'alpha_a': 5.0, # 反社会度放大系数
|
||||||
|
}
|
||||||
|
|
||||||
# 基础减少0.1%
|
# 用户数据存储
|
||||||
current_prob -= 0.1
|
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)
|
||||||
|
|
||||||
# 检查是否包含触发关键词
|
|
||||||
for keyword in self.trigger_plus_keywords:
|
def record_message(self, user_id: str) -> None:
|
||||||
if keyword in message:
|
"""记录用户发送消息的时间"""
|
||||||
current_prob *= 1.14
|
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
|
break
|
||||||
for keyword in self.trigger_plusplus_keywords:
|
|
||||||
if keyword in message:
|
for keyword in self.xm_keywords:
|
||||||
current_prob *= 1.91
|
if keyword in message_lower:
|
||||||
|
metrics.xm_count += 1
|
||||||
|
classified = True
|
||||||
break
|
break
|
||||||
if hit_by_others:
|
|
||||||
# 如果被其他人触发,增加额外几率
|
|
||||||
current_prob += 20.0
|
|
||||||
self.user_probabilities[user_id] = current_prob
|
|
||||||
return current_prob
|
|
||||||
|
|
||||||
def should_trigger(self, user_id: str) -> bool:
|
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:
|
if user_id != self.target_user_id:
|
||||||
return False # 非目标用户不触发
|
return 0.0
|
||||||
probability = self.get_user_probability(user_id)
|
|
||||||
return probability >= 100.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
|
||||||
|
|
||||||
def reset_probability(self, user_id: str):
|
|
||||||
"""重置用户触发几率到初始随机值"""
|
|
||||||
self.user_probabilities[user_id] = random.uniform(40.0, 50.0)
|
|
||||||
|
|
||||||
async def __call__(
|
async def __call__(
|
||||||
self,
|
self,
|
||||||
handler: Callable[[Message, Dict[str, Any]], Awaitable[Any]],
|
handler: Callable[[Message, Dict[str, Any]], Awaitable[Any]],
|
||||||
event: Message,
|
event: Message,
|
||||||
data: Dict[str, Any]
|
data: Dict[str, Any]) -> Any:
|
||||||
) -> Any:
|
|
||||||
"""
|
"""
|
||||||
处理消息的主要方法
|
处理消息的主要方法
|
||||||
"""
|
"""
|
||||||
if not event.text:
|
if not event.text:
|
||||||
return await handler(event, data)
|
return await handler(event, data)
|
||||||
|
|
||||||
user_id = str(event.from_user.id)
|
user_id = str(event.from_user.id)
|
||||||
if event.chat.type in ['group', 'supergroup'] and user_id == self.target_user_id:
|
if event.chat.type in ['group', 'supergroup'] and user_id == self.target_user_id:
|
||||||
# 更新几率
|
self.classify_message(event.text, user_id)
|
||||||
self.update_probability(user_id, event.text)
|
score = self.calculate_qianda_score(user_id)
|
||||||
logging.debug("当前欠打的几率是{}".format(self.get_user_probability(user_id)))
|
logging.debug(f"当前欠打度: {score:.2f}%")
|
||||||
|
|
||||||
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:
|
# 警告阈值:80%
|
||||||
self.update_probability(user_id, event.text, hit_by_others=True)
|
if score >= 80.0 and not self.has_sent_warning[user_id]:
|
||||||
logging.debug("当前欠打的几率是{}".format(self.get_user_probability(user_id)))
|
self.has_sent_warning[user_id] = True
|
||||||
if self.get_user_probability(user_id) >= 80.0:
|
await event.reply("泥欠打了")
|
||||||
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))
|
||||||
|
|
||||||
# 检查是否触发
|
|
||||||
if self.should_trigger(user_id):
|
|
||||||
# 重置几率
|
|
||||||
self.reset_probability(user_id)
|
|
||||||
await event.reply("/打")
|
|
||||||
return await handler(event, data)
|
return await handler(event, data)
|
||||||
|
|
||||||
def get_probability_status(self, user_id: str) -> str:
|
def get_user_status(self, user_id: str) -> str:
|
||||||
"""获取用户当前几率状态(用于调试)"""
|
"""获取用户当前几率状态(用于调试)"""
|
||||||
prob = self.get_user_probability(user_id)
|
score = self.calculate_qianda_score(user_id)
|
||||||
return f"当前触发几率: {prob:.2f}%"
|
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}")
|
6
core/rikki_hit.py
Normal file
6
core/rikki_hit.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
from aiogram.types import Message
|
||||||
|
from core.middleware.rikki import RikkiMiddleware
|
||||||
|
|
||||||
|
async def handle_query_hit_command(message: Message) -> None:
|
||||||
|
hit_status = RikkiMiddleware().get_user_status("5545347637")
|
||||||
|
await message.reply(hit_status)
|
Loading…
Add table
Add a link
Reference in a new issue