update docs

This commit is contained in:
Richard Chien 2020-03-16 20:36:58 +08:00
parent 0ac6a03f0a
commit 0eb37da0b3
21 changed files with 174 additions and 132 deletions

View File

@ -23,7 +23,7 @@ NoneBot 在其底层与 酷Q 交互的部分使用 [python-aiocqhttp](https://gi
## 示意图 ## 示意图
![](diagram.png) ![](docs/assets/diagram.png)
## 文档 ## 文档

View File

@ -1,14 +1,14 @@
--- ---
home: true home: true
heroImage: /logo.png heroImage: /logo.png
actionText: 即刻开始 actionText: 开始使用
actionLink: /guide/ actionLink: /guide/
features: features:
- title: 简洁 - title: 简洁
details: 提供极其简洁易懂的 API使你可以毫无压力地开始验证你的绝佳创意只需编写最少量的代码即可实现丰富的功能。 details: 提供极其简洁易懂的 API使你可以毫无压力地开始验证你的绝佳创意只需编写最少量的代码即可实现丰富的功能。
- title: 易于扩展 - title: 易于扩展
details: 精心设计的消息处理流程及强大的 API 使得你可以很方便地将最简单的原型变为具有大量实用功能的完整聊天机器人,并持续保证扩展性。 details: 精心设计的消息处理流程使得你可以很方便地将原型扩充为具有大量实用功能的完整聊天机器人,并持续保证扩展性。
- title: 高性能 - title: 高性能
details: 基于时下流行的 asyncio 模块,利用 WebSocket 进行通信,以获得极高的性能;同时,支持使用多个机器人账号来负载均衡用户消息,减少业务宕机的可能。 details: 采用异步 I/O利用 WebSocket 进行通信,以获得极高的性能;同时,支持使用多账号同时接入,减少业务宕机的可能。
footer: MIT Licensed | Copyright © 2019 Richard Chien footer: MIT Licensed | Copyright © 2020 Richard Chien
--- ---

View File

@ -12,13 +12,13 @@ sidebar: auto
以下类型均可从 `nonebot.typing` 模块导入。 以下类型均可从 `nonebot.typing` 模块导入。
### `Context_T` ### `Context_T` <Badge text="1.5.0-" type="error"/>
- **类型:** `Dict[str, Any]` - **类型:** `Dict[str, Any]`
- **说明:** - **说明:**
酷Q HTTP API 上报的事件数据对象的类型。 CQHTTP 上报的事件数据对象的类型。
### `Message_T` ### `Message_T`
@ -87,7 +87,7 @@ sidebar: auto
- **说明:** - **说明:**
酷Q HTTP API 插件的 HTTP 接口地址,如果不使用 HTTP 通信,则无需设置。 CQHTTP 插件的 HTTP 接口地址,如果不使用 HTTP 通信,则无需设置。
- **用法:** - **用法:**
@ -95,7 +95,7 @@ sidebar: auto
API_ROOT = 'http://127.0.0.1:5700' API_ROOT = 'http://127.0.0.1:5700'
``` ```
告诉 NoneBot 酷Q HTTP API 插件的 HTTP 服务运行在 `http://127.0.0.1:5700` 告诉 NoneBot CQHTTP 插件的 HTTP 服务运行在 `http://127.0.0.1:5700`
### `ACCESS_TOKEN` ### `ACCESS_TOKEN`
@ -105,7 +105,7 @@ sidebar: auto
- **说明:** - **说明:**
需要和 酷Q HTTP API 插件的配置中的 `access_token` 相同。 需要和 CQHTTP 插件的配置中的 `access_token` 相同。
### `SECRET` ### `SECRET`
@ -115,7 +115,7 @@ sidebar: auto
- **说明:** - **说明:**
需要和 酷Q HTTP API 插件的配置中的 `secret` 相同。 需要和 CQHTTP 插件的配置中的 `secret` 相同。
### `HOST` ### `HOST`
@ -530,7 +530,7 @@ sidebar: auto
bot = nonebot.get_bot() bot = nonebot.get_bot()
@bot.on_message('group') @bot.on_message('group')
async def handle_group_message(ctx: Context_T) async def handle_group_message(event: aiocqhttp.Event)
pass pass
``` ```
@ -554,7 +554,7 @@ sidebar: auto
bot = nonebot.get_bot() bot = nonebot.get_bot()
@bot.on_notice('group_increase') @bot.on_notice('group_increase')
async def handle_group_increase(ctx: Context_T) async def handle_group_increase(event: aiocqhttp.Event)
pass pass
``` ```
@ -578,7 +578,7 @@ sidebar: auto
bot = nonebot.get_bot() bot = nonebot.get_bot()
@bot.on_request('friend', 'group.invite') @bot.on_request('friend', 'group.invite')
async def handle_request(ctx: Context_T) async def handle_request(event: aiocqhttp.Event)
pass pass
``` ```
@ -602,7 +602,7 @@ sidebar: auto
bot = nonebot.get_bot() bot = nonebot.get_bot()
@bot.on_meta_event('heartbeat') @bot.on_meta_event('heartbeat')
async def handle_heartbeat(ctx: Context_T) async def handle_heartbeat(event: aiocqhttp.Event)
pass pass
``` ```
@ -801,10 +801,10 @@ sidebar: auto
- **要求:** - **要求:**
被装饰函数必须是一个 async 函数,且必须接收且仅接收两个位置参数,类型分别为 `NoneBot``Context_T`,即形如: 被装饰函数必须是一个 async 函数,且必须接收且仅接收两个位置参数,类型分别为 `NoneBot``aiocqhttp.Event`,即形如:
```python ```python
async def func(bot: NoneBot, ctx: Context_T): async def func(bot: NoneBot, event: aiocqhttp.Event):
pass pass
``` ```
@ -812,11 +812,11 @@ sidebar: auto
```python ```python
@message_preprocessor @message_preprocessor
async def _(bot: NoneBot, ctx: Context_T): async def _(bot: NoneBot, event: aiocqhttp.Event):
ctx['preprocessed'] = True event['preprocessed'] = True
``` ```
在所有消息处理之前,向消息事件上下文对象中加入 `preprocessed` 字段。 在所有消息处理之前,向消息事件对象中加入 `preprocessed` 字段。
### _class_ `MessageSegment` ### _class_ `MessageSegment`
@ -1160,7 +1160,7 @@ sidebar: auto
- **用法:** - **用法:**
```python ```python
str(ctx['message']) str(event.message)
``` ```
#### `__add__(other)` #### `__add__(other)`
@ -1254,7 +1254,7 @@ sidebar: auto
- **用法:** - **用法:**
```python ```python
text = session.ctx['message'].extract_plain_text() text = session.event.message.extract_plain_text()
``` ```
提取事件上报的原始消息中的纯文本部分。 提取事件上报的原始消息中的纯文本部分。
@ -1301,7 +1301,7 @@ sidebar: auto
- **参数:** - **参数:**
- `name: Union[str, CommandName_T]`: 命令名,如果传入的是字符串则会自动转为元组 - `name: Union[str, CommandName_T]`: 命令名,如果传入的是字符串则会自动转为元组
- `aliases: Iterable[str]`: 命令别名 - `aliases: Union[Iterable[str], str]`: 命令别名
- `permission: int`: 命令所需要的权限,不满足权限的用户将无法触发该命令 - `permission: int`: 命令所需要的权限,不满足权限的用户将无法触发该命令
- `only_to_me: bool`: 是否只响应确定是在和「我」(机器人)说话的命令(在开头或结尾 @ 了机器人,或在开头称呼了机器人昵称) - `only_to_me: bool`: 是否只响应确定是在和「我」(机器人)说话的命令(在开头或结尾 @ 了机器人,或在开头称呼了机器人昵称)
- `privileged: bool`: 是否特权命令,若是,则无论当前是否有命令会话正在运行,都会运行该命令,但运行不会覆盖已有会话,也不会保留新创建的会话 - `privileged: bool`: 是否特权命令,若是,则无论当前是否有命令会话正在运行,都会运行该命令,但运行不会覆盖已有会话,也不会保留新创建的会话
@ -1319,7 +1319,7 @@ sidebar: auto
- **用法:** - **用法:**
```python ```python
@on_command('echo') @on_command('echo', aliases=('复读',))
async def _(session: CommandSession): async def _(session: CommandSession):
await session.send(session.current_arg) await session.send(session.current_arg)
``` ```
@ -1633,11 +1633,11 @@ sidebar: auto
session.finish('感谢您的使用~') session.finish('感谢您的使用~')
``` ```
#### `switch(new_ctx_message)` #### `switch(new_message)`
- **说明:** - **说明:**
结束当前会话,改变当前消息事件上下文中的消息内容,然后重新处理消息事件上下文 结束当前会话,改变当前消息事件中的消息内容,然后重新处理消息事件。
此函数可用于从一个命令中跳出,将用户输入的剩余部分作为新的消息来处理,例如可实现以下对话: 此函数可用于从一个命令中跳出,将用户输入的剩余部分作为新的消息来处理,例如可实现以下对话:
@ -1652,7 +1652,7 @@ sidebar: auto
- **参数:** - **参数:**
- `new_ctx_message: Message_T`: 要覆盖消息事件上下文的新消息内容 - `new_message: Message_T`: 要覆盖消息事件的新消息内容
- **用法:** - **用法:**
@ -1665,7 +1665,7 @@ sidebar: auto
使用「算了」来取消当前命令,转而进入新的消息处理流程。这个例子比较简单,实际应用中可以使用更复杂的 NLP 技术来判断。 使用「算了」来取消当前命令,转而进入新的消息处理流程。这个例子比较简单,实际应用中可以使用更复杂的 NLP 技术来判断。
### _coroutine_ `call_command(bot, ctx, name, *, current_arg='', args=None, check_perm=True, disable_interaction=False)` ### _coroutine_ `call_command(bot, event, name, *, current_arg='', args=None, check_perm=True, disable_interaction=False)`
- **说明:** - **说明:**
@ -1674,7 +1674,7 @@ sidebar: auto
- **参数:** - **参数:**
- `bot: NoneBot`: NoneBot 对象 - `bot: NoneBot`: NoneBot 对象
- `ctx: Context_T`: 事件上下文对象 - `event: aiocqhttp.Event`: 事件对象
- `name: Union[str, CommandName_T]`: 要调用的命令名 - `name: Union[str, CommandName_T]`: 要调用的命令名
- `current_arg: str`: 命令会话的当前输入参数 - `current_arg: str`: 命令会话的当前输入参数
- `args: Optional[CommandArgs_T]`: 命令会话的(初始)参数(将会被并入命令会话的 `state` 属性) - `args: Optional[CommandArgs_T]`: 命令会话的(初始)参数(将会被并入命令会话的 `state` 属性)
@ -1688,12 +1688,12 @@ sidebar: auto
- **用法:** - **用法:**
```python ```python
await call_command(bot, ctx, 'say', current_arg='[CQ:face,id=14]', check_perm=False) await call_command(bot, event, 'say', current_arg='[CQ:face,id=14]', check_perm=False)
``` ```
从内部调用 `say` 命令,且不检查权限。 从内部调用 `say` 命令,且不检查权限。
### `kill_current_session(ctx)` ### `kill_current_session(event)`
- **说明:** - **说明:**
@ -1701,7 +1701,7 @@ sidebar: auto
- **参数:** - **参数:**
- `ctx: Context_T`: 事件上下文对象 - `event: aiocqhttp.Event`: 事件对象
- **返回:** - **返回:**
@ -1712,7 +1712,7 @@ sidebar: auto
```python ```python
@on_command('kill', privileged=True) @on_command('kill', privileged=True)
async def _(session: CommandSession): async def _(session: CommandSession):
kill_current_session(session.ctx) kill_current_session(session.event)
``` ```
在特权命令 `kill` 中强行移除当前正在运行的会话。 在特权命令 `kill` 中强行移除当前正在运行的会话。
@ -2079,7 +2079,7 @@ session.get('arg1', prompt='请输入 arg1',
```python ```python
@on_notice @on_notice
async def _(session: NoticeSession): async def _(session: NoticeSession):
logger.info('有新的通知事件:%s', session.ctx) logger.info('有新的通知事件:%s', session.event)
@on_notice('group_increase') @on_notice('group_increase')
async def _(session: NoticeSession): async def _(session: NoticeSession):
@ -2112,7 +2112,7 @@ session.get('arg1', prompt='请输入 arg1',
```python ```python
@on_request @on_request
async def _(session: RequestSession): async def _(session: RequestSession):
logger.info('有新的请求事件:%s', session.ctx) logger.info('有新的请求事件:%s', session.event)
@on_request('group') @on_request('group')
async def _(session: RequestSession): async def _(session: RequestSession):
@ -2199,13 +2199,30 @@ session.get('arg1', prompt='请输入 arg1',
在当前 Session 对应的上下文中发送 `hello` 在当前 Session 对应的上下文中发送 `hello`
#### `ctx` #### `event` <Badge text="1.5.0+"/>
- **类型:** `aiocqhttp.Event`
- **说明:**
CQHTTP 上报的事件数据对象,具体请参考 [`aiocqhttp.Event`](https://python-aiocqhttp.cqp.moe/module/aiocqhttp/index.html#aiocqhttp.Event) 和 [事件上报](https://cqhttp.cc/docs/#/Post)。
- **用法:**
```python
user_id = session.event['user_id']
group_id = session.event.group_id
```
获取当前事件的 `user_id``group_id` 字段。
#### `ctx` <Badge text="1.5.0-" type="error"/>
- **类型:** `Context_T` - **类型:** `Context_T`
- **说明:** - **说明:**
酷Q HTTP API 上报的事件数据对象,或称事件上下文,具体请参考 [事件上报](https://cqhttp.cc/docs/#/Post)。 CQHTTP 上报的事件数据对象,或称事件上下文,具体请参考 [事件上报](https://cqhttp.cc/docs/#/Post)。
- **用法:** - **用法:**
@ -2213,7 +2230,7 @@ session.get('arg1', prompt='请输入 arg1',
user_id = session.ctx['user_id'] user_id = session.ctx['user_id']
``` ```
获取当前事件上下文`user_id` 字段。 获取当前事件的 `user_id` 字段。
#### _readonly property_ `self_id` <Badge text="1.1.0+"/> #### _readonly property_ `self_id` <Badge text="1.1.0+"/>
@ -2223,7 +2240,7 @@ session.get('arg1', prompt='请输入 arg1',
当前 session 对应的 QQ 机器人账号,在多个机器人账号使用同一个 NoneBot 后端时可用于区分当前收到消息或事件的是哪一个机器人。 当前 session 对应的 QQ 机器人账号,在多个机器人账号使用同一个 NoneBot 后端时可用于区分当前收到消息或事件的是哪一个机器人。
等价于 `session.ctx['self_id']`。 等价于 `session.event.self_id`。
- **用法:** - **用法:**
@ -2289,7 +2306,7 @@ async def _(session):
需要注意的是当一个用户是「群管理员」时ta 同时也是「群成员」;当 ta 是「群主」时ta 同时也是「群管理员」和「群成员」。 需要注意的是当一个用户是「群管理员」时ta 同时也是「群成员」;当 ta 是「群主」时ta 同时也是「群管理员」和「群成员」。
### _coroutine_ `check_permission(bot, ctx, permission_required)` ### _coroutine_ `check_permission(bot, event, permission_required)`
- **说明:** - **说明:**
@ -2298,17 +2315,17 @@ async def _(session):
- **参数:** - **参数:**
- `bot: NoneBot`: NoneBot 对象 - `bot: NoneBot`: NoneBot 对象
- `ctx: Context_T`: 消息事件上下文对象 - `event: aiocqhttp.Event`: 消息事件对象
- `permission_required: int`: 要求的权限值 - `permission_required: int`: 要求的权限值
- **返回:** - **返回:**
- `bool`: 消息事件上下文所对应的用户是否具有所要求的权限 - `bool`: 消息事件所对应的上下文是否具有所要求的权限
- **用法:** - **用法:**
```python ```python
has_perm = await check_permission(bot, ctx, cmd.permission) has_perm = await check_permission(bot, event, cmd.permission)
``` ```
## `nonebot.log` 模块 ## `nonebot.log` 模块
@ -2329,15 +2346,15 @@ async def _(session):
## `nonebot.helpers` 模块 ## `nonebot.helpers` 模块
### `context_id(ctx, *, mode='default', use_hash=False)` ### `context_id(event, *, mode='default', use_hash=False)`
- **说明:** - **说明:**
获取事件上下文的唯一 ID。 获取事件对应的上下文的唯一 ID。
- **参数:** - **参数:**
- `ctx: Context_T`: 事件上下文对象 - `event: aiocqhttp.Event`: 事件对象
- `mode: str`: ID 的计算模式 - `mode: str`: ID 的计算模式
- `'default'`: 默认模式,任何一个上下文都有其唯一 ID - `'default'`: 默认模式,任何一个上下文都有其唯一 ID
- `'group'`: 群组模式,同一个群组或讨论组的上下文(即使是不同用户)具有相同 ID - `'group'`: 群组模式,同一个群组或讨论组的上下文(即使是不同用户)具有相同 ID
@ -2346,26 +2363,26 @@ async def _(session):
- **返回:** - **返回:**
- `str`: 事件上下文的唯一 ID - `str`: 事件对应的上下文的唯一 ID
- **用法:** - **用法:**
```python ```python
ctx_id = context_id(session.ctx, use_hash=True) ctx_id = context_id(session.event, use_hash=True)
``` ```
获取当前 Session 的事件上下文对应的唯一 ID并进行 MD5 哈希,得到的结果可用于图灵机器人等 API 的调用。 获取当前 Session 的事件对应的上下文的唯一 ID并进行 MD5 哈希,得到的结果可用于图灵机器人等 API 的调用。
### _coroutine_ `send(bot, ctx, message, *, ensure_private=False, ignore_failure=True, **kwargs)` ### _coroutine_ `send(bot, event, message, *, ensure_private=False, ignore_failure=True, **kwargs)`
- **说明:** - **说明:**
发送消息到指定事件上下文中。 发送消息到指定事件上下文中。
- **参数:** - **参数:**
- `bot: NoneBot`: NoneBot 对象 - `bot: NoneBot`: NoneBot 对象
- `ctx: Context_T`: 事件上下文对象 - `event: aiocqhttp.Event`: 事件对象
- `message: Message_T`: 要发送的消息内容 - `message: Message_T`: 要发送的消息内容
- `ensure_private: bool`: 确保消息发送到私聊,对于群组和讨论组消息上下文,会私聊发送者 - `ensure_private: bool`: 确保消息发送到私聊,对于群组和讨论组消息上下文,会私聊发送者
- `ignore_failure: bool`: 发送失败时忽略 `CQHttpError` 异常 - `ignore_failure: bool`: 发送失败时忽略 `CQHttpError` 异常
@ -2382,7 +2399,7 @@ async def _(session):
- **用法:** - **用法:**
```python ```python
await send(bot, ctx, 'hello') await send(bot, event, 'hello')
``` ```
### `render_expression(expr, *args, escape_args=True, **kwargs)` ### `render_expression(expr, *args, escape_args=True, **kwargs)`

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -4,6 +4,12 @@ sidebar: auto
# 更新日志 # 更新日志
## next
- 弃用 `session.ctx` 属性,请使用 `session.event` 替代,该对象类型为 `aiocqhttp.Event`,可通过 property 访问内容
- 移除 `nonebot.tying.Context_T`,请使用 `aiocqhttp.Event` 替代
- 修复 `@on_command` 装饰后命令处理函数 docstring 丢失问题
## v1.4.2 ## v1.4.2
- 修复 `CommandSession` 的部分方法在多线程条件下出错 - 修复 `CommandSession` 的部分方法在多线程条件下出错

View File

@ -8,15 +8,15 @@ sidebar: auto
[酷Q](https://cqp.cc) 是一个易语言编写的 QQ 机器人平台,其本身没有任何具体的功能,只是负责实现 QQ 协议,并以 DLL 导出函数的形式向插件提供 API 和事件上报。 [酷Q](https://cqp.cc) 是一个易语言编写的 QQ 机器人平台,其本身没有任何具体的功能,只是负责实现 QQ 协议,并以 DLL 导出函数的形式向插件提供 API 和事件上报。
## CoolQ HTTP API 插件 ## CQHTTP 插件
[CoolQ HTTP API 插件](https://cqhttp.cc/) 是 酷Q 的一个第三方插件,用于将 酷Q 所提供的所有 DLL 接口转换为 HTTP 或 WebSocket 的 web 形式,从而使利用任意语言编写 酷Q 插件成为可能。 [CQHTTP 插件](https://cqhttp.cc/) CoolQ HTTP API 插件,是 酷Q 的一个第三方插件,用于将 酷Q 所提供的所有 DLL 接口转换为 HTTP 或 WebSocket 的 web 形式,从而使利用任意语言编写 酷Q 插件成为可能。
有时被称为 cqhttp、CQHTTP、酷Q HTTP API 等。 有时被称为 cqhttp、CQHTTP、酷Q HTTP API 等。
## aiocqhttp ## aiocqhttp
[aiocqhttp](https://github.com/richardchien/python-aiocqhttp)(或称 python-aiocqhttp是 CoolQ HTTP API 插件的一个 Python 异步 SDK基于 asyncio在 Quart 的基础上封装了与 CoolQ HTTP API 插件的网络交互。 [aiocqhttp](https://github.com/richardchien/python-aiocqhttp)(或称 python-aiocqhttp是 CQHTTP 插件的一个 Python 异步 SDK基于 asyncio在 Quart 的基础上封装了与 CQHTTP 插件的网络交互。
## asyncio ## asyncio
@ -32,9 +32,9 @@ sidebar: auto
## 通信方式 ## 通信方式
CoolQ HTTP API 插件中的一个术语,表示其与通过 web 技术编写的 酷Q 插件之间通信的手段。 CQHTTP 插件中的一个术语,表示其与通过 web 技术编写的 酷Q 插件之间通信的手段。
目前 CoolQ HTTP API 插件支持 HTTP、WebSocket、反向 WebSocket 三种通信方式,见 [通信方式](https://cqhttp.cc/docs/#/CommunicationMethods)NoneBot 支持其中的 HTTP 和反向 WebSocket。 目前 CQHTTP 插件支持 HTTP、WebSocket、反向 WebSocket 三种通信方式,见 [通信方式](https://cqhttp.cc/docs/#/CommunicationMethods)NoneBot 支持其中的 HTTP 和反向 WebSocket。
## 负载均衡 ## 负载均衡
@ -96,10 +96,6 @@ async def _(session):
特别地,命令的 Session 在需要和用户交互的情况下,会一直保留到下一次调用,以保证命令的多次交互能够共享数据。 特别地,命令的 Session 在需要和用户交互的情况下,会一直保留到下一次调用,以保证命令的多次交互能够共享数据。
## 上下文Context
通常通过 `session.ctx` 访问,是 CoolQ HTTP API 插件发送给 NoneBot 的原始事件数据,包含当前事件的来源信息、内容等,具体请参考 CoolQ HTTP API 插件文档的 [事件上报](https://cqhttp.cc/docs/#/Post).
## 表达Expression ## 表达Expression
是 NoneBot 支持的一种消息渲染的机制,可以通过随机选择或函数生成+字符串格式化的方式根据参数生成出自然的、不固定的消息回复,提升用户体验。 是 NoneBot 支持的一种消息渲染的机制,可以通过随机选择或函数生成+字符串格式化的方式根据参数生成出自然的、不固定的消息回复,提升用户体验。
@ -108,11 +104,11 @@ Expression 可以是一个 `str`、元素类型是 `str` 的序列(一般为 `
## CQ 码 ## CQ 码
是 酷Q 用来表示非文本消息的一种表示方法,形如 `[CQ:image,file=ABC.jpg]`。具体的格式规则,请参考 酷Q 文档的 [CQ 码](https://d.cqp.me/Pro/CQ%E7%A0%81) 和 CoolQ HTTP API 插件文档的 [CQ 码](https://cqhttp.cc/docs/#/CQCode)。 是 酷Q 用来表示非文本消息的一种表示方法,形如 `[CQ:image,file=ABC.jpg]`。具体的格式规则,请参考 酷Q 文档的 [CQ 码](https://d.cqp.me/Pro/CQ%E7%A0%81) 和 CQHTTP 插件文档的 [CQ 码](https://cqhttp.cc/docs/#/CQCode)。
## 消息段 ## 消息段
是 CoolQ HTTP API 定义的、和 CQ 码可以互相转换的一个消息表示格式,具体表示方式见 [消息格式](https://cqhttp.cc/docs/#/Message)。 是 CQHTTP 定义的、和 CQ 码可以互相转换的一个消息表示格式,具体表示方式见 [消息格式](https://cqhttp.cc/docs/#/Message)。
除了纯文本消息段之外,每一个消息段都和一个 CQ 码对应,例如下面这个消息段: 除了纯文本消息段之外,每一个消息段都和一个 CQ 码对应,例如下面这个消息段:

View File

@ -12,20 +12,24 @@ NoneBot 是一个基于 [酷Q](https://cqp.cc/) 的 Python 异步 QQ 机器人
除了起到解析消息的作用NoneBot 还为插件提供了大量实用的预设操作和权限控制机制,尤其对于命令处理器,它更是提供了完善且易用的会话机制和内部调用机制,以分别适应命令的连续交互和插件内部功能复用等需求。 除了起到解析消息的作用NoneBot 还为插件提供了大量实用的预设操作和权限控制机制,尤其对于命令处理器,它更是提供了完善且易用的会话机制和内部调用机制,以分别适应命令的连续交互和插件内部功能复用等需求。
NoneBot 在其底层与 酷Q 交互的部分使用 [python-aiocqhttp](https://github.com/richardchien/python-aiocqhttp) 库,后者是 [CoolQ HTTP API 插件](https://cqhttp.cc/) 的一个 Python 异步 SDK在 [Quart](https://pgjones.gitlab.io/quart/) 的基础上封装了与 CoolQ HTTP API 插件的网络交互。 NoneBot 在其底层与 酷Q 交互的部分使用 [python-aiocqhttp](https://github.com/richardchien/python-aiocqhttp) 库,后者是 [CQHTTP 插件](https://cqhttp.cc/) 的一个 Python 异步 SDK在 [Quart](https://pgjones.gitlab.io/quart/) 的基础上封装了与 CQHTTP 插件的网络交互。
得益于 Python 的 [asyncio](https://docs.python.org/3/library/asyncio.html) 机制NoneBot 处理消息的吞吐量有了很大的保障,再配合 CoolQ HTTP API 插件可选的 WebSocket 通信方式也是最建议的通信方式NoneBot 的性能可以达到 HTTP 通信方式的两倍以上,相较于传统同步 I/O 的 HTTP 通信,更是有质的飞跃。 得益于 Python 的 [asyncio](https://docs.python.org/3/library/asyncio.html) 机制NoneBot 处理消息的吞吐量有了很大的保障,再配合 CQHTTP 插件可选的 WebSocket 通信方式也是最建议的通信方式NoneBot 的性能可以达到 HTTP 通信方式的两倍以上,相较于传统同步 I/O 的 HTTP 通信,更是有质的飞跃。
需要注意的是NoneBot 仅支持 Python 3.7+ 及 CoolQ HTTP API 插件 v4.8+。 需要注意的是NoneBot 仅支持 Python 3.7+ 及 CQHTTP 插件 v4.8+。
## 它如何工作? ## 它如何工作?
NoneBot 的运行离不开 酷Q 和 CoolQ HTTP API 插件。酷Q 扮演着「无头 QQ 客户端」的角色,它进行实际的消息、通知、请求的接收和发送,当 酷Q 收到消息时,它将这个消息包装为一个事件(通知和请求同理),并通过它自己的插件机制将事件传送给 CoolQ HTTP API 插件,后者再根据其配置中的 `post_url``ws_reverse_url` 等项来将事件发送至 NoneBot。 NoneBot 的运行离不开 酷Q 和 CQHTTP 插件。酷Q 扮演着「无头 QQ 客户端」的角色,它进行实际的消息、通知、请求的接收和发送,当 酷Q 收到消息时,它将这个消息包装为一个事件(通知和请求同理),并通过它自己的插件机制将事件传送给 CQHTTP 插件,后者再根据其配置中的 `post_url``ws_reverse_url` 等项来将事件发送至 NoneBot。
在 NoneBot 收到事件前,它底层的 aiocqhttp 实际已经先看到了事件aiocqhttp 根据事件的类型信息,通知到 NoneBot 的相应函数。特别地,对于消息类型的事件,还将消息内容转换成了 `aiocqhttp.message.Message` 类型,以便处理。 在 NoneBot 收到事件前,它底层的 aiocqhttp 实际已经先看到了事件aiocqhttp 根据事件的类型信息,通知到 NoneBot 的相应函数。特别地,对于消息类型的事件,还将消息内容转换成了 `aiocqhttp.message.Message` 类型,以便处理。
NoneBot 的事件处理函数收到通知后对于不同类型的事件再做相应的预处理和解析然后调用对应的插件并向其提供适合此类事件的会话Session对象。NoneBot 插件的编写者要做的,就是利用 Session 对象中提供的数据,在插件的处理函数中实现所需的功能。 NoneBot 的事件处理函数收到通知后对于不同类型的事件再做相应的预处理和解析然后调用对应的插件并向其提供适合此类事件的会话Session对象。NoneBot 插件的编写者要做的,就是利用 Session 对象中提供的数据,在插件的处理函数中实现所需的功能。
## 示意图
![NoneBot 工作原理](../assets/diagram.png)
## 特色 ## 特色
- 基于异步 I/O - 基于异步 I/O

View File

@ -18,7 +18,7 @@ awesome-bot
└── config.py └── config.py
``` ```
在后面几章中,我们将在此结构上进行扩展和改进。 在后面几章中,我们将在此结构上进行改进和扩展
## 配置超级用户 ## 配置超级用户

View File

@ -6,7 +6,7 @@ from nonebot import on_notice, NoticeSession
@on_request('group') @on_request('group')
async def _(session: RequestSession): async def _(session: RequestSession):
# 判断验证信息是否符合要求 # 判断验证信息是否符合要求
if session.ctx['comment'] == '暗号': if session.event.comment == '暗号':
# 验证信息正确,同意入群 # 验证信息正确,同意入群
await session.approve() await session.approve()
return return

View File

@ -6,7 +6,7 @@ from nonebot import on_notice, NoticeSession
@on_request('group') @on_request('group')
async def _(session: RequestSession): async def _(session: RequestSession):
# 判断验证信息是否符合要求 # 判断验证信息是否符合要求
if session.ctx['comment'] == '暗号': if session.event.comment == '暗号':
# 验证信息正确,同意入群 # 验证信息正确,同意入群
await session.approve() await session.approve()
return return

View File

@ -6,7 +6,7 @@ from nonebot import on_notice, NoticeSession
@on_request('group') @on_request('group')
async def _(session: RequestSession): async def _(session: RequestSession):
# 判断验证信息是否符合要求 # 判断验证信息是否符合要求
if session.ctx['comment'] == '暗号': if session.event.comment == '暗号':
# 验证信息正确,同意入群 # 验证信息正确,同意入群
await session.approve() await session.approve()
return return

View File

@ -62,7 +62,7 @@ if __name__ == '__main__':
::: warning 注意 ::: warning 注意
如果你运行时没有输出成功导入插件的日志,请确保你的当前工作目录是在 `awesome-bot` 项目的主目录中。 如果你运行时没有输出成功导入插件的日志,请确保你的当前工作目录是在 `awesome-bot` 项目的主目录中。
如果仍然不行,尝试`awesome-bot` 主目录中执行下面的命令: 如果仍然不行,尝试先 `awesome-bot` 主目录中执行下面的命令:
```bash ```bash
export PYTHONPATH=. # Linux / macOS export PYTHONPATH=. # Linux / macOS

View File

@ -4,15 +4,13 @@
## 事件数据 ## 事件数据
在 [发生了什么?](./whats-happened.md) 中我们提到,收到 酷Q 事件后CQHTTP 通过反向 WebSocket 给 NoneBot 发送事件数据。这些数据被 NoneBot 放在了 `session.ctx` 中,是一个字典,你可以通过断点调试或打印等方式查看它的内容,其中的字段名和含义见 CQHTTP 的 [事件列表](https://cqhttp.cc/docs/#/Post?id=事件列表) 中的「上报数据」。 在 [发生了什么?](./whats-happened.md) 中我们提到,收到 酷Q 事件后CQHTTP 通过反向 WebSocket 给 NoneBot 发送事件数据。这些数据被 aiocqhttp 包装为 [`aiocqhttp.Event`](https://python-aiocqhttp.cqp.moe/module/aiocqhttp/#aiocqhttp.Event) 对象,随后被 NoneBot 放在了 `session.event` 属性。该对象本质上是一个字典(但也提供了属性来获取其中的字段),你可以通过断点调试或打印等方式查看它的内容,其中的字段名和含义见 CQHTTP 的 [事件列表](https://cqhttp.cc/docs/#/Post?id=事件列表) 中的「上报数据」。
## API 调用 ## API 调用
前面我们已经多次调用 `CommandSession` 类的 `send()` 方法,而这个方法只能回复给消息的发送方,不能手动指定发送者,因此当我们需要实现将收到的消息经过处理后转发给另一个接收方这样的功能时,这个方法就用不了了。 前面我们已经多次调用 `CommandSession` 类的 `send()` 方法,而这个方法只能回复给消息的发送方,不能手动指定发送者,因此当我们需要实现将收到的消息经过处理后转发给另一个接收方这样的功能时,这个方法就用不了了。
幸运的是,`NoneBot` 类是继承自 [python-aiocqhttp] 的 `CQHttp` 类的,而这个类实现了 `__getattr__()` 魔术方法,由此提供了直接通过 bot 对象调用 CQHTTP 的 API 的能力。 幸运的是,`NoneBot` 类是继承自 aiocqhttp 的 [`CQHttp` 类](https://python-aiocqhttp.cqp.moe/module/aiocqhttp/#aiocqhttp.CQHttp) 的,而这个类实现了 `__getattr__()` 魔术方法,由此提供了直接通过 bot 对象调用 CQHTTP 的 API 的能力。
[python-aiocqhttp]: https://github.com/cqmoe/python-aiocqhttp
::: tip 提示 ::: tip 提示
如果你在使用 HTTP 通信,要调用 CQHTTP API 要在 `config.py` 中添加: 如果你在使用 HTTP 通信,要调用 CQHTTP API 要在 `config.py` 中添加:
@ -50,7 +48,7 @@ await bot.send_private_msg(user_id=12345678, message='你好~')
``` ```
- **当多个机器人使用同一个 NoneBot 后端时**,可能需要加上参数 `self_id=<机器人QQ号>`,例如: - **当多个机器人使用同一个 NoneBot 后端时**,可能需要加上参数 `self_id=<机器人QQ号>`,例如:
```python ```python
info = await bot.get_group_list(self_id=ctx['self_id']) info = await bot.get_group_list(self_id=event.self_id)
``` ```
另外,在需要动态性的场合,除了使用 `getattr()` 方法外,还可以直接调用 `bot.call_action()` 方法,传入 `action``params` 即可,例如上例中,`action` 为 `'send_private_msg'``params` 为 `{'user_id': 12345678, 'message': '你好~'}` 另外,在需要动态性的场合,除了使用 `getattr()` 方法外,还可以直接调用 `bot.call_action()` 方法,传入 `action``params` 即可,例如上例中,`action` 为 `'send_private_msg'``params` 为 `{'user_id': 12345678, 'message': '你好~'}`
@ -61,12 +59,12 @@ await bot.send_private_msg(user_id=12345678, message='你好~')
await bot.send_private_msg(user_id=12345678, message='你好~') await bot.send_private_msg(user_id=12345678, message='你好~')
await bot.send_group_msg(group_id=123456, message='大家好~') await bot.send_group_msg(group_id=123456, message='大家好~')
ctx = session.ctx.copy() params = session.event.copy()
del ctx['message'] del params['message']
await bot.send_msg(**ctx, message='喵~') await bot.send_msg(**params, message='喵~')
await bot.delete_msg(**session.ctx) await bot.delete_msg(**session.event)
await bot.set_group_card(**session.ctx, card='新人请改群名片') await bot.set_group_card(**session.event, card='新人请改群名片')
self_info = await bot.get_login_info() self_info = await bot.get_login_info()
group_member_info = await bot.get_group_member_info(group_id=123456, user_id=12345678, no_cache=True) group_member_info = await bot.get_group_member_info(group_id=123456, user_id=12345678, no_cache=True)
``` ```

View File

@ -22,7 +22,7 @@ if __name__ == '__main__':
3. 在地址 `127.0.0.1:8080` 运行 NoneBot 3. 在地址 `127.0.0.1:8080` 运行 NoneBot
::: tip 提示 ::: tip 提示
这里 `nonebot.run()` 的参数 `host='127.0.0.1'` 表示让 NoneBot 监听本地环回地址,如果你的 酷Q 运行在非本机的其它位置,例如 Docker 容器内、局域网内的另一台机器上等,则这里需要修改 `host` 参数为希望让 CoolQ HTTP API 插件访问的 IP。如果不清楚该使用哪个 IP或者希望本机的所有 IP 都被监听,可以使用 `0.0.0.0` 这里 `nonebot.run()` 的参数 `host='127.0.0.1'` 表示让 NoneBot 监听本地环回地址,如果你的 酷Q 运行在非本机的其它位置,例如 Docker 容器内、局域网内的另一台机器上等,则这里需要修改 `host` 参数为希望让 CQHTTP 插件访问的 IP。如果不清楚该使用哪个 IP或者希望本机的所有 IP 都被监听,可以使用 `0.0.0.0`
::: :::
在命令行使用如下命令即可运行这个 NoneBot 实例: 在命令行使用如下命令即可运行这个 NoneBot 实例:
@ -34,28 +34,29 @@ python bot.py
运行后会产生如下日志: 运行后会产生如下日志:
``` ```
[2019-01-26 14:24:15,984 nonebot] INFO: Succeeded to import "nonebot.plugins.base" [2020-03-16 15:50:26,166 nonebot] INFO: Succeeded to import "nonebot.plugins.base"
[2019-01-26 14:24:15,987 nonebot] INFO: Running on 127.0.0.1:8080 [2020-03-16 15:50:26,166 nonebot] INFO: Running on 127.0.0.1:8080
Running on https://127.0.0.1:8080 (CTRL + C to quit) Running on http://127.0.0.1:8080 (CTRL + C to quit)
[2020-03-16 15:50:26,177] Running on 127.0.0.1:8080 over http (CTRL + C to quit)
``` ```
除此之外可能有一些红色的警告信息和 `ASGI Framework Lifespan error` 等,可以忽略。 除此之外可能有一些红色的提示信息如 `ujson module not found, using json` 等,可以忽略。
## 配置 CoolQ HTTP API 插件 ## 配置 CQHTTP 插件
单纯运行 NoneBot 实例并不会产生任何效果,因为此刻 酷Q 这边还不知道 NoneBot 的存在,也就无法把消息发送给它,因此现在需要对 CoolQ HTTP API 插件做一个简单的配置来让它把消息等事件上报给 NoneBot。 单纯运行 NoneBot 实例并不会产生任何效果,因为此刻 酷Q 这边还不知道 NoneBot 的存在,也就无法把消息发送给它,因此现在需要对 CQHTTP 插件做一个简单的配置来让它把消息等事件上报给 NoneBot。
如果你在之前已经按照 [安装](/guide/installation.md) 的建议使用默认配置运行了一次 CoolQ HTTP API 插件,此时 酷Q 的 `data/app/io.github.richardchien.coolqhttpapi/config/` 目录中应该已经有了一个名为 `<user-id>.json` 的文件(`<user-id>` 为你登录的 QQ 账号)。修改这个文件,**修改如下配置项(如果不存在相应字段则添加)** 如果你在之前已经按照 [安装](/guide/installation.md) 的建议使用默认配置运行了一次 CQHTTP 插件,此时 酷Q 的 `data/app/io.github.richardchien.coolqhttpapi/config/` 目录中应该已经有了一个名为 `<user-id>.json` 的文件(`<user-id>` 为你登录的 QQ 账号)。修改这个文件,**修改如下配置项(如果不存在相应字段则添加)**
::: warning 注意 ::: warning 注意
如果使用 CoolQ HTTP API 插件官方 Docker 镜像运行 酷Q则配置文件所在目录可能是 `app/io.github.richardchien.coolqhttpapi/config/` 如果使用 CQHTTP 插件官方 Docker 镜像运行 酷Q则配置文件所在目录可能是 `app/io.github.richardchien.coolqhttpapi/config/`
::: :::
```json ```json
{ {
"ws_reverse_api_url": "ws://127.0.0.1:8080/ws/api/", "ws_reverse_url": "ws://127.0.0.1:8080/ws/",
"ws_reverse_event_url": "ws://127.0.0.1:8080/ws/event/", "use_ws_reverse": true,
"use_ws_reverse": true "enable_heartbeat": true
} }
``` ```
@ -63,25 +64,35 @@ Running on https://127.0.0.1:8080 (CTRL + C to quit)
**这里的 `127.0.0.1:8080` 对应 `nonebot.run()` 中传入的 `host``port`**,如果在 `nonebot.run()` 中传入的 `host``0.0.0.0`,则插件的配置中需使用任意一个能够访问到 NoneBot 所在环境的 IP**不要直接填 `0.0.0.0`**。特别地,如果你的 酷Q 运行在 Docker 容器中NoneBot 运行在宿主机中,则默认情况下这里需使用 `172.17.0.1`(即宿主机在 Docker 默认网桥上的 IP不同机器有可能不同如果是 macOS 系统或者 Windows 系统,可以考虑使用 `host.docker.internal`,具体解释详见 Docker 文档的 [Use cases and workarounds](https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds) 的「I WANT TO CONNECT FROM A CONTAINER TO A SERVICE ON THE HOST」小标题 **这里的 `127.0.0.1:8080` 对应 `nonebot.run()` 中传入的 `host``port`**,如果在 `nonebot.run()` 中传入的 `host``0.0.0.0`,则插件的配置中需使用任意一个能够访问到 NoneBot 所在环境的 IP**不要直接填 `0.0.0.0`**。特别地,如果你的 酷Q 运行在 Docker 容器中NoneBot 运行在宿主机中,则默认情况下这里需使用 `172.17.0.1`(即宿主机在 Docker 默认网桥上的 IP不同机器有可能不同如果是 macOS 系统或者 Windows 系统,可以考虑使用 `host.docker.internal`,具体解释详见 Docker 文档的 [Use cases and workarounds](https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds) 的「I WANT TO CONNECT FROM A CONTAINER TO A SERVICE ON THE HOST」小标题
::: :::
修改之后,在 酷Q 的应用菜单中重启 CoolQ HTTP API 插件,或直接重启 酷Q以使新的配置文件生效。 如果你的 CQHTTP 插件版本低于 v4.14.0,还需要删除配置文件中已有的 `ws_reverse_api_url``ws_reverse_event_url` 两项。
修改之后,在 酷Q 的应用菜单中重启 CQHTTP 插件,或直接重载应用,以使新的配置文件生效。
## 历史性的第一次对话 ## 历史性的第一次对话
一旦新的配置文件正确生效之后NoneBot 所在的控制台(如果正在运行的话)应该会输出类似下面的内容(两条访问日志): 一旦新的配置文件正确生效之后NoneBot 所在的控制台(如果正在运行的话)应该会输出类似下面的内容(两条访问日志):
``` ```
[2019-01-26 16:23:17,159] 172.29.84.18:50639 GET /ws/api/ 1.1 101 - 986 [2020-03-16 15:50:26,435] 127.0.0.1:56363 GET /ws/ 1.1 101 - 7982
[2019-01-26 16:23:17,201] 172.29.84.18:53839 GET /ws/event/ 1.1 101 - 551 [2020-03-16 15:50:26,438] 127.0.0.1:56364 GET /ws/ 1.1 101 - 8977
``` ```
这表示 CoolQ HTTP API 插件已经成功地连接上了 NoneBot与此同时插件的日志文件中也会输出反向 WebSocket 连接成功的日志。 这表示 CQHTTP 插件已经成功地连接上了 NoneBot与此同时CQHTTP 的日志控制台(和日志文件)中也会输出反向 WebSocket 连接成功的日志。
::: warning 注意 ::: warning 注意
如果到这一步你没有看到上面这样的日志,请查看插件的日志文件中是否在不断尝试重连(可通过将插件的 `show_log_console` 配置项设置为 `true` 来显示日志控制台,方便调试),如果没有在不断重连,也说明连接成功. 如果到这一步你没有看到上面这样的成功日志CQHTTP 的日志中在不断地重连或无反应,请注意检查配置中的 IP 和端口是否确实可以访问。比较常见的出错点包括:
除此之外,也可以直接向机器人随便发送一些消息,观察 NoneBot 运行日志中是否有输出,如果有,说明连接成功。 - NoneBot 监听 `0.0.0.0`,然后在 CQHTTP 配置中填了 `ws://0.0.0.0:8080/ws/`
- 在 Docker 容器内运行 酷Q 和 CQHTTP并通过 `127.0.0.1` 访问宿主机上的 NoneBot
- 想从公网访问,但没有修改云服务商的安全组策略或系统防火墙
- NoneBot 所监听的端口存在冲突,已被其它程序占用
- 弄混了 NoneBot 的 `host`、`port` 参数与 CQHTTP 配置中的 `host`、`port` 参数
- 使用旧版 CQHTTP 插件,且没有删除 `ws_reverse_api_url``ws_reverse_event_url`
- 使用旧版 CQHTTP 插件,且丢失了 `ws://127.0.0.1:8080/ws/` 结尾的 `/`
- `ws://` 错填为 `http://`
- 酷Q 或 CQHTTP 插件启动时遭到外星武器干扰
如果 NoneBot 运行日志中没有任何访问日志,插件的日志中也在不断重连,请注意检查配置中的 IP 和端口是否确实可以访问。 请尝试重启 CQHTTP、重启 酷Q、重启 NoneBot、更换端口、修改防火墙、重启系统、仔细阅读前面的文档及提示、更新 CQHTTP 和 NoneBot 到最新版本等方式来解决
::: :::
现在,尝试向你的 QQ 机器人账号发送如下内容: 现在,尝试向你的 QQ 机器人账号发送如下内容:
@ -90,4 +101,4 @@ Running on https://127.0.0.1:8080 (CTRL + C to quit)
/echo 你好,世界 /echo 你好,世界
``` ```
到这里如果一切都没有问题,你应该会收到机器人给你回复了 `你好,世界`。这一历史性的对话标志着你已经成功地运行了一个 NoneBot 的最小实例,开始了编写更强大的 QQ 机器人的创意之旅! 到这里如果一切 OK,你应该会收到机器人给你回复了 `你好,世界`。这一历史性的对话标志着你已经成功地运行了一个 NoneBot 的最小实例,开始了编写更强大的 QQ 机器人的创意之旅!

View File

@ -3,7 +3,7 @@
## NoneBot ## NoneBot
::: warning 注意 ::: warning 注意
请确保你的 Python 版本 >= 3.6.1 请确保你的 Python 版本 >= 3.7
::: :::
可以使用 pip 安装已发布的最新版本: 可以使用 pip 安装已发布的最新版本:
@ -26,16 +26,16 @@ python setup.py install
前往 酷Q 官方论坛的 [版本发布](https://cqp.cc/b/news) 页面根据需要下载最新版本的 酷Q Air 或 Pro解压后启动 `CQA.exe``CQP.exe` 并登录 QQ 机器人账号。 前往 酷Q 官方论坛的 [版本发布](https://cqp.cc/b/news) 页面根据需要下载最新版本的 酷Q Air 或 Pro解压后启动 `CQA.exe``CQP.exe` 并登录 QQ 机器人账号。
如果你的操作系统是 Linux 或 macOS可以使用版本发布页中 酷Q 官方提供的 Docker 镜像,也可以直接跳至下一个标题,使用 CoolQ HTTP API 插件官方提供的 Docker 镜像。 如果你的操作系统是 Linux 或 macOS可以使用版本发布页中 酷Q 官方提供的 Docker 镜像,也可以直接跳至下一个标题,使用 CQHTTP 插件官方提供的 Docker 镜像。
::: tip 提示 ::: tip 提示
如果这是你第一次使用 酷Q建议完成它自带的新手教程从而对 酷Q 的运行机制有所了解。 如果这是你第一次使用 酷Q建议完成它自带的新手教程对 酷Q 的运行机制有所了解。
::: :::
## CoolQ HTTP API 插件 ## CQHTTP 插件
前往 [CoolQ HTTP API 插件官方文档](https://cqhttp.cc/docs/),按照其教程的「使用方法」安装插件。安装后,请先使用默认配置运行,并查看 酷Q 日志窗口的输出,以确定插件的加载、配置的生成和读取、插件版本等符合预期。 前往 [CQHTTP 插件文档](https://cqhttp.cc/docs/),按照其教程的「使用方法」安装插件。安装后,请先使用默认配置运行,并查看 酷Q 日志窗口的输出,以确定插件的加载、配置的生成和读取、插件版本等符合预期。
::: warning 注意 ::: warning 注意
请确保你安装的插件版本 >= 4.7,通常建议插件在大版本内尽量及时升级至最新版本。 请确保你安装的插件版本 >= 4.8,通常建议插件在大版本内尽量及时升级至最新版本。
::: :::

View File

@ -118,6 +118,10 @@ async def _(session: NLPSession):
在 NoneBot 中,自然语言处理器的工作方式就是将用户的自然语言消息解析成一个命令和命令所需的参数,由于自然语言消息的模糊性,在解析时不可能完全确定用户的意图,因此还需要返回一个置信度作为这个命令的确定程度。 在 NoneBot 中,自然语言处理器的工作方式就是将用户的自然语言消息解析成一个命令和命令所需的参数,由于自然语言消息的模糊性,在解析时不可能完全确定用户的意图,因此还需要返回一个置信度作为这个命令的确定程度。
::: warning 注意
这里的「置信度」与统计学中的置信度没有任何关系只表示对「当前用户输入的意图是触发某命令」这件事有多大把握应理解为普通意义的「confidence」。
:::
::: tip 提示 ::: tip 提示
置信度的计算需要自然语言处理器的编写者进行恰当的设计,以确保各插件之间的功能不会互相冲突。 置信度的计算需要自然语言处理器的编写者进行恰当的设计,以确保各插件之间的功能不会互相冲突。
::: :::

View File

@ -22,7 +22,7 @@ from nonebot import on_request, RequestSession
@on_request('group') @on_request('group')
async def _(session: RequestSession): async def _(session: RequestSession):
# 判断验证信息是否符合要求 # 判断验证信息是否符合要求
if session.ctx['comment'] == '暗号': if session.event.comment == '暗号':
# 验证信息正确,同意入群 # 验证信息正确,同意入群
await session.approve() await session.approve()
return return
@ -30,9 +30,9 @@ async def _(session: RequestSession):
await session.reject('请说暗号') await session.reject('请说暗号')
``` ```
这里首先 `on_request` 装饰器将函数注册为一个请求处理器,`group` 参数表示只处理群请求,这里各请求对应的参数值可以参考 [CoolQ HTTP API 插件的事件上报](https://cqhttp.cc/docs/#/Post?id=%E5%8A%A0%E5%A5%BD%E5%8F%8B%E8%AF%B7%E6%B1%82) 的 `request_type` 字段,目前有 `group``friend` 两种。 这里首先 `on_request` 装饰器将函数注册为一个请求处理器,`group` 参数表示只处理群请求,这里各请求对应的参数值可以参考 [CQHTTP 插件的事件上报](https://cqhttp.cc/docs/#/Post?id=%E5%8A%A0%E5%A5%BD%E5%8F%8B%E8%AF%B7%E6%B1%82) 的 `request_type` 字段,目前有 `group``friend` 两种。
接着判断 `session.ctx['comment']` 是否是正确的暗号,`comment` 字段同样可以在上面 CoolQ HTTP API 插件的事件上报文档中找到,里面包含加群或加好友时的验证信息。 接着判断 `session.event.comment` 是否是正确的暗号,这里 `session.event` 是一个 `aiocqhttp.Event` 对象,即 CQHTTP 上报来的事件的简单包装,`comment` 属性用于获取加群或加好友事件中的验证信息。
最后 `session.approve()``session.reject()` 分别用于同意和拒绝加群请求,如果都不调用,则忽略请求(其它管理员仍然可以处理请求)。 最后 `session.approve()``session.reject()` 分别用于同意和拒绝加群请求,如果都不调用,则忽略请求(其它管理员仍然可以处理请求)。
@ -52,7 +52,7 @@ async def _(session: NoticeSession):
``` ```
::: warning 注意 ::: warning 注意
这里最好预先判断一下是不是你想发送的群(通过 `session.ctx['group_id']`),否则机器人所在的任何群有新成员进入它都会欢迎。 这里最好预先判断一下是不是你想发送的群(通过 `session.event.group_id`),否则机器人所在的任何群有新成员进入它都会欢迎。
::: :::
总的来说这些 `on_*` 装饰器用起来都是差不多的,这里的 `group_increase` 表示群成员增加,其它的通知类型可以参考 [CoolQ HTTP API 插件的事件上报](https://cqhttp.cc/docs/#/Post?id=%E7%BE%A4%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0) 的 `notice_type` 总的来说这些 `on_*` 装饰器用起来都是差不多的,这里的 `group_increase` 表示群成员增加,其它的通知类型可以参考 [CQHTTP 插件的事件上报](https://cqhttp.cc/docs/#/Post?id=%E7%BE%A4%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0) 的 `notice_type`

View File

@ -1,5 +1,9 @@
# 接入图灵机器人 # 接入图灵机器人
::: danger 重要
本章内容可能已经过时,即将更新。
:::
到目前为止我们已经编写了一个相对完整的天气查询插件,包括命令和自然语言处理器,除此之外,使用同样的方法,还可以编写更多功能的插件。 到目前为止我们已经编写了一个相对完整的天气查询插件,包括命令和自然语言处理器,除此之外,使用同样的方法,还可以编写更多功能的插件。
但这样的套路存在一个问题,如果我们不是专业的 NLP 工程师,开放话题的智能聊天仍然是我们无法自己完成的事情,用户只能通过特定插件所支持的句式来使用相应的功能,当用户试图使用我们暂时没有开发的功能时,我们的机器人显得似乎有些无能为力。 但这样的套路存在一个问题,如果我们不是专业的 NLP 工程师,开放话题的智能聊天仍然是我们无法自己完成的事情,用户只能通过特定插件所支持的句式来使用相应的功能,当用户试图使用我们暂时没有开发的功能时,我们的机器人显得似乎有些无能为力。
@ -14,6 +18,10 @@
首先前往 [图灵机器人官网](http://www.tuling123.com/) 注册账号,然后在「机器人管理」页根据它的提示创建机器人,可以设置机器人名字、属性、技能、语料库等。 首先前往 [图灵机器人官网](http://www.tuling123.com/) 注册账号,然后在「机器人管理」页根据它的提示创建机器人,可以设置机器人名字、属性、技能、语料库等。
::: warning 注意
图灵机器人的免费套餐现在需要实名认证后才可使用。
:::
注册完成后先放一边,或者如果有兴趣的话,在网页上的聊天窗口和它聊几句看看效果。 注册完成后先放一边,或者如果有兴趣的话,在网页上的聊天窗口和它聊几句看看效果。
## 编写图灵机器人插件 ## 编写图灵机器人插件

View File

@ -1,32 +1,32 @@
# 发生了什么? # 发生了什么?
上一章中我们已经运行了一个最小的 NoneBot 实例,在看着 QQ 机器人回复了自己的消息的同时你可能想问这是如何实现的具体来说NoneBot、CoolQ HTTP API 插件、酷Q这三者是如何协同工作的本章将对这个问题做一个初步解答。 上一章中我们已经运行了一个最小的 NoneBot 实例,在看着 QQ 机器人回复了自己的消息的同时你可能想问这是如何实现的具体来说NoneBot、CQHTTP 插件、酷Q这三者是如何协同工作的本章将对这个问题做一个初步解答。
::: tip 提示 ::: tip 提示
如果你已经有较丰富的 QQ 机器人开发经验,尤其是使用 CoolQ HTTP API 插件的经验,可以直接跳到 [NoneBot 出场](#nonebot-出场)。 如果你已经有较丰富的 QQ 机器人开发经验,尤其是使用 CQHTTP 插件的经验,可以直接跳到 [NoneBot 出场](#nonebot-出场)。
::: :::
## 一切从 酷Q 开始 ## 一切从 酷Q 开始
我们在 [概览](./) 中提到过酷Q 扮演着「无头 QQ 客户端」的角色,一切的消息、通知、请求的发送和接收,最根本上都是由它来完成的,我们的最小 NoneBot 实例也不例外。 我们在 [概览](./README.md) 中提到过酷Q 扮演着「无头 QQ 客户端」的角色,一切的消息、通知、请求的发送和接收,最根本上都是由它来完成的,我们的最小 NoneBot 实例也不例外。
首先,我们向机器人发送的 `/echo 你好,世界` 进入腾讯的服务器,后者随后会把消息推送给 酷Q就像推送给一个真正的 QQ 客户端一样。到这里酷Q 就已经收到了我们发送的消息了。 首先,我们向机器人发送的 `/echo 你好,世界` 进入腾讯的服务器,后者随后会把消息推送给 酷Q就像推送给一个真正的 QQ 客户端一样。到这里酷Q 就已经收到了我们发送的消息了。
## 进入 CoolQ HTTP API 插件 ## 进入 CQHTTP 插件
酷Q 在收到消息之后,按优先级依次将消息转交给已启用的各插件处理,在我们的例子中,只有一个插件,就是 CoolQ HTTP API 插件。 酷Q 在收到消息之后,按优先级依次将消息转交给已启用的各插件处理,在我们的例子中,只有一个插件,就是 CQHTTP 插件。
CoolQ HTTP API 插件收到消息后会将其包装为一个统一的事件格式并对消息内容进行一个初步的处理例如编码转换、数组化、CQ 码增强等,这里的细节目前为止不需要完全明白,在需要的时候,可以去参考 CoolQ HTTP API 插件的 [文档](https://cqhttp.cc/docs/)。 CQHTTP 插件收到消息后会将其包装为一个统一的事件格式并对消息内容进行一个初步的处理例如编码转换、数组化、CQ 码增强等,这里的细节目前为止不需要完全明白,在需要的时候,可以去参考 CQHTTP 插件的 [文档](https://cqhttp.cc/docs/)。
接着,插件把包装好的事件转换成 JSON 格式,并通过「反向 WebSocket」发送给 NoneBot。这里的「反向 WebSocket」连接的就是我们在 CoolQ HTTP API 插件的配置中指定的 `ws_reverse_url`,即 NoneBot 监听的 WebSocket 入口。 接着,插件把包装好的事件转换成 JSON 格式,并通过「反向 WebSocket」发送给 NoneBot。这里的「反向 WebSocket」连接的就是我们在 CQHTTP 插件的配置中指定的 `ws_reverse_url`,即 NoneBot 监听的 WebSocket 入口。
::: tip 提示 ::: tip 提示
「反向 WebSocket」是 CoolQ HTTP API 插件的一种通信方式,表示插件作为客户端,主动去连接配置文件中指定的 `ws_reverse_url`。除此之外还有 HTTP、正向WebSocket 等方式。 「反向 WebSocket」是 CQHTTP 插件的一种通信方式,表示插件作为客户端,主动去连接配置文件中指定的 `ws_reverse_url`。除此之外还有 HTTP、正向WebSocket 等方式。除了反向 WebSocketNoneBot 也支持通过 HTTP 与 CQHTTP 通信。
::: :::
## NoneBot 出场 ## NoneBot 出场
CoolQ HTTP API 插件通过反向 WebSocket 将消息事件发送到 NoneBot 后NoneBot 就开始了它的处理流程。 CQHTTP 插件通过反向 WebSocket 将消息事件发送到 NoneBot 后NoneBot 就开始了它的处理流程。
### 初步处理 ### 初步处理
@ -53,7 +53,7 @@ if __name__ == '__main__':
第 4 行的 `nonebot.init()` 首先初始化 `nonebot` 包,这是无论如何都需要写的一行代码,并且必须在使用 NoneBot 的任何功能之前调用。 第 4 行的 `nonebot.init()` 首先初始化 `nonebot` 包,这是无论如何都需要写的一行代码,并且必须在使用 NoneBot 的任何功能之前调用。
随后,`nonebot.load_builtin_plugins()` 加载了 NoneBot 的内置插件,这一步不是必须的,尤其在你编写了自己的插件之后,可能不再需要内置插件。 随后,`nonebot.load_builtin_plugins()` 加载了 NoneBot 的内置插件,这一步不是必须的,尤其在你编写了自己的插件之后,可能不再需要内置插件。
NoneBot 的内置插件只包含了两个命令,`echo` 和 `say`,两者的功能都是重复发送者的话,区别在于,`echo` 命令任何人都可以调用(不限制权限),但只能原样重复消息,不能手动指定要发送的 CQ 码,`say` 命令只有超级用户(通常是你自己,需要在配置中指定,下一章会介绍)可以调用,可以在消息中指定要发送的 CQ 码,如下图: NoneBot 的内置插件只包含了两个命令,`echo` 和 `say`,两者的功能都是重复发送者的话,区别在于,`echo` 命令任何人都可以调用(不限制权限),但只能原样重复消息,不能手动指定要发送的 CQ 码,`say` 命令只有超级用户(通常是你自己,需要在配置中指定,下一章会介绍)可以调用,可以在消息中指定要发送的 CQ 码,如下图:
@ -61,7 +61,7 @@ NoneBot 的内置插件只包含了两个命令,`echo` 和 `say`,两者的
<img alt="Echo and Say" src="./assets/echo_and_say.png" /> <img alt="Echo and Say" src="./assets/echo_and_say.png" />
</p> </p>
最后,`nonebot.run(host='127.0.0.1', port=8080)` 让 NoneBot 跑在了地址 `127.0.0.1:8080` 上,向 CoolQ HTTP API 插件提供 `/`、`/ws/`、`/ws/event/`、`/ws/api/` 四个入口,在我们的反向 WebSocket 配置中,插件利用了第二个入口 最后,`nonebot.run(host='127.0.0.1', port=8080)` 让 NoneBot 跑在了地址 `127.0.0.1:8080` 地址上,向 CQHTTP 插件提供 `/`、`/ws/` 等入口,在我们的反向 WebSocket 配置中,插件连接了 `/ws/`
### 命令处理器 ### 命令处理器
@ -77,12 +77,12 @@ async def echo(session: CommandSession):
你现在不用关心它是如何从 Session 中拿到参数的,只需看到,命令处理器中实际内容只有一行 `session.send()` 函数调用,这个调用会直接把参数中的消息内容原样发送。 你现在不用关心它是如何从 Session 中拿到参数的,只需看到,命令处理器中实际内容只有一行 `session.send()` 函数调用,这个调用会直接把参数中的消息内容原样发送。
## 再次进入 CoolQ HTTP API 插件 ## 再次进入 CQHTTP 插件
命令处理器在调用 `session.send()` 之后NoneBot 把消息内容发送给了 CoolQ HTTP API 插件那边已连接的反向 WebSocket 客户端同时告诉它要把消息发送到和收到消息相同的地方即接收到消息所在的群组、讨论组或私聊。CoolQ HTTP API 插件明白了 NoneBot 的要求之后,会对消息做一些必要的处理,然后按照指示调用 酷Q 提供的相应接口。 命令处理器在调用 `session.send()` 之后NoneBot 把消息内容发送给了 CQHTTP 插件那边已连接的反向 WebSocket 客户端同时告诉它要把消息发送到和收到消息相同的地方即接收到消息所在的群组、讨论组或私聊。CQHTTP 插件明白了 NoneBot 的要求之后,会对消息做一些必要的处理,然后按照指示调用 酷Q 提供的相应接口。
## 一切又在 酷Q 结束 ## 一切又在 酷Q 结束
酷Q 收到 CoolQ HTTP API 插件的接口调用之后,将消息内容发送给腾讯的服务器,就像一个真正的 QQ 客户端一样,于是你就收到了 QQ 机器人发来的消息了。 酷Q 收到 CQHTTP 插件的接口调用之后,将消息内容发送给腾讯的服务器,就像一个真正的 QQ 客户端一样,于是你就收到了 QQ 机器人发来的消息了。
至此,我们已经理清楚了第一次对话中每一步到底都发生了些什么,以及 NoneBot 如何解析消息并调用到相应的命令处理器来进行回复。下面的几章中我们将一步一步地对最小 NoneBot 实例进行扩充,以实现一些非常棒的功能! 至此,我们已经理清楚了第一次对话中每一步到底都发生了些什么,以及 NoneBot 如何解析消息并调用到相应的命令处理器来进行回复。下面的几章中我们将一步一步地对最小 NoneBot 实例进行扩充,以实现一些非常棒的功能!

View File

@ -2,6 +2,4 @@
在阅读完前面的入门指南之后,你已经具备了实现具有复杂功能的 QQ 机器人的基本知识,可以开始编写完整的作品了。 在阅读完前面的入门指南之后,你已经具备了实现具有复杂功能的 QQ 机器人的基本知识,可以开始编写完整的作品了。
然而NoneBot 并不止步于此。在使用 NoneBot 编写功能时你可能会时常遇到一些绝佳的想法但这些想法在已有的基本知识的基础上无法实现。幸运的是NoneBot 已经预先为大多数这样的使用场景提供了相应的接口,以帮助你实现想要的逻辑。 在实际编写代码时,可能需要参考 [CQHTTP 文档](https://cqhttp.cc/docs/) 和 [aiocqhttp 文档](https://python-aiocqhttp.cqp.moe/);对于一些高级主题,可以参考本文档 [进阶](../advanced/README.md) 部分;另外,也可以参考 [cczu-osa/aki](https://github.com/cczu-osa/aki) 中的一些实践,比如模块划分、数据库访问等。
NoneBot 的这部分用法我们称之为进阶用法,关于进阶用法的介绍,见 [进阶](../advanced/)。通常,你不需要在初次使用时就掌握进阶用法,而是建议在实际编程中发现有需要时再去查阅。

View File

@ -1,6 +1,6 @@
{ {
"scripts": { "scripts": {
"docs:dev": "vuepress dev -h 0.0.0.0 -p 9090 --debug docs", "docs:dev": "vuepress dev -h 127.0.0.1 -p 8888 --debug docs",
"docs:build": "vuepress build docs" "docs:build": "vuepress build docs"
}, },
"devDependencies": { "devDependencies": {