mirror of
https://github.com/Refound-445/nonebot-plugin-nailongremove.git
synced 2025-09-27 00:59:13 +08:00
test
This commit is contained in:
parent
bbfd55dff0
commit
f5ac064996
244
README.md
244
README.md
@ -1,244 +0,0 @@
|
||||
<!-- markdownlint-disable MD031 MD033 MD036 MD041 -->
|
||||
|
||||
<div align="center">
|
||||
|
||||
<a href="https://v2.nonebot.dev/store">
|
||||
<img src="https://raw.githubusercontent.com/A-kirami/nonebot-plugin-template/resources/nbp_logo.png" width="180" height="180" alt="NoneBotPluginLogo">
|
||||
</a>
|
||||
|
||||
<p>
|
||||
<img src="https://raw.githubusercontent.com/lgc-NB2Dev/readme/main/template/plugin.svg" alt="NoneBotPluginText">
|
||||
</p>
|
||||
|
||||
# Nonebot-Plugin-NaiLongRemove
|
||||
|
||||
_✨ 一个基于 AI 模型的简单插件~ ✨_
|
||||
|
||||
<img src="https://img.shields.io/badge/python-3.9+-blue.svg" alt="python">
|
||||
<a href="https://pdm.fming.dev">
|
||||
<img src="https://img.shields.io/badge/pdm-managed-blueviolet" alt="pdm-managed">
|
||||
</a>
|
||||
|
||||
<br />
|
||||
|
||||
<a href="https://pydantic.dev">
|
||||
<img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/lgc-NB2Dev/readme/main/template/pyd-v1-or-v2.json" alt="Pydantic Version 1 Or 2" >
|
||||
</a>
|
||||
<a href="./LICENSE">
|
||||
<img src="https://img.shields.io/github/license/Refound-445/nonebot-plugin-nailongremove.svg" alt="license">
|
||||
</a>
|
||||
<a href="https://pypi.python.org/pypi/nonebot-plugin-nailongremove">
|
||||
<img src="https://img.shields.io/pypi/v/nonebot-plugin-nailongremove.svg" alt="pypi">
|
||||
</a>
|
||||
<a href="https://pypi.python.org/pypi/nonebot-plugin-nailongremove">
|
||||
<img src="https://img.shields.io/pypi/dm/nonebot-plugin-nailongremove" alt="pypi download">
|
||||
</a>
|
||||
|
||||
<br />
|
||||
|
||||
<a href="https://registry.nonebot.dev/plugin/nonebot-plugin-nailongremove:nonebot_plugin_nailongremove">
|
||||
<img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fnbbdg.lgc2333.top%2Fplugin%2Fnonebot-plugin-nailongremove" alt="NoneBot Registry">
|
||||
</a>
|
||||
<a href="https://registry.nonebot.dev/plugin/nonebot-plugin-nailongremove:nonebot_plugin_nailongremove">
|
||||
<img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fnbbdg.lgc2333.top%2Fplugin-adapters%2Fnonebot-plugin-nailongremove" alt="Supported Adapters">
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
## 📖 介绍
|
||||
|
||||
### 声明
|
||||
|
||||
本插件仅供娱乐和学习交流。
|
||||
|
||||
### 简介
|
||||
|
||||
NaiLongRemove 是一款由简单的 AI 模型建立的奶龙识别插件,可以识别群中的奶龙表情包并撤回该表情。
|
||||
|
||||
### 技术
|
||||
|
||||
目前插件支持两种模型,可通过配置文件更换,详见文档下方配置一节。
|
||||
用户可以根据需要自行选择心仪的模型,两个模型性能都已经经过优化,但仍可能会有不同程度的误差,也欢迎各位继续反馈给我们~
|
||||
|
||||
## 💿 安装
|
||||
|
||||
**如果你从来没接触过 NoneBot,请查看 [这个文档](https://github.com/Refound-445/nonebot-plugin-nailongremove/blob/main/docs/tutorial.md)**
|
||||
|
||||
以下提到的方法 任选**其一** 即可
|
||||
|
||||
<details open>
|
||||
<summary>[推荐] 使用 nb-cli 安装</summary>
|
||||
在 nonebot2 项目的根目录下打开命令行, 输入以下指令即可安装
|
||||
|
||||
```bash
|
||||
nb plugin install nonebot-plugin-nailongremove
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>使用包管理器安装</summary>
|
||||
在 nonebot2 项目的插件目录下, 打开命令行, 根据你使用的包管理器, 输入相应的安装命令
|
||||
|
||||
<details>
|
||||
<summary>pip</summary>
|
||||
|
||||
```bash
|
||||
pip install nonebot-plugin-nailongremove
|
||||
```
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>pdm</summary>
|
||||
|
||||
```bash
|
||||
pdm add nonebot-plugin-nailongremove
|
||||
```
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>poetry</summary>
|
||||
|
||||
```bash
|
||||
poetry add nonebot-plugin-nailongremove
|
||||
```
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>conda</summary>
|
||||
|
||||
```bash
|
||||
conda install nonebot-plugin-nailongremove
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
打开 nonebot2 项目根目录下的 `pyproject.toml` 文件, 在 `[tool.nonebot]` 部分的 `plugins` 项里追加写入
|
||||
|
||||
```toml
|
||||
[tool.nonebot]
|
||||
plugins = [
|
||||
# ...
|
||||
"nonebot_plugin_nailongremove"
|
||||
]
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
安装完成之后请参考 [这里](https://github.com/Refound-445/nonebot-plugin-nailongremove/blob/main/docs/tutorial.md#4-%E6%A8%A1%E5%9E%8B%E7%9B%B8%E5%85%B3%E9%85%8D%E7%BD%AE) 完成模型配置相关操作
|
||||
|
||||
## ⚙️ 配置
|
||||
|
||||
在 nonebot2 项目的 `.env` 文件中添加下表中的必填配置
|
||||
|
||||
| 配置项 | 必填 | 默认值 | 说明 |
|
||||
| :-------------------------: | :--: | :--------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
|
||||
| **全局配置** | | | |
|
||||
| `PROXY` | 否 | `None` | 下载模型等文件时使用的代理地址 |
|
||||
| **响应配置** | | | |
|
||||
| `NAILONG_BYPASS_SUPERUSER` | 否 | `True` | 是否不检查超级用户发送的图片 |
|
||||
| `NAILONG_BYPASS_ADMIN` | 否 | `True` | 是否不检查群组管理员发送的图片 |
|
||||
| `NAILONG_NEED_ADMIN` | 否 | `False` | 当自身不为群组管理员时是否不检查群内所有图片 |
|
||||
| `NAILONG_LIST_SCENES` | 否 | `[]` | 聊天场景 ID 黑白名单列表<br />在单级聊天下为该聊天 ID,如 QQ 群号;<br />在多级聊天下为以 `_` 分割的各级聊天 ID,如频道下的子频道或频道下私聊 |
|
||||
| `NAILONG_BLACKLIST` | 否 | `True` | 是否使用黑名单模式 |
|
||||
| `NAILONG_USER_BLACKLIST` | 否 | `[]` | 用户 ID 黑名单列表 |
|
||||
| `NAILONG_PRIORITY` | 否 | `100` | Matcher 优先级 |
|
||||
| **行为配置** | | | |
|
||||
| `NAILONG_RECALL` | 否 | `True` | 是否撤回消息 |
|
||||
| `NAILONG_MUTE_SECONDS` | 否 | `0` | 设置禁言时间,默认为 0 即不禁言<br/>单位:秒 |
|
||||
| `NAILONG_TIP` | 否 | `{"nailong": "本群禁止发奶龙!"}` | 发送的提示,使用 [Alconna 的消息模板](https://nonebot.dev/docs/best-practice/alconna/uniseg#%E4%BD%BF%E7%94%A8%E6%B6%88%E6%81%AF%E6%A8%A1%E6%9D%BF),可用变量见下,可以根据标签自定义对应值,如遇其中没有的标签会回退到 `nailong` |
|
||||
| `NAILONG_FAILED_TIP` | 否 | `{"nailong": "{:Reply($message_id)}呜,不要发奶龙了嘛 🥺 👉👈"}` | 撤回失败或禁用撤回时发送的提示,同上 |
|
||||
| `NAILONG_CHECK_ALL_FRAMES` | 否 | `False` | 使用模型 1 时是否检查图片中的所有帧,启用该项后消息模板中的 `$checked_result` 变量当原图为动图时会变为动图 |
|
||||
| **模型通用配置** | | | |
|
||||
| `NAILONG_MODEL_DIR` | 否 | `./data/nailongremove` | 模型的下载位置 |
|
||||
| `NAILONG_MODEL` | 否 | `1` | 选择需要加载的模型,可用模型见下 |
|
||||
| `NAILONG_AUTO_UPDATE_MODEL` | 否 | `True` | 是否自动更新模型 |
|
||||
| `NAILONG_CONCURRENCY` | 否 | `1` | 当图片为动图时,针对该图片并发识别图片帧的最大并发数 |
|
||||
| `NAILONG_ONNX_PROVIDERS` | 否 | `["CPUExecutionProvider"]` | 加载 onnx 模型使用的 provider 列表,请参考上方安装文档 |
|
||||
| **模型 1 特定配置** | | | |
|
||||
| `NAILONG_MODEL1_TYPE` | 否 | `tiny` | 模型 1 使用的模型类型,可用 `tiny` / `m` |
|
||||
| `NAILONG_MODEL1_YOLOX_SIZE` | 否 | `None` | 针对模型 1,自定义模型输入可能会有尺寸更改 |
|
||||
| `NAILONG_MODEL1_SCORE` | 否 | `{"nailong": 0.5}` | 模型 1 置信度阈值,范围 `0` ~ `1`,可以根据标签自定义对应值,设置对应标签的阈值以检测该标签,设为 `null` 或者不填可以忽略该标签 |
|
||||
| **杂项配置** | | | |
|
||||
| `NAILONG_GITHUB_TOKEN` | 否 | `None` | GitHub Access Token,遇到模型下载或更新问题时可尝试填写 |
|
||||
|
||||
### 可用模型
|
||||
|
||||
- `0`:基于 Renet50 图像分类模型训练推理,感谢 @spawner1145 提供的模型,原链接:[spawner1145/NailongRecognize](https://github.com/spawner1145/NailongRecognize.git)
|
||||
- `1`:基于 YOLOX 目标检测模型训练推理,感谢 @NKXingXh 提供的模型,原链接:[nkxingxh/NailongDetection](https://github.com/nkxingxh/NailongDetection)
|
||||
|
||||
### 消息模板可用变量
|
||||
|
||||
| 变量名 | 类型 | 说明 |
|
||||
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- |
|
||||
| `$event` | [`Event`](https://nonebot.dev/docs/api/adapters/#Event) | 当前事件 |
|
||||
| `$target` | [`Target`](https://nonebot.dev/docs/best-practice/alconna/uniseg#%E6%B6%88%E6%81%AF%E5%8F%91%E9%80%81%E5%AF%B9%E8%B1%A1) | 事件目标 |
|
||||
| `$message_id` | `str` | 消息 ID |
|
||||
| `$msg` | [`UniMessage`](https://nonebot.dev/docs/best-practice/alconna/uniseg#%E9%80%9A%E7%94%A8%E6%B6%88%E6%81%AF%E5%BA%8F%E5%88%97) | 当前消息 |
|
||||
| `$ss` | [`Session`](https://github.com/RF-Tar-Railt/nonebot-plugin-uninfo?tab=readme-ov-file#session) | 当前会话 |
|
||||
| `$checked_result` | [`Image`](https://nonebot.dev/docs/best-practice/alconna/uniseg#%E9%80%9A%E7%94%A8%E6%B6%88%E6%81%AF%E6%AE%B5) | 框选出对应目标后的图片,仅在模型配置为 `1` 时存在 |
|
||||
|
||||
## 🎉 使用
|
||||
|
||||
只要有人发奶龙表情包被识别出来,就会被撤回并提醒。
|
||||
|
||||
## 📞 联系
|
||||
|
||||
- Nonebot2 官方交流群:768887710(基础的安装部署问题可在这里询问)
|
||||
- 人工智能学习交流群:949992679(学习交流 AI 相关技术可以来这里捏)
|
||||
- 机器人插件学习交流群:200980266(机器人 BUG 模型精度等问题反馈来这里哟)
|
||||
|
||||
欢迎大家进群一起学习交流~
|
||||
|
||||
## 📝 更新日志
|
||||
|
||||
### 2.3.1
|
||||
|
||||
- 修改插件依赖以避免一些问题,影响了安装过程,请查看安装文档了解
|
||||
- 对应配置项修改:删除配置项 `NAILONG_ONNX_TRY_TO_USE_GPU`,添加配置项 `NAILONG_ONNX_PROVIDERS`
|
||||
|
||||
### 2.3.0
|
||||
|
||||
- 支持了检查 GIF 中的所有帧并将结果重新封成 GIF,默认禁用,同时弃用 `$checked_image` 变量,新增 `$checked_result` 变量
|
||||
- 现在模型 1 的输入大小可以根据模型类型自动配置了,但是如果配置项指定了那么会优先使用
|
||||
- 支持处理含有其他标签的图片了,部分配置项支持根据标签自定义对应值
|
||||
- 增加用户黑名单
|
||||
- 默认模型调整至 1
|
||||
|
||||
### 2.2.1
|
||||
|
||||
- 优化模型自动更新(可能是反向优化)
|
||||
|
||||
### 2.2.0
|
||||
|
||||
- 重命名配置项 `NAILONG_YOLOX_SIZE` -> `NAILONG_MODEL1_YOLOX_SIZE`
|
||||
- 模型 1 现可以自动获取最新版本,也可以通过配置选择要使用的模型类型
|
||||
- 模型 1 现可通过配置项控制识别置信度阈值
|
||||
- 加载 onnx 模型时会默认尝试使用 GPU,如果失败则会显示一串警告,如果不想看见警告参考上面关闭对应配置
|
||||
|
||||
### 2.1.4
|
||||
|
||||
- 修复 `NAILONG_NEED_ADMIN` 配置不生效的 Bug
|
||||
|
||||
### 2.1.3
|
||||
|
||||
- 修复忽略群管与超级用户无效的 Bug
|
||||
|
||||
### 2.1.2
|
||||
|
||||
- 重构部分代码,修复潜在 Bug
|
||||
|
||||
### 2.1.1
|
||||
|
||||
- 新增变量 `$checked_image`
|
||||
|
||||
### 2.1.0
|
||||
|
||||
- 从原仓库下载模型
|
||||
|
||||
### 2.0.0
|
||||
|
||||
- 重构插件,适配多平台
|
||||
- 更新了两个新模型,优化了模型精度,用户可自行选择其中之一进行推理
|
||||
- 增加了禁言、群黑白名单、可选关闭管理员检测等功能
|
||||
- 增加了自动更新模型可选
|
1
README.md
Symbolic link
1
README.md
Symbolic link
@ -0,0 +1 @@
|
||||
./packages/nonebot-plugin-nailongremove-base/README.md
|
244
packages/nonebot-plugin-nailongremove-base/README.md
Normal file
244
packages/nonebot-plugin-nailongremove-base/README.md
Normal file
@ -0,0 +1,244 @@
|
||||
<!-- markdownlint-disable MD031 MD033 MD036 MD041 -->
|
||||
|
||||
<div align="center">
|
||||
|
||||
<a href="https://v2.nonebot.dev/store">
|
||||
<img src="https://raw.githubusercontent.com/A-kirami/nonebot-plugin-template/resources/nbp_logo.png" width="180" height="180" alt="NoneBotPluginLogo">
|
||||
</a>
|
||||
|
||||
<p>
|
||||
<img src="https://raw.githubusercontent.com/lgc-NB2Dev/readme/main/template/plugin.svg" alt="NoneBotPluginText">
|
||||
</p>
|
||||
|
||||
# Nonebot-Plugin-NaiLongRemove
|
||||
|
||||
_✨ 一个基于 AI 模型的简单插件~ ✨_
|
||||
|
||||
<img src="https://img.shields.io/badge/python-3.9+-blue.svg" alt="python">
|
||||
<a href="https://pdm.fming.dev">
|
||||
<img src="https://img.shields.io/badge/pdm-managed-blueviolet" alt="pdm-managed">
|
||||
</a>
|
||||
|
||||
<br />
|
||||
|
||||
<a href="https://pydantic.dev">
|
||||
<img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/lgc-NB2Dev/readme/main/template/pyd-v1-or-v2.json" alt="Pydantic Version 1 Or 2" >
|
||||
</a>
|
||||
<a href="./LICENSE">
|
||||
<img src="https://img.shields.io/github/license/Refound-445/nonebot-plugin-nailongremove.svg" alt="license">
|
||||
</a>
|
||||
<a href="https://pypi.python.org/pypi/nonebot-plugin-nailongremove">
|
||||
<img src="https://img.shields.io/pypi/v/nonebot-plugin-nailongremove.svg" alt="pypi">
|
||||
</a>
|
||||
<a href="https://pypi.python.org/pypi/nonebot-plugin-nailongremove">
|
||||
<img src="https://img.shields.io/pypi/dm/nonebot-plugin-nailongremove" alt="pypi download">
|
||||
</a>
|
||||
|
||||
<br />
|
||||
|
||||
<a href="https://registry.nonebot.dev/plugin/nonebot-plugin-nailongremove:nonebot_plugin_nailongremove">
|
||||
<img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fnbbdg.lgc2333.top%2Fplugin%2Fnonebot-plugin-nailongremove" alt="NoneBot Registry">
|
||||
</a>
|
||||
<a href="https://registry.nonebot.dev/plugin/nonebot-plugin-nailongremove:nonebot_plugin_nailongremove">
|
||||
<img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fnbbdg.lgc2333.top%2Fplugin-adapters%2Fnonebot-plugin-nailongremove" alt="Supported Adapters">
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
## 📖 介绍
|
||||
|
||||
### 声明
|
||||
|
||||
本插件仅供娱乐和学习交流。
|
||||
|
||||
### 简介
|
||||
|
||||
NaiLongRemove 是一款由简单的 AI 模型建立的奶龙识别插件,可以识别群中的奶龙表情包并撤回该表情。
|
||||
|
||||
### 技术
|
||||
|
||||
目前插件支持两种模型,可通过配置文件更换,详见文档下方配置一节。
|
||||
用户可以根据需要自行选择心仪的模型,两个模型性能都已经经过优化,但仍可能会有不同程度的误差,也欢迎各位继续反馈给我们~
|
||||
|
||||
## 💿 安装
|
||||
|
||||
**如果你从来没接触过 NoneBot,请查看 [这个文档](https://github.com/Refound-445/nonebot-plugin-nailongremove/blob/main/docs/tutorial.md)**
|
||||
|
||||
以下提到的方法 任选**其一** 即可
|
||||
|
||||
<details open>
|
||||
<summary>[推荐] 使用 nb-cli 安装</summary>
|
||||
在 nonebot2 项目的根目录下打开命令行, 输入以下指令即可安装
|
||||
|
||||
```bash
|
||||
nb plugin install nonebot-plugin-nailongremove
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>使用包管理器安装</summary>
|
||||
在 nonebot2 项目的插件目录下, 打开命令行, 根据你使用的包管理器, 输入相应的安装命令
|
||||
|
||||
<details>
|
||||
<summary>pip</summary>
|
||||
|
||||
```bash
|
||||
pip install nonebot-plugin-nailongremove
|
||||
```
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>pdm</summary>
|
||||
|
||||
```bash
|
||||
pdm add nonebot-plugin-nailongremove
|
||||
```
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>poetry</summary>
|
||||
|
||||
```bash
|
||||
poetry add nonebot-plugin-nailongremove
|
||||
```
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>conda</summary>
|
||||
|
||||
```bash
|
||||
conda install nonebot-plugin-nailongremove
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
打开 nonebot2 项目根目录下的 `pyproject.toml` 文件, 在 `[tool.nonebot]` 部分的 `plugins` 项里追加写入
|
||||
|
||||
```toml
|
||||
[tool.nonebot]
|
||||
plugins = [
|
||||
# ...
|
||||
"nonebot_plugin_nailongremove"
|
||||
]
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
安装完成之后请参考 [这里](https://github.com/Refound-445/nonebot-plugin-nailongremove/blob/main/docs/tutorial.md#4-%E6%A8%A1%E5%9E%8B%E7%9B%B8%E5%85%B3%E9%85%8D%E7%BD%AE) 完成模型配置相关操作
|
||||
|
||||
## ⚙️ 配置
|
||||
|
||||
在 nonebot2 项目的 `.env` 文件中添加下表中的必填配置
|
||||
|
||||
| 配置项 | 必填 | 默认值 | 说明 |
|
||||
| :-------------------------: | :--: | :--------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
|
||||
| **全局配置** | | | |
|
||||
| `PROXY` | 否 | `None` | 下载模型等文件时使用的代理地址 |
|
||||
| **响应配置** | | | |
|
||||
| `NAILONG_BYPASS_SUPERUSER` | 否 | `True` | 是否不检查超级用户发送的图片 |
|
||||
| `NAILONG_BYPASS_ADMIN` | 否 | `True` | 是否不检查群组管理员发送的图片 |
|
||||
| `NAILONG_NEED_ADMIN` | 否 | `False` | 当自身不为群组管理员时是否不检查群内所有图片 |
|
||||
| `NAILONG_LIST_SCENES` | 否 | `[]` | 聊天场景 ID 黑白名单列表<br />在单级聊天下为该聊天 ID,如 QQ 群号;<br />在多级聊天下为以 `_` 分割的各级聊天 ID,如频道下的子频道或频道下私聊 |
|
||||
| `NAILONG_BLACKLIST` | 否 | `True` | 是否使用黑名单模式 |
|
||||
| `NAILONG_USER_BLACKLIST` | 否 | `[]` | 用户 ID 黑名单列表 |
|
||||
| `NAILONG_PRIORITY` | 否 | `100` | Matcher 优先级 |
|
||||
| **行为配置** | | | |
|
||||
| `NAILONG_RECALL` | 否 | `True` | 是否撤回消息 |
|
||||
| `NAILONG_MUTE_SECONDS` | 否 | `0` | 设置禁言时间,默认为 0 即不禁言<br/>单位:秒 |
|
||||
| `NAILONG_TIP` | 否 | `{"nailong": "本群禁止发奶龙!"}` | 发送的提示,使用 [Alconna 的消息模板](https://nonebot.dev/docs/best-practice/alconna/uniseg#%E4%BD%BF%E7%94%A8%E6%B6%88%E6%81%AF%E6%A8%A1%E6%9D%BF),可用变量见下,可以根据标签自定义对应值,如遇其中没有的标签会回退到 `nailong` |
|
||||
| `NAILONG_FAILED_TIP` | 否 | `{"nailong": "{:Reply($message_id)}呜,不要发奶龙了嘛 🥺 👉👈"}` | 撤回失败或禁用撤回时发送的提示,同上 |
|
||||
| `NAILONG_CHECK_ALL_FRAMES` | 否 | `False` | 使用模型 1 时是否检查图片中的所有帧,启用该项后消息模板中的 `$checked_result` 变量当原图为动图时会变为动图 |
|
||||
| **模型通用配置** | | | |
|
||||
| `NAILONG_MODEL_DIR` | 否 | `./data/nailongremove` | 模型的下载位置 |
|
||||
| `NAILONG_MODEL` | 否 | `1` | 选择需要加载的模型,可用模型见下 |
|
||||
| `NAILONG_AUTO_UPDATE_MODEL` | 否 | `True` | 是否自动更新模型 |
|
||||
| `NAILONG_CONCURRENCY` | 否 | `1` | 当图片为动图时,针对该图片并发识别图片帧的最大并发数 |
|
||||
| `NAILONG_ONNX_PROVIDERS` | 否 | `["CPUExecutionProvider"]` | 加载 onnx 模型使用的 provider 列表,请参考上方安装文档 |
|
||||
| **模型 1 特定配置** | | | |
|
||||
| `NAILONG_MODEL1_TYPE` | 否 | `tiny` | 模型 1 使用的模型类型,可用 `tiny` / `m` |
|
||||
| `NAILONG_MODEL1_YOLOX_SIZE` | 否 | `None` | 针对模型 1,自定义模型输入可能会有尺寸更改 |
|
||||
| `NAILONG_MODEL1_SCORE` | 否 | `{"nailong": 0.5}` | 模型 1 置信度阈值,范围 `0` ~ `1`,可以根据标签自定义对应值,设置对应标签的阈值以检测该标签,设为 `null` 或者不填可以忽略该标签 |
|
||||
| **杂项配置** | | | |
|
||||
| `NAILONG_GITHUB_TOKEN` | 否 | `None` | GitHub Access Token,遇到模型下载或更新问题时可尝试填写 |
|
||||
|
||||
### 可用模型
|
||||
|
||||
- `0`:基于 Renet50 图像分类模型训练推理,感谢 @spawner1145 提供的模型,原链接:[spawner1145/NailongRecognize](https://github.com/spawner1145/NailongRecognize.git)
|
||||
- `1`:基于 YOLOX 目标检测模型训练推理,感谢 @NKXingXh 提供的模型,原链接:[nkxingxh/NailongDetection](https://github.com/nkxingxh/NailongDetection)
|
||||
|
||||
### 消息模板可用变量
|
||||
|
||||
| 变量名 | 类型 | 说明 |
|
||||
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- |
|
||||
| `$event` | [`Event`](https://nonebot.dev/docs/api/adapters/#Event) | 当前事件 |
|
||||
| `$target` | [`Target`](https://nonebot.dev/docs/best-practice/alconna/uniseg#%E6%B6%88%E6%81%AF%E5%8F%91%E9%80%81%E5%AF%B9%E8%B1%A1) | 事件目标 |
|
||||
| `$message_id` | `str` | 消息 ID |
|
||||
| `$msg` | [`UniMessage`](https://nonebot.dev/docs/best-practice/alconna/uniseg#%E9%80%9A%E7%94%A8%E6%B6%88%E6%81%AF%E5%BA%8F%E5%88%97) | 当前消息 |
|
||||
| `$ss` | [`Session`](https://github.com/RF-Tar-Railt/nonebot-plugin-uninfo?tab=readme-ov-file#session) | 当前会话 |
|
||||
| `$checked_result` | [`Image`](https://nonebot.dev/docs/best-practice/alconna/uniseg#%E9%80%9A%E7%94%A8%E6%B6%88%E6%81%AF%E6%AE%B5) | 框选出对应目标后的图片,仅在模型配置为 `1` 时存在 |
|
||||
|
||||
## 🎉 使用
|
||||
|
||||
只要有人发奶龙表情包被识别出来,就会被撤回并提醒。
|
||||
|
||||
## 📞 联系
|
||||
|
||||
- Nonebot2 官方交流群:768887710(基础的安装部署问题可在这里询问)
|
||||
- 人工智能学习交流群:949992679(学习交流 AI 相关技术可以来这里捏)
|
||||
- 机器人插件学习交流群:200980266(机器人 BUG 模型精度等问题反馈来这里哟)
|
||||
|
||||
欢迎大家进群一起学习交流~
|
||||
|
||||
## 📝 更新日志
|
||||
|
||||
### 2.3.1
|
||||
|
||||
- 修改插件依赖以避免一些问题,影响了安装过程,请查看安装文档了解
|
||||
- 对应配置项修改:删除配置项 `NAILONG_ONNX_TRY_TO_USE_GPU`,添加配置项 `NAILONG_ONNX_PROVIDERS`
|
||||
|
||||
### 2.3.0
|
||||
|
||||
- 支持了检查 GIF 中的所有帧并将结果重新封成 GIF,默认禁用,同时弃用 `$checked_image` 变量,新增 `$checked_result` 变量
|
||||
- 现在模型 1 的输入大小可以根据模型类型自动配置了,但是如果配置项指定了那么会优先使用
|
||||
- 支持处理含有其他标签的图片了,部分配置项支持根据标签自定义对应值
|
||||
- 增加用户黑名单
|
||||
- 默认模型调整至 1
|
||||
|
||||
### 2.2.1
|
||||
|
||||
- 优化模型自动更新(可能是反向优化)
|
||||
|
||||
### 2.2.0
|
||||
|
||||
- 重命名配置项 `NAILONG_YOLOX_SIZE` -> `NAILONG_MODEL1_YOLOX_SIZE`
|
||||
- 模型 1 现可以自动获取最新版本,也可以通过配置选择要使用的模型类型
|
||||
- 模型 1 现可通过配置项控制识别置信度阈值
|
||||
- 加载 onnx 模型时会默认尝试使用 GPU,如果失败则会显示一串警告,如果不想看见警告参考上面关闭对应配置
|
||||
|
||||
### 2.1.4
|
||||
|
||||
- 修复 `NAILONG_NEED_ADMIN` 配置不生效的 Bug
|
||||
|
||||
### 2.1.3
|
||||
|
||||
- 修复忽略群管与超级用户无效的 Bug
|
||||
|
||||
### 2.1.2
|
||||
|
||||
- 重构部分代码,修复潜在 Bug
|
||||
|
||||
### 2.1.1
|
||||
|
||||
- 新增变量 `$checked_image`
|
||||
|
||||
### 2.1.0
|
||||
|
||||
- 从原仓库下载模型
|
||||
|
||||
### 2.0.0
|
||||
|
||||
- 重构插件,适配多平台
|
||||
- 更新了两个新模型,优化了模型精度,用户可自行选择其中之一进行推理
|
||||
- 增加了禁言、群黑白名单、可选关闭管理员检测等功能
|
||||
- 增加了自动更新模型可选
|
@ -1,115 +1,115 @@
|
||||
from typing import Any, Awaitable, Callable, Iterable, List, TypeVar
|
||||
|
||||
from nonebot import logger, on_message
|
||||
from nonebot.adapters import Bot as BaseBot, Event as BaseEvent
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.rule import Rule
|
||||
from nonebot_plugin_alconna.uniseg import UniMessage, UniMsg
|
||||
from nonebot_plugin_uninfo import QryItrface, Uninfo
|
||||
|
||||
from .config import DEFAULT_LABEL, config
|
||||
from .frame_source import iter_sources_in_message, source_extractors
|
||||
from .model import check
|
||||
from .uniapi import mute, recall
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
def judge_list(lst: Iterable[T], val: T, blacklist: bool) -> bool:
|
||||
return (val not in lst) if blacklist else (val in lst)
|
||||
|
||||
|
||||
async def execute_functions_any_ok(
|
||||
func: Iterable[Callable[[], Awaitable[Any]]],
|
||||
) -> bool:
|
||||
ok = False
|
||||
for f in func:
|
||||
try:
|
||||
await f()
|
||||
except Exception as e:
|
||||
logger.warning(f"{type(e).__name__}: {e}")
|
||||
logger.opt(exception=e).debug("Stacktrace:")
|
||||
else:
|
||||
ok = True
|
||||
return ok
|
||||
|
||||
|
||||
async def nailong_rule(
|
||||
bot: BaseBot,
|
||||
event: BaseEvent,
|
||||
session: Uninfo,
|
||||
ss_interface: QryItrface,
|
||||
msg: UniMsg,
|
||||
) -> bool:
|
||||
return (
|
||||
# check if it's a group chat
|
||||
bool(session.member) # this prop only exists in group chats
|
||||
# user blacklist
|
||||
and (session.user.id not in config.nailong_user_blacklist)
|
||||
# scene blacklist or whitelist
|
||||
and judge_list(
|
||||
config.nailong_list_scenes,
|
||||
session.scene_path,
|
||||
config.nailong_blacklist,
|
||||
)
|
||||
# bypass superuser
|
||||
and ((not config.nailong_bypass_superuser) or (not await SUPERUSER(bot, event)))
|
||||
# bypass group admin
|
||||
and (
|
||||
(not config.nailong_bypass_admin)
|
||||
or ((not session.member.role) or session.member.role.level <= 1)
|
||||
)
|
||||
# msg has supported seg
|
||||
and (any(True for x in msg if type(x) in source_extractors))
|
||||
# self is admin
|
||||
and (
|
||||
(not config.nailong_need_admin)
|
||||
or bool(
|
||||
(
|
||||
self_info := await ss_interface.get_member(
|
||||
session.scene.type,
|
||||
session.scene.id,
|
||||
user_id=session.self_id,
|
||||
)
|
||||
)
|
||||
and self_info.role
|
||||
and self_info.role.level > 1,
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
nailong = on_message(rule=Rule(nailong_rule), priority=config.nailong_priority)
|
||||
|
||||
|
||||
@nailong.handle()
|
||||
async def handle_function(bot: BaseBot, ev: BaseEvent, msg: UniMsg, session: Uninfo):
|
||||
async for source, seg in iter_sources_in_message(msg):
|
||||
try:
|
||||
check_res = await check(source)
|
||||
except Exception:
|
||||
logger.exception(f"Failed to check {seg!r}")
|
||||
continue
|
||||
if not check_res.ok:
|
||||
continue
|
||||
|
||||
functions: List[Callable[[], Awaitable[Any]]] = []
|
||||
if config.nailong_recall:
|
||||
functions.append(lambda: recall(bot, ev))
|
||||
if config.nailong_mute_seconds > 0:
|
||||
functions.append(lambda: mute(bot, ev, config.nailong_mute_seconds))
|
||||
punish_ok = functions and (await execute_functions_any_ok(functions))
|
||||
|
||||
template_dict = config.nailong_tip if punish_ok else config.nailong_failed_tip
|
||||
template_str = template_dict[
|
||||
check_res.label if (check_res.label in template_dict) else DEFAULT_LABEL
|
||||
]
|
||||
mapping = {
|
||||
"$event": ev,
|
||||
"$target": msg.get_target(),
|
||||
"$message_id": msg.get_message_id(),
|
||||
"$msg": msg,
|
||||
"$ss": session,
|
||||
**check_res.extra_vars,
|
||||
}
|
||||
await UniMessage.template(template_str).format_map(mapping).finish()
|
||||
from typing import Any, Awaitable, Callable, Iterable, List, TypeVar
|
||||
|
||||
from nonebot import logger, on_message
|
||||
from nonebot.adapters import Bot as BaseBot, Event as BaseEvent
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot.rule import Rule
|
||||
from nonebot_plugin_alconna.uniseg import UniMessage, UniMsg
|
||||
from nonebot_plugin_uninfo import QryItrface, Uninfo
|
||||
|
||||
from .config import DEFAULT_LABEL, config
|
||||
from .frame_source import iter_sources_in_message, source_extractors
|
||||
from .model import check
|
||||
from .uniapi import mute, recall
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
def judge_list(lst: Iterable[T], val: T, blacklist: bool) -> bool:
|
||||
return (val not in lst) if blacklist else (val in lst)
|
||||
|
||||
|
||||
async def execute_functions_any_ok(
|
||||
func: Iterable[Callable[[], Awaitable[Any]]],
|
||||
) -> bool:
|
||||
ok = False
|
||||
for f in func:
|
||||
try:
|
||||
await f()
|
||||
except Exception as e:
|
||||
logger.warning(f"{type(e).__name__}: {e}")
|
||||
logger.opt(exception=e).debug("Stacktrace:")
|
||||
else:
|
||||
ok = True
|
||||
return ok
|
||||
|
||||
|
||||
async def nailong_rule(
|
||||
bot: BaseBot,
|
||||
event: BaseEvent,
|
||||
session: Uninfo,
|
||||
ss_interface: QryItrface,
|
||||
msg: UniMsg,
|
||||
) -> bool:
|
||||
return (
|
||||
# check if it's a group chat
|
||||
bool(session.member) # this prop only exists in group chats
|
||||
# user blacklist
|
||||
and (session.user.id not in config.nailong_user_blacklist)
|
||||
# scene blacklist or whitelist
|
||||
and judge_list(
|
||||
config.nailong_list_scenes,
|
||||
session.scene_path,
|
||||
config.nailong_blacklist,
|
||||
)
|
||||
# bypass superuser
|
||||
and ((not config.nailong_bypass_superuser) or (not await SUPERUSER(bot, event)))
|
||||
# bypass group admin
|
||||
and (
|
||||
(not config.nailong_bypass_admin)
|
||||
or ((not session.member.role) or session.member.role.level <= 1)
|
||||
)
|
||||
# msg has supported seg
|
||||
and (any(True for x in msg if type(x) in source_extractors))
|
||||
# self is admin
|
||||
and (
|
||||
(not config.nailong_need_admin)
|
||||
or bool(
|
||||
(
|
||||
self_info := await ss_interface.get_member(
|
||||
session.scene.type,
|
||||
session.scene.id,
|
||||
user_id=session.self_id,
|
||||
)
|
||||
)
|
||||
and self_info.role
|
||||
and self_info.role.level > 1,
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
nailong = on_message(rule=Rule(nailong_rule), priority=config.nailong_priority)
|
||||
|
||||
|
||||
@nailong.handle()
|
||||
async def handle_function(bot: BaseBot, ev: BaseEvent, msg: UniMsg, session: Uninfo):
|
||||
async for source, seg in iter_sources_in_message(msg):
|
||||
try:
|
||||
check_res = await check(source)
|
||||
except Exception:
|
||||
logger.exception(f"Failed to check {seg!r}")
|
||||
continue
|
||||
if not check_res.ok:
|
||||
continue
|
||||
|
||||
functions: List[Callable[[], Awaitable[Any]]] = []
|
||||
if config.nailong_recall:
|
||||
functions.append(lambda: recall(bot, ev))
|
||||
if config.nailong_mute_seconds > 0:
|
||||
functions.append(lambda: mute(bot, ev, config.nailong_mute_seconds))
|
||||
punish_ok = functions and (await execute_functions_any_ok(functions))
|
||||
|
||||
template_dict = config.nailong_tip if punish_ok else config.nailong_failed_tip
|
||||
template_str = template_dict[
|
||||
check_res.label if (check_res.label in template_dict) else DEFAULT_LABEL
|
||||
]
|
||||
mapping = {
|
||||
"$event": ev,
|
||||
"$target": msg.get_target(),
|
||||
"$message_id": msg.get_message_id(),
|
||||
"$msg": msg,
|
||||
"$ss": session,
|
||||
**check_res.extra_vars,
|
||||
}
|
||||
await UniMessage.template(template_str).format_map(mapping).finish()
|
File diff suppressed because it is too large
Load Diff
43
packages/nonebot-plugin-nailongremove-base/pyproject.toml
Normal file
43
packages/nonebot-plugin-nailongremove-base/pyproject.toml
Normal file
@ -0,0 +1,43 @@
|
||||
[project]
|
||||
name = "nonebot-plugin-nailongremove-base"
|
||||
dynamic = ["version"]
|
||||
description = "识别目标并撤回图片插件"
|
||||
authors = [
|
||||
{ name = "445", email = "2877834692@qq.com" },
|
||||
{ name = "student_2333", email = "lgc2333@126.com" },
|
||||
]
|
||||
requires-python = "<4.0,>=3.9"
|
||||
dependencies = [
|
||||
"nonebot2>=2.2.0",
|
||||
"nonebot-plugin-alconna>=0.53.1",
|
||||
"nonebot-plugin-uninfo>=0.5.0",
|
||||
"opencv-python>=4.5",
|
||||
"numpy>=1.19",
|
||||
"keras>=2.4",
|
||||
"pillow>=9",
|
||||
"cookit[pydantic]>=0.8.1",
|
||||
"httpx>=0.27.2",
|
||||
"githubkit>=0.11.14",
|
||||
"yarl>=1.17.1",
|
||||
"tqdm>=4.66.6",
|
||||
]
|
||||
license = { text = "MIT" }
|
||||
readme = "README.md"
|
||||
keywords = ["nonebot", "plugin", "image"]
|
||||
|
||||
[project.urls]
|
||||
homepage = "https://github.com/Refound-445/nonebot-plugin-nailongremove"
|
||||
repository = "https://github.com/Refound-445/nonebot-plugin-nailongremove"
|
||||
|
||||
[project.optional-dependencies]
|
||||
|
||||
[build-system]
|
||||
requires = ["pdm-backend"]
|
||||
build-backend = "pdm.backend"
|
||||
|
||||
[tool.pdm.build]
|
||||
includes = []
|
||||
|
||||
[tool.pdm.version]
|
||||
source = "file"
|
||||
path = "nonebot_plugin_nailongremove/__init__.py"
|
1
packages/nonebot-plugin-nailongremove-cpu/.gitignore
vendored
Normal file
1
packages/nonebot-plugin-nailongremove-cpu/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
pyproject.toml
|
@ -0,0 +1,31 @@
|
||||
[project]
|
||||
name = "nonebot-plugin-nailongremove"
|
||||
version = "%%version%%"
|
||||
description = "识别目标并撤回图片插件"
|
||||
authors = [
|
||||
{ name = "445", email = "2877834692@qq.com" },
|
||||
{ name = "student_2333", email = "lgc2333@126.com" },
|
||||
]
|
||||
requires-python = "<4.0,>=3.9"
|
||||
dependencies = [
|
||||
"nonebot-plugin-nailongremove-base==%%version%%",
|
||||
"torch>=2.4",
|
||||
"torchvision>=0.19",
|
||||
"onnxruntime>=1.19.2",
|
||||
]
|
||||
license = { text = "MIT" }
|
||||
readme = "README.md"
|
||||
keywords = ["nonebot", "plugin", "image"]
|
||||
|
||||
[project.urls]
|
||||
homepage = "https://github.com/Refound-445/nonebot-plugin-nailongremove"
|
||||
repository = "https://github.com/Refound-445/nonebot-plugin-nailongremove"
|
||||
|
||||
[project.optional-dependencies]
|
||||
|
||||
[build-system]
|
||||
requires = ["pdm-backend"]
|
||||
build-backend = "pdm.backend"
|
||||
|
||||
[tool.pdm.build]
|
||||
includes = []
|
1
packages/nonebot-plugin-nailongremove-gpu/.gitignore
vendored
Normal file
1
packages/nonebot-plugin-nailongremove-gpu/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
pyproject.toml
|
@ -0,0 +1,30 @@
|
||||
[project]
|
||||
name = "nonebot-plugin-nailongremove-gpu"
|
||||
version = "%%version%%"
|
||||
description = "识别目标并撤回图片插件"
|
||||
authors = [
|
||||
{ name = "445", email = "2877834692@qq.com" },
|
||||
{ name = "student_2333", email = "lgc2333@126.com" },
|
||||
]
|
||||
requires-python = "<4.0,>=3.9"
|
||||
dependencies = [
|
||||
"nonebot-plugin-nailongremove-base==%%version%%",
|
||||
"%%torch%%",
|
||||
"onnxruntime-gpu>=1.19.2",
|
||||
]
|
||||
license = { text = "MIT" }
|
||||
readme = "README.md"
|
||||
keywords = ["nonebot", "plugin", "image"]
|
||||
|
||||
[project.urls]
|
||||
homepage = "https://github.com/Refound-445/nonebot-plugin-nailongremove"
|
||||
repository = "https://github.com/Refound-445/nonebot-plugin-nailongremove"
|
||||
|
||||
[project.optional-dependencies]
|
||||
|
||||
[build-system]
|
||||
requires = ["pdm-backend"]
|
||||
build-backend = "pdm.backend"
|
||||
|
||||
[tool.pdm.build]
|
||||
includes = []
|
@ -1,63 +1,35 @@
|
||||
[project]
|
||||
name = "nonebot-plugin-nailongremove"
|
||||
dynamic = ["version"]
|
||||
description = "识别目标并撤回图片插件"
|
||||
authors = [
|
||||
{ name = "445", email = "2877834692@qq.com" },
|
||||
{ name = "student_2333", email = "lgc2333@126.com" },
|
||||
]
|
||||
name = "nailong-workspace"
|
||||
version = "0"
|
||||
requires-python = "<4.0,>=3.9"
|
||||
dependencies = [
|
||||
"nonebot2>=2.2.0",
|
||||
"nonebot-plugin-alconna>=0.53.1",
|
||||
"nonebot-plugin-uninfo>=0.5.0",
|
||||
"opencv-python>=4.5",
|
||||
"numpy>=1.19",
|
||||
"keras>=2.4",
|
||||
"pillow>=9",
|
||||
"cookit[pydantic]>=0.8.1",
|
||||
"httpx>=0.27.2",
|
||||
"githubkit>=0.11.14",
|
||||
"yarl>=1.17.1",
|
||||
"tqdm>=4.66.6",
|
||||
"torch>=2.4",
|
||||
]
|
||||
dependencies = []
|
||||
license = { text = "MIT" }
|
||||
readme = "README.md"
|
||||
keywords = ["nonebot", "plugin", "image"]
|
||||
|
||||
[project.urls]
|
||||
homepage = "https://github.com/Refound-445/nonebot-plugin-nailongremove"
|
||||
repository = "https://github.com/Refound-445/nonebot-plugin-nailongremove"
|
||||
|
||||
[project.optional-dependencies]
|
||||
model0 = ["torchvision>=0.19"]
|
||||
model1 = []
|
||||
all = ["nonebot-plugin-nailongremove[model0,model1]"]
|
||||
[tool.pdm.dev-dependencies]
|
||||
dev = [
|
||||
"httpx>=0.27.2",
|
||||
"beautifulsoup4>=4.12.3",
|
||||
"lxml>=5.3.0",
|
||||
# "-e file:///${PROJECT_ROOT}/packages/nonebot-plugin-nailongremove-base#egg=nonebot-plugin-nailongremove-base",
|
||||
# "-e file:///${PROJECT_ROOT}/packages/nonebot-plugin-nailongremove-cpu#egg=nonebot-plugin-nailongremove",
|
||||
# "-e file:///${PROJECT_ROOT}/packages/nonebot-plugin-nailongremove-gpu#egg=nonebot-plugin-nailongremove-gpu",
|
||||
]
|
||||
|
||||
[build-system]
|
||||
requires = ["pdm-backend"]
|
||||
build-backend = "pdm.backend"
|
||||
|
||||
[tool.pdm.dev-dependencies]
|
||||
dev = [
|
||||
"nonebot-adapter-discord>=0.1.8",
|
||||
"nonebot-adapter-dodo>=0.2.1",
|
||||
"nonebot-adapter-feishu>=2.6.0",
|
||||
"nonebot-adapter-kaiheila>=0.3.4",
|
||||
"nonebot-adapter-kritor>=0.3.2",
|
||||
"nonebot-adapter-mirai>=2.3.3",
|
||||
"nonebot-adapter-onebot>=2.4.5",
|
||||
"nonebot-adapter-qq>=1.5.2",
|
||||
"nonebot-adapter-red>=0.9.0",
|
||||
"nonebot-adapter-satori>=0.12.6",
|
||||
"nonebot-adapter-telegram>=0.1.0b18",
|
||||
"nonebot-adapter-tailchat>=0.1.0b12",
|
||||
]
|
||||
[tool.pdm]
|
||||
distribution = false
|
||||
|
||||
[tool.pdm.build]
|
||||
includes = []
|
||||
[tool.pdm.scripts]
|
||||
render = { call = "scripts.render:main" }
|
||||
|
||||
[tool.pdm.version]
|
||||
source = "file"
|
||||
path = "nonebot_plugin_nailongremove/__init__.py"
|
||||
install-base = { shell = "cd packages/nonebot-plugin-nailongremove-base && pdm install && cd ../.." }
|
||||
install-cpu-s = { shell = "cd packages/nonebot-plugin-nailongremove-cpu && pdm install && cd ../.." }
|
||||
install-gpu-s = { shell = "cd packages/nonebot-plugin-nailongremove-gpu && pdm install && cd ../.." }
|
||||
install-cpu = { composite = ["install-base", "install-cpu"] }
|
||||
install-gpu = { composite = ["install-base", "install-gpu"] }
|
||||
|
||||
lock-base = { shell = "cd packages/nonebot-plugin-nailongremove-base && pdm lock && cd ../.." }
|
||||
|
120
scripts/render.py
Normal file
120
scripts/render.py
Normal file
@ -0,0 +1,120 @@
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import List, Optional, TypedDict, cast
|
||||
|
||||
import bs4
|
||||
import httpx
|
||||
import tomllib
|
||||
from packaging.version import Version
|
||||
|
||||
ROOT_PATH = Path(__file__).parent.parent
|
||||
PACKAGES_PATH = ROOT_PATH / "packages"
|
||||
SUFFIX = ".template.toml"
|
||||
TORCH_BASE = "https://download.pytorch.org"
|
||||
TORCH_INDEX = f"{TORCH_BASE}/whl/cu124"
|
||||
|
||||
PKG_FILENAME_RE = re.compile(
|
||||
r"^(?P<name>.+?)-(?P<ver>.+?)-(?P<py>.+?)-(?P<abi>.+?)-(?P<platform>.+?)"
|
||||
r"(?P<ext>\..+)$",
|
||||
)
|
||||
VERSION_RE = re.compile(
|
||||
r"""^(\s*)__version__(\s*)=(\s*)(?P<q>['"])(?P<v>.+?)(?P=q)(\s*);?(\s*)$""",
|
||||
re.MULTILINE,
|
||||
)
|
||||
|
||||
|
||||
class PkgFilenameReGroups(TypedDict):
|
||||
name: str
|
||||
ver: str
|
||||
py: str
|
||||
abi: str
|
||||
platform: str
|
||||
ext: str
|
||||
|
||||
|
||||
def get_version() -> str:
|
||||
base_pkg_path = PACKAGES_PATH / "nonebot-plugin-nailongremove-base"
|
||||
base_toml_path = base_pkg_path / "pyproject.toml"
|
||||
toml_dict = tomllib.loads(base_toml_path.read_text(encoding="u8"))
|
||||
version = toml_dict["tool"]["pdm"]["version"]
|
||||
if version["source"] != "file":
|
||||
raise NotImplementedError
|
||||
version_file_path = base_pkg_path / version["path"]
|
||||
version_file_raw = version_file_path.read_text(encoding="u8")
|
||||
version_match = VERSION_RE.search(version_file_raw)
|
||||
if not version_match:
|
||||
raise ValueError("Version not found in pyproject.toml")
|
||||
return version_match.group("v")
|
||||
|
||||
|
||||
VERSION = get_version()
|
||||
|
||||
|
||||
def format_markers(m: re.Match[str]) -> Optional[str]:
|
||||
g = cast(PkgFilenameReGroups, m.groupdict())
|
||||
if (not g["py"].startswith("cp")) or (g["abi"].endswith("m")):
|
||||
return None
|
||||
|
||||
markers: List[str] = []
|
||||
markers.append(f"python_version == '{g['py'][2]}.{g['py'][3:]}'")
|
||||
|
||||
common_os = {
|
||||
"win": "win32",
|
||||
"linux": "linux",
|
||||
}
|
||||
if x := next((x for x in common_os if g["platform"].startswith(f"{x}_")), None):
|
||||
markers.extend(
|
||||
(
|
||||
f"sys_platform == '{common_os[x]}'",
|
||||
f"platform_machine == '{g['platform'][len(x) + 1:]}'",
|
||||
),
|
||||
)
|
||||
|
||||
return " and ".join(markers)
|
||||
|
||||
|
||||
def get_torch_deps() -> str:
|
||||
def get_deps(pkg: str) -> List[str]:
|
||||
html = httpx.get(f"{TORCH_INDEX}/{pkg}/").raise_for_status().text
|
||||
soup = bs4.BeautifulSoup(html, "lxml")
|
||||
tags: "bs4.ResultSet[bs4.Tag]" = soup.find_all("a")
|
||||
links = [
|
||||
(m, f"{TORCH_BASE}{h}")
|
||||
for x in tags
|
||||
if (
|
||||
isinstance((h := x.get("href")), str)
|
||||
and (m := PKG_FILENAME_RE.match(x.text))
|
||||
)
|
||||
]
|
||||
links.sort(key=lambda x: Version(x[0]["ver"]), reverse=True)
|
||||
ver: str = links[1][0]["ver"]
|
||||
links = [x for x in links if x[0]["ver"] == ver]
|
||||
return [f"{pkg} @ {x} ; {ms}" for m, x in links if (ms := format_markers(m))]
|
||||
|
||||
deps = [
|
||||
*get_deps("torch"),
|
||||
*get_deps("torchvision"),
|
||||
]
|
||||
return "\n ".join(f'"{x}",' for x in deps).strip(",")
|
||||
|
||||
|
||||
TORCH = get_torch_deps()
|
||||
|
||||
|
||||
def process(file_path: Path):
|
||||
file_path.with_name(file_path.name.replace(".template", "")).write_text(
|
||||
file_path.read_text(encoding="u8")
|
||||
.replace("%%version%%", VERSION)
|
||||
.replace('"%%torch%%"', TORCH),
|
||||
"u8",
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
for p in PACKAGES_PATH.iterdir():
|
||||
for f in (x for x in p.iterdir() if x.name.endswith(SUFFIX)):
|
||||
process(f)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Reference in New Issue
Block a user