From ae83b669085906df1b4ba3e2b39b52ff60edf31c Mon Sep 17 00:00:00 2001 From: passthem Date: Sun, 12 Oct 2025 11:50:15 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=9B=BE=E5=83=8F=E9=BB=91?= =?UTF-8?q?=E7=99=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- konabot/common/nb/exc.py | 9 +++++ konabot/common/nb/extract_image.py | 24 ++++++++++++ konabot/common/nb/match_keyword.py | 16 ++++++++ konabot/common/nb/reply_image.py | 13 +++++++ konabot/plugins/errman.py | 45 +++++++++++++++++++++++ konabot/plugins/image_process/__init__.py | 13 +++++++ 6 files changed, 120 insertions(+) create mode 100644 konabot/common/nb/exc.py create mode 100644 konabot/common/nb/match_keyword.py create mode 100644 konabot/common/nb/reply_image.py create mode 100644 konabot/plugins/errman.py create mode 100644 konabot/plugins/image_process/__init__.py diff --git a/konabot/common/nb/exc.py b/konabot/common/nb/exc.py new file mode 100644 index 0000000..46a3db2 --- /dev/null +++ b/konabot/common/nb/exc.py @@ -0,0 +1,9 @@ +from nonebot_plugin_alconna import UniMessage + + +class BotExceptionMessage(Exception): + def __init__(self, msg: UniMessage | str) -> None: + super().__init__() + if isinstance(msg, str): + msg = UniMessage().text(msg) + self.msg = msg diff --git a/konabot/common/nb/extract_image.py b/konabot/common/nb/extract_image.py index 27b8ef9..eecbf87 100644 --- a/konabot/common/nb/extract_image.py +++ b/konabot/common/nb/extract_image.py @@ -1,17 +1,23 @@ from io import BytesIO +from typing import Annotated import httpx import PIL.Image from loguru import logger +import nonebot +from nonebot.matcher import Matcher from nonebot.adapters import Bot, Event, Message from nonebot.adapters.discord import Bot as DiscordBot from nonebot.adapters.onebot.v11 import Bot as OnebotV11Bot from nonebot.adapters.onebot.v11 import Message as OnebotV11Message from nonebot.adapters.onebot.v11 import MessageEvent as OnebotV11MessageEvent +import nonebot.params from nonebot_plugin_alconna import Image, RefNode, Reply, UniMessage from PIL import UnidentifiedImageError from returns.result import Failure, Result, Success +from konabot.common.nb.exc import BotExceptionMessage + async def download_image_bytes(url: str) -> Result[bytes, str]: # if "/matcha/cache/" in url: @@ -133,3 +139,21 @@ async def extract_image_from_message( else: return Failure("暂时不支持在这里中通过引用的方式获取图片") return Failure("请在消息中包含图片,或者引用一个含有图片的消息") + + +async def _ext_img( + evt: Event, + bot: Bot, + matcher: Matcher, +) -> PIL.Image.Image | None: + match await extract_image_from_message(evt.get_message(), evt, bot): + case Success(img): + return img + case Failure(err): + # raise BotExceptionMessage(err) + await matcher.send(await UniMessage().text(err).export()) + return None + assert False + + +PIL_Image = Annotated[PIL.Image.Image, nonebot.params.Depends(_ext_img)] diff --git a/konabot/common/nb/match_keyword.py b/konabot/common/nb/match_keyword.py new file mode 100644 index 0000000..ee6be51 --- /dev/null +++ b/konabot/common/nb/match_keyword.py @@ -0,0 +1,16 @@ +import re + +from nonebot_plugin_alconna import Text, UniMsg + + +def match_keyword(*patterns: str | re.Pattern): + async def _matcher(msg: UniMsg): + text = msg.get(Text).extract_plain_text().strip() + for pattern in patterns: + if isinstance(pattern, str) and text == pattern: + return True + if isinstance(pattern, re.Pattern) and re.match(pattern, text): + return True + return False + + return _matcher diff --git a/konabot/common/nb/reply_image.py b/konabot/common/nb/reply_image.py new file mode 100644 index 0000000..c42579f --- /dev/null +++ b/konabot/common/nb/reply_image.py @@ -0,0 +1,13 @@ +from io import BytesIO + +import PIL +import PIL.Image +from nonebot.adapters import Bot +from nonebot.matcher import Matcher +from nonebot_plugin_alconna import UniMessage + + +async def reply_image(matcher: type[Matcher], bot: Bot, img: PIL.Image.Image): + data = BytesIO() + img.save(data, "PNG") + await matcher.send(await UniMessage().image(raw=data).export(bot)) diff --git a/konabot/plugins/errman.py b/konabot/plugins/errman.py new file mode 100644 index 0000000..fe7c451 --- /dev/null +++ b/konabot/plugins/errman.py @@ -0,0 +1,45 @@ +from typing import Any + +from nonebot.adapters import Bot +from nonebot.matcher import Matcher +from nonebot.message import run_postprocessor +from nonebot_plugin_alconna import UniMessage +from returns.primitives.exceptions import UnwrapFailedError + +from konabot.common.nb.exc import BotExceptionMessage + + +@run_postprocessor +async def _(bot: Bot, matcher: Matcher, exc: BotExceptionMessage | AssertionError | UnwrapFailedError): + if isinstance(exc, BotExceptionMessage): + msg = exc.msg + await matcher.send(await msg.export(bot)) + if isinstance(exc, AssertionError): + if exc.args: + err_msg = exc.args[0] + + err_msg_res: UniMessage + if isinstance(err_msg, str): + err_msg_res = UniMessage().text(err_msg) + elif isinstance(err_msg, UniMessage): + err_msg_res = err_msg + else: + return + + await matcher.send(await err_msg_res.export(bot)) + if isinstance(exc, UnwrapFailedError): + obj = exc.halted_container + try: + failure: Any = obj.failure() + + err_msg_res: UniMessage + if isinstance(failure, str): + err_msg_res = UniMessage().text(failure) + elif isinstance(failure, UniMessage): + err_msg_res = failure + else: + return + + await matcher.send(await err_msg_res.export(bot)) + except: + pass diff --git a/konabot/plugins/image_process/__init__.py b/konabot/plugins/image_process/__init__.py new file mode 100644 index 0000000..0d679bd --- /dev/null +++ b/konabot/plugins/image_process/__init__.py @@ -0,0 +1,13 @@ +from nonebot import on_message +from nonebot.adapters import Bot + +from konabot.common.nb.extract_image import PIL_Image +from konabot.common.nb.match_keyword import match_keyword +from konabot.common.nb.reply_image import reply_image + +cmd_black_white = on_message(rule=match_keyword("黑白")) + + +@cmd_black_white.handle() +async def _(img: PIL_Image, bot: Bot): + await reply_image(cmd_black_white, bot, img.convert("LA"))