Skip to main content
Version: Next

使用平台接口

在 NoneBot 中,除了使用事件响应器操作发送文本消息外,我们还可以直接通过使用协议适配器提供的方法来使用平台特定的接口,完成发送特殊消息、获取信息等其他平台提供的功能。同时,在部分无法使用事件响应器的情况中,例如定时任务,我们也可以使用平台接口来完成需要的功能。

发送平台特殊消息

在之前的章节中,我们介绍了如何向用户发送文本消息以及如何处理平台消息,现在我们来向用户发送平台特殊消息。

注意

在以下的示例中,我们将使用 Console 协议适配器来演示如何发送平台消息。在实际使用中,你需要确保你使用的消息序列类型与你所要发送的平台类型一致。

import inspect
from nonebot.adapters.console import MessageSegment

@weather.got("location", prompt=MessageSegment.emoji("question") + "请输入地名")
async def got_location(location: str = ArgPlainText()):
result = await weather.send(
MessageSegment.markdown(
inspect.cleandoc(
f"""
# {location}

- 今天

⛅ 多云 20℃~24℃
"""
)
)
)
NoneBot
/天气
❓请输入地名
北京
┏━━━━━━━━━━━━━━━━┓
┃      北京       ┃
┗━━━━━━━━━━━━━━━━┛
• 今天
⛅ 多云 20℃~24℃

在上面的示例中,我们使用了 Console 协议适配器提供的 MessageSegment 类来发送平台特定的消息 emojimarkdown。这两种消息可以显示在终端中,但是无法在其他平台上使用。在事件响应器操作中,我们可以使用 str、消息序列、消息段、消息模板四种类型来发送消息,但其中只有 str纯文本形式的消息模板类型消息可以在所有平台上使用。

send 事件响应器操作实际上是由协议适配器通过调用平台 API 来实现的,通常会将 API 调用的结果作为返回值返回。

调用平台 API

在 NoneBot 中,我们可以通过 Bot 对象来调用协议适配器支持的平台 API,来完成更多的功能。

获取 Bot

在调用平台 API 之前,我们首先要获得 Bot 对象。有两种方式可以获得 Bot 对象。

在事件处理流程的上下文中,我们可以直接使用依赖注入 Bot 来获取:

from nonebot.adapters import Bot

@weather.got("location", prompt="请输入地名")
async def got_location(bot: Bot, location: str = ArgPlainText()):
...

依赖注入会确保你获得的 Bot 对象与类型注解的 Bot 类型一致。也就是说,如果你使用的是 Bot 基类,将会允许任何平台的 Bot 对象;如果你使用的是平台特定的 Bot 类型,将会只允许该平台的 Bot 对象,其他类型的 Bot 将会跳过这个事件处理函数。更多详情请参考事件处理重载

在其他情况下,我们可以通过 NoneBot 提供的方法来获取 Bot 对象,这些方法将会在使用适配器中详细介绍:

from nonebot import get_bot

# 获取当前所有 Bot 中的第一个
bot = get_bot()
# 获取指定 ID 的 Bot
bot = get_bot("bot_id")

调用 API

在获得 Bot 对象后,我们可以通过 Bot 的实例方法来调用平台 API:

# 通过 bot.api_name(**kwargs) 的方法调用 API
result = await bot.get_user_info(user_id=12345678)

# 通过 bot.call_api(api_name, **kwargs) 的方法调用 API
result = await bot.call_api("get_user_info", user_id=12345678)
注意

实际可以使用的 API 以及参数取决于平台提供的接口以及协议适配器的实现,请参考协议适配器以及平台文档。

在了解了如何调用 API 后,我们可以来改进 weather 插件,使得消息发送后,调用 Console 接口响铃提醒机器人用户:

from nonebot.adapters.console import Bot, MessageSegment

@weather.got("location", prompt=MessageSegment.emoji("question") + "请输入地名")
async def got_location(bot: Bot, location: str = ArgPlainText()):
await weather.send(
MessageSegment.markdown(
inspect.cleandoc(
f"""
# {location}

- 今天

⛅ 多云 20℃~24℃
"""
)
)
)
await bot.bell()