diff --git a/pkg/qqbot/bansess/__init__.py b/pkg/qqbot/bansess/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pkg/qqbot/bansess/bansess.py b/pkg/qqbot/bansess/bansess.py deleted file mode 100644 index 74ffd3f7..00000000 --- a/pkg/qqbot/bansess/bansess.py +++ /dev/null @@ -1,70 +0,0 @@ -# 处理对会话的禁用配置 -# 过去的 banlist -from __future__ import annotations -import re - -from ...core import app -from ...config import manager as cfg_mgr - - -class SessionBanManager: - - ap: app.Application = None - - banlist_mgr: cfg_mgr.ConfigManager - - def __init__(self, ap: app.Application): - self.ap = ap - - async def initialize(self): - self.banlist_mgr = await cfg_mgr.load_python_module_config( - "banlist.py", - "res/templates/banlist-template.py" - ) - - async def is_banned( - self, launcher_type: str, launcher_id: int, sender_id: int - ) -> bool: - if not self.banlist_mgr.data['enable']: - return False - - result = False - - if launcher_type == 'group': - if not self.banlist_mgr.data['enable_group']: # 未启用群聊响应 - result = True - # 检查是否显式声明发起人QQ要被person忽略 - elif sender_id in self.banlist_mgr.data['person']: - result = True - else: - for group_rule in self.banlist_mgr.data['group']: - if type(group_rule) == int: - if group_rule == launcher_id: - result = True - elif type(group_rule) == str: - if group_rule.startswith('!'): - reg_str = group_rule[1:] - if re.match(reg_str, str(launcher_id)): - result = False - break - else: - if re.match(group_rule, str(launcher_id)): - result = True - elif launcher_type == 'person': - if not self.banlist_mgr.data['enable_private']: - result = True - else: - for person_rule in self.banlist_mgr.data['person']: - if type(person_rule) == int: - if person_rule == launcher_id: - result = True - elif type(person_rule) == str: - if person_rule.startswith('!'): - reg_str = person_rule[1:] - if re.match(reg_str, str(launcher_id)): - result = False - break - else: - if re.match(person_rule, str(launcher_id)): - result = True - return result diff --git a/pkg/qqbot/cntfilter/__init__.py b/pkg/qqbot/cntfilter/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pkg/qqbot/cntfilter/cntfilter.py b/pkg/qqbot/cntfilter/cntfilter.py deleted file mode 100644 index 4c7305c0..00000000 --- a/pkg/qqbot/cntfilter/cntfilter.py +++ /dev/null @@ -1,93 +0,0 @@ -from __future__ import annotations - -from ...core import app -from . import entities -from . import filter -from .filters import cntignore, banwords, baiduexamine - - -class ContentFilterManager: - - ao: app.Application - - filter_chain: list[filter.ContentFilter] - - def __init__(self, ap: app.Application) -> None: - self.ap = ap - self.filter_chain = [] - - async def initialize(self): - self.filter_chain.append(cntignore.ContentIgnore(self.ap)) - - if self.ap.cfg_mgr.data['sensitive_word_filter']: - self.filter_chain.append(banwords.BanWordFilter(self.ap)) - - if self.ap.cfg_mgr.data['baidu_check']: - self.filter_chain.append(baiduexamine.BaiduCloudExamine(self.ap)) - - for filter in self.filter_chain: - await filter.initialize() - - async def pre_process(self, message: str) -> entities.FilterManagerResult: - """请求llm前处理消息 - 只要有一个不通过就不放行,只放行 PASS 的消息 - """ - if not self.ap.cfg_mgr.data['income_msg_check']: # 不检查收到的消息,直接放行 - return entities.FilterManagerResult( - level=entities.ManagerResultLevel.CONTINUE, - replacement=message, - user_notice='', - console_notice='' - ) - else: - for filter in self.filter_chain: - if entities.EnableStage.PRE in filter.enable_stages: - result = await filter.process(message) - - if result.level in [ - entities.ResultLevel.BLOCK, - entities.ResultLevel.MASKED - ]: - return entities.FilterManagerResult( - level=entities.ManagerResultLevel.INTERRUPT, - replacement=result.replacement, - user_notice=result.user_notice, - console_notice=result.console_notice - ) - elif result.level == entities.ResultLevel.PASS: - message = result.replacement - - return entities.FilterManagerResult( - level=entities.ManagerResultLevel.CONTINUE, - replacement=message, - user_notice='', - console_notice='' - ) - - async def post_process(self, message: str) -> entities.FilterManagerResult: - """请求llm后处理响应 - 只要是 PASS 或者 MASKED 的就通过此 filter,将其 replacement 设置为message,进入下一个 filter - """ - for filter in self.filter_chain: - if entities.EnableStage.POST in filter.enable_stages: - result = await filter.process(message) - - if result.level == entities.ResultLevel.BLOCK: - return entities.FilterManagerResult( - level=entities.ManagerResultLevel.INTERRUPT, - replacement=result.replacement, - user_notice=result.user_notice, - console_notice=result.console_notice - ) - elif result.level in [ - entities.ResultLevel.PASS, - entities.ResultLevel.MASKED - ]: - message = result.replacement - - return entities.FilterManagerResult( - level=entities.ManagerResultLevel.CONTINUE, - replacement=message, - user_notice='', - console_notice='' - ) diff --git a/pkg/qqbot/cntfilter/entities.py b/pkg/qqbot/cntfilter/entities.py deleted file mode 100644 index 7ab05675..00000000 --- a/pkg/qqbot/cntfilter/entities.py +++ /dev/null @@ -1,64 +0,0 @@ - -import typing -import enum - -import pydantic - - -class ResultLevel(enum.Enum): - """结果等级""" - PASS = enum.auto() - """通过""" - - WARN = enum.auto() - """警告""" - - MASKED = enum.auto() - """已掩去""" - - BLOCK = enum.auto() - """阻止""" - - -class EnableStage(enum.Enum): - """启用阶段""" - PRE = enum.auto() - """预处理""" - - POST = enum.auto() - """后处理""" - - -class FilterResult(pydantic.BaseModel): - level: ResultLevel - - replacement: str - """替换后的消息""" - - user_notice: str - """不通过时,用户提示消息""" - - console_notice: str - """不通过时,控制台提示消息""" - - -class ManagerResultLevel(enum.Enum): - """处理器结果等级""" - CONTINUE = enum.auto() - """继续""" - - INTERRUPT = enum.auto() - """中断""" - -class FilterManagerResult(pydantic.BaseModel): - - level: ManagerResultLevel - - replacement: str - """替换后的消息""" - - user_notice: str - """用户提示消息""" - - console_notice: str - """控制台提示消息""" diff --git a/pkg/qqbot/cntfilter/filter.py b/pkg/qqbot/cntfilter/filter.py deleted file mode 100644 index 57792145..00000000 --- a/pkg/qqbot/cntfilter/filter.py +++ /dev/null @@ -1,34 +0,0 @@ -# 内容过滤器的抽象类 -from __future__ import annotations -import abc - -from ...core import app -from . import entities - - -class ContentFilter(metaclass=abc.ABCMeta): - - ap: app.Application - - def __init__(self, ap: app.Application): - self.ap = ap - - @property - def enable_stages(self): - """启用的阶段 - """ - return [ - entities.EnableStage.PRE, - entities.EnableStage.POST - ] - - async def initialize(self): - """初始化过滤器 - """ - pass - - @abc.abstractmethod - async def process(self, message: str) -> entities.FilterResult: - """处理消息 - """ - raise NotImplementedError diff --git a/pkg/qqbot/cntfilter/filters/__init__.py b/pkg/qqbot/cntfilter/filters/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pkg/qqbot/cntfilter/filters/baiduexamine.py b/pkg/qqbot/cntfilter/filters/baiduexamine.py deleted file mode 100644 index a658897b..00000000 --- a/pkg/qqbot/cntfilter/filters/baiduexamine.py +++ /dev/null @@ -1,61 +0,0 @@ -from __future__ import annotations - -import aiohttp - -from .. import entities -from .. import filter as filter_model - - -BAIDU_EXAMINE_URL = "https://aip.baidubce.com/rest/2.0/solution/v1/text_censor/v2/user_defined?access_token={}" -BAIDU_EXAMINE_TOKEN_URL = "https://aip.baidubce.com/oauth/2.0/token" - - -class BaiduCloudExamine(filter_model.ContentFilter): - """百度云内容审核""" - - async def _get_token(self) -> str: - async with aiohttp.ClientSession() as session: - async with session.post( - BAIDU_EXAMINE_TOKEN_URL, - params={ - "grant_type": "client_credentials", - "client_id": self.ap.cfg_mgr.data['baidu_api_key'], - "client_secret": self.ap.cfg_mgr.data['baidu_secret_key'] - } - ) as resp: - return (await resp.json())['access_token'] - - async def process(self, message: str) -> entities.FilterResult: - - async with aiohttp.ClientSession() as session: - async with session.post( - BAIDU_EXAMINE_URL.format(await self._get_token()), - headers={'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json'}, - data=f"text={message}".encode('utf-8') - ) as resp: - result = await resp.json() - - if "error_code" in result: - return entities.FilterResult( - level=entities.ResultLevel.BLOCK, - replacement=message, - user_notice='', - console_notice=f"百度云判定出错,错误信息:{result['error_msg']}" - ) - else: - conclusion = result["conclusion"] - - if conclusion in ("合规"): - return entities.FilterResult( - level=entities.ResultLevel.PASS, - replacement=message, - user_notice='', - console_notice=f"百度云判定结果:{conclusion}" - ) - else: - return entities.FilterResult( - level=entities.ResultLevel.BLOCK, - replacement=message, - user_notice=self.ap.cfg_mgr.data['inappropriate_message_tips'], - console_notice=f"百度云判定结果:{conclusion}" - ) \ No newline at end of file diff --git a/pkg/qqbot/cntfilter/filters/banwords.py b/pkg/qqbot/cntfilter/filters/banwords.py deleted file mode 100644 index 9451c7b8..00000000 --- a/pkg/qqbot/cntfilter/filters/banwords.py +++ /dev/null @@ -1,44 +0,0 @@ -from __future__ import annotations -import re - -from .. import filter as filter_model -from .. import entities -from ....config import manager as cfg_mgr - - -class BanWordFilter(filter_model.ContentFilter): - """根据内容禁言""" - - sensitive: cfg_mgr.ConfigManager - - async def initialize(self): - self.sensitive = await cfg_mgr.load_json_config( - "sensitive.json", - "res/templates/sensitive-template.json" - ) - - async def process(self, message: str) -> entities.FilterResult: - found = False - - for word in self.sensitive.data['words']: - match = re.findall(word, message) - - if len(match) > 0: - found = True - - for i in range(len(match)): - if self.sensitive.data['mask_word'] == "": - message = message.replace( - match[i], self.sensitive.data['mask'] * len(match[i]) - ) - else: - message = message.replace( - match[i], self.sensitive.data['mask_word'] - ) - - return entities.FilterResult( - level=entities.ResultLevel.MASKED if found else entities.ResultLevel.PASS, - replacement=message, - user_notice='[bot] 消息中存在不合适的内容, 请更换措辞' if found else '', - console_notice='' - ) \ No newline at end of file diff --git a/pkg/qqbot/cntfilter/filters/cntignore.py b/pkg/qqbot/cntfilter/filters/cntignore.py deleted file mode 100644 index 81408868..00000000 --- a/pkg/qqbot/cntfilter/filters/cntignore.py +++ /dev/null @@ -1,43 +0,0 @@ -from __future__ import annotations -import re - -from .. import entities -from .. import filter as filter_model - - -class ContentIgnore(filter_model.ContentFilter): - """根据内容忽略消息""" - - @property - def enable_stages(self): - return [ - entities.EnableStage.PRE, - ] - - async def process(self, message: str) -> entities.FilterResult: - if 'prefix' in self.ap.cfg_mgr.data['ignore_rules']: - for rule in self.ap.cfg_mgr.data['ignore_rules']['prefix']: - if message.startswith(rule): - return entities.FilterResult( - level=entities.ResultLevel.BLOCK, - replacement='', - user_notice='', - console_notice='根据 ignore_rules 中的 prefix 规则,忽略消息' - ) - - if 'regexp' in self.ap.cfg_mgr.data['ignore_rules']: - for rule in self.ap.cfg_mgr.data['ignore_rules']['regexp']: - if re.search(rule, message): - return entities.FilterResult( - level=entities.ResultLevel.BLOCK, - replacement='', - user_notice='', - console_notice='根据 ignore_rules 中的 regexp 规则,忽略消息' - ) - - return entities.FilterResult( - level=entities.ResultLevel.PASS, - replacement=message, - user_notice='', - console_notice='' - ) \ No newline at end of file diff --git a/pkg/qqbot/longtext/__init__.py b/pkg/qqbot/longtext/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pkg/qqbot/longtext/longtext.py b/pkg/qqbot/longtext/longtext.py deleted file mode 100644 index 697f65e4..00000000 --- a/pkg/qqbot/longtext/longtext.py +++ /dev/null @@ -1,56 +0,0 @@ -from __future__ import annotations -import os -import traceback - -from PIL import Image, ImageDraw, ImageFont -from mirai.models.message import MessageComponent, Plain - -from ...core import app -from . import strategy -from .strategies import image, forward - - -class LongTextProcessor: - - ap: app.Application - - strategy_impl: strategy.LongTextStrategy - - def __init__(self, ap: app.Application): - self.ap = ap - - async def initialize(self): - config = self.ap.cfg_mgr.data - if self.ap.cfg_mgr.data['blob_message_strategy'] == 'image': - use_font = config['font_path'] - try: - # 检查是否存在 - if not os.path.exists(use_font): - # 若是windows系统,使用微软雅黑 - if os.name == "nt": - use_font = "C:/Windows/Fonts/msyh.ttc" - if not os.path.exists(use_font): - self.ap.logger.warn("未找到字体文件,且无法使用Windows自带字体,更换为转发消息组件以发送长消息,您可以在config.py中调整相关设置。") - config['blob_message_strategy'] = "forward" - else: - self.ap.logger.info("使用Windows自带字体:" + use_font) - self.ap.cfg_mgr.data['font_path'] = use_font - else: - self.ap.logger.warn("未找到字体文件,且无法使用系统自带字体,更换为转发消息组件以发送长消息,您可以在config.py中调整相关设置。") - self.ap.cfg_mgr.data['blob_message_strategy'] = "forward" - except: - traceback.print_exc() - self.ap.logger.error("加载字体文件失败({}),更换为转发消息组件以发送长消息,您可以在config.py中调整相关设置。".format(use_font)) - self.ap.cfg_mgr.data['blob_message_strategy'] = "forward" - - if self.ap.cfg_mgr.data['blob_message_strategy'] == 'image': - self.strategy_impl = image.Text2ImageStrategy(self.ap) - elif self.ap.cfg_mgr.data['blob_message_strategy'] == 'forward': - self.strategy_impl = forward.ForwardComponentStrategy(self.ap) - await self.strategy_impl.initialize() - - async def check_and_process(self, message: str) -> list[MessageComponent]: - if len(message) > self.ap.cfg_mgr.data['blob_message_threshold']: - return await self.strategy_impl.process(message) - else: - return [Plain(message)] \ No newline at end of file diff --git a/pkg/qqbot/longtext/strategies/__init__.py b/pkg/qqbot/longtext/strategies/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pkg/qqbot/longtext/strategies/forward.py b/pkg/qqbot/longtext/strategies/forward.py deleted file mode 100644 index d1b5c36c..00000000 --- a/pkg/qqbot/longtext/strategies/forward.py +++ /dev/null @@ -1,62 +0,0 @@ -# 转发消息组件 -from __future__ import annotations -import typing - -from mirai.models import MessageChain -from mirai.models.message import MessageComponent, ForwardMessageNode -from mirai.models.base import MiraiBaseModel - -from .. import strategy as strategy_model - - -class ForwardMessageDiaplay(MiraiBaseModel): - title: str = "群聊的聊天记录" - brief: str = "[聊天记录]" - source: str = "聊天记录" - preview: typing.List[str] = [] - summary: str = "查看x条转发消息" - - -class Forward(MessageComponent): - """合并转发。""" - type: str = "Forward" - """消息组件类型。""" - display: ForwardMessageDiaplay - """显示信息""" - node_list: typing.List[ForwardMessageNode] - """转发消息节点列表。""" - def __init__(self, *args, **kwargs): - if len(args) == 1: - self.node_list = args[0] - super().__init__(**kwargs) - super().__init__(*args, **kwargs) - - def __str__(self): - return '[聊天记录]' - - -class ForwardComponentStrategy(strategy_model.LongTextStrategy): - - async def process(self, message: str) -> list[MessageComponent]: - display = ForwardMessageDiaplay( - title="群聊的聊天记录", - brief="[聊天记录]", - source="聊天记录", - preview=["QQ用户: "+message], - summary="查看1条转发消息" - ) - - node_list = [ - ForwardMessageNode( - sender_id=self.ap.im_mgr.bot_account_id, - sender_name='QQ用户', - message_chain=MessageChain([message]) - ) - ] - - forward = Forward( - display=display, - node_list=node_list - ) - - return [forward] diff --git a/pkg/qqbot/longtext/strategies/image.py b/pkg/qqbot/longtext/strategies/image.py deleted file mode 100644 index 4f789098..00000000 --- a/pkg/qqbot/longtext/strategies/image.py +++ /dev/null @@ -1,197 +0,0 @@ -from __future__ import annotations - -import typing -import os -import base64 -import time -import re - -from PIL import Image, ImageDraw, ImageFont - -from mirai.models import MessageChain, Image as ImageComponent -from mirai.models.message import MessageComponent - -from .. import strategy as strategy_model - - -class Text2ImageStrategy(strategy_model.LongTextStrategy): - - text_render_font: ImageFont.FreeTypeFont - - async def initialize(self): - self.text_render_font = ImageFont.truetype(self.ap.cfg_mgr.data['font_path'], 32, encoding="utf-8") - - async def process(self, message: str) -> list[MessageComponent]: - img_path = self.text_to_image( - text_str=message, - save_as='temp/{}.png'.format(int(time.time())) - ) - - compressed_path, size = self.compress_image( - img_path, - outfile="temp/{}_compressed.png".format(int(time.time())) - ) - - with open(compressed_path, 'rb') as f: - img = f.read() - - b64 = base64.b64encode(img) - - # 删除图片 - os.remove(img_path) - - if os.path.exists(compressed_path): - os.remove(compressed_path) - - return [ - ImageComponent( - base64=b64.decode('utf-8'), - ) - ] - - def indexNumber(self, path=''): - """ - 查找字符串中数字所在串中的位置 - :param path:目标字符串 - :return:: : [['1', 16], ['2', 35], ['1', 51]] - """ - kv = [] - nums = [] - beforeDatas = re.findall('[\d]+', path) - for num in beforeDatas: - indexV = [] - times = path.count(num) - if times > 1: - if num not in nums: - indexs = re.finditer(num, path) - for index in indexs: - iV = [] - i = index.span()[0] - iV.append(num) - iV.append(i) - kv.append(iV) - nums.append(num) - else: - index = path.find(num) - indexV.append(num) - indexV.append(index) - kv.append(indexV) - # 根据数字位置排序 - indexSort = [] - resultIndex = [] - for vi in kv: - indexSort.append(vi[1]) - indexSort.sort() - for i in indexSort: - for v in kv: - if i == v[1]: - resultIndex.append(v) - return resultIndex - - - def get_size(self, file): - # 获取文件大小:KB - size = os.path.getsize(file) - return size / 1024 - - - def get_outfile(self, infile, outfile): - if outfile: - return outfile - dir, suffix = os.path.splitext(infile) - outfile = '{}-out{}'.format(dir, suffix) - return outfile - - - def compress_image(self, infile, outfile='', kb=100, step=20, quality=90): - """不改变图片尺寸压缩到指定大小 - :param infile: 压缩源文件 - :param outfile: 压缩文件保存地址 - :param mb: 压缩目标,KB - :param step: 每次调整的压缩比率 - :param quality: 初始压缩比率 - :return: 压缩文件地址,压缩文件大小 - """ - o_size = self.get_size(infile) - if o_size <= kb: - return infile, o_size - outfile = self.get_outfile(infile, outfile) - while o_size > kb: - im = Image.open(infile) - im.save(outfile, quality=quality) - if quality - step < 0: - break - quality -= step - o_size = self.get_size(outfile) - return outfile, self.get_size(outfile) - - - def text_to_image(self, text_str: str, save_as="temp.png", width=800): - - text_str = text_str.replace("\t", " ") - - # 分行 - lines = text_str.split('\n') - - # 计算并分割 - final_lines = [] - - text_width = width-80 - - self.ap.logger.debug("lines: {}, text_width: {}".format(lines, text_width)) - for line in lines: - # 如果长了就分割 - line_width = self.text_render_font.getlength(line) - self.ap.logger.debug("line_width: {}".format(line_width)) - if line_width < text_width: - final_lines.append(line) - continue - else: - rest_text = line - while True: - # 分割最前面的一行 - point = int(len(rest_text) * (text_width / line_width)) - - # 检查断点是否在数字中间 - numbers = self.indexNumber(rest_text) - - for number in numbers: - if number[1] < point < number[1] + len(number[0]) and number[1] != 0: - point = number[1] - break - - final_lines.append(rest_text[:point]) - rest_text = rest_text[point:] - line_width = self.text_render_font.getlength(rest_text) - if line_width < text_width: - final_lines.append(rest_text) - break - else: - continue - # 准备画布 - img = Image.new('RGBA', (width, max(280, len(final_lines) * 35 + 65)), (255, 255, 255, 255)) - draw = ImageDraw.Draw(img, mode='RGBA') - - self.ap.logger.debug("正在绘制图片...") - # 绘制正文 - line_number = 0 - offset_x = 20 - offset_y = 30 - for final_line in final_lines: - draw.text((offset_x, offset_y + 35 * line_number), final_line, fill=(0, 0, 0), font=self.text_render_font) - # 遍历此行,检查是否有emoji - idx_in_line = 0 - for ch in final_line: - # 检查字符占位宽 - char_code = ord(ch) - if char_code >= 127: - idx_in_line += 1 - else: - idx_in_line += 0.5 - - line_number += 1 - - self.ap.logger.debug("正在保存图片...") - img.save(save_as) - - return save_as diff --git a/pkg/qqbot/longtext/strategy.py b/pkg/qqbot/longtext/strategy.py deleted file mode 100644 index 5c6bfb9c..00000000 --- a/pkg/qqbot/longtext/strategy.py +++ /dev/null @@ -1,22 +0,0 @@ -from __future__ import annotations -import abc -import typing - -import mirai -from mirai.models.message import MessageComponent - -from ...core import app - - -class LongTextStrategy(metaclass=abc.ABCMeta): - ap: app.Application - - def __init__(self, ap: app.Application): - self.ap = ap - - async def initialize(self): - pass - - @abc.abstractmethod - async def process(self, message: str) -> list[MessageComponent]: - return [] diff --git a/pkg/qqbot/resprule/__init__.py b/pkg/qqbot/resprule/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pkg/qqbot/resprule/entities.py b/pkg/qqbot/resprule/entities.py deleted file mode 100644 index ffee3081..00000000 --- a/pkg/qqbot/resprule/entities.py +++ /dev/null @@ -1,9 +0,0 @@ -import pydantic -import mirai - - -class RuleJudgeResult(pydantic.BaseModel): - - matching: bool = False - - replacement: mirai.MessageChain = None diff --git a/pkg/qqbot/resprule/resprule.py b/pkg/qqbot/resprule/resprule.py deleted file mode 100644 index 9ea8321d..00000000 --- a/pkg/qqbot/resprule/resprule.py +++ /dev/null @@ -1,58 +0,0 @@ -from __future__ import annotations - -import mirai - -from ...core import app -from . import entities, rule -from .rules import atbot, prefix, regexp, random - - -class GroupRespondRuleChecker: - """群组响应规则检查器 - """ - - ap: app.Application - - rule_matchers: list[rule.GroupRespondRule] - - def __init__(self, ap: app.Application): - self.ap = ap - - async def initialize(self): - """初始化检查器 - """ - self.rule_matchers = [ - atbot.AtBotRule(self.ap), - prefix.PrefixRule(self.ap), - regexp.RegExpRule(self.ap), - random.RandomRespRule(self.ap), - ] - - for rule_matcher in self.rule_matchers: - await rule_matcher.initialize() - - async def check( - self, - message_text: str, - message_chain: mirai.MessageChain, - launcher_id: int, - sender_id: int, - ) -> entities.RuleJudgeResult: - """检查消息是否匹配规则 - """ - rules = self.ap.cfg_mgr.data['response_rules'] - - use_rule = rules['default'] - - if str(launcher_id) in use_rule: - use_rule = use_rule[str(launcher_id)] - - for rule_matcher in self.rule_matchers: - res = await rule_matcher.match(message_text, message_chain, use_rule) - if res.matching: - return res - - return entities.RuleJudgeResult( - matching=False, - replacement=message_chain - ) diff --git a/pkg/qqbot/resprule/rule.py b/pkg/qqbot/resprule/rule.py deleted file mode 100644 index e530d063..00000000 --- a/pkg/qqbot/resprule/rule.py +++ /dev/null @@ -1,31 +0,0 @@ -from __future__ import annotations -import abc - -import mirai - -from ...core import app -from . import entities - - -class GroupRespondRule(metaclass=abc.ABCMeta): - """群组响应规则的抽象类 - """ - - ap: app.Application - - def __init__(self, ap: app.Application): - self.ap = ap - - async def initialize(self): - pass - - @abc.abstractmethod - async def match( - self, - message_text: str, - message_chain: mirai.MessageChain, - rule_dict: dict - ) -> entities.RuleJudgeResult: - """判断消息是否匹配规则 - """ - raise NotImplementedError diff --git a/pkg/qqbot/resprule/rules/__init__.py b/pkg/qqbot/resprule/rules/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pkg/qqbot/resprule/rules/atbot.py b/pkg/qqbot/resprule/rules/atbot.py deleted file mode 100644 index eefc4891..00000000 --- a/pkg/qqbot/resprule/rules/atbot.py +++ /dev/null @@ -1,28 +0,0 @@ -from __future__ import annotations - -import mirai - -from .. import rule as rule_model -from .. import entities - - -class AtBotRule(rule_model.GroupRespondRule): - - async def match( - self, - message_text: str, - message_chain: mirai.MessageChain, - rule_dict: dict - ) -> entities.RuleJudgeResult: - - if message_chain.has(mirai.At(self.ap.im_mgr.bot_account_id)) and rule_dict['at']: - message_chain.remove(mirai.At(self.ap.im_mgr.bot_account_id)) - return entities.RuleJudgeResult( - matching=True, - replacement=message_chain, - ) - - return entities.RuleJudgeResult( - matching=False, - replacement = message_chain - ) diff --git a/pkg/qqbot/resprule/rules/prefix.py b/pkg/qqbot/resprule/rules/prefix.py deleted file mode 100644 index 31ead5ab..00000000 --- a/pkg/qqbot/resprule/rules/prefix.py +++ /dev/null @@ -1,29 +0,0 @@ -import mirai - -from .. import rule as rule_model -from .. import entities - - -class PrefixRule(rule_model.GroupRespondRule): - - async def match( - self, - message_text: str, - message_chain: mirai.MessageChain, - rule_dict: dict - ) -> entities.RuleJudgeResult: - prefixes = rule_dict['prefix'] - - for prefix in prefixes: - if message_text.startswith(prefix): - return entities.RuleJudgeResult( - matching=True, - replacement=mirai.MessageChain([ - mirai.Plain(message_text[len(prefix):]) - ]), - ) - - return entities.RuleJudgeResult( - matching=False, - replacement=message_chain - ) diff --git a/pkg/qqbot/resprule/rules/random.py b/pkg/qqbot/resprule/rules/random.py deleted file mode 100644 index 1e8354b5..00000000 --- a/pkg/qqbot/resprule/rules/random.py +++ /dev/null @@ -1,22 +0,0 @@ -import random - -import mirai - -from .. import rule as rule_model -from .. import entities - - -class RandomRespRule(rule_model.GroupRespondRule): - - async def match( - self, - message_text: str, - message_chain: mirai.MessageChain, - rule_dict: dict - ) -> entities.RuleJudgeResult: - random_rate = rule_dict['random_rate'] - - return entities.RuleJudgeResult( - matching=random.random() < random_rate, - replacement=message_chain - ) \ No newline at end of file diff --git a/pkg/qqbot/resprule/rules/regexp.py b/pkg/qqbot/resprule/rules/regexp.py deleted file mode 100644 index 0d621fe4..00000000 --- a/pkg/qqbot/resprule/rules/regexp.py +++ /dev/null @@ -1,31 +0,0 @@ -import re - -import mirai - -from .. import rule as rule_model -from .. import entities - - -class RegExpRule(rule_model.GroupRespondRule): - - async def match( - self, - message_text: str, - message_chain: mirai.MessageChain, - rule_dict: dict - ) -> entities.RuleJudgeResult: - regexps = rule_dict['regexp'] - - for regexp in regexps: - match = re.match(regexp, message_text) - - if match: - return entities.RuleJudgeResult( - matching=True, - replacement=message_chain, - ) - - return entities.RuleJudgeResult( - matching=False, - replacement=message_chain - )