mirror of
https://github.com/suyiiyii/nonebot-bison.git
synced 2026-05-09 18:27:56 +08:00
📝 文档迁移到 vuepress hope 主题 (#490)
* ⬆️ Bump the docs-update group with 3 updates Bumps the docs-update group with 3 updates: [@vuepress/client](https://github.com/vuepress/core), [vue](https://github.com/vuejs/core) and [vuepress](https://github.com/vuejs/vuepress/tree/HEAD/packages/vuepress). Updates `@vuepress/client` from 2.0.0-rc.0 to 2.0.0-rc.2 - [Release notes](https://github.com/vuepress/core/releases) - [Changelog](https://github.com/vuepress/core/blob/main/CHANGELOG.md) - [Commits](https://github.com/vuepress/core/compare/v2.0.0-rc.0...v2.0.0-rc.2) Updates `vue` from 3.4.3 to 3.4.21 - [Release notes](https://github.com/vuejs/core/releases) - [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md) - [Commits](https://github.com/vuejs/core/compare/v3.4.3...v3.4.21) Updates `vuepress` from 2.0.0-rc.0 to 2.0.0-rc.8 - [Release notes](https://github.com/vuejs/vuepress/releases) - [Changelog](https://github.com/vuejs/vuepress/blob/master/CHANGELOG.md) - [Commits](https://github.com/vuejs/vuepress/commits/HEAD/packages/vuepress) --- updated-dependencies: - dependency-name: "@vuepress/client" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: docs-update - dependency-name: vue dependency-type: direct:development update-type: version-update:semver-patch dependency-group: docs-update - dependency-name: vuepress dependency-type: direct:development update-type: version-update:semver-patch dependency-group: docs-update ... Signed-off-by: dependabot[bot] <support@github.com> * 💄 auto fix by pre-commit hooks * 📝 使用 vuepress hope 主题 * 📝 更新文档中的过时内容 --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Azide <rukuy@qq.com>
This commit is contained in:
+179
-51
@@ -1,26 +1,47 @@
|
||||
---
|
||||
sidebar: auto
|
||||
---
|
||||
|
||||
# 基本开发须知
|
||||
|
||||
## 语言以及工具
|
||||
|
||||
1. 本项目使用了`python3.9`的特性进行开发,所以请确保你的 Python 版本>=3.9
|
||||
1. 本项目使用了`python3.10`的特性进行开发,所以请确保你的 Python 版本>=3.10
|
||||
2. 本项目使用 poetry 进行依赖管理,请确保开发之前已经进行过`poetry install`,运行时在`poetry shell`的环境中进行运行
|
||||
3. 本项目使用的 node 项目管理工具是 yarn
|
||||
3. 本项目使用的 node 项目管理工具是 pnpm
|
||||
|
||||
::: tip 参考
|
||||
可以参考[安装 - 直接运行](../usage/install.md#直接运行)中的内容
|
||||
:::
|
||||
|
||||
## 前端
|
||||
|
||||
本项目使用了前端,如果单独 clone 仓库本身,里面是**不包含**编译过的前端的,请使用`yarn && yarn build`进行前端的构建。
|
||||
如果想要开发前端,推荐在`.env.dev`中加入`BISON_OUTER_URL="http://localhost:3000/bison/"`,然后分别运行 bot 和`yarn dev`
|
||||
本项目使用了前端,如果单独 clone 仓库本身,里面是**不包含**编译过的前端的,请使用`pnpm i && pnpm build`进行前端的构建。
|
||||
|
||||
如果想要开发前端,推荐的步骤是:
|
||||
|
||||
1. 在`.env.dev`中添加`BISON_OUTER_URL`配置项
|
||||
|
||||
```env
|
||||
BISON_OUTER_URL="http://localhost:3000/bison/"`
|
||||
```
|
||||
|
||||
2. 运行 bot
|
||||
|
||||
```bash
|
||||
poetry run nb run
|
||||
```
|
||||
|
||||
3. 运行前端:
|
||||
|
||||
```bash
|
||||
cd admin_fronted
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
::: warning
|
||||
请在开发前端的时候删除项目根目录中的`node_modules`,否则编译和运行的时候可能会出现奇怪的问题。
|
||||
请在开发前端的时候删除项目**根目录**中的`node_modules`,否则编译和运行的时候可能会出现奇怪的问题。
|
||||
:::
|
||||
|
||||
## 文档
|
||||
|
||||
文档的相关部分在`docs`目录中,可以在项目根目录执行`yarn docs:dev`预览文件更改效果。
|
||||
文档的相关部分在`docs`目录中,可以在项目根目录执行`pnpm docs:dev`预览文件更改效果。
|
||||
|
||||
## 代码格式
|
||||
|
||||
@@ -39,13 +60,13 @@ Nonebot 项目使用了全异步的处理方式,所以你需要对异步,Pyt
|
||||
## 基本概念
|
||||
|
||||
- `nonebot_bison.post`: 可以理解为推送内容,其中包含需要发送的文字,图片,链接,平台信息等,分为:
|
||||
- `nonebot_bison.post.Post`: 简单的推送内容格式,需要发送的内容由 bison 处理
|
||||
- `nonebot_bison.post.CustomPost`: 基于 markdown 语法的,自由度较高的推送内容格式
|
||||
- `nonebot_bison.post.Post`: 推送内容格式,传入需要发送的内容由 Theme 模块处理
|
||||
- 详细的介绍可参见[生成 bison 的推送文本](#生成-bison-的推送文本)
|
||||
- `nonebot_bison.types.RawPost`: 从站点/平台中爬到的单条信息
|
||||
- `nonebot_bison.types.Target`: 目标账号,Bilibili,微博等社交媒体中的账号
|
||||
- `nonebot_bison.types.Category`: 信息分类,例如视频,动态,图文,文章等
|
||||
- `nonebot_bison.types.Tag`: 信息标签,例如微博中的超话或者 hashtag
|
||||
- `nonebot_bison.theme.Theme`: 用于渲染`nonebot_bison.post.Post`的模块,可以理解为一个模板引擎,生成可发送的消息
|
||||
|
||||
## 快速上手
|
||||
|
||||
@@ -74,8 +95,8 @@ Nonebot 项目使用了全异步的处理方式,所以你需要对异步,Pyt
|
||||
|
||||
## 实现方法
|
||||
|
||||
现在你需要在`nonebot_bison/platform`下新建一个 py 文件,
|
||||
在里面新建一个类,继承推送类型的基类,重载一些关键的函数,然后……就完成了,不需要修改别的东西了。
|
||||
现在你需要在`nonebot_bison/platform`下新建一个 `.py` 文件,
|
||||
在里面新建一个类,继承推送类型的基类,重载一些关键的函数,然后……就完成了~(??)~,不需要修改别的东西了。
|
||||
|
||||
### 不同类型 Platform 的实现适配以及逻辑
|
||||
|
||||
@@ -94,7 +115,7 @@ Nonebot 项目使用了全异步的处理方式,所以你需要对异步,Pyt
|
||||
4. 调用`parse`生成正式推文
|
||||
:::
|
||||
|
||||
参考[nonebot_bison.platform.Weibo](https://github.com/felinae98/nonebot-bison/blob/v0.5.3/src/plugins/nonebot_bison/platform/weibo.py)
|
||||
参考[nonebot_bison.platform.Weibo](https://github.com/MountainDash/nonebot-bison/blob/v0.9.1/nonebot_bison/platform/weibo.py)
|
||||
|
||||
- `nonebot_bison.platform.platform.StatusChange`
|
||||
需要实现:
|
||||
@@ -109,7 +130,7 @@ Nonebot 项目使用了全异步的处理方式,所以你需要对异步,Pyt
|
||||
3. 通过则进入`parser`生成 Post
|
||||
:::
|
||||
|
||||
参考[nonenot_bison.platform.AkVersion](https://github.com/felinae98/nonebot-bison/blob/v0.5.3/src/plugins/nonebot_bison/platform/arknights.py#L86)
|
||||
参考[nonenot_bison.platform.AkVersion](https://github.com/MountainDash/nonebot-bison/blob/v0.9.1/nonebot_bison/platform/arknights.py#L122)
|
||||
|
||||
- `nonebot_bison.platform.platform.SimplePost`
|
||||
需要实现:
|
||||
@@ -139,11 +160,13 @@ Nonebot 项目使用了全异步的处理方式,所以你需要对异步,Pyt
|
||||
- `enable_tag` 平台发布内容是否带 Tag,例如微博
|
||||
- `platform_name` 唯一的,英文的识别标识,比如`weibo`
|
||||
- `async get_target_name(Target) -> Optional[str]` 通常用于获取帐号的名称,如果平台没有帐号概念,可以直接返回平台的`name`
|
||||
- `get_tags(RawPost) -> Optional[Collection[Tag]]` (可选) 从 RawPost 中提取 Tag
|
||||
- `get_tags(RawPost) -> Optional[Collection[Tag]]` (可选)从 RawPost 中提取 Tag
|
||||
- `get_category(RawPos) -> Optional[Category]` (可选)从 RawPost 中提取 Category
|
||||
- `async parse(RawPost) -> Post` 将获取到的 RawPost 处理成 Post
|
||||
- `async parse_target(str) -> Target` (可选)定制化处理传入用户输入的 Target 字符串,返回 Target(一般是把用户的主页链接解析为 Target),如果输入本身就是 Target,则直接返回 Target
|
||||
- `parse_target_promot` (可选)在要求用户输入 Target 的时候显示的提示文字
|
||||
- `default_theme` (可选)默认的渲染主题,如果用户没有指定渲染主题,则优先使用这个主题进行渲染,不显式覆盖则为`basic`
|
||||
- `use_batch` (可选)是否使用批量获取,如果使用批量获取,那么会调用`batch_get_sub_list`,否则调用`get_sub_list`
|
||||
|
||||
### 特有的方法/成员
|
||||
|
||||
@@ -152,6 +175,8 @@ Nonebot 项目使用了全异步的处理方式,所以你需要对异步,Pyt
|
||||
`get_sub_list(Target) -> list[RawPost]` 用于获取对应 Target 的 RawPost 列表,与上一次`get_sub_list`获取的列表比较,过滤出新的 RawPost
|
||||
- 对于`nonebot_bison.platform.platform.SimplePost`
|
||||
`get_sub_list` 用于获取对应 Target 的 RawPost 列表,但不会与上次获取的结果进行比较,而是直接进行发送
|
||||
- `async def batch_get_sub_list(list[Target]) -> list[list[RawPost]]` (可选)输入一个`Target`的 list,输出一个`RawPost`的 list 的 list,用于批量获取 RawPost
|
||||
- 其他类似`get_sub_list`,但是可以一次性获取多个 Target 的 RawPost
|
||||
- `get_id(RawPost) -> Any` 输入一个`RawPost`,从`RawPost`中获取一个唯一的 ID,这个 ID 会用来判断这条`RawPost`是不是之前收到过
|
||||
- `get_date(RawPost) -> Optional[int]` 输入一个`RawPost`,如果可以从`RawPost`中提取出发文的时间,返回发文时间的 timestamp,否则返回`None`
|
||||
- `async get_status(Target) -> Any`
|
||||
@@ -167,7 +192,7 @@ Nonebot 项目使用了全异步的处理方式,所以你需要对异步,Pyt
|
||||
|
||||
你可以参照`tests/platforms/test_*.py`中的内容对单元测试进行编写。
|
||||
|
||||
为保证多次运行测试的一致性,可以 mock http 的响应,测试的内容应包括[获取 RawPost](https://github.com/felinae98/nonebot-bison/blob/v0.5.3/tests/platforms/test_weibo.py#L59),处理成 Post
|
||||
为保证多次运行测试的一致性,可以 mock http 的响应,测试的内容应包括[获取 RawPost](https://github.com/MountainDash/nonebot-bison/blob/v0.9.1/tests/platforms/test_weibo.py#L43),处理成 Post
|
||||
,测试分类以及提取 tag 等,当然最好和 rsshub 做一个交叉验证。
|
||||
|
||||
## 一些例子
|
||||
@@ -193,25 +218,25 @@ class Weibo(NewMessage):
|
||||
has_target = True
|
||||
|
||||
async def get_target_name(self, target: Target) -> Optional[str]:
|
||||
#获取Target对应的用户名
|
||||
#获取 Target 对应的用户名
|
||||
...
|
||||
async def get_sub_list(self, target: Target) -> list[RawPost]:
|
||||
#获取对应Target的RawPost列表,会与上一次get_sub_list获取的列表比较,过滤出新的RawPost
|
||||
#获取对应 Target 的 RawPost 列表,会与上一次 get_sub_list 获取的列表比较,过滤出新的 RawPost
|
||||
...
|
||||
def get_id(self, post: RawPost) -> Any:
|
||||
#获取可以标识每个Rawpost的,不与之前RawPost重复的id,用于过滤出新的RawPost
|
||||
#获取可以标识每个 Rawpost 的,不与之前 RawPost 重复的 id,用于过滤出新的 RawPost
|
||||
...
|
||||
def get_date(self, raw_post: RawPost) -> float:
|
||||
#获取RawPost的发布时间,若bot过滤出的新RawPost发布时间与当前时间差超过2小时,该RawPost将被忽略,可以返回None
|
||||
#获取 RawPost 的发布时间,若 bot 过滤出的新 RawPost 发布时间与当前时间差超过 2 小时,该 RawPost 将被忽略,可以返回 None
|
||||
...
|
||||
def get_tags(self, raw_post: RawPost) -> Optional[list[Tag]]:
|
||||
#获取RawPost中包含的微博话题(#xxx#中的内容)
|
||||
...
|
||||
def get_category(self, raw_post: RawPost) -> Category:
|
||||
#获取该RawPost在该类定义categories的具体分类(转发?视频?图文?...?)
|
||||
#获取该 RawPost 在该类定义 categories 的具体分类 (转发?视频?图文?...?)
|
||||
...
|
||||
async def parse(self, raw_post: RawPost) -> Post:
|
||||
#将需要bot推送的RawPost处理成正式推送的Post
|
||||
#将需要 bot 推送的 RawPost 处理成正式推送的 Post
|
||||
...
|
||||
```
|
||||
|
||||
@@ -219,41 +244,144 @@ class Weibo(NewMessage):
|
||||
|
||||
### 什么是`nonebot_bison.post`
|
||||
|
||||
可以认为`nonebot_bison.post`是最终要交付给 bison 推送到群内的内容,经过`parse`函数处理过后的报文应该返回属于`nonebot_bison.post`下的某个类
|
||||
可以认为`nonebot_bison.post`是最终要交付给 bison 的 Theme 模块渲染,最终推送到群内的内容。
|
||||
|
||||
`parse`函数的工作就是将`nonebot_bison.types.RawPost`中的数据相应传入`nonebot_bison.post.Post`中
|
||||
|
||||
经过`parse`函数处理过后的报文应该返回属于`nonebot_bison.post`下的某个类。
|
||||
|
||||
目前 bison 所支持的类有:
|
||||
|
||||
- `nonebot_bison.post.Post`
|
||||
- `nonebot_bison.post.CustomPost`
|
||||
|
||||
### 什么是`nonebot_bison.post.Post`
|
||||
|
||||
Post 类存在参数`text`与`pics`,分别对应接收文本与图片类消息,需要注意的是`pics`接收的是一个列表 List,列表中的值可以为 url 或者 bytes。
|
||||
Post 会将`text`与`pics`分为若干条消息进行分别发送
|
||||
可选参数:
|
||||
使用`compress`参数将所有消息压缩为一条进行发送。
|
||||
使用`extra_msg`可以携带额外的消息进行发送
|
||||
使用`override_use_pic`参数可以无视全局配置中的 bison_use_pic 配置进行强制指定
|
||||
可参考[Post 的用法](https://github.com/felinae98/nonebot-bison/blob/v0.5.4/src/plugins/nonebot_bison/platform/arknights.py#L227)
|
||||
|
||||
### 什么是`nonebot_bison.post.CustomPost`
|
||||
|
||||
CustomPost 类能接受的消息为[`List[MessageSegment]`](https://github.com/botuniverse/onebot-11/blob/master/message/array.md#%E6%B6%88%E6%81%AF%E6%AE%B5)
|
||||
::: tip
|
||||
|
||||
消息段(Message Segment 或 Segment)
|
||||
表示聊天消息的一个部分,在一些平台上,聊天消息支持图文混排,其中就会有多个消息段,分别表示每个图片和每段文字。
|
||||
:::
|
||||
准确来说,CustomPost 只支持使用 MessageSegment 内的`text`和`image`类型,CustomPost 会将 List 中的每个`text`类型元素理解为一个单行的 text 文本,
|
||||
当然,markdown 语法可以在每个`text`类型元素使用,但如果这样,在不开启`bison_use_pic`**全局配置项** 的情况下,bison 会将写在 text 类型元素里的 markdown 语法按原样推送,不会解析。
|
||||
对于上述情况,建议开启 CustomPost 的`override_use_pic`选项,这样 CustomPost 只会发送经过 markdown 语法渲染好的图片,而非文本消息。
|
||||
CustomPost 的可选参数及作用与上文中的[Post](#什么是nonebot-bison-post-post)一致。
|
||||
::: details CustomPost 例子
|
||||
最通用的 Post,理论上包含所有常用的数据
|
||||
|
||||
```python
|
||||
async def parse(self, raw_post:RawPost) -> str:
|
||||
#假定传入的raw_post为List[MessageSegment]
|
||||
#do something...
|
||||
return CustomPost(message_segments=raw_post, only_pic=True)
|
||||
class Post(AbstractPost):
|
||||
platform: "Platform"
|
||||
"""来源平台"""
|
||||
content: str
|
||||
"""文本内容"""
|
||||
title: str | None = None
|
||||
"""标题"""
|
||||
images: list[str | bytes | Path | BytesIO] | None = None
|
||||
"""图片列表"""
|
||||
timestamp: int | None = None
|
||||
"""发布/获取时间戳"""
|
||||
url: str | None = None
|
||||
"""来源链接"""
|
||||
avatar: str | bytes | Path | BytesIO | None = None
|
||||
"""发布者头像"""
|
||||
nickname: str | None = None
|
||||
"""发布者昵称"""
|
||||
description: str | None = None
|
||||
"""发布者个性签名等"""
|
||||
repost: "Post | None" = None
|
||||
"""转发的 Post"""
|
||||
```
|
||||
|
||||
额外参数 (AbstractPost):
|
||||
|
||||
- 使用`compress`参数将所有消息压缩为一条进行发送。
|
||||
- 使用`extra_msg`可以携带额外的消息进行发送。
|
||||
可参考[Post 的用法](https://github.com/MountainDash/nonebot-bison/blob/v0.9.1/nonebot_bison/platform/arknights.py#L240)
|
||||
|
||||
## 制作主题
|
||||
|
||||
### 什么是主题
|
||||
|
||||
主题是用于渲染`nonebot_bison.post.Post`的模块,可以理解为一个模板引擎,生成可发送的消息。
|
||||
|
||||
RawPost 通过`Platform.parse`函数处理成 Post,然后通过`Theme.render`函数渲染成可发送的消息。
|
||||
|
||||
### 主题的注册
|
||||
|
||||
Bison 在启动时会尝试注册所有在`nonebot_bison/theme/themes`下的主题,如果你的主题在这个目录下,并指定了 `__theme_meta__`,那么它会被自动注册。
|
||||
|
||||
若配置项`BISON_THEME_USE_BROWSER=false`,则在注册的主题需要浏览器渲染,即`need_browser`字段为`True`时,会发出注册警告
|
||||
|
||||
同时,你也可以手动调用`nonebot_bison.theme.theme_manager.register`来注册主题
|
||||
|
||||
::: tip 另一种加载方式
|
||||
理论上你自己的 Theme 可以创建在别的位置,甚至作为一个插件
|
||||
这样的话想要注册这个 Theme,就需要在插件里这样做:
|
||||
|
||||
```python
|
||||
from nonebot_bison.theme import theme_manager
|
||||
from .path.to.your.theme import ATheme
|
||||
|
||||
theme_manager.register(ATheme())
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
### 主题的实现
|
||||
|
||||
主题需要继承`nonebot_bison.theme.Theme`,并实现`render`函数
|
||||
|
||||
在某个 Platform 获取到 Post 之后,会根据 主题渲染规则,将 Post 传入对应的 Theme 中,然后调用`render`函数,将 Post 渲染成可发送的消息。
|
||||
|
||||
::: info 主题渲染规则
|
||||
|
||||
```python
|
||||
def get_priority_themes(self) -> list[str]:
|
||||
"""获取渲染所使用的 theme 名列表,按照优先级排序"""
|
||||
themes_by_priority: list[str] = []
|
||||
# 最先使用用户指定的 theme
|
||||
if user_theme := self.get_config_theme():
|
||||
themes_by_priority.append(user_theme)
|
||||
# 然后使用平台默认的 theme
|
||||
if self.platform.default_theme not in themes_by_priority:
|
||||
themes_by_priority.append(self.platform.default_theme)
|
||||
# 最后使用最基础的 theme
|
||||
if "basic" not in themes_by_priority:
|
||||
themes_by_priority.append("basic")
|
||||
return themes_by_priority
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
在获取到可渲染的主题列表后,会按照列表中的顺序依次调用`render`函数。
|
||||
|
||||
如果某个主题渲染失败,会继续调用下一个主题,直到渲染成功或者没有主题可用。
|
||||
|
||||
### 例子
|
||||
|
||||
想要创建一个主题,首先需要在`nonebot_bison/theme/themes`目录下创建一个新的目录,比如`mytheme`
|
||||
|
||||
然后在`mytheme`目录下创建一个`__init__.py`文件
|
||||
|
||||
接下来创建一个`build.py`文件,用于生成主题
|
||||
|
||||
在文件中写入:
|
||||
|
||||
```python
|
||||
from typing import TYPE_CHECKING, Literal
|
||||
|
||||
from nonebot_bison.theme import Theme
|
||||
if TYPE_CHECKING:
|
||||
from nonebot_bison.post import Post
|
||||
|
||||
class MyTheme(Theme):
|
||||
name: Literal["mytheme"] = "mytheme"
|
||||
|
||||
# 可选,该主题渲染是否需要浏览器
|
||||
# need_browser: bool = ...
|
||||
|
||||
async def render(self, post: "Post") -> list[MessageSegmentFactory]:
|
||||
...
|
||||
```
|
||||
|
||||
在`render`函数中,将传入的 post 中的数据用你所希望的方式渲染成 MessageSegmentFactory,就完成了一个主题的制作
|
||||
|
||||
然后在`__init__.py`中注册这个主题:
|
||||
|
||||
```python
|
||||
from .build import MyTheme
|
||||
|
||||
__theme_meta__ = MyTheme()
|
||||
```
|
||||
|
||||
这样就完成了一个主题的创建,Bison 会在启动时自动加载这个主题。
|
||||
|
||||
Reference in New Issue
Block a user