跳到主要内容

调用 API

在 PepperBot 中,所有的主动行为,比如发送群消息,接受加群请求,上传群文件,踢出群成员,都是通过调用 API 实现的

有哪些 API

所以 PepperBot 有哪些 API 呢?完整的 API 参考文档[在此]

PepperBot 标榜自己是一个“符合直觉”的框架,所以,所有的 API,绑定的class,基本都是和 API 有联系的,比如

对于消息链,或者说一条消息,比较符合直觉的操作,可以有“撤回这条消息”,“直接回复这条消息”之类,所以,在 chain 对象上,我们绑定了如下方法

await chain.withdraw()
await chain.reply(
Text("在QQ中,会自动使用消息的‘回复’功能")
)

对于发送当前消息的群成员来说,比较符合直觉的操作有“禁言该成员”,“踢出该成员”之类的操作,所以又

await sender.ban(30) # 禁言30分钟
await sender.kick()

像“主动发送一条消息”,“主动上传群文件”之类的操作,显然,是由bot自己完成的,所以相应的

await bot.group_message(Text("一条跨平台群消息"))
await bot.upload_group_file("filepath")

选择合适的 API

是否有注意到,在上方的的 API 示例中,我们并没有提供“QQ 群号”,“QQ 号”之类的参数?

为了尽量的减少模板代码,PepperBot 假设,所有操作,默认都是对当前发生的事件所在的群操作的,这样的话,用户就不需要手动注入很多“已知”的参数了

但是,如果我们想要实现类似,“当在 A 群收到消息时,向 B 群发送一条消息”,甚至“当在 QQ 的 A 群收到消息时,向微信的 B 群发送一条消息”,要怎么办呢?

这里,我们引入了arbitrary API(中文“任意 API”的意思)

PepperBot 的 API 架构

简单来说,对于不同的平台(QQ、微信),PepperBot 分别实现了对应的adapter,API 都是绑定到对应的adapter上的,arbitrary API,实际上,就是直接调用adapter上的 API,而不是绑定在如bot, chain上的,已经封装过一次的 API

具体见[贡献指南/更多 API]

在上方举例的,botchain等对象的 API,都是没有前缀(onebot,keaimao)的,也就是说,他们都是跨平台的 API,收到 QQ 消息时,API 内部会自动调用 QQ 协议端(go-cqhttp)的接口,同理,收到微信消息时,API 内部会调用微信协议端(可爱猫)的接口

当我们使用 arbitrary API时,并没有这样的“自动化”,每次调用时,我们需要手动选择对应的平台

比如,想要调用 QQ 的群消息 API

from pepperbot.adapters.onebot.api import OnebotV11Api

async def group_message(self):
await OnebotV11Api.group_message("123456", Text("只发送给QQ的消息"))

调用微信的群消息 API

from pepperbot.adapters.keaimao.api import KeaimaoApi

async def group_message(self):
await KeaimaoApi.group_message("123456@chatroom", Text("只发送给微信的消息"))

每次使用arbitrary API时,都要导入,很麻烦,所以在bot上,直接绑定了arbitrary API,可以直接这样使用

async def group_message(self, bot: UniversalGroupBot):
await bot.arbitrary.onebot.group_message("123456", Text("QQ消息"))
await bot.arbitrary.keaimao.group_message("123456@chatroom", Text("微信消息"))

封装过的 API,默认发送至当前消息来源,而我们使用arbitrary API时,则需要手动指定

handler外部使用 arbitrary 风格的 API

bot身上,我们绑定了 arbitrary 这样的工具字段,但是如果我们想要在handler外部,比如实现定时任务或者一次性任务时,也想要实现 arbitrary.onebot 这样的效果,而不是手动导入,要怎么做呢?

from pepperbot.core.bot.universal import ArbitraryApi

async def main():
ArbitraryApi.onebot.group_message("123456", Text("QQ消息"))

asyncio.run(main())

在跨平台事件内部,判断消息来源

但是现在,我们还是没法实现"QQ 中收到消息后,向微信发送消息"的功能,因为我们并不知道,我们收到的事件来自何方

可以通过protocol来判断,在bot上,我们绑定了一些工具属性

比如,当消息来自 QQ 时,bot.onebot为 True,不然为 False

但消息来自于微信是,bot.keaimao为 True,不然为 False

现在,我们可以实现我们的目标了

async def group_message(self, bot: UniversalGroupBot, chain: MessageChain):
if bot.onebot: # 转发qq消息至微信
await bot.arbitrary.keaimao.group_message("19521241254@chatroom", *chain.segments)

if bot.keaimao: # 转发微信消息至qq
await bot.arbitrary.onebot.group_message("1041902989", *chain.segments)

获取需要的参数

那么,从哪里获取群号,QQ号呢?

PepperBot 中,所有的事件,都有raw_event这个参数,也就是未经 PepperBot 处理的,直接从协议端接受到的事件,都是字典格式

关于字典的字段,可以查看go-cqhttp可爱猫自己的文档

async def group_message(self, raw_event: Dict):
if bot.onebot:
group_id = raw_event["group_id"]

bot, chain等对象上,也有绑定一些参数,具体见[文档]

bot.bot_id
chain.source_id

PepperBot 未实现,但是协议端实现了的 API

PepperBot 只封装了最常用,最值得封装的 API,所以想要调用 PepperBot 尚未封装的 API 时,我们可以使用api_caller

api_caller其实就是一个维持了 session 的 http 客户端,方便我们向协议端发送 http 请求。PepperBot 中,基于httpx实现

不同平台的api_caller,都存放在 api_callers 中,但是每次通过

api_callers["protocol"]

的形式调用,多少有些不便,所以提供了几个工具函数

from pepperbot.store.meta import get_onebot_caller, get_keaimao_caller

api_caller都实现了这样的接口

async def api_caller(action: str, **kwargs):
...

所以,我们可以总结出这样的用法

await get_onebot_caller()("action", arg1="arg1", arg2=222, arg3=True)

action 一般对应具体的操作,在go-cqhttp中,对应 api 的path,在可爱猫中,对应 api 的EventType,诸如此类

kwargs 对应其余参数

信息

注意,get_onebot_caller 之类的函数,返回的是 api_caller 对象,其本身也是可调用的,也就是说,要()()两次

await get_onebot_caller()("action", arg1="arg1")

等价于

onebot_caller = get_onebot_caller()
await onebot_caller("action", arg1="arg1")