Skip to content

nonebot/plugin-alconna

Repository files navigation

nonebot

NoneBot Plugin Alconna

✨ Alconna Usage For NoneBot2 ✨

license pypi python

该插件提供了 AlconnaNoneBot2 适配版本与工具

特性

  • 完整的 Alconna 特性支持
  • 基本的 rule, matcher 与 依赖注入
  • 自动回复命令帮助信息 (help, shortcut, completion) 选项
  • 现有全部协议的 Segment 标注
  • match_value, match_path 等检查函数
  • 补全会话支持
  • 跨平台的接收与发送消息(被动+主动)
  • 多种内建工具

讨论

QQ 交流群: 链接

使用方法

NoneBot 文档: 📖这里 仓库内介绍: 📦这里

消息解析

from nonebot.adapters.onebot.v12 import Message, MessageSegment
from arclet.alconna import Alconna, Option, Args

msg = Message("Hello! --foo 123")
img = MessageSegment.image("1.png")
print(msg)

alc = Alconna("Hello!", Option("--foo", Args["foo", int]))
res = alc.parse(msg)
assert res.matched
assert res.query("foo.foo") == 123
assert not alc.parse(Message(["Hello!", img])).matched

MessageSegment 标注

特定适配器:

from nonebot_plugin_alconna.adapters.onebot12 import Mention
from nonebot.adapters.onebot.v12 import Message
from arclet.alconna import Alconna, Args

msg = Message(["Hello!", Mention("123")])
print(msg)  # Hello![mention:user_id=123]

alc = Alconna("Hello!", Args["target", Mention])
res = alc.parse(msg)
assert res.matched
assert res.query("target").data['user_id'] == '123'

通用标注:

from nonebot.adapters.onebot.v12 import Message as Ob12Msg, MessageSegment as Ob12MS
from nonebot.adapters.onebot.v11 import Message as Ob11Msg, MessageSegment as Ob11MS
from nonebot_plugin_alconna import At
from arclet.alconna import Alconna, Args

msg1 = Ob12Msg(["Hello!", Ob12MS.mention("123")]) # Hello![mention:user_id=123]
msg2 = Ob11Msg(["Hello!", Ob11MS.at(123)]) # Hello![CQ:at,qq=123]


alc = Alconna("Hello!", Args["target", At])
res1 = alc.parse(msg1)
assert res1.matched
target = res1.query("target")
assert isinstance(target, At)
assert target.target == '123'

res2 = alc.parse(msg2)
assert res2.matched
target = res2.query("target")
assert isinstance(target, At)
assert target.target == '123'

Matcher 与 依赖注入

...
from nonebot import require
require("nonebot_plugin_alconna")
...

from nonebot_plugin_alconna import (
    on_alconna, 
    Match,
    Query,
    AlconnaMatch, 
    AlconnaQuery,
    AlcMatches,
    AlcResult
)
from arclet.alconna import Alconna, Args, Option

test = on_alconna(
    Alconna(
        "test",
        Option("foo", Args["bar", int]),
        Option("baz", Args["qux", bool, False])
    ),
    auto_send_output=True
)


@test.handle()
async def handle_test1(result: AlcResult):
    await test.send(f"matched: {result.matched}")
    await test.send(f"maybe output: {result.output}")

@test.handle()
async def handle_test2(result: AlcMatches):
    await test.send(f"head result: {result.header_result}")
    await test.send(f"args: {result.all_matched_args}")

@test.handle()
async def handle_test3(bar: Match[int] = AlconnaMatch("bar")):
    if bar.available:    
        await test.send(f"foo={bar.result}")

@test.handle()
async def handle_test4(qux: Query[bool] = AlconnaQuery("baz.qux", False)):
    if qux.available:
        await test.send(f"baz.qux={qux.result}")

条件控制

...
from nonebot import require
require("nonebot_plugin_alconna")
...

from arclet.alconna import Alconna, Subcommand, Option, Args
from nonebot_plugin_alconna import on_alconna, AlconnaResult, CommandResult

pip = Alconna(
    "pip",
    Subcommand(
        "install", 
        Args["pak", str],
        Option("--upgrade"),
        Option("--force-reinstall")
    ),
    Subcommand(
        "list",
        Option("--out-dated")
    )
)

pip_cmd = on_alconna(pip)

@pip_cmd.assign("install.pak", "pip")
async def update(arp: CommandResult = AlconnaResult()):
    ...

@pip_cmd.assign("list")
async def list_(arp: CommandResult = AlconnaResult()):
    ...

install_cmd = pip_cmd.dispatch("install")

@install_cmd.handle()
async def install(arp: CommandResult = AlconnaResult()):
    ...

@install_cmd.assign("install.pak", "nonebot")
async def nonebot(arp: CommandResult = AlconnaResult()):
    ...

跨平台消息

from nonebot import get_driver
from nonebot_plugin_alconna import UniMessage, SupportScope, on_alconna

driver = get_driver
test = on_alconna("test")

@test.handle()
async def handle_test():
    r = await UniMessage.image(path="path/to/img").send()
    if r.recallable:
        await r.reply("图片已发送,10秒后撤回")
        await r.recall(delay=10, index=0)

@test.got("foo", prompt=UniMessage.template("{:Reply($message_id)}请输入图片"))
async def handle_foo():
    await test.send("图片已收到")

@driver.on_startup
async def_():
    await Target.group("123456789", SupportScope.qq_client).send(UniMessage.image(path="test.png"))

配置

目前配置项有:

  • ALCONNA_AUTO_SEND_OUTPUT : 是否全局启用输出信息自动发送
  • ALCONNA_USE_COMMAND_START : 是否将 COMMAND_START 作为全局命令前缀
  • ALCONNA_AUTO_COMPLETION: 是否全局启用补全会话功能
  • ALCONNA_USE_ORIGIN: 是否全局使用原始消息 (即未经过 to_me 等处理的)
  • ALCONNA_USE_PARAM: 是否使用特制的 Param 提供更好的依赖注入
  • ALCONNA_USE_CMD_SEP: 是否将 COMMAND_SEP 作为全局命令分隔符
  • ALCONNA_GLOBAL_EXTENSIONS: 全局加载的扩展, 路径以 . 分隔, 如 foo.bar.baz:DemoExtension
  • ALCONNA_CONTEXT_STYLE: 全局命令上下文插值的风格,None 为关闭,bracket 为 {...},parentheses 为 $(...)
  • ALCONNA_ENABLE_SAA_PATCH: 是否启用 SAA 补丁
  • ALCONNA_APPLY_FILEHOST: 是否启用文件托管
  • ALCONNA_APPLY_FETCH_TARGETS: 是否启动时拉取一次发送对象列表

参数解释

def on_alconna(
    command: Alconna | str,
    skip_for_unmatch: bool = True,
    auto_send_output: bool = False,
    aliases: set[str | tuple[str, ...]] | None = None,
    comp_config: CompConfig | None = None,
    extensions: list[type[Extension] | Extension] | None = None,
    exclude_ext: list[type[Extension] | str] | None = None,
    use_origin: bool = False,
    use_cmd_start: bool = False,
    use_cmd_sep: bool = False,
    **kwargs,
) -> type[AlconnaMatcher]:
  • command: Alconna 命令
  • skip_for_unmatch: 是否在命令不匹配时跳过该响应
  • auto_send_output: 是否自动发送输出信息并跳过响应
  • aliases: 命令别名, 作用类似于 on_command
  • comp_config: 补全会话配置, 不传入则不启用补全会话
  • extensions: 需要加载的匹配扩展, 可以是扩展类或扩展实例
  • exclude_ext: 需要排除的匹配扩展, 可以是扩展类或扩展的id
  • use_origin: 是否使用未经 to_me 等处理过的消息
  • use_cmd_start: 是否使用 COMMAND_START 作为命令前缀
  • use_cmd_sep: 是否使用 COMMAND_SEP 作为命令分隔符

提供了 MessageSegment标注 的协议:

协议名称 路径
OneBot 协议 adapters.onebot11, adapters.onebot12
Telegram adapters.telegram
飞书 adapters.feishu
GitHub adapters.github
QQ bot adapters.qq
钉钉 adapters.ding
Console adapters.console
开黑啦 adapters.kook
Mirai adapters.mirai
Ntchat adapters.ntchat
MineCraft adapters.minecraft
BiliBili Live adapters.bilibili
Walle-Q adapters.onebot12
Discord adapters.discord
Red 协议 adapters.red
Satori adapters.satori
Dodo IM adapters.dodo
Kritor adapters.kritor

便捷装饰器

funcommand 装饰器用于将一个接受任意参数,返回 strMessageMessageSegment 的函数转换为命令响应器。

from nonebot_plugin_alconna import funcommand

@funcommand()
async def echo(msg: str):
    return msg

体验

demo bot