mirror of
https://github.com/nonebot/nonebot2.git
synced 2025-02-19 00:59:11 +08:00
Add docs for writing "usage" command
This commit is contained in:
parent
f8ec3ace43
commit
9d138a0595
@ -48,6 +48,7 @@ module.exports = {
|
||||
'notice-and-request',
|
||||
'calling-cqhttp-api',
|
||||
'scheduler',
|
||||
'usage',
|
||||
'whats-next',
|
||||
]
|
||||
}
|
||||
|
21
docs/guide/code/awesome-bot-7/awesome/plugins/group_admin.py
Normal file
21
docs/guide/code/awesome-bot-7/awesome/plugins/group_admin.py
Normal file
@ -0,0 +1,21 @@
|
||||
from nonebot import on_request, RequestSession
|
||||
from nonebot import on_notice, NoticeSession
|
||||
|
||||
|
||||
# 将函数注册为群请求处理器
|
||||
@on_request('group')
|
||||
async def _(session: RequestSession):
|
||||
# 判断验证信息是否符合要求
|
||||
if session.ctx['comment'] == '暗号':
|
||||
# 验证信息正确,同意入群
|
||||
await session.approve()
|
||||
return
|
||||
# 验证信息错误,拒绝入群
|
||||
await session.reject('请说暗号')
|
||||
|
||||
|
||||
# 将函数注册为群成员增加通知处理器
|
||||
@on_notice('group_increase')
|
||||
async def _(session: NoticeSession):
|
||||
# 发送欢迎消息
|
||||
await session.send('欢迎新朋友~')
|
16
docs/guide/code/awesome-bot-7/awesome/plugins/scheduler.py
Normal file
16
docs/guide/code/awesome-bot-7/awesome/plugins/scheduler.py
Normal file
@ -0,0 +1,16 @@
|
||||
from datetime import datetime
|
||||
|
||||
import nonebot
|
||||
import pytz
|
||||
from aiocqhttp.exceptions import Error as CQHttpError
|
||||
|
||||
|
||||
@nonebot.scheduler.scheduled_job('cron', hour='*')
|
||||
async def _():
|
||||
bot = nonebot.get_bot()
|
||||
now = datetime.now(pytz.timezone('Asia/Shanghai'))
|
||||
try:
|
||||
await bot.send_group_msg(group_id=672076603,
|
||||
message=f'现在{now.hour}点整啦!')
|
||||
except CQHttpError:
|
||||
pass
|
93
docs/guide/code/awesome-bot-7/awesome/plugins/tuling.py
Normal file
93
docs/guide/code/awesome-bot-7/awesome/plugins/tuling.py
Normal file
@ -0,0 +1,93 @@
|
||||
import json
|
||||
from typing import Optional
|
||||
|
||||
import aiohttp
|
||||
from aiocqhttp.message import escape
|
||||
from nonebot import on_command, CommandSession
|
||||
from nonebot import on_natural_language, NLPSession, NLPResult
|
||||
from nonebot.helpers import context_id, render_expression
|
||||
|
||||
__plugin_name__ = '智能聊天'
|
||||
__plugin_usage__ = r"""
|
||||
智能聊天
|
||||
|
||||
直接跟我聊天即可~
|
||||
""".strip()
|
||||
|
||||
# 定义无法获取图灵回复时的「表达(Expression)」
|
||||
EXPR_DONT_UNDERSTAND = (
|
||||
'我现在还不太明白你在说什么呢,但没关系,以后的我会变得更强呢!',
|
||||
'我有点看不懂你的意思呀,可以跟我聊些简单的话题嘛',
|
||||
'其实我不太明白你的意思……',
|
||||
'抱歉哦,我现在的能力还不能够明白你在说什么,但我会加油的~'
|
||||
)
|
||||
|
||||
|
||||
# 注册一个仅内部使用的命令,不需要 aliases
|
||||
@on_command('tuling')
|
||||
async def tuling(session: CommandSession):
|
||||
# 获取可选参数,这里如果没有 message 参数,命令不会被中断,message 变量会是 None
|
||||
message = session.get_optional('message')
|
||||
|
||||
# 通过封装的函数获取图灵机器人的回复
|
||||
reply = await call_tuling_api(session, message)
|
||||
if reply:
|
||||
# 如果调用图灵机器人成功,得到了回复,则转义之后发送给用户
|
||||
# 转义会把消息中的某些特殊字符做转换,以避免 酷Q 将它们理解为 CQ 码
|
||||
await session.send(escape(reply))
|
||||
else:
|
||||
# 如果调用失败,或者它返回的内容我们目前处理不了,发送无法获取图灵回复时的「表达」
|
||||
# 这里的 render_expression() 函数会将一个「表达」渲染成一个字符串消息
|
||||
await session.send(render_expression(EXPR_DONT_UNDERSTAND))
|
||||
|
||||
|
||||
@on_natural_language
|
||||
async def _(session: NLPSession):
|
||||
# 以置信度 60.0 返回 tuling 命令
|
||||
# 确保任何消息都在且仅在其它自然语言处理器无法理解的时候使用 tuling 命令
|
||||
return NLPResult(60.0, 'tuling', {'message': session.msg_text})
|
||||
|
||||
|
||||
async def call_tuling_api(session: CommandSession, text: str) -> Optional[str]:
|
||||
# 调用图灵机器人的 API 获取回复
|
||||
|
||||
if not text:
|
||||
return None
|
||||
|
||||
url = 'http://openapi.tuling123.com/openapi/api/v2'
|
||||
|
||||
# 构造请求数据
|
||||
payload = {
|
||||
'reqType': 0,
|
||||
'perception': {
|
||||
'inputText': {
|
||||
'text': text
|
||||
}
|
||||
},
|
||||
'userInfo': {
|
||||
'apiKey': session.bot.config.TULING_API_KEY,
|
||||
'userId': context_id(session.ctx, use_hash=True)
|
||||
}
|
||||
}
|
||||
|
||||
group_unique_id = context_id(session.ctx, mode='group', use_hash=True)
|
||||
if group_unique_id:
|
||||
payload['userInfo']['groupId'] = group_unique_id
|
||||
|
||||
try:
|
||||
# 使用 aiohttp 库发送最终的请求
|
||||
async with aiohttp.ClientSession() as sess:
|
||||
async with sess.post(url, json=payload) as response:
|
||||
if response.status != 200:
|
||||
# 如果 HTTP 响应状态码不是 200,说明调用失败
|
||||
return None
|
||||
|
||||
resp_payload = json.loads(await response.text())
|
||||
if resp_payload['results']:
|
||||
for result in resp_payload['results']:
|
||||
if result['resultType'] == 'text':
|
||||
# 返回文本类型的回复
|
||||
return result['values']['text']
|
||||
except (aiohttp.ClientError, json.JSONDecodeError, KeyError):
|
||||
# 抛出上面任何异常,说明调用失败
|
||||
return None
|
20
docs/guide/code/awesome-bot-7/awesome/plugins/usage.py
Normal file
20
docs/guide/code/awesome-bot-7/awesome/plugins/usage.py
Normal file
@ -0,0 +1,20 @@
|
||||
import nonebot
|
||||
from nonebot import on_command, CommandSession
|
||||
|
||||
|
||||
@on_command('usage', aliases=['使用帮助', '帮助', '使用方法'])
|
||||
async def _(session: CommandSession):
|
||||
# 获取设置了名称的插件列表
|
||||
plugins = list(filter(lambda p: p.name, nonebot.get_loaded_plugins()))
|
||||
|
||||
arg = session.current_arg_text.strip().lower()
|
||||
if not arg:
|
||||
# 如果用户没有发送参数,则发送功能列表
|
||||
await session.send(
|
||||
'我现在支持的功能有:\n\n' + '\n'.join(p.name for p in plugins))
|
||||
return
|
||||
|
||||
# 如果发了参数则发送相应命令的使用帮助
|
||||
for p in plugins:
|
||||
if p.name.lower() == arg:
|
||||
await session.send(p.usage)
|
@ -0,0 +1,50 @@
|
||||
from nonebot import on_command, CommandSession
|
||||
from nonebot import on_natural_language, NLPSession, NLPResult
|
||||
from jieba import posseg
|
||||
|
||||
from .data_source import get_weather_of_city
|
||||
|
||||
__plugin_name__ = '天气'
|
||||
__plugin_usage__ = r"""
|
||||
天气查询
|
||||
|
||||
天气 [城市名称]
|
||||
"""
|
||||
|
||||
|
||||
@on_command('weather', aliases=('天气', '天气预报', '查天气'))
|
||||
async def weather(session: CommandSession):
|
||||
city = session.get('city', prompt='你想查询哪个城市的天气呢?')
|
||||
weather_report = await get_weather_of_city(city)
|
||||
await session.send(weather_report)
|
||||
|
||||
|
||||
@weather.args_parser
|
||||
async def _(session: CommandSession):
|
||||
stripped_arg = session.current_arg_text.strip()
|
||||
if session.current_key:
|
||||
session.args[session.current_key] = stripped_arg
|
||||
elif stripped_arg:
|
||||
session.args['city'] = stripped_arg
|
||||
|
||||
|
||||
# on_natural_language 装饰器将函数声明为一个自然语言处理器
|
||||
# keywords 表示需要响应的关键词,类型为任意可迭代对象,元素类型为 str
|
||||
# 如果不传入 keywords,则响应所有没有被当作命令处理的消息
|
||||
@on_natural_language(keywords=('天气',))
|
||||
async def _(session: NLPSession):
|
||||
# 去掉消息首尾的空白符
|
||||
stripped_msg_text = session.msg_text.strip()
|
||||
# 对消息进行分词和词性标注
|
||||
words = posseg.lcut(stripped_msg_text)
|
||||
|
||||
city = None
|
||||
# 遍历 posseg.lcut 返回的列表
|
||||
for word in words:
|
||||
# 每个元素是一个 pair 对象,包含 word 和 flag 两个属性,分别表示词和词性
|
||||
if word.flag == 'ns':
|
||||
# ns 词性表示地名
|
||||
city = word.word
|
||||
|
||||
# 返回处理结果,三个参数分别为置信度、命令名、命令会话的参数
|
||||
return NLPResult(90.0, 'weather', {'city': city})
|
@ -0,0 +1,2 @@
|
||||
async def get_weather_of_city(city: str) -> str:
|
||||
return f'{city}的天气是……'
|
11
docs/guide/code/awesome-bot-7/bot.py
Normal file
11
docs/guide/code/awesome-bot-7/bot.py
Normal file
@ -0,0 +1,11 @@
|
||||
from os import path
|
||||
|
||||
import nonebot
|
||||
|
||||
import config
|
||||
|
||||
if __name__ == '__main__':
|
||||
nonebot.init(config)
|
||||
nonebot.load_plugins(path.join(path.dirname(__file__), 'awesome', 'plugins'),
|
||||
'awesome.plugins')
|
||||
nonebot.run()
|
10
docs/guide/code/awesome-bot-7/config.py
Normal file
10
docs/guide/code/awesome-bot-7/config.py
Normal file
@ -0,0 +1,10 @@
|
||||
from nonebot.default_config import *
|
||||
|
||||
HOST = '0.0.0.0'
|
||||
PORT = 8080
|
||||
|
||||
SUPERUSERS = {12345678}
|
||||
COMMAND_START.add('')
|
||||
NICKNAME = {'小明', '明明'}
|
||||
|
||||
TULING_API_KEY = ''
|
4
docs/guide/code/awesome-bot-7/requirements.txt
Normal file
4
docs/guide/code/awesome-bot-7/requirements.txt
Normal file
@ -0,0 +1,4 @@
|
||||
nonebot>=1.0.0
|
||||
jieba
|
||||
aiohttp
|
||||
pytz
|
@ -13,7 +13,7 @@
|
||||
使用下面命令安装可选功能(会自动安装 APScheduler):
|
||||
|
||||
```bash
|
||||
pip install nonebot[scheduler]
|
||||
pip install "nonebot[scheduler]"
|
||||
```
|
||||
|
||||
安装成功之后就可以通过 `nonebot.scheduler` 访问 [`AsyncIOScheduler`](https://apscheduler.readthedocs.io/en/latest/modules/schedulers/asyncio.html#apscheduler.schedulers.asyncio.AsyncIOScheduler) 对象。
|
||||
|
76
docs/guide/usage.md
Normal file
76
docs/guide/usage.md
Normal file
@ -0,0 +1,76 @@
|
||||
# 编写使用帮助
|
||||
|
||||
经过前面的部分,我们已经给机器人编写了天气查询和图灵聊天插件,当然,你可能已经另外编写了更多具有个性化功能的插件。
|
||||
|
||||
现在,为了让用户能够更方便的使用,是时候编写一个使用帮助了。
|
||||
|
||||
::: tip 提示
|
||||
本章的完整代码可以在 [awesome-bot-7](https://github.com/richardchien/nonebot/tree/master/docs/guide/code/awesome-bot-7) 查看。
|
||||
:::
|
||||
|
||||
## 给插件添加名称和用法
|
||||
|
||||
这里以天气查询和图灵聊天两个插件为例,分别在 `awesome/plugins/weather/__init__.py` 和 `awesome/plugins/tuling.py` 两个文件的开头,通过 `__plugin_name__` 和 `__plugin_usage__` 两个特殊变量设置插件的名称和使用方法,如下:
|
||||
|
||||
```python
|
||||
# awesome/plugins/weather/__init__.py
|
||||
|
||||
# ... 各种 import
|
||||
|
||||
__plugin_name__ = '天气'
|
||||
__plugin_usage__ = r"""
|
||||
天气查询
|
||||
|
||||
天气 [城市名称]
|
||||
"""
|
||||
```
|
||||
|
||||
```python
|
||||
# awesome/plugins/tuling.py
|
||||
|
||||
# ... 各种 import
|
||||
|
||||
__plugin_name__ = '智能聊天'
|
||||
__plugin_usage__ = r"""
|
||||
智能聊天
|
||||
|
||||
直接跟我聊天即可~
|
||||
""".strip()
|
||||
```
|
||||
|
||||
一旦使用 `__plugin_name__` 和 `__plugin_usage__` 特殊变量设置了插件的名称和使用方法,NoneBot 在加载插件时就能够读取到这些内容,并存放在已加载插件的数据结构中。
|
||||
|
||||
## 编写使用帮助命令
|
||||
|
||||
新建插件 `awesome/plugins/usage.py`,编写内容如下:
|
||||
|
||||
```python {8,13-14,20}
|
||||
import nonebot
|
||||
from nonebot import on_command, CommandSession
|
||||
|
||||
|
||||
@on_command('usage', aliases=['使用帮助', '帮助', '使用方法'])
|
||||
async def _(session: CommandSession):
|
||||
# 获取设置了名称的插件列表
|
||||
plugins = list(filter(lambda p: p.name, nonebot.get_loaded_plugins()))
|
||||
|
||||
arg = session.current_arg_text.strip().lower()
|
||||
if not arg:
|
||||
# 如果用户没有发送参数,则发送功能列表
|
||||
await session.send(
|
||||
'我现在支持的功能有:\n\n' + '\n'.join(p.name for p in plugins))
|
||||
return
|
||||
|
||||
# 如果发了参数则发送相应命令的使用帮助
|
||||
for p in plugins:
|
||||
if p.name.lower() == arg:
|
||||
await session.send(p.usage)
|
||||
```
|
||||
|
||||
这里高亮的内容是重点:
|
||||
|
||||
- `nonebot.get_loaded_plugins()` 函数用于获取所有已经加载的插件,**注意,由于可能存在插件没有设置 `__plugin_name__` 变量的情况,插件的名称有可能为空**,因此建议过滤一下
|
||||
- 插件的 `name` 属性(`plugin.name`)用于获得插件模块的 `__plugin_name__` 特殊变量的值
|
||||
- 插件的 `usage` 属性(`plugin.usage`)用于获得插件模块的 `__plugin_usage__` 特殊变量的值
|
||||
|
||||
到这里,使用帮助命令就已经编写完成了。如果愿意,可以继续按照自己的思路实现相对应的自然语言处理器,以优化使用体验。
|
Loading…
x
Reference in New Issue
Block a user