本文介绍的是封装在hoshino.Service
中的触发器类型,如果您要查看nonebot原生的触发器,可以前往nonebot的官方文档进行查阅,本文中可能会给出一些简单的介绍,但不会作出详细说明。HoshinoBot 的触发器是通用的程序入口,通过内部维护的前缀树实现高效率的消息预处理。
本教程附带示范代码,如果想要尝试,请将本项目中的trigger-demo
目录拷贝至到hoshino/modules/
目录下,并在hoshino/config/__bot__.py
的MODULES_ON
中仿照格式添加'trigger-demo'
。
HoshinoBot对消息的触发方法在文件msghandler.py
中使用nonebot自带的装饰器@message_preprocessor
来预处理,当接收到消息后,会按照顺序进行如下的步骤:
- 检查是否是群聊消息,如果否则过滤
- 检查是否是指令,如果否则过滤,如果是则输出日志显示指令已被触发
- 检查消息接受条件是否符合,即是否是仅对自己发送
- 检查权限是否允许
- 调用对应方法
因此,当您在控制台看到日志显示指令被触发,而实际并未响应时,应当依照此顺序检查错误的环节。
注意本条目内容由测试而来,优先级排序实际上只是优先级数值只用于相互对比(越大优先级越高),并无可量化的含义。
本条目仅用来排查错误,请勿利用本条目特性来开发。
使用已on_*
开头的装饰器来添加命令,如果有一条消息有多个匹配指令,会按照优先级来触发。同一优先级会先按照命令匹配程度来触发,如果命令匹配程度一致,则按照命令注册的先后顺序(即在代码中的先后顺序)触发。
相同优先级的示例代码——priority_0.py
from hoshino import Service
from hoshino.typing import CQEvent
sv = Service('priority-demo-0')
@sv.on_prefix('优先级0')
async def demo_fun_0(bot, ev:CQEvent):
await bot.send(ev, '触发了on_prefix呦~~~')
@sv.on_fullmatch('优先级0测试')
async def demo_fun_1(bot, ev:CQEvent):
await bot.send(ev, '触发了on_fullmatch呦~~~')
当发送指令【优先级测试】时,由于触发器on_fullmatch
和on_prefix
优先级相同,但是on_fullmatch
匹配度更高,因此会优先触发on_fullmatch
,即便调换两个函数的顺序,也会触发on_fullmatch
。
如果将全字匹配的条件改为“优先级”三个字,则会按照导入的先后顺序触发。
不同优先级的示例代码——priority_1.py
from hoshino import Service
from hoshino.typing import CQEvent
sv = Service('priority-demo-1')
@sv.on_keyword('优先级1')
async def demo_fun_0(bot, ev:CQEvent):
await bot.send(ev, '触发了on_keyword呦~~~')
@sv.on_fullmatch('优先级1')
async def demo_fun_1(bot, ev:CQEvent):
await bot.send(ev, '触发了on_fullmatch呦~~~')
由于on_fullmatch
的优先级高于on_keyword
,因此虽然关键词触发的方法更靠前,但是此时只会触发on_fullmatch
。
推荐您在选择触发器时,先选择低优先级的触发器来完成(如果可以满足需求),以免与其他插件的指令产生冲突,当您确定要使用on_prefix
触发器时,您的触发关键词应当注意规避现有插件的指令、群聊经常出现的词、其他插件可能会用到的词。
消息触发器封装于服务层中,使用服务提供的on_*
装饰器作为入口,后跟方法,一个触发器只能对应一个函数方法,但是一个函数方法可以有多个触发器作为入口。
多匹配的实例代码——mulmatch.py
from hoshino import Service
from hoshino.typing import CQEvent
sv = Service('mulmatch-demo')
@sv.on_prefix('之后')
@sv.on_suffix('之前')
async def demo_fun_0(bot, ev:CQEvent):
msg = ev.message.extract_plain_text()
await bot.send(ev, f'提取到了的文本内容是:\n{msg}')
在群聊中发送”XXX之前“或”之后XXX“,均会触发相关函数。此种情况仍受到优先级约束。
以下触发器均为Service
类中封装的方法。由于原生HoshinoBot 过滤了群聊以外的消息,因此本页所示触发器均为群聊消息有效,如果需私聊指令,可以考虑:
- 使用nonebot原生触发器
on_command
- 修改
msghandler.py
,使得其不过滤非群聊消息
装饰器:on_fullmatch
优先级:999
触发条件:当接收到的消息与触发词完全相同时触发。
原型:
def on_fullmatch(self, word, only_to_me=False) -> Callable:
#...
参数与缺省值:
word
,全字匹配的条件,可以使用元组或列表配置多个(使用列表时最终也会转换为元组)。only_to_me
,指令是否需要@机器人,缺省值为False,即不@也可触发。
用法示例——fullmatch.py
from hoshino import Service
from hoshino.typing import CQEvent
sv = Service('fullmatch-demo')
@sv.on_fullmatch('你好')
async def demo_fun_0(bot, ev:CQEvent):
await bot.send(ev, '你好!')
@sv.on_fullmatch(('老婆', '老公'), only_to_me=True)
async def demo_fun_1(bot, ev):
await bot.send(ev, '???')
装饰器:on_prefix
优先级:999
触发条件:当接收到的消息以触发词开头时触发。当使用CQEvent.message.extract_plain_text()
提取消息内容时将不会包含前缀关键词。
原型:
def on_prefix(self, prefix, only_to_me=False) -> Callable:
# ...
参数与缺省值:
prefix
,前缀触发的关键词,可以使用元组或列表配置多个(使用列表时最终也会转换为元组)。only_to_me
,指令是否需要@机器人,缺省值为False,即不@也可触发。
用法示例——prefix.py
from hoshino import Service
from hoshino.typing import CQEvent
sv = Service('prefix-demo')
@sv.on_prefix('内容提取')
async def demo_fun_0(bot, ev:CQEvent):
msg = ev.message.extract_plain_text()
await bot.send(ev, f'prefix提取到了的文本内容是:\n{msg}')
@sv.on_prefix(['提取', '试试提取'], only_to_me=True)
async def demo_fun_1(bot, ev:CQEvent):
msg = ev.message.extract_plain_text()
await bot.send(ev, f'prefix提取到了的文本内容是:\n{msg}')
装饰器:on_suffix
优先级:22
触发条件:于on_prefix
类似,当接收到的消息以触发词结尾时触发。使用CQEvent.message.extract_plain_text()
提取消息内容时将不会包含后缀关键词。
原型:
def on_suffix(self, suffix, only_to_me=False) -> Callable:
# ...
参数与缺省值:
suffix
,后缀触发的关键词,可以使用元组或列表配置多个(使用列表时最终也会转换为元组)。only_to_me
,指令是否需要@机器人,缺省值为False,即不@也可触发。
示例代码——suffix.py
from hoshino import Service
from hoshino.typing import CQEvent
sv = Service('suffix-demo')
@sv.on_suffix('前面')
async def demo_fun_0(bot, ev:CQEvent):
msg = ev.message.extract_plain_text()
await bot.send(ev, f'suffix提取到了的文本内容是:\n{msg}')
@sv.on_suffix(('之前', '以前'), only_to_me=True)
async def demo_fun_1(bot, ev:CQEvent):
msg = ev.message.extract_plain_text()
await bot.send(ev, f'suffix提取到了的文本内容是:\n{msg}')
装饰器:on_keyword
优先级:21
触发条件:当接受到的消息包含该命令时,即触发。
原型:
def on_keyword(self, keywords, only_to_me=False, normalize=True) -> Callable:
# ...
参数与缺省值:
-
keywords
,触发的关键词,可以元组配置多个 -
only_to_me
,指令是否需要@机器人,缺省值为False,即不@也可触发。 -
normalize
,是否进行归一化处理,缺省值为True。如果处理,则会规范化Unicode字符、字母转换为小写、繁体转换为简体,详细方法可查看trigger.py
中的normalize_str()
函数。仅此触发器包含normalize,HoshinoBot于2020年8月10日之后已支持自动繁简转换,其他触发器添加的简体指令可以直接用繁体触发
用法示例——keyword.py
from hoshino import Service
from hoshino.typing import CQEvent
sv = Service('keyword-demo')
@sv.on_keyword('色图')
async def demo_fun_0(bot, ev:CQEvent):
await bot.send(ev, '发点色图。--鲁迅')
@sv.on_keyword(('憨批', '憨憨'), only_to_me=True)
async def demo_fun_1(bot, ev:CQEvent):
await bot.send(ev, '别骂辣别骂辣')
@sv.on_keyword('鏡華', normalize=False)
async def demo_fun_2(bot, ev:CQEvent):
# 仅当繁体或日文汉字时触发
await bot.send(ev, '叫我?')
@sv.on_keyword('小倉唯')
async def demo_fun_3(bot, ev:CQEvent):
# 日本汉字、简体字、繁体字均触发
await bot.send(ev, '叫我干嘛~')
on_rex
效率极低不推荐使用,当接收到的消息符合正则表达式时触发。
on_message
捕获所有消息,不推荐使用;
on_command
以第一个单词作为触发词,不符合中文习惯,不推荐使用;
on_natural_language
效率极低不推荐使用。
具体使用方法与 nonebot 相同,此处不再赘述。
only_to_me
参数类型 bool
,只有当 bot 被使用 @
提及时才会触发,默认值 False
具体使用方法与 nonebot 相同。