nonebot-plugin-easy-aidraw 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Agnes4m <Z735803792@163.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,193 @@
1
+ Metadata-Version: 2.4
2
+ Name: nonebot-plugin-easy-aidraw
3
+ Version: 0.1.0
4
+ Summary: AI绘图插件 for NoneBot2,支持多种绘图API
5
+ Author-email: Agnes4m <Z735803792@163.com>
6
+ License-Expression: MIT
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: nonebot2>=2.5.0
11
+ Requires-Dist: httpx>=0.25.0
12
+ Requires-Dist: pillow>=10.0.0
13
+ Requires-Dist: pydantic>=2.0.0
14
+ Requires-Dist: nonebot-plugin-alconna>=0.62.0
15
+ Dynamic: license-file
16
+
17
+ <!-- markdownlint-disable MD026 MD031 MD033 MD036 MD041 MD046 MD051 -->
18
+ <div align="center">
19
+ <img src="https://raw.githubusercontent.com/Agnes4m/nonebot_plugin_l4d2_server/main/image/logo.png" width="180" height="180" alt="AgnesDigitalLogo">
20
+ <br>
21
+ <p><img src="https://s2.loli.net/2022/06/16/xsVUGRrkbn1ljTD.png" width="240" alt="NoneBotPluginText"></p>
22
+ </div>
23
+
24
+ <div align="center">
25
+
26
+ # nonebot_plugin_aidraw 0.1.0
27
+
28
+ _✨Nonebot & AI 绘图 插件 ✨_
29
+
30
+ <div align = "center">
31
+ <a href="https://github.com/Agnes4m/nonebot_plugin_aidraw" target="_blank">仓库</a> &nbsp; · &nbsp;
32
+ <a href="https://github.com/Agnes4m/nonebot_plugin_aidraw/issues" target="_blank">指令 & 反馈</a> &nbsp; · &nbsp;
33
+ <a href="https://github.com/Agnes4m/nonebot_plugin_aidraw/issues" target="_blank">常见问题</a>
34
+ </div><br>
35
+
36
+ <img src="https://img.shields.io/badge/python-3.10+-blue?logo=python&logoColor=edb641" alt="python">
37
+ <a href ="LICENSE">
38
+ <img src="https://img.shields.io/github/license/Agnes4m/nonebot_plugin_aidraw" alt="aidrawlogo">
39
+ </a>
40
+ <img src="https://img.shields.io/badge/nonebot-2.1.0+-red.svg" alt="NoneBot">
41
+ <a href="https://pypi.python.org/pypi/nonebot-plugin-aidraw">
42
+ <img src="https://img.shields.io/pypi/v/nonebot-plugin-aidraw?logo=python&logoColor=edb641" alt="python">
43
+ </a>
44
+ </br>
45
+ <a href="https://github.com/astral-sh/ruff">
46
+ <img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json" alt="ruff">
47
+ </a>
48
+ <a href="https://github.com/psf/black">
49
+ <img src="https://img.shields.io/badge/code%20style-black-000000.svg?logo=python&logoColor=edb641" alt="black">
50
+ </a>
51
+
52
+ <img src="https://img.shields.io/badge/alconna-0.50.0+-red.svg" alt="NoneBot">
53
+
54
+ <a href="https://github.com/Agnes4m/nonebot_plugin_aidraw/issues">
55
+ <img alt="GitHub issues" src="https://img.shields.io/github/issues/Agnes4m/nonebot_plugin_aidraw" alt="issues">
56
+ </a>
57
+
58
+ <a href="https://pypi.python.org/pypi/nonebot-plugin-aidraw">
59
+ <img src="https://img.shields.io/pypi/dm/nonebot-plugin-aidraw" alt="pypi download">
60
+ </a>
61
+ </br>
62
+ <a href="https://jq.qq.com/?_wv=1027&k=HdjoCcAe">
63
+ <img src="https://img.shields.io/badge/QQ%E7%BE%A4-399365126-orange?style=flat-square" alt="QQ Chat Group">
64
+ </a>
65
+ </div>
66
+
67
+ ## 快速使用
68
+
69
+
70
+ ### 安装
71
+
72
+ 以下提到的方法 任选**其一** 即可
73
+
74
+ <details open>
75
+ <summary>[推荐] 使用 nb-cli 安装</summary>
76
+ 在 nonebot2 项目的根目录下打开命令行, 输入以下指令即可安装
77
+
78
+ ```bash
79
+ nb plugin install nonebot-plugin-aidraw
80
+ ```
81
+
82
+ </details>
83
+
84
+ <details>
85
+ <summary>使用包管理器安装</summary>
86
+ 在 nonebot2 项目的插件目录下, 打开命令行, 根据你使用的包管理器, 输入相应的安装命令
87
+
88
+ <details>
89
+ <summary>pip</summary>
90
+
91
+ ```bash
92
+ pip install nonebot-plugin-aidraw
93
+ ```
94
+
95
+ </details>
96
+ <details>
97
+ <summary>pdm</summary>
98
+
99
+ ```bash
100
+ pdm add nonebot-plugin-aidraw
101
+ ```
102
+
103
+ </details>
104
+ <details>
105
+ <summary>poetry</summary>
106
+
107
+ ```bash
108
+ poetry add nonebot-plugin-aidraw
109
+ ```
110
+
111
+ </details>
112
+ <details>
113
+ <summary>conda</summary>
114
+
115
+ ```bash
116
+ conda install nonebot-plugin-aidraw
117
+ ```
118
+
119
+ </details>
120
+ <details>
121
+ <summary>uv</summary>
122
+
123
+ ```bash
124
+ uv install nonebot-plugin-aidraw
125
+ ```
126
+
127
+ </details>
128
+ </details>
129
+
130
+ ### env最简化配置
131
+
132
+ draw_api_url = "http://localhost:8080" # API 地址
133
+ draw_api_key = "" # API 密钥
134
+ draw_model = "gpt-image-2" # 模型名称
135
+
136
+ ## 功能
137
+
138
+ - `绘图` 调用绘图 API 生成图片
139
+
140
+ ### 支持的绘图后端
141
+
142
+ - 任意 OpenAI 兼容的 `/v1/images/generations` 接口(如 OpenAI、Gemini、本地自部署等)
143
+ - 返回 `url` 时直接转发图片链接
144
+ - 自定义 API 地址、密钥、模型、尺寸、超时
145
+
146
+ ### NSFW 过滤
147
+
148
+ - 群聊场景下可选启用 NSFW 关键词过滤(`DRAW_NSFW_ENABLED=true` + `DRAW_NSFW_KEYWORDS=[...]`)
149
+ - 私聊自动跳过检测
150
+
151
+ ### 输出容错
152
+
153
+ - 一旦拿到图片 URL,即使后续发送环节出现小问题,也不会再向用户推送错误消息,避免误扰
154
+
155
+
156
+ ## 主要功能
157
+
158
+ - [x] 调用 OpenAI 兼容绘图接口生成图片
159
+ - [x] 支持自定义 API 地址、密钥、模型
160
+ - [x] 支持 base64 / URL 两种返回格式
161
+ - [x] 群聊 NSFW 关键词过滤(可关闭)
162
+ - [x] 黑白名单访问控制(支持群组/用户 ID)
163
+
164
+ ## env 设置
165
+
166
+ ```bash
167
+ draw_api_url = "http://localhost:8080" # API 地址
168
+ draw_api_key = "" # API 密钥
169
+ draw_model = "flux" # 模型名称
170
+ draw_backend = "openai" # 后端类型: openai/gemini/sd
171
+ draw_default_size = "1024x1024" # 图片尺寸
172
+ draw_timeout = 120 # 超时时间(秒)
173
+ draw_nsfw_enabled = false # NSFW 检测(仅群聊)
174
+ draw_nsfw_keywords = [] # NSFW 关键词
175
+ draw_whitelist_mode = false # 白名单模式
176
+ draw_whitelist = [] # 白名单
177
+ draw_blacklist = [] # 黑名单
178
+ ```
179
+
180
+ > `draw_api_url` 留空时使用后端默认地址;填写时作为后缀拼接到 base URL 后面
181
+ > ID 格式:`group_123456`(群组)或 `123456`(私聊)
182
+
183
+ ## 其他
184
+
185
+ - 如果您有发现 BUG 或者更好的建议,欢迎提 Issue & Pr
186
+ - 如果本插件对你有帮助,不要忘了点个 Star~
187
+ - 本项目仅供学习使用,请勿用于商业用途
188
+ - [MIT License](https://github.com/Agnes4m/nonebot_plugin_aidraw/blob/main/LICENSE) ©[@Agnes4m](https://github.com/Agnes4m)
189
+
190
+ ## 🌐 感谢
191
+
192
+ - [nonebot2](https://github.com/nonebot/nonebot2) - 聊天机器人的基础框架
193
+ - [nonebot-plugin-alconna](https://github.com/nonebot-plugin-alconna/nonebot-plugin-alconna) - NoneBot2 的 Alconna 适配
@@ -0,0 +1,177 @@
1
+ <!-- markdownlint-disable MD026 MD031 MD033 MD036 MD041 MD046 MD051 -->
2
+ <div align="center">
3
+ <img src="https://raw.githubusercontent.com/Agnes4m/nonebot_plugin_l4d2_server/main/image/logo.png" width="180" height="180" alt="AgnesDigitalLogo">
4
+ <br>
5
+ <p><img src="https://s2.loli.net/2022/06/16/xsVUGRrkbn1ljTD.png" width="240" alt="NoneBotPluginText"></p>
6
+ </div>
7
+
8
+ <div align="center">
9
+
10
+ # nonebot_plugin_aidraw 0.1.0
11
+
12
+ _✨Nonebot & AI 绘图 插件 ✨_
13
+
14
+ <div align = "center">
15
+ <a href="https://github.com/Agnes4m/nonebot_plugin_aidraw" target="_blank">仓库</a> &nbsp; · &nbsp;
16
+ <a href="https://github.com/Agnes4m/nonebot_plugin_aidraw/issues" target="_blank">指令 & 反馈</a> &nbsp; · &nbsp;
17
+ <a href="https://github.com/Agnes4m/nonebot_plugin_aidraw/issues" target="_blank">常见问题</a>
18
+ </div><br>
19
+
20
+ <img src="https://img.shields.io/badge/python-3.10+-blue?logo=python&logoColor=edb641" alt="python">
21
+ <a href ="LICENSE">
22
+ <img src="https://img.shields.io/github/license/Agnes4m/nonebot_plugin_aidraw" alt="aidrawlogo">
23
+ </a>
24
+ <img src="https://img.shields.io/badge/nonebot-2.1.0+-red.svg" alt="NoneBot">
25
+ <a href="https://pypi.python.org/pypi/nonebot-plugin-aidraw">
26
+ <img src="https://img.shields.io/pypi/v/nonebot-plugin-aidraw?logo=python&logoColor=edb641" alt="python">
27
+ </a>
28
+ </br>
29
+ <a href="https://github.com/astral-sh/ruff">
30
+ <img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json" alt="ruff">
31
+ </a>
32
+ <a href="https://github.com/psf/black">
33
+ <img src="https://img.shields.io/badge/code%20style-black-000000.svg?logo=python&logoColor=edb641" alt="black">
34
+ </a>
35
+
36
+ <img src="https://img.shields.io/badge/alconna-0.50.0+-red.svg" alt="NoneBot">
37
+
38
+ <a href="https://github.com/Agnes4m/nonebot_plugin_aidraw/issues">
39
+ <img alt="GitHub issues" src="https://img.shields.io/github/issues/Agnes4m/nonebot_plugin_aidraw" alt="issues">
40
+ </a>
41
+
42
+ <a href="https://pypi.python.org/pypi/nonebot-plugin-aidraw">
43
+ <img src="https://img.shields.io/pypi/dm/nonebot-plugin-aidraw" alt="pypi download">
44
+ </a>
45
+ </br>
46
+ <a href="https://jq.qq.com/?_wv=1027&k=HdjoCcAe">
47
+ <img src="https://img.shields.io/badge/QQ%E7%BE%A4-399365126-orange?style=flat-square" alt="QQ Chat Group">
48
+ </a>
49
+ </div>
50
+
51
+ ## 快速使用
52
+
53
+
54
+ ### 安装
55
+
56
+ 以下提到的方法 任选**其一** 即可
57
+
58
+ <details open>
59
+ <summary>[推荐] 使用 nb-cli 安装</summary>
60
+ 在 nonebot2 项目的根目录下打开命令行, 输入以下指令即可安装
61
+
62
+ ```bash
63
+ nb plugin install nonebot-plugin-aidraw
64
+ ```
65
+
66
+ </details>
67
+
68
+ <details>
69
+ <summary>使用包管理器安装</summary>
70
+ 在 nonebot2 项目的插件目录下, 打开命令行, 根据你使用的包管理器, 输入相应的安装命令
71
+
72
+ <details>
73
+ <summary>pip</summary>
74
+
75
+ ```bash
76
+ pip install nonebot-plugin-aidraw
77
+ ```
78
+
79
+ </details>
80
+ <details>
81
+ <summary>pdm</summary>
82
+
83
+ ```bash
84
+ pdm add nonebot-plugin-aidraw
85
+ ```
86
+
87
+ </details>
88
+ <details>
89
+ <summary>poetry</summary>
90
+
91
+ ```bash
92
+ poetry add nonebot-plugin-aidraw
93
+ ```
94
+
95
+ </details>
96
+ <details>
97
+ <summary>conda</summary>
98
+
99
+ ```bash
100
+ conda install nonebot-plugin-aidraw
101
+ ```
102
+
103
+ </details>
104
+ <details>
105
+ <summary>uv</summary>
106
+
107
+ ```bash
108
+ uv install nonebot-plugin-aidraw
109
+ ```
110
+
111
+ </details>
112
+ </details>
113
+
114
+ ### env最简化配置
115
+
116
+ draw_api_url = "http://localhost:8080" # API 地址
117
+ draw_api_key = "" # API 密钥
118
+ draw_model = "gpt-image-2" # 模型名称
119
+
120
+ ## 功能
121
+
122
+ - `绘图` 调用绘图 API 生成图片
123
+
124
+ ### 支持的绘图后端
125
+
126
+ - 任意 OpenAI 兼容的 `/v1/images/generations` 接口(如 OpenAI、Gemini、本地自部署等)
127
+ - 返回 `url` 时直接转发图片链接
128
+ - 自定义 API 地址、密钥、模型、尺寸、超时
129
+
130
+ ### NSFW 过滤
131
+
132
+ - 群聊场景下可选启用 NSFW 关键词过滤(`DRAW_NSFW_ENABLED=true` + `DRAW_NSFW_KEYWORDS=[...]`)
133
+ - 私聊自动跳过检测
134
+
135
+ ### 输出容错
136
+
137
+ - 一旦拿到图片 URL,即使后续发送环节出现小问题,也不会再向用户推送错误消息,避免误扰
138
+
139
+
140
+ ## 主要功能
141
+
142
+ - [x] 调用 OpenAI 兼容绘图接口生成图片
143
+ - [x] 支持自定义 API 地址、密钥、模型
144
+ - [x] 支持 base64 / URL 两种返回格式
145
+ - [x] 群聊 NSFW 关键词过滤(可关闭)
146
+ - [x] 黑白名单访问控制(支持群组/用户 ID)
147
+
148
+ ## env 设置
149
+
150
+ ```bash
151
+ draw_api_url = "http://localhost:8080" # API 地址
152
+ draw_api_key = "" # API 密钥
153
+ draw_model = "flux" # 模型名称
154
+ draw_backend = "openai" # 后端类型: openai/gemini/sd
155
+ draw_default_size = "1024x1024" # 图片尺寸
156
+ draw_timeout = 120 # 超时时间(秒)
157
+ draw_nsfw_enabled = false # NSFW 检测(仅群聊)
158
+ draw_nsfw_keywords = [] # NSFW 关键词
159
+ draw_whitelist_mode = false # 白名单模式
160
+ draw_whitelist = [] # 白名单
161
+ draw_blacklist = [] # 黑名单
162
+ ```
163
+
164
+ > `draw_api_url` 留空时使用后端默认地址;填写时作为后缀拼接到 base URL 后面
165
+ > ID 格式:`group_123456`(群组)或 `123456`(私聊)
166
+
167
+ ## 其他
168
+
169
+ - 如果您有发现 BUG 或者更好的建议,欢迎提 Issue & Pr
170
+ - 如果本插件对你有帮助,不要忘了点个 Star~
171
+ - 本项目仅供学习使用,请勿用于商业用途
172
+ - [MIT License](https://github.com/Agnes4m/nonebot_plugin_aidraw/blob/main/LICENSE) ©[@Agnes4m](https://github.com/Agnes4m)
173
+
174
+ ## 🌐 感谢
175
+
176
+ - [nonebot2](https://github.com/nonebot/nonebot2) - 聊天机器人的基础框架
177
+ - [nonebot-plugin-alconna](https://github.com/nonebot-plugin-alconna/nonebot-plugin-alconna) - NoneBot2 的 Alconna 适配
@@ -0,0 +1,24 @@
1
+ """nonebot_plugin_easy_aidraw - AI绘图插件"""
2
+
3
+ __version__ = "0.1.0"
4
+
5
+ from nonebot import require
6
+ from nonebot.plugin import PluginMetadata, inherit_supported_adapters
7
+
8
+ from .config import EnvConfig
9
+ from .handler import draw_command
10
+
11
+ require("nonebot_plugin_alconna")
12
+
13
+ __plugin_meta__ = PluginMetadata(
14
+ name="AI绘图",
15
+ description="AI绘图插件,支持调用本地或远程的绘图API生成图片",
16
+ usage="使用 /绘图 <提示词> 生成图片\n例如: /绘图 一只可爱的小猫",
17
+ type="application",
18
+ homepage="https://github.com/Agnes4m/nonebot_plugin_easy_aidraw",
19
+ config=EnvConfig,
20
+ supported_adapters=inherit_supported_adapters("nonebot_plugin_alconna"),
21
+ extra={"version": __version__, "author": "Agnes4m"},
22
+ )
23
+
24
+ __all__ = ["EnvConfig", "__plugin_meta__", "draw_command"]
@@ -0,0 +1,145 @@
1
+ """绘图 API 调用与配置访问"""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+
7
+ import httpx
8
+ from nonebot import get_driver
9
+ from nonebot.adapters import Event
10
+ from nonebot.log import logger
11
+
12
+ _config: dict | None = None
13
+
14
+ BACKEND_BASES = {
15
+ "openai": "https://api.openai.com",
16
+ "gemini": "https://generativelanguage.googleapis.com",
17
+ "sd": "http://localhost:7860",
18
+ }
19
+
20
+ BACKEND_PATHS = {
21
+ "openai": "/v1/images/generations",
22
+ "gemini": "/v1beta/images/generations",
23
+ "sd": "/sdapi/v1/txt2img",
24
+ }
25
+
26
+
27
+ def _get_config() -> dict:
28
+ """延迟获取配置"""
29
+ global _config
30
+ if _config is None:
31
+ config_dict = dict(get_driver().config)
32
+ api_url = config_dict.get("draw_api_url", "")
33
+ backend = config_dict.get("draw_backend", "openai")
34
+ base = BACKEND_BASES.get(backend, BACKEND_BASES["openai"])
35
+ path = api_url if api_url else BACKEND_PATHS.get(backend, BACKEND_PATHS["openai"])
36
+ full_url = base + path if not path.startswith("http") else path
37
+ _config = {
38
+ "api_url": full_url,
39
+ "api_key": config_dict.get("draw_api_key", ""),
40
+ "model": config_dict.get("draw_model", "flux"),
41
+ "default_size": config_dict.get("draw_default_size", "1024x1024"),
42
+ "timeout": config_dict.get("draw_timeout", 120),
43
+ "nsfw_enabled": config_dict.get("draw_nsfw_enabled", False),
44
+ "nsfw_keywords": config_dict.get("draw_nsfw_keywords", []),
45
+ }
46
+ return _config
47
+
48
+
49
+ def is_private_message(event: Event) -> bool:
50
+ """判断是否为私聊消息"""
51
+ session_id = event.get_session_id()
52
+ return not session_id.startswith(("group_", "channel_"))
53
+
54
+
55
+ def check_whitelist_blacklist(event: Event) -> tuple[bool, str]:
56
+ """检查黑白名单,返回 (是否通过, 原因)"""
57
+ config = _get_config()
58
+ session_id = event.get_session_id()
59
+
60
+ if session_id.startswith("group_"):
61
+ target_id = "group_" + session_id.split("_")[1]
62
+ else:
63
+ target_id = session_id.split("_", 1)[-1]
64
+
65
+ whitelist = config.get("draw_whitelist", [])
66
+ blacklist = config.get("draw_blacklist", [])
67
+ whitelist_mode = config.get("draw_whitelist_mode", False)
68
+
69
+ if whitelist_mode:
70
+ if target_id not in whitelist:
71
+ return False, "不在白名单中"
72
+ return True, ""
73
+ else:
74
+ if target_id in blacklist:
75
+ return False, "在黑名单中"
76
+ return True, ""
77
+
78
+
79
+ def check_nsfw(prompt: str) -> tuple[bool, str | None]:
80
+ """检查 prompt 是否包含 NSFW 关键词"""
81
+ config = _get_config()
82
+
83
+ if not config.get("nsfw_enabled", False):
84
+ return False, None
85
+
86
+ nsfw_keywords = config.get("nsfw_keywords", [])
87
+ if not nsfw_keywords:
88
+ return False, None
89
+
90
+ words = re.findall(r"[\w\u4e00-\u9fff]+", prompt.lower())
91
+
92
+ nsfw_set = {kw.lower() for kw in nsfw_keywords}
93
+ for word in words:
94
+ if word in nsfw_set:
95
+ return True, word
96
+
97
+ return False, None
98
+
99
+
100
+ async def generate_image(prompt: str, image_urls: list[str] | None = None) -> str | None:
101
+ """调用API生成图片,返回图片URL"""
102
+ config = _get_config()
103
+
104
+ if not config["api_key"]:
105
+ raise ValueError("未配置 DRAW_API_KEY,请检查配置文件")
106
+
107
+ headers = {
108
+ "Authorization": f"Bearer {config['api_key']}",
109
+ "Content-Type": "application/json",
110
+ }
111
+
112
+ payload = {
113
+ "model": config["model"],
114
+ "prompt": prompt,
115
+ "size": config["default_size"],
116
+ }
117
+
118
+ if image_urls:
119
+ payload["extra_body"] = {
120
+ "image": image_urls,
121
+ "response_format": "url",
122
+ }
123
+
124
+ async with httpx.AsyncClient(timeout=config["timeout"]) as client:
125
+ logger.info(
126
+ f"[绘图] 发起请求: url={config['api_url']}, "
127
+ f"model={config['model']}, prompt_len={len(prompt)}, "
128
+ f"size={config['default_size']}, image_count={len(image_urls) if image_urls else 0}"
129
+ )
130
+ logger.debug(f"[绘图] 请求体: {payload}")
131
+ logger.debug(f"[绘图] 请求头: {headers}")
132
+ response = await client.post(config["api_url"], json=payload, headers=headers)
133
+ logger.info(f"[绘图] 响应状态: {response.status_code}")
134
+ logger.debug(f"[绘图] 响应体: {response.text[:500]}")
135
+ response.raise_for_status()
136
+
137
+ data = response.json()
138
+ logger.debug(f"[绘图] API返回: {data}")
139
+
140
+ if "data" in data and len(data["data"]) > 0:
141
+ img_data = data["data"][0]
142
+ if url := img_data.get("url"):
143
+ return url
144
+ raise ValueError("API未返回图片URL")
145
+ raise ValueError(f"API返回格式异常: {data}")
@@ -0,0 +1,20 @@
1
+ """子包配置模块"""
2
+
3
+ from pydantic import BaseModel
4
+
5
+
6
+ class EnvConfig(BaseModel):
7
+ draw_api_url: str = "http://localhost:8080"
8
+ draw_api_key: str = ""
9
+ draw_model: str = "flux"
10
+ draw_backend: str = "openai"
11
+ draw_default_size: str = "1024x1024"
12
+ draw_timeout: int = 120
13
+ draw_nsfw_enabled: bool = False
14
+ draw_nsfw_keywords: list[str] = []
15
+ draw_whitelist_mode: bool = False
16
+ draw_whitelist: list[str] = []
17
+ draw_blacklist: list[str] = []
18
+
19
+ class Config:
20
+ populate_by_name = True
@@ -0,0 +1,54 @@
1
+ """命令注册与业务处理"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from arclet.alconna import Alconna, CommandMeta
6
+ from nonebot.adapters import Event
7
+ from nonebot.log import logger
8
+ from nonebot_plugin_alconna import Image, UniMessage, UniMsg, on_alconna
9
+
10
+ from .api import check_nsfw, check_whitelist_blacklist, generate_image, is_private_message
11
+
12
+ draw_alc = Alconna(
13
+ "绘图",
14
+ meta=CommandMeta(description="AI绘图命令", example="/绘图 一只可爱的小猫"),
15
+ )
16
+
17
+ draw_command = on_alconna(draw_alc, auto_send_output=False, use_origin=True, skip_for_unmatch=False)
18
+
19
+
20
+ @draw_command.handle()
21
+ async def handle_draw(event: Event, unimsg: UniMsg):
22
+ if not (passed := check_whitelist_blacklist(event))[0]:
23
+ return await UniMessage.text(f"❌ 访问被拒绝:{passed[1]}").finish()
24
+
25
+ prompt = unimsg.extract_plain_text().strip()
26
+ for prefix in ["/绘图", "绘图", "/画", "画"]:
27
+ if prompt.startswith(prefix):
28
+ prompt = prompt[len(prefix) :].strip()
29
+ break
30
+
31
+ image_urls = [img.data["url"] for img in unimsg[Image] if img.data.get("url")]
32
+
33
+ logger.info(f"[绘图] 用户请求绘图: {prompt}, 附带图片: {len(image_urls)}")
34
+
35
+ if not is_private_message(event):
36
+ is_nsfw, keyword = check_nsfw(prompt)
37
+ if is_nsfw:
38
+ logger.warning(f"[绘图] 检测到敏感词: {keyword}")
39
+ return await UniMessage.text(f"❌ 检测到敏感词「{keyword}」,请修改提示词").finish()
40
+
41
+ if not prompt:
42
+ return await UniMessage.text("❌ 请提供绘图提示词\n例如: /绘图 一只可爱的小猫").finish()
43
+ await UniMessage.text("🎨 正在生成图片,请稍候...").send()
44
+
45
+ image_url = await generate_image(prompt, image_urls or None)
46
+
47
+ if not image_url:
48
+ return await UniMessage.text("❌ 图片生成失败").finish()
49
+ logger.info(f"[绘图] 图片生成成功: {image_url}")
50
+ try:
51
+ await UniMessage.image(url=image_url).send()
52
+ except Exception as e:
53
+ logger.error(f"[绘图] 发送失败: {e}")
54
+ await UniMessage.text(f"❌ 发送失败,可手动访问: {image_url}").finish()
@@ -0,0 +1,193 @@
1
+ Metadata-Version: 2.4
2
+ Name: nonebot-plugin-easy-aidraw
3
+ Version: 0.1.0
4
+ Summary: AI绘图插件 for NoneBot2,支持多种绘图API
5
+ Author-email: Agnes4m <Z735803792@163.com>
6
+ License-Expression: MIT
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: nonebot2>=2.5.0
11
+ Requires-Dist: httpx>=0.25.0
12
+ Requires-Dist: pillow>=10.0.0
13
+ Requires-Dist: pydantic>=2.0.0
14
+ Requires-Dist: nonebot-plugin-alconna>=0.62.0
15
+ Dynamic: license-file
16
+
17
+ <!-- markdownlint-disable MD026 MD031 MD033 MD036 MD041 MD046 MD051 -->
18
+ <div align="center">
19
+ <img src="https://raw.githubusercontent.com/Agnes4m/nonebot_plugin_l4d2_server/main/image/logo.png" width="180" height="180" alt="AgnesDigitalLogo">
20
+ <br>
21
+ <p><img src="https://s2.loli.net/2022/06/16/xsVUGRrkbn1ljTD.png" width="240" alt="NoneBotPluginText"></p>
22
+ </div>
23
+
24
+ <div align="center">
25
+
26
+ # nonebot_plugin_aidraw 0.1.0
27
+
28
+ _✨Nonebot & AI 绘图 插件 ✨_
29
+
30
+ <div align = "center">
31
+ <a href="https://github.com/Agnes4m/nonebot_plugin_aidraw" target="_blank">仓库</a> &nbsp; · &nbsp;
32
+ <a href="https://github.com/Agnes4m/nonebot_plugin_aidraw/issues" target="_blank">指令 & 反馈</a> &nbsp; · &nbsp;
33
+ <a href="https://github.com/Agnes4m/nonebot_plugin_aidraw/issues" target="_blank">常见问题</a>
34
+ </div><br>
35
+
36
+ <img src="https://img.shields.io/badge/python-3.10+-blue?logo=python&logoColor=edb641" alt="python">
37
+ <a href ="LICENSE">
38
+ <img src="https://img.shields.io/github/license/Agnes4m/nonebot_plugin_aidraw" alt="aidrawlogo">
39
+ </a>
40
+ <img src="https://img.shields.io/badge/nonebot-2.1.0+-red.svg" alt="NoneBot">
41
+ <a href="https://pypi.python.org/pypi/nonebot-plugin-aidraw">
42
+ <img src="https://img.shields.io/pypi/v/nonebot-plugin-aidraw?logo=python&logoColor=edb641" alt="python">
43
+ </a>
44
+ </br>
45
+ <a href="https://github.com/astral-sh/ruff">
46
+ <img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json" alt="ruff">
47
+ </a>
48
+ <a href="https://github.com/psf/black">
49
+ <img src="https://img.shields.io/badge/code%20style-black-000000.svg?logo=python&logoColor=edb641" alt="black">
50
+ </a>
51
+
52
+ <img src="https://img.shields.io/badge/alconna-0.50.0+-red.svg" alt="NoneBot">
53
+
54
+ <a href="https://github.com/Agnes4m/nonebot_plugin_aidraw/issues">
55
+ <img alt="GitHub issues" src="https://img.shields.io/github/issues/Agnes4m/nonebot_plugin_aidraw" alt="issues">
56
+ </a>
57
+
58
+ <a href="https://pypi.python.org/pypi/nonebot-plugin-aidraw">
59
+ <img src="https://img.shields.io/pypi/dm/nonebot-plugin-aidraw" alt="pypi download">
60
+ </a>
61
+ </br>
62
+ <a href="https://jq.qq.com/?_wv=1027&k=HdjoCcAe">
63
+ <img src="https://img.shields.io/badge/QQ%E7%BE%A4-399365126-orange?style=flat-square" alt="QQ Chat Group">
64
+ </a>
65
+ </div>
66
+
67
+ ## 快速使用
68
+
69
+
70
+ ### 安装
71
+
72
+ 以下提到的方法 任选**其一** 即可
73
+
74
+ <details open>
75
+ <summary>[推荐] 使用 nb-cli 安装</summary>
76
+ 在 nonebot2 项目的根目录下打开命令行, 输入以下指令即可安装
77
+
78
+ ```bash
79
+ nb plugin install nonebot-plugin-aidraw
80
+ ```
81
+
82
+ </details>
83
+
84
+ <details>
85
+ <summary>使用包管理器安装</summary>
86
+ 在 nonebot2 项目的插件目录下, 打开命令行, 根据你使用的包管理器, 输入相应的安装命令
87
+
88
+ <details>
89
+ <summary>pip</summary>
90
+
91
+ ```bash
92
+ pip install nonebot-plugin-aidraw
93
+ ```
94
+
95
+ </details>
96
+ <details>
97
+ <summary>pdm</summary>
98
+
99
+ ```bash
100
+ pdm add nonebot-plugin-aidraw
101
+ ```
102
+
103
+ </details>
104
+ <details>
105
+ <summary>poetry</summary>
106
+
107
+ ```bash
108
+ poetry add nonebot-plugin-aidraw
109
+ ```
110
+
111
+ </details>
112
+ <details>
113
+ <summary>conda</summary>
114
+
115
+ ```bash
116
+ conda install nonebot-plugin-aidraw
117
+ ```
118
+
119
+ </details>
120
+ <details>
121
+ <summary>uv</summary>
122
+
123
+ ```bash
124
+ uv install nonebot-plugin-aidraw
125
+ ```
126
+
127
+ </details>
128
+ </details>
129
+
130
+ ### env最简化配置
131
+
132
+ draw_api_url = "http://localhost:8080" # API 地址
133
+ draw_api_key = "" # API 密钥
134
+ draw_model = "gpt-image-2" # 模型名称
135
+
136
+ ## 功能
137
+
138
+ - `绘图` 调用绘图 API 生成图片
139
+
140
+ ### 支持的绘图后端
141
+
142
+ - 任意 OpenAI 兼容的 `/v1/images/generations` 接口(如 OpenAI、Gemini、本地自部署等)
143
+ - 返回 `url` 时直接转发图片链接
144
+ - 自定义 API 地址、密钥、模型、尺寸、超时
145
+
146
+ ### NSFW 过滤
147
+
148
+ - 群聊场景下可选启用 NSFW 关键词过滤(`DRAW_NSFW_ENABLED=true` + `DRAW_NSFW_KEYWORDS=[...]`)
149
+ - 私聊自动跳过检测
150
+
151
+ ### 输出容错
152
+
153
+ - 一旦拿到图片 URL,即使后续发送环节出现小问题,也不会再向用户推送错误消息,避免误扰
154
+
155
+
156
+ ## 主要功能
157
+
158
+ - [x] 调用 OpenAI 兼容绘图接口生成图片
159
+ - [x] 支持自定义 API 地址、密钥、模型
160
+ - [x] 支持 base64 / URL 两种返回格式
161
+ - [x] 群聊 NSFW 关键词过滤(可关闭)
162
+ - [x] 黑白名单访问控制(支持群组/用户 ID)
163
+
164
+ ## env 设置
165
+
166
+ ```bash
167
+ draw_api_url = "http://localhost:8080" # API 地址
168
+ draw_api_key = "" # API 密钥
169
+ draw_model = "flux" # 模型名称
170
+ draw_backend = "openai" # 后端类型: openai/gemini/sd
171
+ draw_default_size = "1024x1024" # 图片尺寸
172
+ draw_timeout = 120 # 超时时间(秒)
173
+ draw_nsfw_enabled = false # NSFW 检测(仅群聊)
174
+ draw_nsfw_keywords = [] # NSFW 关键词
175
+ draw_whitelist_mode = false # 白名单模式
176
+ draw_whitelist = [] # 白名单
177
+ draw_blacklist = [] # 黑名单
178
+ ```
179
+
180
+ > `draw_api_url` 留空时使用后端默认地址;填写时作为后缀拼接到 base URL 后面
181
+ > ID 格式:`group_123456`(群组)或 `123456`(私聊)
182
+
183
+ ## 其他
184
+
185
+ - 如果您有发现 BUG 或者更好的建议,欢迎提 Issue & Pr
186
+ - 如果本插件对你有帮助,不要忘了点个 Star~
187
+ - 本项目仅供学习使用,请勿用于商业用途
188
+ - [MIT License](https://github.com/Agnes4m/nonebot_plugin_aidraw/blob/main/LICENSE) ©[@Agnes4m](https://github.com/Agnes4m)
189
+
190
+ ## 🌐 感谢
191
+
192
+ - [nonebot2](https://github.com/nonebot/nonebot2) - 聊天机器人的基础框架
193
+ - [nonebot-plugin-alconna](https://github.com/nonebot-plugin-alconna/nonebot-plugin-alconna) - NoneBot2 的 Alconna 适配
@@ -0,0 +1,12 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ nonebot_plugin_easy_aidraw/__init__.py
5
+ nonebot_plugin_easy_aidraw/api.py
6
+ nonebot_plugin_easy_aidraw/config.py
7
+ nonebot_plugin_easy_aidraw/handler.py
8
+ nonebot_plugin_easy_aidraw.egg-info/PKG-INFO
9
+ nonebot_plugin_easy_aidraw.egg-info/SOURCES.txt
10
+ nonebot_plugin_easy_aidraw.egg-info/dependency_links.txt
11
+ nonebot_plugin_easy_aidraw.egg-info/requires.txt
12
+ nonebot_plugin_easy_aidraw.egg-info/top_level.txt
@@ -0,0 +1,5 @@
1
+ nonebot2>=2.5.0
2
+ httpx>=0.25.0
3
+ pillow>=10.0.0
4
+ pydantic>=2.0.0
5
+ nonebot-plugin-alconna>=0.62.0
@@ -0,0 +1 @@
1
+ nonebot_plugin_easy_aidraw
@@ -0,0 +1,76 @@
1
+ [project]
2
+ name = "nonebot-plugin-easy-aidraw"
3
+ version = "0.1.0"
4
+ description = "AI绘图插件 for NoneBot2,支持多种绘图API"
5
+ authors = [
6
+ {name = "Agnes4m", email = "Z735803792@163.com"},
7
+ ]
8
+ dependencies = [
9
+ "nonebot2>=2.5.0",
10
+ "httpx>=0.25.0",
11
+ "pillow>=10.0.0",
12
+ "pydantic>=2.0.0",
13
+ "nonebot-plugin-alconna>=0.62.0",
14
+ ]
15
+ requires-python = ">=3.10"
16
+ readme = "README.md"
17
+ license = "MIT"
18
+
19
+ [build-system]
20
+ requires = ["setuptools>=61.0"]
21
+ build-backend = "setuptools.build_meta"
22
+
23
+ [tool.setuptools.packages.find]
24
+ where = ["."]
25
+ include = ["nonebot_plugin_easy_aidraw*"]
26
+ exclude = ["img*"]
27
+
28
+ [tool.black]
29
+ line-length = 120
30
+ target-version = ["py310", "py311", "py312", "py313", "py314"]
31
+ include = '\.pyi?$'
32
+ extend-exclude = ''''''
33
+
34
+ [tool.isort]
35
+ profile = "black"
36
+ line_length = 120
37
+ length_sort = false
38
+ skip_gitignore = true
39
+ force_sort_within_sections = true
40
+ extra_standard_library = ["typing_extensions"]
41
+
42
+ [tool.ruff]
43
+ line-length = 120
44
+ target-version = "py310"
45
+ respect-gitignore = true
46
+
47
+ [tool.ruff.lint]
48
+ select = ["E", "W", "F", "UP", "C", "T", "PYI", "PT", "Q", "I"]
49
+ ignore = ["C901", "T201", "E731", "E402"]
50
+
51
+ [tool.ruff.lint.isort]
52
+ length-sort = false
53
+ force-sort-within-sections = true
54
+ extra-standard-library = ["typing_extensions"]
55
+
56
+ [tool.pyright]
57
+ pythonVersion = "3.10"
58
+ pythonPlatform = "All"
59
+ typeCheckingMode = "basic"
60
+ reportShadowedImports = false
61
+
62
+ [tool.nonebot]
63
+ plugin_dirs = []
64
+ builtin_plugins = []
65
+
66
+ [tool.nonebot.plugins]
67
+ "@local" = ["nonebot_plugin_easy_aidraw"]
68
+
69
+ [tool.nonebot.adapters]
70
+ "@local" = []
71
+
72
+ [dependency-groups]
73
+ dev = [
74
+ "black>=26.5.0",
75
+ "ruff>=0.15.13",
76
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+