├── .idea
├── .gitignore
├── inspectionProfiles
│ ├── Project_Default.xml
│ └── profiles_settings.xml
├── misc.xml
├── modules.xml
├── pictureChange.iml
└── vcs.xml
├── LICENSE
├── README.md
├── __init__.py
├── __pycache__
├── __init__.cpython-311.pyc
├── __init__.cpython-312.pyc
├── __init__.cpython-38.pyc
├── pictureChange.cpython-311.pyc
├── pictureChange.cpython-312.pyc
└── pictureChange.cpython-38.pyc
├── adminService
├── README.md
├── __pycache__
│ └── admin_service.cpython-311.pyc
├── admin_service.py
└── config.json
├── config.json
├── groupService
├── __pycache__
│ ├── change_config.cpython-311.pyc
│ ├── config_cache.cpython-311.pyc
│ ├── find_group.cpython-311.pyc
│ ├── find_group.cpython-312.pyc
│ └── find_group.cpython-38.pyc
├── change_config.py
├── config.json
├── config_cache.py
└── find_group.py
├── message
├── __pycache__
│ ├── message_handle.cpython-311.pyc
│ ├── message_handle.cpython-312.pyc
│ ├── message_handle.cpython-38.pyc
│ ├── message_limit.cpython-311.pyc
│ ├── message_limit.cpython-312.pyc
│ ├── message_limit.cpython-38.pyc
│ ├── message_reply.cpython-311.pyc
│ ├── message_reply.cpython-312.pyc
│ ├── message_reply.cpython-38.pyc
│ ├── message_sd_reply.cpython-311.pyc
│ ├── message_sd_reply.cpython-312.pyc
│ ├── message_sd_reply.cpython-38.pyc
│ ├── message_type.cpython-311.pyc
│ ├── message_type.cpython-312.pyc
│ ├── message_type.cpython-38.pyc
│ ├── music_handle.cpython-311.pyc
│ ├── music_handle.cpython-312.pyc
│ ├── music_handle.cpython-38.pyc
│ ├── request_handle.cpython-311.pyc
│ ├── request_handle.cpython-312.pyc
│ └── request_handle.cpython-38.pyc
├── message_handle.py
├── message_limit.py
├── message_reply.py
├── message_sd_reply.py
├── message_type.py
├── music_handle.py
├── request_handle.py
└── run.log
├── nohup.out
├── pictureChange.py
├── requirements.txt
├── util
├── __init__.py
├── __pycache__
│ ├── __init__.cpython-311.pyc
│ ├── __init__.cpython-312.pyc
│ ├── __init__.cpython-38.pyc
│ ├── baidu_image.cpython-311.pyc
│ ├── baidu_image.cpython-312.pyc
│ ├── baidu_image.cpython-38.pyc
│ ├── file_handle.cpython-311.pyc
│ ├── file_handle.cpython-312.pyc
│ ├── file_handle.cpython-38.pyc
│ ├── image_handle.cpython-311.pyc
│ ├── image_handle.cpython-312.pyc
│ ├── image_handle.cpython-38.pyc
│ ├── translate_prompt.cpython-311.pyc
│ ├── translate_prompt.cpython-312.pyc
│ └── translate_prompt.cpython-38.pyc
├── baidu_image.py
├── file_handle.py
├── image_handle.py
└── translate_prompt.py
└── work
├── __init__.py
├── __pycache__
├── __init__.cpython-311.pyc
├── __init__.cpython-312.pyc
├── __init__.cpython-38.pyc
├── common.cpython-311.pyc
├── common.cpython-312.pyc
└── common.cpython-38.pyc
└── common.py
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # 默认忽略的文件
2 | /shelf/
3 | /workspace.xml
4 | # 基于编辑器的 HTTP 客户端请求
5 | /httpRequests/
6 | # Datasource local storage ignored files
7 | /dataSources/
8 | /dataSources.local.xml
9 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/pictureChange.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## 插件描述
2 |
3 | - 支持运用百度AI进行图像处理
4 | - 支持运用stable diffusion webui进行图像处理
5 | - 支持运用stable diffusion webui画图,不影响dall-3画图
6 | - 支持运用suno音乐组合AI进行图生音,文生音
7 | - 支持运用AI进行文件总结,图片总结等
8 | - 支持多种stable diffusion模型
9 | - 支持管理员控制群聊图像,文件,音乐,更改群聊模型等功能
10 | - 支持并发控制,管理员参数控制
11 | - 支持stable diffusion图生图,文生图自定义模板
12 | - 支持企业微信,个人号,公众号部署
13 |
14 |
15 | ### 1.使用前先安装stable diffusion webui,并在它的启动参数中添加 "--api",并开启**种子数**。
16 |
17 | * 安装具体信息,请参考[视频](https://www.bilibili.com/video/BV1iM4y1y7oA/?spm_id_from=333.337.search-card.all.click)。
18 | * 部署运行后,保证主机能够成功访问http://127.0.0.1:7860/
19 | * 如果是服务器部署则不必需要内网穿透,如果是本地电脑部署推荐[cpolar](https://dashboard.cpolar.com/signup)启动内网穿透
20 |
21 | #### **如下图**
22 |
23 | 
24 |
25 | #### **请确保图片的文件名字有种子数进行命名**
26 |
27 | 
28 |
29 | ### 2.**确保图片位置填写正确**
30 |
31 | 
32 |
33 | ```
34 | "file_url": "file=D:/sd/sd-webui-aki/sd-webui-aki-v4.2/sd-webui-aki-v4.2/outputs/, #这个地址是你图片生成的地址"
35 | ```
36 |
37 | ### 3. 请确保**安装**本插件的依赖包```pip3 install -r requireents.txt```
38 |
39 | ```
40 | pip3 install -r requirements.txt
41 | ```
42 |
43 |
44 | ```config.json
45 | # config.json文件内容示例
46 | {
47 | # 是否使用pictureChange插件功能
48 | "use_pictureChange": true,
49 | # 是否使用SD功能
50 | "use_stable_diffusion": false,
51 | # 是否开启Suno音乐功能
52 | "use_music_handle": true,
53 | # 是否开启文件识别功能
54 | "use_file_handle": true,
55 | # 是否开启群聊管理功能
56 | "use_group_handle": true,
57 | # Stable Diffusion 最大并发数
58 | "max_number": 3,
59 | # 触发suno音乐关键词
60 | "music_create_prefix": [
61 | "唱",
62 | "帮我唱"
63 | ],
64 | # 触发SD画图关键词
65 | "image_create_prefix": [
66 | "SD画",
67 | "SD帮我画"
68 | ],
69 | # 是否使用翻译提示词,否的话使用当前对话机器人进行翻译
70 | "is_use_fanyi": false,
71 | # 百度翻译API密钥
72 | "baidu_api_key": "0fqG8crG04FDU",
73 | # 百度翻译API密钥
74 | "baidu_secret_key": "RQXZgD9j7hZqgse",
75 | # 外部识别图片和文件或者suno音乐的API BASE URL
76 | "openai_api_base": "https://xxx/v1",
77 | # 外部识别图片和文件或者suno音乐的API密钥
78 | "openai_api_key": "sk-8toj6An",
79 | "music_model": "suno-v3.5",
80 | # 识别图片的模型
81 | "image_recognize_model": "gpt-4o",
82 | # 识别文件的模型
83 | "file_recognize_model": "gpt-4o",
84 | # 识别图片的提示词
85 | "image_recognize_prompt": "请帮我描述这个图片的内容。【重要】1.请不要用markdown语法输出 2.请仔细阅读之后把你描述的内容分析给我!",
86 | # 识别文件的提示词
87 | "file_recognize_prompt": "请帮我描述这个文件的内容,【重要】1.请不要用markdown语法输出 2.请仔细阅读之后把你描述的内容分析给我!",
88 | # 识别图片的提示词
89 | "image_music_prompt": "请帮我描述这个图片的内容,将这段内容按照语义分成 Title(题目),Song Description(歌曲描述),Type of Music(音乐类型)。并根据用户的意图生成对应语言的歌曲提示词。请直接了当地输出Title(题目),Song Description(歌曲描述),Type of Music(音乐类型),[重点]不要超过100字!!!",
90 | # 图生图最大尺寸
91 | "max_size": 1024,
92 | # SD启动参数
93 | "start": {
94 | "host": "127.0.0.1",
95 | "port": 7860,
96 | "use_https": false
97 | },
98 | # 本地SD图片存放位置
99 | "file_url": "file=G:/sd/sd-webui-aki-v4.8/outputs/",
100 | # 默认参数
101 | "defaults": {
102 | "params": {
103 | "sampler_name": "Euler a",
104 | "steps": 20,
105 | "width": 1024,
106 | "height": 1024,
107 | "cfg_scale": 7,
108 | "prompt": "absurdres, 8k",
109 | "negative_prompt": "(((nsfw))),EasyNegative,badhandv4,ng_deepnegative_v1_75t,(worst quality:2), (low quality:2), (normal quality:2), lowres, ((monochrome)), ((grayscale)), bad anatomy,DeepNegative, skin spots, acnes, skin blemishes,(fat:1.2),facing away, looking away,tilted head, lowres,bad anatomy,bad hands, missing fingers,extra digit, fewer digits,bad feet,poorly drawn hands,poorly drawn face,mutation,deformed,extra fingers,extra limbs,extra arms,extra legs,malformed limbs,fused fingers,too many fingers,long neck,cross-eyed,mutated hands,polar lowres,bad body,bad proportions,gross proportions,missing arms,missing legs,extra digit, extra arms, extra leg, extra foot,teethcroppe,signature, watermark, username,blurry,cropped,jpeg artifacts,text,error,Lower body exposure",
110 | "enable_hr": false,
111 | "hr_scale": 2,
112 | "hr_upscaler": "Latent",
113 | "hr_second_pass_steps": 15,
114 | "denoising_strength": 0.7
115 | },
116 | "options": {
117 | "sd_model_checkpoint": "anything-v5-PrtRE.safetensors [7f96a1a9ca]"
118 | }
119 | },
120 | "rules": [
121 | {
122 | "keywords": [
123 | "横版",
124 | "壁纸"
125 | ],
126 | "params": {
127 | "width": 640,
128 | "height": 384
129 | },
130 | "desc": "分辨率会变成640x384"
131 | },
132 | {
133 | "keywords": [
134 | "竖版"
135 | ],
136 | "params": {
137 | "width": 384,
138 | "height": 640
139 | },
140 | "desc": "分辨率会变成384x640"
141 | },
142 | {
143 | "keywords": [
144 | "高清"
145 | ],
146 | "params": {
147 | "enable_hr": true,
148 | "hr_scale": 1.4
149 | },
150 | "desc": "出图分辨率长宽都会提高1.4倍"
151 | },
152 | {
153 | "keywords": [
154 | "二次元"
155 | ],
156 | # 切换模型
157 | "options": {
158 | "sd_model_checkpoint": "anything-v5-PrtRE.safetensors [7f96a1a9ca]"
159 | },
160 | "desc": "使用二次元风格模型出图"
161 | },
162 | {
163 | "keywords": [
164 | "现实"
165 | ],
166 | # 切换模型
167 | "options": {
168 | "sd_model_checkpoint": "absolutereality_v181.safetensors [463d6a9fe8]"
169 | },
170 | "desc": "使用现实风格模型出图"
171 | }
172 | ],
173 | # 可自定义图生图角色
174 | "roles": [
175 | {
176 | "title": "👧 可爱女生",
177 | "enable": false,
178 | "prompt": "multiple girls,Masterpiece,best quality, ",
179 | "negative_prompt": "(((nsfw))),EasyNegative,badhandv4,ng_deepnegative_v1_75t,(worst quality:2), (low quality:2), (normal quality:2), lowres, ((monochrome)), ((grayscale)), bad anatomy,DeepNegative, skin spots, acnes, skin blemishes,(fat:1.2),facing away, looking away,tilted head, lowres,bad anatomy,bad hands, missing fingers,extra digit, fewer digits,bad feet,poorly drawn hands,poorly drawn face,mutation,deformed,extra fingers,extra limbs,extra arms,extra legs,malformed limbs,fused fingers,too many fingers,long neck,cross-eyed,mutated hands,polar lowres,bad body,bad proportions,gross proportions,missing arms,missing legs,extra digit, extra arms, extra leg, extra foot,teethcroppe,signature, watermark, username,blurry,cropped,jpeg artifacts,text,error,Lower body exposure",
180 | "denoising_strength": 0.5,
181 | "cfg_scale": 7.0,
182 | "options": {
183 | "sd_model_checkpoint": "anything-v5-PrtRE.safetensors [7f96a1a9ca]"
184 | }
185 | },
186 | {
187 | "title": "🧑 帅气男神",
188 | "enable": true,
189 | "prompt": "multiple boys, male focus, topless male, messy hair, looking at viewer, outdoors, beautiful lighting, deep shadow, best quality, masterpiece, ultra highres, photorealistic, blurry background,",
190 | "negative_prompt": "cartoon, anime, sketches,(worst quality, low quality), (deformed, distorted, disfigured), (bad eyes, wrong lips, weird mouth, bad teeth, mutated hands and fingers:1.2), bad anatomy, wrong anatomy, amputation, extra limb, missing limb, floating limbs, disconnected limbs, mutation, ugly, disgusting, (bad_pictures, negative_hand-neg:1.2)",
191 | "denoising_strength": 0.45,
192 | "cfg_scale": 8.0,
193 | "options": {
194 | "sd_model_checkpoint": "anything-v5-PrtRE.safetensors [7f96a1a9ca]"
195 | }
196 | }
197 | ]
198 | }
199 |
200 | ```
201 |
202 |
203 | - groupService/config.json
204 |
205 | ```groupService/config.json
206 | {
207 | # 控制群聊的功能
208 | "AllFunction": {
209 | # 是否进行图片处理
210 | "IS_IMAGE": "True",
211 | # 是否进行文件处理
212 | "IS_FILE": "True",
213 | # 是否进行音乐处理
214 | "IS_MUSIC": "True",
215 | # 群聊可用模型列表
216 | "MODEL": [
217 | "gpt-4o",
218 | "glm-4",
219 | "abab6.5-chat",
220 | "abab6.5s-chat"
221 | ]
222 | },
223 | "group": [
224 | {
225 | # 群聊名称
226 | "name": "500 Not Found",
227 | "function": {
228 | "IMAGE": "True",
229 | "FILE": "True",
230 | "MUSIC": "True",
231 | "MODEL": "abab6.5s-chat",
232 | "发送消息": "True"
233 | }
234 | }
235 | ]
236 | }
237 | ```
238 |
239 | - adminService/config.json
240 | ```adminService/config.json
241 | {
242 | "admin_id": [],
243 | "admin_password": "xxx"
244 | }
245 | ```
246 |
247 |
248 |
249 |
250 | 使用实例
251 |
252 |
253 |
254 | #### 图生图
255 |
256 | 
257 |
258 | 
259 |
260 | 
261 |
262 | #### 画图
263 |
264 | 
265 |
266 | 
267 |
268 | #### 支持放大 变换操作
269 |
270 | 
271 |
272 | 
273 |
274 | #### suno音乐
275 |
276 | - 1. 文生音
277 | 
278 |
279 | - 2. 图生音
280 | 
281 |
282 | #### 文件识别
283 | 
284 |
285 | #### 图片识别
286 | 
287 |
288 | #### 群聊管理和config管理
289 | 
290 |
291 |
292 |
293 |
294 | ### 贡献与支持
295 |
296 | - 欢迎贡献代码,提出问题和建议。如果你发现了bug或者有新的功能想法,请提交一个Issue让我知道。你也可以通过Fork项目并提交Pull
297 | Request来贡献代码。 如果你想部署这个项目,给我一个星星⭐,这是对我最大的支持!
298 | - 敲代码不易,希望客官给点赞助,让我更好修改代码!
299 | 
300 |
301 |
302 |
303 |
--------------------------------------------------------------------------------
/__init__.py:
--------------------------------------------------------------------------------
1 | from .pictureChange import *
2 |
--------------------------------------------------------------------------------
/__pycache__/__init__.cpython-311.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/__pycache__/__init__.cpython-311.pyc
--------------------------------------------------------------------------------
/__pycache__/__init__.cpython-312.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/__pycache__/__init__.cpython-312.pyc
--------------------------------------------------------------------------------
/__pycache__/__init__.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/__pycache__/__init__.cpython-38.pyc
--------------------------------------------------------------------------------
/__pycache__/pictureChange.cpython-311.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/__pycache__/pictureChange.cpython-311.pyc
--------------------------------------------------------------------------------
/__pycache__/pictureChange.cpython-312.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/__pycache__/pictureChange.cpython-312.pyc
--------------------------------------------------------------------------------
/__pycache__/pictureChange.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/__pycache__/pictureChange.cpython-38.pyc
--------------------------------------------------------------------------------
/adminService/README.md:
--------------------------------------------------------------------------------
1 | # 管理员小工具
2 | 通过自身存储的账号与密码,实现对环境变量的配置。
3 | 请将config.json.template修改为config.json后再进行使用。调用请初始化adminService类
4 | 将此文件夹放入项目根目录下,调用时请使用相对路径
5 | ## 自身配置:
6 |
7 | ```json
8 | {
9 | "admin_id": [], # 管理员id,可以传入不同的特殊id作为表示符
10 | "admin_password": "", # 管理员密码
11 | }
12 | ```
13 |
14 | ## 使用方法:
15 | ```python
16 | from adminService.adminService import adminService
17 |
18 | ad = adminService()
19 |
20 | # 认证管理员
21 | ad.verify_admin(admin_id, admin_password)
22 |
23 | # 判断管理员
24 | ad.is_admin(admin_id)
25 |
26 | # 修改管理员密码
27 | ad.change_password(admin_id, new_password)
28 |
29 | # 清空管理员名单
30 | ad.clear_admin(admin_id)
31 |
32 | # 添加项目json值,可变参数(config[key1][key2][key3]=value), value需要使用value=格式
33 | ad.append_json(admin_id, key1, key2, key3, value)
34 |
35 | # 修改项目json值,同上
36 | ad.update_json(admin_id, key1, key2, key3, value)
37 |
38 | ```
39 |
--------------------------------------------------------------------------------
/adminService/__pycache__/admin_service.cpython-311.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/adminService/__pycache__/admin_service.cpython-311.pyc
--------------------------------------------------------------------------------
/adminService/admin_service.py:
--------------------------------------------------------------------------------
1 | import json
2 | import os
3 | import random
4 | import string
5 |
6 | from common.log import logger
7 | from plugins import PluginManager
8 |
9 |
10 | class admin_service:
11 | def __init__(self):
12 | # 存储的管理员及激活码
13 | self.admin_id = []
14 | self.admin_password = []
15 | # 读取配置文件
16 | config_path = os.path.join(os.path.dirname(__file__), "config.json")
17 | with open(config_path, "r", encoding="utf-8") as f:
18 | config = json.load(f)
19 | self.admin_id = config["admin_id"]
20 | self.admin_password = config["admin_password"]
21 | if self.admin_password == "":
22 | # 生成随机密码
23 | self.admin_password = ''.join(random.sample(string.ascii_letters + string.digits, 8))
24 | logger.info(
25 | f"[adminService] 读取配置文件成功! admin_id: {self.admin_id}, admin_password: {self.admin_password}")
26 |
27 | # 认证管理员,然后写入config中
28 | def verify_admin(self, user_id: str, admin_password: str) -> bool:
29 | if admin_password != self.admin_password:
30 | return False
31 | config_path = os.path.join(os.path.dirname(__file__), "config.json")
32 | self.admin_id.append(user_id)
33 | with open(config_path, "r", encoding="utf-8") as f:
34 | config = json.load(f)
35 | config["admin_id"].append(user_id)
36 | with open(config_path, "w", encoding="utf-8") as f:
37 | json.dump(config, f, ensure_ascii=False, indent=4)
38 | return True
39 |
40 | def is_admin(self, user_id: str) -> bool:
41 | return user_id in self.admin_id
42 |
43 | # 修改管理员密码
44 | def update_password(self, user_id: str, admin_password: str) -> bool:
45 | if not self.is_admin(user_id):
46 | logger.info("False!")
47 | return False
48 | self.admin_password = admin_password
49 | # 保存配置文件, 修改配置文件为新密码
50 | config_path = os.path.join(os.path.dirname(__file__), "config.json")
51 | with open(config_path, "r", encoding="utf-8") as f:
52 | config = json.load(f)
53 | config["admin_password"] = admin_password
54 | logger.info(admin_password)
55 | with open(config_path, "w", encoding="utf-8") as f:
56 | json.dump(config, f, ensure_ascii=False, indent=4)
57 | logger.info(f"[adminService] 修改管理员密码成功! admin_password: {self.admin_password}")
58 | return True
59 |
60 | # 清空现有的管理员名单
61 | def clear_admin(self, user_id: str) -> bool:
62 | if not self.is_admin(user_id):
63 | return False
64 | config_path = os.path.join(os.path.dirname(__file__), "config.json")
65 | with open(config_path, "r", encoding="utf-8") as f:
66 | config = json.load(f)
67 | config["admin_id"] = []
68 | config["admin_id"].append(user_id)
69 | with open(config_path, "w", encoding="utf-8") as f:
70 | json.dump(config, f, ensure_ascii=False, indent=4)
71 | logger.info(f"[adminService] 清空管理员成功!")
72 | return True
73 |
74 | # 修改插件目录下的json文件,不定参数代表传递几层,如config["start"]["host"]
75 | def update_json(self, user_id: str, target: str, *args, value: str) -> bool:
76 | if not self.is_admin(user_id):
77 | return False
78 |
79 | # 设定文件路径
80 | config_path = os.path.join(os.path.dirname(__file__), "../config.json")
81 | try:
82 | with open(config_path, "r", encoding="utf-8") as f:
83 | config = json.load(f)
84 |
85 | # 使用递归函数设置值
86 | def set_nested_value(d, keys, key_value):
87 |
88 | if len(keys) == 1:
89 | d[keys[0]] = key_value
90 | else:
91 | if keys[0] not in d:
92 | d[keys[0]] = {}
93 | set_nested_value(d[keys[0]], keys[1:], key_value)
94 |
95 | if not isinstance(value, bool):
96 | if value.isdigit():
97 | value = int(value)
98 |
99 | # 调用递归函数
100 | set_nested_value(config, [target] + list(args), value)
101 |
102 | with open(config_path, "w", encoding="utf-8") as f:
103 | json.dump(config, f, ensure_ascii=False, indent=4)
104 |
105 | PluginManager().reload_plugin("pictureChange")
106 | logger.info(f"[adminService] 修改json成功! target: {target}, value: {value}")
107 | return True
108 | except Exception as e:
109 | logger.info(f"[adminService] 修改json失败! target: {target}, value: {value}, error: {str(e)}")
110 | return False
111 |
112 | # 添加元素
113 | def append_json(self, user_id: str, target: str, *args, value: str) -> bool:
114 | if not self.is_admin(user_id):
115 | return False
116 |
117 | # 设定文件路径
118 | config_path = os.path.join(os.path.dirname(__file__), "../config.json")
119 | try:
120 | with open(config_path, "r", encoding="utf-8") as f:
121 | config = json.load(f)
122 |
123 | # 使用递归函数设置值
124 | def set_nested_value(d, keys, key_value):
125 | if len(keys) == 1:
126 | d[keys[0]].append(key_value)
127 | else:
128 | if keys[0] not in d:
129 | d[keys[0]] = []
130 | set_nested_value(d[keys[0]], keys[1:], key_value)
131 |
132 | # 调用递归函数
133 | set_nested_value(config, [target] + list(args), value)
134 |
135 | with open(config_path, "w", encoding="utf-8") as f:
136 | json.dump(config, f, ensure_ascii=False, indent=4)
137 |
138 | logger.info(f"[adminService] 修改json成功! target: {target}, value: {value}")
139 | return True
140 | except Exception as e:
141 | logger.info(f"[adminService] 修改json失败! target: {target}, value: {value}, error: {str(e)}")
142 | return False
143 |
--------------------------------------------------------------------------------
/adminService/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "admin_id": [
3 | "@19750fec00553c8d0ad6383a26c643ca5d68a52eebb26ba90f2a8af4975faf72"
4 | ],
5 | "admin_password": "20031028"
6 | }
--------------------------------------------------------------------------------
/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "use_pictureChange": true,
3 | "use_stable_diffusion": true,
4 | "use_music_handle": true,
5 | "use_file_handle": true,
6 | "use_group_handle": true,
7 | "max_number": 3,
8 | "music_create_prefix": [
9 | "唱",
10 | "帮我唱"
11 | ],
12 | "image_create_prefix": [
13 | "SD画",
14 | "SD帮我画"
15 | ],
16 | "is_use_fanyi": false,
17 | "file_url": "file=G:/sd/sd-webui-aki-v4.8/outputs/",
18 | "baidu_api_key": "0fqG8crG04FDU",
19 | "baidu_secret_key": "RQXZgD9j7hZqgse",
20 | "openai_api_base": "https://oneapi.clivia.fun/v1",
21 | "openai_api_key": "sk-8toj6AnHN1ASCAzs65FdE8D792E749",
22 | "music_model": "suno-v3.5",
23 | "image_recognize_model": "gpt-4o",
24 | "file_recognize_model": "gpt-4o",
25 | "image_recognize_prompt": "请帮我描述这个图片的内容。【重要】1.请不要用markdown语法输出 2.请仔细阅读之后把你描述的内容分析给我!",
26 | "file_recognize_prompt": "请帮我描述这个文件的内容,【重要】1.请不要用markdown语法输出 2.请仔细阅读之后把你描述的内容分析给我!",
27 | "image_music_prompt": "请帮我描述这个图片的内容,将这段内容按照语义分成 Title(题目),Song Description(歌曲描述),Type of Music(音乐类型)。并根据用户的意图生成对应语言的歌曲提示词。请直接了当地输出Title(题目),Song Description(歌曲描述),Type of Music(音乐类型),[重点]不要超过100字!!!",
28 | "use_group": [],
29 | "max_size": 1024,
30 | "start": {
31 | "host": "127.0.0.1",
32 | "port": 7860,
33 | "use_https": false
34 | },
35 | "defaults": {
36 | "params": {
37 | "sampler_name": "Euler a",
38 | "steps": 20,
39 | "width": 1024,
40 | "height": 1024,
41 | "cfg_scale": 7,
42 | "prompt": "absurdres, 8k",
43 | "negative_prompt": "(((nsfw))),EasyNegative,badhandv4,ng_deepnegative_v1_75t,(worst quality:2), (low quality:2), (normal quality:2), lowres, ((monochrome)), ((grayscale)), bad anatomy,DeepNegative, skin spots, acnes, skin blemishes,(fat:1.2),facing away, looking away,tilted head, lowres,bad anatomy,bad hands, missing fingers,extra digit, fewer digits,bad feet,poorly drawn hands,poorly drawn face,mutation,deformed,extra fingers,extra limbs,extra arms,extra legs,malformed limbs,fused fingers,too many fingers,long neck,cross-eyed,mutated hands,polar lowres,bad body,bad proportions,gross proportions,missing arms,missing legs,extra digit, extra arms, extra leg, extra foot,teethcroppe,signature, watermark, username,blurry,cropped,jpeg artifacts,text,error,Lower body exposure",
44 | "enable_hr": false,
45 | "hr_scale": 2,
46 | "hr_upscaler": "Latent",
47 | "hr_second_pass_steps": 15,
48 | "denoising_strength": 0.7
49 | },
50 | "options": {
51 | "sd_model_checkpoint": "anything-v5-PrtRE.safetensors [7f96a1a9ca]"
52 | }
53 | },
54 | "rules": [
55 | {
56 | "keywords": [
57 | "横版",
58 | "壁纸"
59 | ],
60 | "params": {
61 | "width": 640,
62 | "height": 384
63 | },
64 | "desc": "分辨率会变成640x384"
65 | },
66 | {
67 | "keywords": [
68 | "竖版"
69 | ],
70 | "params": {
71 | "width": 384,
72 | "height": 640
73 | },
74 | "desc": "分辨率会变成384x640"
75 | },
76 | {
77 | "keywords": [
78 | "机甲少女"
79 | ],
80 | "params": {
81 | "negative_prompt": "(((nsfw))),EasyNegative,badhandv4,ng_deepnegative_v1_75t,(worst quality:2), (low quality:2), (normal quality:2), lowres, ((monochrome)), ((grayscale)), bad anatomy,DeepNegative, skin spots, acnes, skin blemishes,(fat:1.2),facing away, looking away,tilted head, lowres,bad anatomy,bad hands, missing fingers,extra digit, fewer digits,bad feet,poorly drawn hands,poorly drawn face,mutation,deformed,extra fingers,extra limbs,extra arms,extra legs,malformed limbs,fused fingers,too many fingers,long neck,cross-eyed,mutated hands,polar lowres,bad body,bad proportions,gross proportions,missing arms,missing legs,extra digit, extra arms, extra leg, extra foot,teethcroppe,signature, watermark, username,blurry,cropped,jpeg artifacts,text,error,Lower body exposure",
82 | "prompt": "masterpiece, best quality,"
83 | },
84 | "desc": "输出机甲少女风格"
85 | },
86 | {
87 | "keywords": [
88 | "港风"
89 | ],
90 | "params": {
91 | "negative_prompt": "(((nsfw))),EasyNegative,badhandv4,ng_deepnegative_v1_75t,(worst quality:2), (low quality:2), (normal quality:2), lowres, ((monochrome)), ((grayscale)), bad anatomy,DeepNegative, skin spots, acnes, skin blemishes,(fat:1.2),facing away, looking away,tilted head, lowres,bad anatomy,bad hands, missing fingers,extra digit, fewer digits,bad feet,poorly drawn hands,poorly drawn face,mutation,deformed,extra fingers,extra limbs,extra arms,extra legs,malformed limbs,fused fingers,too many fingers,long neck,cross-eyed,mutated hands,polar lowres,bad body,bad proportions,gross proportions,missing arms,missing legs,extra digit, extra arms, extra leg, extra foot,teethcroppe,signature, watermark, username,blurry,cropped,jpeg artifacts,text,error,Lower body exposure",
92 | "prompt": "masterpiece, best quality,"
93 | },
94 | "desc": "输出港风风格"
95 | },
96 | {
97 | "keywords": [
98 | "国风"
99 | ],
100 | "params": {
101 | "negative_prompt": "(((nsfw))),EasyNegative,badhandv4,ng_deepnegative_v1_75t,(worst quality:2), (low quality:2), (normal quality:2), lowres, ((monochrome)), ((grayscale)), bad anatomy,DeepNegative, skin spots, acnes, skin blemishes,(fat:1.2),facing away, looking away,tilted head, lowres,bad anatomy,bad hands, missing fingers,extra digit, fewer digits,bad feet,poorly drawn hands,poorly drawn face,mutation,deformed,extra fingers,extra limbs,extra arms,extra legs,malformed limbs,fused fingers,too many fingers,long neck,cross-eyed,mutated hands,polar lowres,bad body,bad proportions,gross proportions,missing arms,missing legs,extra digit, extra arms, extra leg, extra foot,teethcroppe,signature, watermark, username,blurry,cropped,jpeg artifacts,text,error,Lower body exposure",
102 | "prompt": "masterpiece, best quality, "
103 | },
104 | "desc": "输出国风风格"
105 | },
106 | {
107 | "keywords": [
108 | "高清"
109 | ],
110 | "params": {
111 | "enable_hr": true,
112 | "hr_scale": 1.4
113 | },
114 | "desc": "出图分辨率长宽都会提高1.4倍"
115 | },
116 | {
117 | "keywords": [
118 | "二次元"
119 | ],
120 | "params": {
121 | "negative_prompt": "(((nsfw))),EasyNegative,badhandv4,ng_deepnegative_v1_75t,(worst quality:2), (low quality:2), (normal quality:2), lowres, ((monochrome)), ((grayscale)), bad anatomy,DeepNegative, skin spots, acnes, skin blemishes,(fat:1.2),facing away, looking away,tilted head, lowres,bad anatomy,bad hands, missing fingers,extra digit, fewer digits,bad feet,poorly drawn hands,poorly drawn face,mutation,deformed,extra fingers,extra limbs,extra arms,extra legs,malformed limbs,fused fingers,too many fingers,long neck,cross-eyed,mutated hands,polar lowres,bad body,bad proportions,gross proportions,missing arms,missing legs,extra digit, extra arms, extra leg, extra foot,teethcroppe,signature, watermark, username,blurry,cropped,jpeg artifacts,text,error,Lower body exposure",
122 | "prompt": "masterpiece, best quality"
123 | },
124 | "options": {
125 | "sd_model_checkpoint": "anything-v5-PrtRE.safetensors [7f96a1a9ca]"
126 | },
127 | "desc": "使用二次元风格模型出图"
128 | },
129 | {
130 | "keywords": [
131 | "现实"
132 | ],
133 | "params": {
134 | "negative_prompt": "(((nsfw))),EasyNegative,badhandv4,ng_deepnegative_v1_75t,(worst quality:2), (low quality:2), (normal quality:2), lowres, ((monochrome)), ((grayscale)), bad anatomy,DeepNegative, skin spots, acnes, skin blemishes,(fat:1.2),facing away, looking away,tilted head, lowres,bad anatomy,bad hands, missing fingers,extra digit, fewer digits,bad feet,poorly drawn hands,poorly drawn face,mutation,deformed,extra fingers,extra limbs,extra arms,extra legs,malformed limbs,fused fingers,too many fingers,long neck,cross-eyed,mutated hands,polar lowres,bad body,bad proportions,gross proportions,missing arms,missing legs,extra digit, extra arms, extra leg, extra foot,teethcroppe,signature, watermark, username,blurry,cropped,jpeg artifacts,text,error,Lower body exposure",
135 | "prompt": "masterpiece, best quality"
136 | },
137 | "options": {
138 | "sd_model_checkpoint": "absolutereality_v181.safetensors [463d6a9fe8]"
139 | },
140 | "desc": "使用现实风格模型出图"
141 | },
142 | {
143 | "keywords": [
144 | "Q版"
145 | ],
146 | "params": {
147 | "negative_prompt": "(((nsfw))),EasyNegative,badhandv4,ng_deepnegative_v1_75t,(worst quality:2), (low quality:2), (normal quality:2), lowres, ((monochrome)), ((grayscale)), bad anatomy,DeepNegative, skin spots, acnes, skin blemishes,(fat:1.2),facing away, looking away,tilted head, lowres,bad anatomy,bad hands, missing fingers,extra digit, fewer digits,bad feet,poorly drawn hands,poorly drawn face,mutation,deformed,extra fingers,extra limbs,extra arms,extra legs,malformed limbs,fused fingers,too many fingers,long neck,cross-eyed,mutated hands,polar lowres,bad body,bad proportions,gross proportions,missing arms,missing legs,extra digit, extra arms, extra leg, extra foot,teethcroppe,signature, watermark, username,blurry,cropped,jpeg artifacts,text,error,Lower body exposure",
148 | "prompt": "masterpiece, best quality"
149 | },
150 | "options": {
151 | "sd_model_checkpoint": "QteaMix-fp16.safetensors [0c1efcbbd6]"
152 | },
153 | "desc": "使用Q版风格模型出图"
154 | }
155 | ],
156 | "roles": [
157 | {
158 | "title": "🌈 温柔女孩(强推)",
159 | "enable": false,
160 | "prompt": "multiple girls,masterpiece, best quality, ",
161 | "negative_prompt": "(((nsfw))),EasyNegative,badhandv4,ng_deepnegative_v1_75t,(worst quality:2), (low quality:2), (normal quality:2), lowres, ((monochrome)), ((grayscale)), bad anatomy,DeepNegative, skin spots, acnes, skin blemishes,(fat:1.2),facing away, looking away,tilted head, lowres,bad anatomy,bad hands, missing fingers,extra digit, fewer digits,bad feet,poorly drawn hands,poorly drawn face,mutation,deformed,extra fingers,extra limbs,extra arms,extra legs,malformed limbs,fused fingers,too many fingers,long neck,cross-eyed,mutated hands,polar lowres,bad body,bad proportions,gross proportions,missing arms,missing legs,extra digit, extra arms, extra leg, extra foot,teethcroppe,signature, watermark, username,blurry,cropped,jpeg artifacts,text,error,Lower body exposure",
162 | "denoising_strength": 0.4,
163 | "cfg_scale": 7.0,
164 | "options": {
165 | "sd_model_checkpoint": "anything-v5-PrtRE.safetensors [7f96a1a9ca]"
166 | }
167 | },
168 | {
169 | "title": "👧 可爱女生",
170 | "enable": false,
171 | "prompt": "multiple girls,Masterpiece,best quality, ",
172 | "negative_prompt": "(((nsfw))),EasyNegative,badhandv4,ng_deepnegative_v1_75t,(worst quality:2), (low quality:2), (normal quality:2), lowres, ((monochrome)), ((grayscale)), bad anatomy,DeepNegative, skin spots, acnes, skin blemishes,(fat:1.2),facing away, looking away,tilted head, lowres,bad anatomy,bad hands, missing fingers,extra digit, fewer digits,bad feet,poorly drawn hands,poorly drawn face,mutation,deformed,extra fingers,extra limbs,extra arms,extra legs,malformed limbs,fused fingers,too many fingers,long neck,cross-eyed,mutated hands,polar lowres,bad body,bad proportions,gross proportions,missing arms,missing legs,extra digit, extra arms, extra leg, extra foot,teethcroppe,signature, watermark, username,blurry,cropped,jpeg artifacts,text,error,Lower body exposure",
173 | "denoising_strength": 0.5,
174 | "cfg_scale": 7.0,
175 | "options": {
176 | "sd_model_checkpoint": "anything-v5-PrtRE.safetensors [7f96a1a9ca]"
177 | }
178 | },
179 | {
180 | "title": "🧑 帅气男神",
181 | "enable": true,
182 | "prompt": "multiple boys, male focus, topless male, messy hair, looking at viewer, outdoors, beautiful lighting, deep shadow, best quality, masterpiece, ultra highres, photorealistic, blurry background,",
183 | "negative_prompt": "cartoon, anime, sketches,(worst quality, low quality), (deformed, distorted, disfigured), (bad eyes, wrong lips, weird mouth, bad teeth, mutated hands and fingers:1.2), bad anatomy, wrong anatomy, amputation, extra limb, missing limb, floating limbs, disconnected limbs, mutation, ugly, disgusting, (bad_pictures, negative_hand-neg:1.2)",
184 | "denoising_strength": 0.45,
185 | "cfg_scale": 8.0,
186 | "options": {
187 | "sd_model_checkpoint": "anything-v5-PrtRE.safetensors [7f96a1a9ca]"
188 | }
189 | },
190 | {
191 | "title": "💑 动漫情侣(推荐)",
192 | "enable": false,
193 | "prompt": "couple,masterpiece, best quality, ",
194 | "negative_prompt": "(((nsfw))),EasyNegative,badhandv4,ng_deepnegative_v1_75t,(worst quality:2), (low quality:2), (normal quality:2), lowres, ((monochrome)), ((grayscale)), bad anatomy,DeepNegative, skin spots, acnes, skin blemishes,(fat:1.2),facing away, looking away,tilted head, lowres,bad anatomy,bad hands, missing fingers,extra digit, fewer digits,bad feet,poorly drawn hands,poorly drawn face,mutation,deformed,extra fingers,extra limbs,extra arms,extra legs,malformed limbs,fused fingers,too many fingers,long neck,cross-eyed,mutated hands,polar lowres,bad body,bad proportions,gross proportions,missing arms,missing legs,extra digit, extra arms, extra leg, extra foot,teethcroppe,signature, watermark, username,blurry,cropped,jpeg artifacts,text,error,Lower body exposure",
195 | "denoising_strength": 0.4,
196 | "cfg_scale": 7.0,
197 | "options": {
198 | "sd_model_checkpoint": "anything-v5-PrtRE.safetensors [7f96a1a9ca]"
199 | }
200 | },
201 | {
202 | "title": "🦄 Q版可爱",
203 | "enable": false,
204 | "prompt": "masterpiece, best quality, ",
205 | "negative_prompt": "(((nsfw))),EasyNegative,badhandv4,ng_deepnegative_v1_75t,(worst quality:2), (low quality:2), (normal quality:2), lowres, ((monochrome)), ((grayscale)), bad anatomy,DeepNegative, skin spots, acnes, skin blemishes,(fat:1.2),facing away, looking away,tilted head, lowres,bad anatomy,bad hands, missing fingers,extra digit, fewer digits,bad feet,poorly drawn hands,poorly drawn face,mutation,deformed,extra fingers,extra limbs,extra arms,extra legs,malformed limbs,fused fingers,too many fingers,long neck,cross-eyed,mutated hands,polar lowres,bad body,bad proportions,gross proportions,missing arms,missing legs,extra digit, extra arms, extra leg, extra foot,teethcroppe,signature, watermark, username,blurry,cropped,jpeg artifacts,text,error,Lower body exposure",
206 | "denoising_strength": 0.45,
207 | "cfg_scale": 7.0,
208 | "options": {
209 | "sd_model_checkpoint": "QteaMix-fp16.safetensors [0c1efcbbd6]"
210 | }
211 | },
212 | {
213 | "title": "💖 Q版情侣",
214 | "enable": false,
215 | "prompt": "couple,masterpiece, best quality ",
216 | "negative_prompt": "(((nsfw))),EasyNegative,badhandv4,ng_deepnegative_v1_75t,(worst quality:2), (low quality:2), (normal quality:2), lowres, ((monochrome)), ((grayscale)), bad anatomy,DeepNegative, skin spots, acnes, skin blemishes,(fat:1.2),facing away, looking away,tilted head, lowres,bad anatomy,bad hands, missing fingers,extra digit, fewer digits,bad feet,poorly drawn hands,poorly drawn face,mutation,deformed,extra fingers,extra limbs,extra arms,extra legs,malformed limbs,fused fingers,too many fingers,long neck,cross-eyed,mutated hands,polar lowres,bad body,bad proportions,gross proportions,missing arms,missing legs,extra digit, extra arms, extra leg, extra foot,teethcroppe,signature, watermark, username,blurry,cropped,jpeg artifacts,text,error,Lower body exposure",
217 | "denoising_strength": 0.4,
218 | "cfg_scale": 7.0,
219 | "options": {
220 | "sd_model_checkpoint": "QteaMix-fp16.safetensors [0c1efcbbd6]"
221 | }
222 | },
223 | {
224 | "title": "🏎 机甲女孩",
225 | "enable": false,
226 | "prompt": "multiple girls,,masterpiece, best quality,girls",
227 | "negative_prompt": "(((nsfw))),EasyNegative,badhandv4,ng_deepnegative_v1_75t,(worst quality:2), (low quality:2), (normal quality:2), lowres, ((monochrome)), ((grayscale)), bad anatomy,DeepNegative, skin spots, acnes, skin blemishes,(fat:1.2),facing away, looking away,tilted head, lowres,bad anatomy,bad hands, missing fingers,extra digit, fewer digits,bad feet,poorly drawn hands,poorly drawn face,mutation,deformed,extra fingers,extra limbs,extra arms,extra legs,malformed limbs,fused fingers,too many fingers,long neck,cross-eyed,mutated hands,polar lowres,bad body,bad proportions,gross proportions,missing arms,missing legs,extra digit, extra arms, extra leg, extra foot,teethcroppe,signature, watermark, username,blurry,cropped,jpeg artifacts,text,error,Lower body exposure",
228 | "denoising_strength": 0.5,
229 | "cfg_scale": 8.0,
230 | "options": {
231 | "sd_model_checkpoint": "anything-v5-PrtRE.safetensors [7f96a1a9ca]"
232 | }
233 | },
234 | {
235 | "title": "🌸 美丽女孩",
236 | "enable": false,
237 | "prompt": "multiple girls,,masterpiece, best quality",
238 | "negative_prompt": "(((nsfw))),EasyNegative,badhandv4,ng_deepnegative_v1_75t,(worst quality:2), (low quality:2), (normal quality:2), lowres, ((monochrome)), ((grayscale)), bad anatomy,DeepNegative, skin spots, acnes, skin blemishes,(fat:1.2),facing away, looking away,tilted head, lowres,bad anatomy,bad hands, missing fingers,extra digit, fewer digits,bad feet,poorly drawn hands,poorly drawn face,mutation,deformed,extra fingers,extra limbs,extra arms,extra legs,malformed limbs,fused fingers,too many fingers,long neck,cross-eyed,mutated hands,polar lowres,bad body,bad proportions,gross proportions,missing arms,missing legs,extra digit, extra arms, extra leg, extra foot,teethcroppe,signature, watermark, username,blurry,cropped,jpeg artifacts,text,error,Lower body exposure",
239 | "denoising_strength": 0.45,
240 | "cfg_scale": 8.0,
241 | "options": {
242 | "sd_model_checkpoint": "anything-v5-PrtRE.safetensors [7f96a1a9ca]"
243 | }
244 | }
245 | ]
246 | }
--------------------------------------------------------------------------------
/groupService/__pycache__/change_config.cpython-311.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/groupService/__pycache__/change_config.cpython-311.pyc
--------------------------------------------------------------------------------
/groupService/__pycache__/config_cache.cpython-311.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/groupService/__pycache__/config_cache.cpython-311.pyc
--------------------------------------------------------------------------------
/groupService/__pycache__/find_group.cpython-311.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/groupService/__pycache__/find_group.cpython-311.pyc
--------------------------------------------------------------------------------
/groupService/__pycache__/find_group.cpython-312.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/groupService/__pycache__/find_group.cpython-312.pyc
--------------------------------------------------------------------------------
/groupService/__pycache__/find_group.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/groupService/__pycache__/find_group.cpython-38.pyc
--------------------------------------------------------------------------------
/groupService/change_config.py:
--------------------------------------------------------------------------------
1 | import json
2 | import os
3 | import re
4 | import threading
5 |
6 | from common.log import logger
7 | from plugins.pictureChange.groupService.config_cache import group_cache
8 |
9 | """
10 |
11 | """
12 |
13 |
14 | class group_config:
15 | def __init__(self):
16 | self.config = None
17 | self.config_file = os.path.join(os.path.dirname(__file__), "config.json")
18 | self.mode = None
19 | self.load_config()
20 | self.lock = threading.Lock()
21 |
22 | def load_config(self):
23 | try:
24 | with open(self.config_file, 'r', encoding='utf-8') as file:
25 | self.config = json.load(file)
26 | except FileNotFoundError:
27 | self.config = {
28 | "AllFunction": {
29 | "IS_IMAGE": True,
30 | "IS_FILE": True,
31 | "IS_MUSIC": True,
32 | "MODEL": ["GPT3-5", "GLM-4"]
33 | },
34 | "group": []
35 | }
36 | self.save_config()
37 |
38 | def save_config(self):
39 | with open(self.config_file, 'w', encoding='utf-8') as file:
40 | json.dump(self.config, file, ensure_ascii=False, indent=4)
41 | self.load_config()
42 |
43 | def ins_command(self, ins):
44 | with self.lock: # 使用线程锁确保同一时间只有一个线程访问
45 | if ins == "#help":
46 | self.mode = "help"
47 | return ("修改总功能,请使用#change [funct] to [state]来修改总功能\n"
48 | "修改已有群聊功能模式,请使用#change [funct] in [group_name] to [state]来修改群聊功能状态\n新增群聊模式,请使用#add ["
49 | "group_name]来新增群聊"
50 | "\n删除群聊模式,请使用#del [group_name]来删除群聊\n"
51 | "修改群聊模型模式,请使用#modify [group_name] to [model]来修改模型")
52 | if ins[:7] == "#change":
53 | self.mode = "modify_group_function"
54 | reply = self.change_command(ins)
55 | elif ins[:13] == "#change Model":
56 | self.mode = "modify_group_model"
57 | reply = self.change_command(ins)
58 | elif ins[:4] == "#add":
59 | self.mode = "add_group"
60 | reply = self.add_command(ins)
61 | elif ins[:4] == "#del":
62 | self.mode = "del_group"
63 | reply = self.del_command(ins)
64 | elif ins[:7] == "#modify":
65 | self.mode = "modify_group_model"
66 | reply = self.change_command(ins)
67 | else:
68 | self.mode = None
69 | reply = f"未知指令 {ins}"
70 | group_cache.load_from_json()
71 | logger.info("已将更新数据放入缓存")
72 | return reply
73 |
74 | def change_command(self, command):
75 | def normalize_state(value_state):
76 | return value_state.capitalize()
77 |
78 | change_pattern = re.compile(r'^#modify (\w+) to (\w+)$')
79 | group_change_pattern = re.compile(r'^#change (\w+) in (.+) to (\w+)$')
80 | model_change_pattern = re.compile(r'#modify (.+?) to (.+)')
81 | if self.mode == "all_function":
82 | change_match = change_pattern.match(command)
83 | if change_match:
84 | funct, state = change_match.groups()
85 | funct = funct.upper()
86 | state = normalize_state(state)
87 | # 将状态字符串转换为布尔类型
88 | if state.lower() == "true":
89 | state = True
90 | elif state.lower() == "false":
91 | state = False
92 | if funct in (key.upper() for key in self.config["AllFunction"]):
93 | self.config["AllFunction"][funct] = state
94 | self.save_config()
95 | return f"功能 {funct} 已修改为 {state}"
96 | else:
97 | return f"功能 {funct} 不存在于 AllFunction 中"
98 | else:
99 | return f"未知指令 {command}"
100 |
101 | elif self.mode == "modify_group_function":
102 | group_change_match = group_change_pattern.match(command)
103 | if group_change_match:
104 | funct, group_name, state = group_change_match.groups()
105 | funct = funct.upper()
106 | # 假设 normalize_state 已经处理好状态字符串
107 | state = normalize_state(state)
108 | # 将状态字符串转换为布尔类型
109 | if state.lower() == "true":
110 | state = True
111 | elif state.lower() == "false":
112 | state = False
113 | if funct == "MODEL":
114 | return "您没有对应权限"
115 | group_found = False
116 | for group in self.config["group"]:
117 | if group["name"] == group_name:
118 | if funct in (key.upper() for key in group["function"]):
119 | group["function"][funct] = state
120 | self.save_config()
121 | return f"群聊 {group_name} 的功能 {funct} 已修改为 {state}"
122 | else:
123 | return f"功能 {funct} 不存在于群聊 {group_name} 中"
124 | if not group_found:
125 | return f"没有找到对应群聊 {group_name}"
126 | else:
127 | return f"未知指令 {command}"
128 |
129 | elif self.mode == "modify_group_model":
130 | model_change_match = model_change_pattern.match(command)
131 | if model_change_match:
132 | group_name, model = model_change_match.groups()
133 | group_found = False
134 | for group in self.config["group"]:
135 | if group["name"] == group_name:
136 | if model in (m for m in self.config["AllFunction"]["MODEL"]):
137 | group["function"]["MODEL"] = model
138 | self.save_config()
139 | return f"群聊 {group_name} 的模型已修改为 {model}"
140 | else:
141 | return f"模型 {model} 不存在于可用模型列表中"
142 | if not group_found:
143 | return f"没有找到对应群聊 {group_name}"
144 | else:
145 | return f"未知指令 {command}"
146 | else:
147 | return f"当前模式不支持此指令 {command}"
148 |
149 | def add_command(self, command):
150 | add_pattern = re.compile(r'^#add (.+)$')
151 | add_match = add_pattern.match(command)
152 | if add_match:
153 | group_name = add_match.group(1)
154 | for group in self.config["group"]:
155 | if group["name"] == group_name:
156 | return f"群聊名 {group_name} 已经被使用"
157 | new_group = {
158 | "name": group_name,
159 | "function": {
160 | "IMAGE": self.config["AllFunction"]["IS_IMAGE"],
161 | "FILE": self.config["AllFunction"]["IS_FILE"],
162 | "MUSIC": self.config["AllFunction"]["IS_MUSIC"],
163 | "MODEL": self.config["AllFunction"]["MODEL"][0],
164 | "ENABLE": True,
165 | }
166 | }
167 | self.config["group"].append(new_group)
168 | self.save_config()
169 | return f"群聊 {group_name} 已成功新增"
170 | else:
171 | return f"未知指令 {command}"
172 |
173 | def del_command(self, command):
174 | del_pattern = re.compile(r'^#del (.+)$')
175 | del_match = del_pattern.match(command)
176 | if del_match:
177 | group_name = del_match.group(1)
178 | group_found = False
179 | for group in self.config["group"]:
180 | if group["name"] == group_name:
181 | self.config["group"].remove(group)
182 | self.save_config()
183 | return f"群聊 {group_name} 已成功删除"
184 | if not group_found:
185 | return f"没有找到对应群聊 {group_name}"
186 | else:
187 | return f"未知指令 {command}"
188 |
189 | # # 测试代码
190 | # manager = GroupConfig()
191 | # print(manager.config["group"])
192 | # print(manager.ins_command("#modify 500 Not Found to abab6.5s-chat"))
193 |
--------------------------------------------------------------------------------
/groupService/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "AllFunction": {
3 | "IS_IMAGE": true,
4 | "IS_FILE": true,
5 | "IS_MUSIC": true,
6 | "MODEL": [
7 | "gpt-4o",
8 | "glm-4",
9 | "abab6.5-chat",
10 | "abab6.5s-chat"
11 | ]
12 | },
13 | "group": [
14 | {
15 | "name": "小羊一家🏡",
16 | "function": {
17 | "IMAGE": true,
18 | "FILE": true,
19 | "MUSIC": true,
20 | "MODEL": "abab6.5s-chat",
21 | "ENABLE": true
22 | }
23 | },
24 | {
25 | "name": "小羊一家",
26 | "function": {
27 | "IMAGE": true,
28 | "FILE": true,
29 | "MUSIC": true,
30 | "MODEL": "gpt-4o",
31 | "ENABLE": true
32 | }
33 | }
34 | ]
35 | }
--------------------------------------------------------------------------------
/groupService/config_cache.py:
--------------------------------------------------------------------------------
1 | import json
2 | import os
3 |
4 |
5 | class group_cache:
6 | _cached_data = None
7 |
8 | @staticmethod
9 | def load_from_json():
10 | # 从JSON文件加载数据到静态缓存
11 | cursor = os.path.dirname(__file__)
12 | config_path = os.path.join(cursor, "config.json")
13 | if os.path.exists(config_path):
14 | with open(config_path, "r", encoding="utf-8") as f:
15 | group_cache._cached_data = json.load(f)
16 | else:
17 | raise FileNotFoundError(f"配置文件 {config_path} 未找到。")
18 |
19 | @staticmethod
20 | def get_cached_data():
21 | # 获取缓存数据
22 | if group_cache._cached_data:
23 | return group_cache._cached_data
24 | else:
25 | group_cache.load_from_json()
26 | return group_cache._cached_data
27 |
28 | @staticmethod
29 | def refresh_cache():
30 | # 强制刷新缓存数据
31 | group_cache.load_from_json()
32 |
--------------------------------------------------------------------------------
/groupService/find_group.py:
--------------------------------------------------------------------------------
1 | from common.log import logger
2 | from plugins.pictureChange.groupService.config_cache import group_cache
3 |
4 |
5 | class find_group:
6 | @staticmethod
7 | def find_group(group_name):
8 | all_conf = group_cache().get_cached_data() # 从缓存获取内容
9 | # 获取群聊名称,要放到插件,将上面改成def find_group(self, e_context: EventContext),去掉下行注释
10 | # group_name = e_context["msg"].other_user_nickname
11 | if all_conf is None:
12 | logger.info("缓存内容不存在")
13 |
14 | if all_conf['group']:
15 | for group in all_conf["group"]:
16 | if group_name == group["name"]:
17 | funct_dic = group["function"]
18 | funct_values = list(funct_dic.values())
19 | funct_keys = list(funct_dic.keys())
20 | values = list(all_conf["AllFunction"].values())
21 | keys = list(all_conf["AllFunction"].keys())
22 | ans_dic = {}
23 | for i in range(len(keys)):
24 | if i == len(keys) - 1: # 保证最后一个列表项为model即可
25 | if funct_values[i] in values[i]:
26 | ans_dic[funct_keys[i]] = funct_values[i]
27 | continue
28 | if values[i] and funct_values[i]:
29 | ans_dic[funct_keys[i]] = True
30 | else:
31 | ans_dic[funct_keys[i]] = False
32 |
33 | if funct_dic["ENABLE"]:
34 | ans_dic["ENABLE"] = True
35 | else:
36 | ans_dic["ENABLE"] = False
37 | return ans_dic
38 | else:
39 | return None
40 | else:
41 | return None
42 |
43 | # print(find_group.find_group("小羊一家"))
44 |
--------------------------------------------------------------------------------
/message/__pycache__/message_handle.cpython-311.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/message/__pycache__/message_handle.cpython-311.pyc
--------------------------------------------------------------------------------
/message/__pycache__/message_handle.cpython-312.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/message/__pycache__/message_handle.cpython-312.pyc
--------------------------------------------------------------------------------
/message/__pycache__/message_handle.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/message/__pycache__/message_handle.cpython-38.pyc
--------------------------------------------------------------------------------
/message/__pycache__/message_limit.cpython-311.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/message/__pycache__/message_limit.cpython-311.pyc
--------------------------------------------------------------------------------
/message/__pycache__/message_limit.cpython-312.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/message/__pycache__/message_limit.cpython-312.pyc
--------------------------------------------------------------------------------
/message/__pycache__/message_limit.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/message/__pycache__/message_limit.cpython-38.pyc
--------------------------------------------------------------------------------
/message/__pycache__/message_reply.cpython-311.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/message/__pycache__/message_reply.cpython-311.pyc
--------------------------------------------------------------------------------
/message/__pycache__/message_reply.cpython-312.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/message/__pycache__/message_reply.cpython-312.pyc
--------------------------------------------------------------------------------
/message/__pycache__/message_reply.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/message/__pycache__/message_reply.cpython-38.pyc
--------------------------------------------------------------------------------
/message/__pycache__/message_sd_reply.cpython-311.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/message/__pycache__/message_sd_reply.cpython-311.pyc
--------------------------------------------------------------------------------
/message/__pycache__/message_sd_reply.cpython-312.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/message/__pycache__/message_sd_reply.cpython-312.pyc
--------------------------------------------------------------------------------
/message/__pycache__/message_sd_reply.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/message/__pycache__/message_sd_reply.cpython-38.pyc
--------------------------------------------------------------------------------
/message/__pycache__/message_type.cpython-311.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/message/__pycache__/message_type.cpython-311.pyc
--------------------------------------------------------------------------------
/message/__pycache__/message_type.cpython-312.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/message/__pycache__/message_type.cpython-312.pyc
--------------------------------------------------------------------------------
/message/__pycache__/message_type.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/message/__pycache__/message_type.cpython-38.pyc
--------------------------------------------------------------------------------
/message/__pycache__/music_handle.cpython-311.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/message/__pycache__/music_handle.cpython-311.pyc
--------------------------------------------------------------------------------
/message/__pycache__/music_handle.cpython-312.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/message/__pycache__/music_handle.cpython-312.pyc
--------------------------------------------------------------------------------
/message/__pycache__/music_handle.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/message/__pycache__/music_handle.cpython-38.pyc
--------------------------------------------------------------------------------
/message/__pycache__/request_handle.cpython-311.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/message/__pycache__/request_handle.cpython-311.pyc
--------------------------------------------------------------------------------
/message/__pycache__/request_handle.cpython-312.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/message/__pycache__/request_handle.cpython-312.pyc
--------------------------------------------------------------------------------
/message/__pycache__/request_handle.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/message/__pycache__/request_handle.cpython-38.pyc
--------------------------------------------------------------------------------
/message/message_handle.py:
--------------------------------------------------------------------------------
1 | # 用于初始化消息
2 | from channel.chat_message import ChatMessage
3 |
4 |
5 | # 初始化消息
6 | def init_content(e_context):
7 | context = e_context['context']
8 | msg: ChatMessage = context["msg"]
9 | msg.prepare()
10 | return context.content.strip()
11 |
--------------------------------------------------------------------------------
/message/message_limit.py:
--------------------------------------------------------------------------------
1 | from plugins.pictureChange.message import message_reply as MessageReply
2 |
3 |
4 | class MessageLimit:
5 | use_number = 0
6 | wait_number = 0
7 |
8 | def __init__(self):
9 | pass
10 |
11 | @classmethod
12 | def isLimit(cls, max_number: int, e_context):
13 | if cls.use_number + 1 > max_number:
14 | cls.wait_number += 1
15 | replyText = f"🧸当前排队人数为 {str(cls.wait_number)}\n🚀 请耐心等待一至两分钟,再发送 '一张图片',让我为您进行图片操作"
16 | MessageReply.reply_Text_Message(True, replyText, e_context)
17 | return True
18 | return False
19 |
20 | @classmethod
21 | def success(cls, max_number: int):
22 | if cls.use_number > 0:
23 | cls.use_number -= 1
24 | if max_number > cls.use_number:
25 | cls.wait_number = 0
26 | if cls.wait_number > 0:
27 | cls.wait_number -= 1
28 |
29 | @classmethod
30 | def using(cls):
31 | cls.use_number += 1
32 |
--------------------------------------------------------------------------------
/message/message_reply.py:
--------------------------------------------------------------------------------
1 | from bridge.reply import ReplyType, Reply
2 | from common.log import logger
3 | from plugins import EventAction
4 |
5 |
6 | # 根据reply_type,reply_content发送消息类型
7 | # 根据is_break决定是否结束会话
8 | def reply_message(is_break, reply_type, reply_content, e_context):
9 | reply = Reply()
10 | reply.type = reply_type
11 | reply.content = reply_content
12 | e_context["reply"] = reply
13 | e_context.action = EventAction.BREAK_PASS if is_break else EventAction.CONTINUE
14 | return e_context
15 |
16 |
17 | # 根据reply_content发送文本消息
18 | # 根据is_break决定是否结束会话
19 | def reply_Text_Message(is_break, reply_content, e_context):
20 | reply_message(is_break, ReplyType.TEXT, reply_content, e_context)
21 |
22 |
23 | # 根据reply_content发送错误文本消息
24 | # 根据is_break决定是否结束会话
25 | def reply_Error_Message(is_break, reply_content, e_context):
26 | logger.error(reply_content)
27 | reply_message(is_break, ReplyType.ERROR, reply_content, e_context)
28 |
29 |
30 | # 根据reply_content(image_url)获取图片,发送图片消息
31 | # 根据is_break决定是否结束会话
32 | def reply_Image_Url_Message(is_break, reply_content, e_context):
33 | reply_message(is_break, ReplyType.IMAGE_URL, reply_content, e_context)
34 |
35 |
36 | # 根据reply_content(图片文件二进制)发送音频消息
37 | # 根据is_break决定是否结束会话
38 | def reply_Image_Message(is_break, reply_content, e_context):
39 | reply_message(is_break, ReplyType.IMAGE, reply_content, e_context)
40 |
41 |
42 | # 根据reply_content(音频文件二进制)发送音频消息
43 | # 根据is_break决定是否结束会话
44 | def reply_Video_Message(is_break, reply_content, e_context):
45 | reply_message(is_break, ReplyType.VIDEO, reply_content, e_context)
46 |
47 |
48 | # 根据reply_content(video_url)获取音频,发送音频消息
49 | # 根据is_break决定是否结束会话
50 | def reply_Video_Url_Message(is_break, reply_content, e_context):
51 | reply_message(is_break, ReplyType.VIDEO_URL, reply_content, e_context)
52 |
53 |
54 | # 立即发送文本消息(reply_content),不结束会话
55 | def tem_reply_Text_Message(reply_content, e_context):
56 | reply = Reply(ReplyType.TEXT, reply_content)
57 | e_context['channel'].send(reply, e_context["context"])
58 |
59 |
60 | # 立即发送图片消息(reply_content),不结束会话
61 | def tem_reply_Image_Message(reply_content, e_context):
62 | reply = Reply(ReplyType.IMAGE, reply_content)
63 | e_context['channel'].send(reply, e_context["context"])
64 |
65 |
66 | # 立即发送图片消息(reply_content),不结束会话
67 | def tem_reply_Image_Url_Message(reply_content, e_context):
68 | reply = Reply(ReplyType.IMAGE_URL, reply_content)
69 | e_context['channel'].send(reply, e_context["context"])
70 |
71 |
72 | # 立即发送音频消息(reply_content),不结束会话
73 | def tem_reply_Video_Message(reply_content, e_context):
74 | try:
75 | reply = Reply(ReplyType.FILE, reply_content)
76 | e_context['channel'].send(reply, e_context["context"])
77 | except Exception as e:
78 | logger.error(f"Error sending video: {e}")
79 |
80 |
81 | # 立即发送音频消息(reply_content),不结束会话
82 | def tem_reply_Video_Url_Message(reply_content, e_context):
83 | reply = Reply(ReplyType.VIDEO_URL, reply_content)
84 | e_context['channel'].send(reply, e_context["context"])
85 |
--------------------------------------------------------------------------------
/message/message_sd_reply.py:
--------------------------------------------------------------------------------
1 | import io
2 | import os
3 | import time
4 |
5 | import requests
6 | import webuiapi
7 | from PIL import Image
8 |
9 | from common.log import logger
10 | from plugins.pictureChange.message import message_reply as message_reply, message_type
11 | from plugins.pictureChange.util import translate_prompt, image_handle, file_handle
12 |
13 |
14 | # 用于回复图片消息
15 | def reply_image(result, start_time, file_content, request_bot_name, modelName, image_type, is_wecom, e_context):
16 | # 发送图片
17 | b_img = io.BytesIO()
18 | result.image.save(b_img, format="PNG")
19 | message_reply.tem_reply_Image_Message(b_img, e_context)
20 | all_seeds = result.info['all_seeds']
21 | imageMessage_reply(all_seeds, start_time, request_bot_name, modelName, image_type, is_wecom, e_context)
22 | file_handle.delete_file(file_content)
23 |
24 |
25 | # 用于图片信息文本回复
26 | def imageMessage_reply(all_seeds, start_time, request_bot_name, modelName, image_type, is_wecom, e_context):
27 | end_time = time.time()
28 | elapsed_time = end_time - start_time
29 | minutes = int(elapsed_time // 60)
30 | seconds = int(elapsed_time % 60)
31 |
32 | replyText = message_type.on_image_reply(request_bot_name, image_type, all_seeds,
33 | modelName, minutes, seconds, is_wecom)
34 | message_reply.reply_Text_Message(True, replyText, e_context)
35 |
36 |
37 | # 用于stable_diffusion创建图片
38 | def create_Image(content, is_use_fanyi, bot_prompt, rules, Model,
39 | request_bot_name, start_args, params, options,
40 | session_id, is_wecom, e_context):
41 | try:
42 | start_time = time.time()
43 | if ":" in content:
44 | keywords, prompt = content.split(":", 1)
45 | else:
46 | keywords = content
47 | prompt = ""
48 | keywords = keywords.split()
49 | unused_keywords = []
50 |
51 | # Match keywords to rules
52 | for keyword in keywords:
53 | for rule in rules:
54 | if keyword in rule["keywords"]:
55 | logger.info("[SD] keyword matched: %s" % keyword)
56 | params.update(rule["params"])
57 | if "options" in rule:
58 | options.update(rule["options"])
59 | break
60 | else:
61 | unused_keywords.append(keyword)
62 | logger.info("[SD] keyword not matched: %s" % keyword)
63 |
64 | params["prompt"] = params.get("prompt", "")
65 |
66 | if unused_keywords:
67 | if prompt:
68 | prompt += f", {', '.join(unused_keywords)}"
69 | else:
70 | prompt = ', '.join(unused_keywords)
71 | translate_prompt.translatePrompt(is_use_fanyi, bot_prompt, prompt, params, session_id)
72 | api = webuiapi.WebUIApi(**start_args)
73 | if options:
74 | logger.info("[SD] cover options={}".format(options))
75 | api.set_options(options)
76 | logger.info("[SD] params={}".format(params))
77 |
78 | result = api.txt2img(
79 | batch_size=4,
80 | n_iter=1,
81 | do_not_save_samples=True,
82 | do_not_save_grid=True,
83 | save_images=True,
84 | **params
85 | )
86 | # Process model name
87 | model = options["sd_model_checkpoint"]
88 | modelName = next((member.name for member in Model if model == member.value), model)
89 | logger.info(f"SD使用了其他模型:{modelName}")
90 |
91 | # Send image and additional instructions
92 | b_img = io.BytesIO()
93 | result.image.save(b_img, format="PNG")
94 | message_reply.tem_reply_Image_Message(b_img, e_context)
95 | all_seeds = result.info['all_seeds']
96 | imageMessage_reply(all_seeds, start_time, request_bot_name, modelName, "txt2img-images", is_wecom, e_context)
97 |
98 | except Exception as e:
99 | logger.error(f"【SD】创作图片时出现错误:{e}")
100 | replyText = "hum......,请联系管理员或者稍后再试吧!"
101 | message_reply.reply_Error_Message(True, replyText, e_context)
102 | return
103 |
104 |
105 | # 用于stable_diffusion自定义图生图
106 | def custom_Image(content, is_use_fanyi, bot_prompt, Model, request_bot_name, start_args, session_id,
107 | negative_prompt, maxsize: int, is_wecom, e_context):
108 | start_time = time.time()
109 | start_index = content.find("tmp/")
110 | end_index = content.find(".png")
111 | file_content = content[start_index:end_index + 4]
112 | start_index = content.find("[关键词]") + 5
113 | keywords = content[start_index:].split()
114 | keywords_string = ' '.join(keywords)
115 | prompt = keywords_string
116 | prompt = translate_prompt.simple_translatePrompt(is_use_fanyi, bot_prompt, prompt, session_id)
117 | logger.info(f"[SD] prompt: {prompt}")
118 |
119 | images = []
120 | logger.info(f"{file_content}")
121 | if os.path.isfile(file_content):
122 | try:
123 | # 从文件中读取数据
124 | with open(file_content, 'rb') as file:
125 | image_data = file.read()
126 | logger.info("图片读取成功")
127 | except Exception as e:
128 | logger.error(f"读取图片数据时出现错误:{e}")
129 | message_reply.reply_Error_Message(True, str(e), e_context)
130 | return
131 |
132 | try:
133 | image = Image.open(io.BytesIO(image_data))
134 | images.append(image)
135 | width, height = image.size
136 | width, height = image_handle.adjust_image(width, height, maxsize)
137 | logger.info(f"width: {width} height: {height}")
138 |
139 | except Exception as e:
140 | message_reply.reply_Error_Message(True, str(e), e_context)
141 | return
142 |
143 | sdModel = getattr(Model, content.split()[3]).value
144 | default_options = {
145 | "sd_model_checkpoint": sdModel
146 | }
147 | api = webuiapi.WebUIApi(**start_args)
148 | api.set_options(default_options)
149 | # 调用img2img函数,并传递修改后的images列表作为参数
150 | result = api.img2img(
151 | images=images,
152 | steps=20,
153 | denoising_strength=0.70,
154 | cfg_scale=7.0,
155 | width=width,
156 | height=height,
157 | batch_size=4,
158 | n_iter=1,
159 | do_not_save_samples=True,
160 | do_not_save_grid=True,
161 | save_images=True,
162 | prompt=prompt,
163 | negative_prompt=negative_prompt,
164 | )
165 | model = default_options["sd_model_checkpoint"]
166 | for member in Model:
167 | if model == member.value:
168 | modelName = member.name
169 | break
170 | else:
171 | modelName = model
172 | logger.info("使用了其他模型")
173 | # 发送图片
174 | reply_image(result, start_time, file_content, request_bot_name, modelName, "img2img-images", is_wecom,
175 | e_context)
176 |
177 | else:
178 | replyText = f"🥰请先发送图片给我,我将为您进行图片操作"
179 | message_reply.reply_Text_Message(True, replyText, e_context)
180 |
181 |
182 | # 用于stable_diffusion按照config.json变换图生图
183 | def change_Image(content, Model, request_bot_name, start_args, default_options,
184 | role_options, denoising_strength, cfg_scale,
185 | prompt, negative_prompt, title, maxsize: int, is_wecom, e_context):
186 | start_time = time.time()
187 | file_content = content.split()[2]
188 | images = []
189 | logger.info(f"{file_content}")
190 | if os.path.isfile(file_content):
191 | try:
192 | # 从文件中读取数据
193 | with open(file_content, 'rb') as file:
194 | image_data = file.read()
195 | logger.info("图片读取成功")
196 | except Exception as e:
197 | logger.error(f"读取图片数据时出现错误:{e}")
198 | message_reply.reply_Error_Message(True, str(e), e_context)
199 | return
200 |
201 | image = Image.open(io.BytesIO(image_data))
202 | width, height = image.size
203 | width, height = image_handle.adjust_image(width, height, int(maxsize))
204 | logger.info(f"width: {width} height: {height}")
205 | images.append(image)
206 |
207 | options = {**default_options, **role_options}
208 | # 更改固定模型
209 | api = webuiapi.WebUIApi(**start_args)
210 | api.set_options(options)
211 | # 调用img2img函数,并传递修改后的images列表作为参数
212 | result = api.img2img(
213 | images=images,
214 | steps=20,
215 | denoising_strength=denoising_strength,
216 | cfg_scale=cfg_scale,
217 | width=width,
218 | height=height,
219 | batch_size=4,
220 | n_iter=1,
221 | do_not_save_samples=True,
222 | do_not_save_grid=True,
223 | save_images=True,
224 | prompt=prompt,
225 | negative_prompt=negative_prompt,
226 | )
227 |
228 | model = options["sd_model_checkpoint"]
229 | for member in Model:
230 | if model == member.value:
231 | modelName = member.name
232 | break
233 | else:
234 | modelName = model
235 | logger.info("使用了其他模型")
236 |
237 | # 发送图片
238 | reply_image(result, start_time, file_content, request_bot_name, modelName, "img2img-images", is_wecom,
239 | e_context)
240 |
241 | else:
242 | replyText = f"🥰请先发送图片给我,我将为您进行{title}"
243 | message_reply.reply_Text_Message(True, replyText, e_context)
244 |
245 |
246 | # 用于stable_diffusion变换图生图
247 | def transform_Image(content, Model, request_bot_name, start_args, use_https, host, port, file_url,
248 | prompt, negative_prompt, maxsize: int, is_wecom, e_context):
249 | start_time = time.time()
250 | file_content = content.split()[2]
251 | images = []
252 | logger.info(f"{file_content}")
253 | model = getattr(Model, content.split()[3]).value
254 | image_url = image_handle.format_image_url(use_https, host, port, file_url, file_content)
255 | # 发送 GET 请求获取图像数据
256 | response = requests.get(image_url)
257 | # 检查响应状态码是否为 200,表示请求成功
258 | if response.status_code == 200:
259 | # 获取图像的二进制数据
260 | image_data = response.content
261 | # 将二进制图像数据转换为 PIL Image 对象
262 | image = Image.open(io.BytesIO(image_data))
263 | width, height = image.size
264 | width, height = image_handle.adjust_image(width, height, int(maxsize))
265 | # 将PIL Image对象添加到images列表中
266 | images.append(image)
267 | default_options = {
268 | "sd_model_checkpoint": model
269 | }
270 | api = webuiapi.WebUIApi(**start_args)
271 | api.set_options(default_options)
272 | # 调用img2img函数,并传递修改后的images列表作为参数
273 | result = api.img2img(
274 | images=images,
275 | steps=20,
276 | denoising_strength=0.5,
277 | cfg_scale=7.0,
278 | batch_size=4,
279 | n_iter=1,
280 | do_not_save_samples=True,
281 | do_not_save_grid=True,
282 | save_images=True,
283 | width=width,
284 | height=height,
285 | prompt=prompt,
286 | negative_prompt=negative_prompt,
287 | )
288 | # 发送图片
289 | for member in Model:
290 | if model == member.value:
291 | modelName = member.name
292 | break
293 | else:
294 | modelName = model
295 | logger.info("使用了其他模型")
296 |
297 | # 发送图片
298 | reply_image(result, start_time, file_content, request_bot_name, modelName, "img2img-images", is_wecom,
299 | e_context)
300 |
301 | else:
302 | replyText = f"🥰请先发送图片给我,我将为您进行图片操作"
303 | message_reply.reply_Text_Message(True, replyText, e_context)
304 |
305 |
306 | # 用于放大图片
307 | def large_Image(content, use_https, host, port, file_url, e_context):
308 | try:
309 | file_content = content.split()[2]
310 | logger.info(f"{file_content}")
311 | image_url = image_handle.format_image_url(use_https, host, port, file_url, file_content)
312 | logger.info(f"图片地址为:{image_url}")
313 | response = requests.get(image_url)
314 | response.raise_for_status()
315 | message_reply.reply_Image_Url_Message(True, image_url, e_context)
316 | except Exception as e:
317 | replyText = "[😭转换图片失败]" + str(e) + "\n快联系管理员解决问题吧🥰🥰🥰"
318 | message_reply.reply_Text_Message(True, replyText, e_context)
319 |
--------------------------------------------------------------------------------
/message/message_type.py:
--------------------------------------------------------------------------------
1 | # 接收到图片消息时的回复格式
2 | def in_image_reply(file_content, request_bot_name, role_options, use_stable_diffusion,
3 | use_music_handle, use_file_handle, is_wecom):
4 | if not is_wecom:
5 | replyText = (f"\n🥰 您的图片编号:\n💖 {file_content}\n\n❗ 请输入指令,以进行图片操作\n"
6 | f"✅ 支持以下指令")
7 | if use_music_handle:
8 | replyText += f"\n\n{request_bot_name}🎧 图生音 {file_content}"
9 |
10 | if use_file_handle:
11 | replyText += f"\n\n{request_bot_name}🖼️ 图像描述 {file_content}"
12 |
13 | if use_stable_diffusion:
14 | replyText += f"\n\n{request_bot_name}🤖 图像修复 {file_content}"
15 |
16 | for role in role_options:
17 | replyText += f"\n\n{request_bot_name} {role['title']} {file_content}"
18 |
19 | replyText += f"\n\n{request_bot_name}🎡 自定义 {file_content} [关键词] 例如 黑色头发 白色短袖 等关键词"
20 |
21 | replyText += f"\n\n{request_bot_name}👀 暂不处理 {file_content}"
22 |
23 | else:
24 | replyText = f"🥰 您的图片编号:\n💖 {file_content}\n\n❗ 请点击指令,以进行图片操作"
25 | if use_music_handle:
26 | replyText += ("\n\n{}".
27 | format(request_bot_name, "🎧 图生音", file_content, "🎧 图生音"))
28 | if use_file_handle:
29 | replyText += ("\n\n{}".
30 | format(request_bot_name, "🖼️ 图像描述", file_content, "🖼️ 图像描述"))
31 |
32 | if use_stable_diffusion:
33 | replyText += ("\n\n{}".
34 | format(request_bot_name, "🤖 图像修复", file_content, "🤖 图像修复"))
35 | for role in role_options:
36 | replyText += ("\n\n{}".
37 | format(request_bot_name, role['title'], file_content, role['title']))
38 | replyText += f"\n\n{request_bot_name}🎡 自定义 {file_content} [关键词] 例如 黑色头发 白色短袖 等关键词"
39 |
40 | replyText += ("\n\n{}".
41 | format(request_bot_name, "👀 暂不处理", file_content, "👀 暂不处理"))
42 |
43 | if use_stable_diffusion:
44 | replyText += "\n\n🥰 温馨提示\n👑 MODEL_1 : 动漫\n🏆 MODEL_2 : 现实\n🧩 MODEL_3 : Q版"
45 |
46 | replyText += "\n\n🚀 发送指令后,请耐心等待一至两分钟,作品将很快呈现出来!"
47 | return replyText
48 |
49 |
50 | # 图片消息时的回复格式
51 | def on_image_reply(request_bot_name, image_type, all_seeds, modelname, minutes, seconds, is_wecom):
52 | replyText = f"🔥 图片创作成功!\n⏱ 图片处理耗时:{minutes}分钟 {seconds}秒\n🧸点击指令,我将为您进行图片操作!\n\n✅ 支持指令"
53 | composition_1 = 0
54 | composition_2 = 0
55 | if not is_wecom:
56 | for seed in all_seeds:
57 | composition_1 += 1
58 | replyText += ("\n\n{} 🤖 放大 {}.png {}"
59 | .format(request_bot_name, f"{image_type}/{seed}", composition_1))
60 | for seed in all_seeds:
61 | composition_2 += 1
62 | replyText += ("\n\n{} 🎡 变换 {}.png {} {}"
63 | .format(request_bot_name, f"{image_type}/{seed}", modelname, composition_2))
64 | else:
65 | for seed in all_seeds:
66 | composition_1 += 1
67 | if composition_1 % 2 == 0:
68 | replyText += "\t\t"
69 | else:
70 | replyText += "\n\n"
71 | replyText += "{}".format(
72 | request_bot_name, f"txt2img-images/{seed}", f"🤖 放大 {composition_1}")
73 | for seed in all_seeds:
74 | composition_2 += 1
75 | if composition_2 % 2 == 0:
76 | replyText += "\t\t"
77 | else:
78 | replyText += "\n\n"
79 | replyText += "{}".format(
80 | request_bot_name, f"txt2img-images/{seed}", modelname, f"🎡 变换 {composition_2}")
81 | replyText += ("\n\n🥰 温馨提示\n✨ 1:左上 2:右上 3:左下 4:右下\n👑 MODEL_1 : 动漫\n🏆 MODEL_2 : 现实\n🧩 MODEL_3 : Q版\n🌈 "
82 | f"图片不满意的话,点击变换\n{request_bot_name}帮你再画一幅吧!\n💖 感谢您的使用!")
83 | return replyText
84 |
85 |
86 | # 用于主函数的帮助回复
87 | def on_help_reply(trigger, rules):
88 | help_text = "💨 结合百度AI 和 Stable-Diffusion 来文生图和图生图,suno音乐,文件和图片识别,群聊聊天模型转换\n\n"
89 | help_text += (
90 | f"💖 使用方法:\n\n\"{trigger}[关键词1] [关键词2]...:提示语\"的格式作画,如\"{trigger}画高清:男孩,强壮,挺拔,running"
91 | f",黑色耳机,白色短袖(中间有个羊字),黑色头发,黑色短裤\"\n\n")
92 | help_text += "🥰 目前可用关键词:\n\n"
93 | for rule in rules:
94 | keywords = [f"[{keyword}]" for keyword in rule['keywords']]
95 | help_text += f"{','.join(keywords)}"
96 | if "desc" in rule:
97 | help_text += f"-{rule['desc']}\n"
98 | else:
99 | help_text += "\n"
100 | help_text += (
101 | "\n🥰发送 '一张图片',我将为您进行图片操作\n"
102 | )
103 | help_text += ("\n🤖 管理员操作\n\n"
104 | "认证管理员 `认证 [管理员密码]`\n\n"
105 | "修改属性 `修改pictureChange参数 [参数名称] [参数数值]`\n\n"
106 | "清空管理员 `清空管理员`\n\n"
107 | "修改管理员密码 `修改密码 [管理员密码]`\n\n"
108 | "修改群聊总功能 `群聊修改 #change [funct] to [state]`\n\n"
109 | "修改已有群聊功能模式 `群聊修改 #change [funct] in [group_name] to [state]`\n\n"
110 | "新增群聊模式 `群聊修改 #add [group_name]` \n\n"
111 | "删除群聊模式 `群聊修改 #del [group_name]`\n\n"
112 | "修改群聊模型模式 `群聊修改 #modify [group_name] to [model]`\n\n"
113 | "[funct]: IMAGE / FILE / MUSIC / MODEL\n\n"
114 | "[state]: true / false\n")
115 | return help_text
116 |
--------------------------------------------------------------------------------
/message/music_handle.py:
--------------------------------------------------------------------------------
1 | import json
2 | import os
3 | import re
4 | import time
5 | import urllib
6 |
7 | import requests
8 |
9 | from bot import bot_factory
10 | from bridge.bridge import Bridge
11 | from common.log import logger
12 | from plugins import EventAction
13 | from plugins.pictureChange.message import message_reply
14 |
15 |
16 | def music_prompt(bot_prompt, prompt, e_context):
17 | """
18 | 用于生成音乐提示
19 | :param bot_prompt: 机器人提示
20 | :param prompt: 用户提示
21 | :param e_context: 会话消息
22 | :return: 生成的音乐提示
23 | """
24 | try:
25 | context = e_context['context']
26 | session_id = context.content.strip()
27 | bot = bot_factory.create_bot(Bridge().btype['chat'])
28 | session = bot.sessions.build_session(session_id, bot_prompt)
29 | # 不带有之前的提示词
30 | # session.add_query(prompt)
31 | result = bot.reply_text(session)
32 | return str(result.get("content"))
33 | except Exception:
34 | # logger.error("music_handle: music prompt error")
35 | return prompt
36 |
37 |
38 | class music_handle:
39 | def __init__(self):
40 | super().__init__()
41 |
42 | # 用于将文本转换为音乐
43 | @staticmethod
44 | def text_to_music(bot_prompt, is_use_gpt, url, key, prompt, model, is_wecom, e_context):
45 | """
46 | 用于将文本转换为音乐
47 | :param bot_prompt: 机器人提示
48 | :param is_use_gpt: 是否使用GPT(是:文生音;否:图生音)
49 | :param url: 请求的URL
50 | :param key: 授权Key
51 | :param prompt: 用户提示
52 | :param model: 模型
53 | :param is_wecom: 是否为企业微信
54 | :param e_context: 上下文
55 | :return: None
56 | """
57 | if is_use_gpt:
58 | prompt = music_prompt(bot_prompt, prompt, e_context)
59 |
60 | # 设置请求头
61 | headers = {
62 | 'Authorization': f'Bearer {key}',
63 | 'Content-Type': 'application/json'
64 | }
65 | # 设置请求体
66 | payload = {
67 | "model": model,
68 | "stream": True,
69 | "messages": [
70 | {
71 | "content": str(prompt),
72 | "role": "user"
73 | }
74 | ]
75 | }
76 |
77 | # 初始化音乐相关变量,包括歌名、类型、完整歌词、歌曲图片、临时链接、歌曲、视频
78 | song_name = ""
79 | genre = ""
80 | full_lyrics = ""
81 | song_image = ""
82 | music_link1 = ""
83 | music_link2 = ""
84 | song1 = ""
85 | video1 = ""
86 |
87 | # 初始化布尔标识
88 | song_info_printed = False
89 | lyrics_image_printed = False
90 | music_links_printed = False
91 | songs_printed = False
92 | videos_printed = False
93 |
94 | try:
95 | # 发送请求并处理响应
96 | with requests.post(url, headers=headers, json=payload, stream=True) as response:
97 | response.raise_for_status()
98 | for i, line in enumerate(response.iter_lines()):
99 | line = line.decode('utf-8')
100 | if line.startswith("data:") and "[DONE]" not in line:
101 | try:
102 | # 将UTF-8字符串重新编码为GBK并处理可能的编码错误
103 | line_gbk = line.replace("data: ", "")
104 | json_data = json.loads(line_gbk)
105 | if 'choices' in json_data and len(json_data['choices']) > 0:
106 | delta = json_data['choices'][0].get('delta', {})
107 | message_content = delta.get('content', "")
108 | # 处理生成音乐提示的不同部分
109 | if "违规" in message_content:
110 | replyText = (f"⚠️⚠️ 违规 ⚠️⚠️\n\n🤖 歌曲提示\n\n{str(prompt)}\n\n"
111 | f"🚨 注意\n\n😭您的提示词中存在违规词,歌曲创作失败😭\n\n"
112 | f"🤗 请更换提示词,我会为您重新创作✨")
113 | message_reply.tem_reply_Text_Message(replyText, e_context)
114 | break
115 | if "ID" in message_content:
116 | replyText = (f"🤯 Creating\n\n🤖 歌曲提示\n\n{prompt}\n\n"
117 | "🤩 音乐已经生成,敬请期待!\n\n🤗 温馨提示:用英文表述音乐术语,结果会更准确哟~")
118 | message_reply.tem_reply_Text_Message(replyText, e_context)
119 | if "歌名" in message_content:
120 | song_name_match = re.search(r'歌名\*\*:(.+?)\n', message_content)
121 | if song_name_match:
122 | song_name = song_name_match.group(1).strip()
123 | elif "类型" in message_content:
124 | genre_match = re.search(r'类型\*\*:(.+)', message_content)
125 | if genre_match:
126 | genre = genre_match.group(1).strip()
127 | elif "完整歌词" in message_content:
128 | lyrics_match = re.search(r'```\n(.+?)\n```', message_content, re.DOTALL)
129 | if lyrics_match:
130 | full_lyrics = lyrics_match.group(1).strip()
131 | elif "image_large_url" in message_content:
132 | url_match = re.search(r'https?://.*?\)', message_content)
133 | if url_match:
134 | song_image = url_match.group(0).rstrip(')')
135 | elif "实时音乐" in message_content:
136 | music_links = re.findall(r'https?://\S+', message_content)
137 | if music_link1:
138 | music_link2 = music_links[0]
139 | if len(music_links) > 0 and not music_link1:
140 | music_link1 = music_links[0]
141 | elif "CDN" in message_content and "音乐" in message_content:
142 | url_matches = re.findall(r'https?://\S+\.mp3', message_content)
143 | for idx, match in enumerate(url_matches):
144 | if idx == 0:
145 | song1 = match
146 | elif idx == 1:
147 | song2 = match
148 | elif "视频链接" in message_content:
149 | url_matches = re.findall(r'https?://\S+\.mp4', message_content)
150 | for idx, match in enumerate(url_matches):
151 | if idx == 0:
152 | video1 = match
153 | elif idx == 1:
154 | video2 = match
155 |
156 | if is_wecom:
157 | # 处理企业微信消息
158 | if song_name and genre and full_lyrics and not song_info_printed:
159 | replyText = (f"⭐⭐ 歌曲信息 ⭐⭐\n\n『🤖 歌名』\n"
160 | f"{song_name}\n\n『💄 类型』\n{genre}"
161 | f"\n\n『📖 完整歌词』\n{full_lyrics}"
162 | f"\n\n👀 更多\n\n🚨 歌曲图片和实时音乐链接正在火速生成中🚀🚀🚀")
163 | message_reply.tem_reply_Text_Message(replyText, e_context)
164 |
165 | song_info_printed = True
166 | if song_image and not lyrics_image_printed:
167 | message_reply.tem_reply_Image_Url_Message(song_image, e_context)
168 | lyrics_image_printed = True
169 | if music_link1 and music_link2 and not music_links_printed:
170 | replyText = (
171 | f"🎵🎵 即刻体验 🎵🎵\n\n『实时音乐1️⃣』\n{music_link1}\n\n『实时音乐2️⃣』\n{music_link2}\n\n"
172 | f"🚀 音乐MP3和视频正在火速生成中,大概需要2-3分钟,请耐心等待!")
173 | message_reply.tem_reply_Text_Message(replyText, e_context)
174 | music_links_printed = True
175 | if song1 and song2 and not songs_printed:
176 | replyText = f"🎧🎧 音乐 🎧🎧\n\n{song1}"
177 | message_reply.tem_reply_Text_Message(replyText, e_context)
178 | songs_printed = True
179 | if video1 and video2 and not videos_printed:
180 | replyText = f"📽📽 视频 📽📽\n\n{video1}"
181 | message_reply.tem_reply_Text_Message(replyText, e_context)
182 | videos_printed = True
183 | else:
184 | # 处理普通消息
185 | # 同时回复歌名、类型和完整歌词
186 | if song_name and genre and full_lyrics and not song_info_printed:
187 | replyText = (f"⭐⭐ 歌曲信息 ⭐⭐\n\n『🤖 歌名』\n"
188 | f"{song_name}\n\n『💄 类型』\n{genre}"
189 | f"\n\n『📖 完整歌词』\n{full_lyrics}"
190 | f"\n\n👀 更多\n\n🚨 歌曲图片和实时音乐链接正在火速生成中🚀🚀🚀")
191 | message_reply.tem_reply_Text_Message(replyText, e_context)
192 | song_info_printed = True
193 | # 回复歌曲图片
194 | if song_image and not lyrics_image_printed:
195 | message_reply.tem_reply_Image_Url_Message(song_image, e_context)
196 | lyrics_image_printed = True
197 | # 回复实时音乐链接
198 | if music_link1 and music_link2 and not music_links_printed:
199 | replyText = (
200 | f"🎵🎵 即刻体验 🎵🎵\n\n『实时音乐1️⃣』\n{music_link1}\n\n『实时音乐2️⃣』\n{music_link2}\n\n"
201 | f"🚀 音乐MP3和视频正在火速生成中,大概需要2-3分钟,请耐心等待!")
202 | message_reply.tem_reply_Text_Message(replyText, e_context)
203 | music_links_printed = True
204 | # 回复歌曲
205 | if song1 and song2 and not songs_printed:
206 | while requests.get(song1).status_code != 200:
207 | time.sleep(1)
208 | # 生成唯一的文件名
209 | query = "music_" + str(int(time.time()))
210 | file_name1 = f"{query}.mp3"
211 | file_path1 = os.path.join("tmp", file_name1)
212 | # 确保 tmp 目录存在
213 | if not os.path.exists("tmp"):
214 | os.makedirs("tmp")
215 | try:
216 | with urllib.request.urlopen(song1) as response1, open(file_path1,
217 | 'wb') as out_file1:
218 | out_file1.write(response1.read())
219 | logger.info(f"[singsong]Music {file_path1} 下载成功, {song1}")
220 | message_reply.tem_reply_Video_Message(file_path1, e_context)
221 | songs_printed = True
222 | except Exception as e:
223 | logger.error(f"Error downloading song: {e}")
224 | continue
225 | # 回复视频
226 | if video1 and video2 and not videos_printed:
227 | while requests.get(video1).status_code != 200:
228 | time.sleep(1)
229 | logger.info(f"{video1}")
230 | message_reply.reply_Video_Url_Message(True, video1, e_context)
231 | videos_printed = True
232 | break
233 | except Exception:
234 | continue
235 |
236 | elif "[DONE]" in line:
237 | break
238 |
239 | else:
240 | continue
241 |
242 | except Exception as e:
243 | message_reply.reply_Error_Message(True, f"music_handle: {e}", e_context)
244 | raise Exception(f"An error occurred: {e}")
245 | finally:
246 | e_context.action = EventAction.BREAK_PASS
247 |
--------------------------------------------------------------------------------
/message/request_handle.py:
--------------------------------------------------------------------------------
1 | # 识别图片消息的请求体
2 | def recognize_message(prompt: str, image_url: str, model: str):
3 | return {
4 | "messages": [
5 | {
6 | "role": "user",
7 | "content": [
8 | {
9 | "type": "text",
10 | "text": prompt
11 | },
12 | {
13 | "type": "image_url",
14 | "image_url": {
15 | "url": image_url
16 | }
17 | }
18 | ]
19 | }
20 | ],
21 | "stream": False,
22 | "model": model
23 | }
24 |
25 |
26 | # 创造图片的请求体
27 | def image_message(prompt: str, model: str):
28 | return {
29 | "model": model,
30 | "prompt": prompt
31 | }
32 |
33 |
34 | # 创造音乐的请求体
35 | def music_message(prompt: str, model: str):
36 | return {
37 | "model": model,
38 | "stream": False,
39 | "messages": [
40 | {
41 | "content": prompt,
42 | "role": "user"
43 | }
44 | ]
45 | }
46 |
--------------------------------------------------------------------------------
/message/run.log:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/message/run.log
--------------------------------------------------------------------------------
/nohup.out:
--------------------------------------------------------------------------------
1 | python3: can't open file 'app.py': [Errno 2] No such file or directory
2 |
--------------------------------------------------------------------------------
/pictureChange.py:
--------------------------------------------------------------------------------
1 | import plugins
2 | from bridge.context import ContextType
3 | from bridge.reply import ReplyType
4 | from plugins import *
5 | from plugins.pictureChange.adminService.admin_service import admin_service
6 | from plugins.pictureChange.groupService.change_config import group_config
7 | from plugins.pictureChange.groupService.find_group import find_group
8 | from plugins.pictureChange.message import message_reply as MessageReply, message_type
9 | from plugins.pictureChange.message.message_limit import MessageLimit
10 | from plugins.pictureChange.util import file_handle
11 | from plugins.pictureChange.work.common import Common
12 |
13 |
14 | @plugins.register(name="pictureChange",
15 | desc="百度AI 和 Stable-Diffusion 来文生图和图生图, suno音乐,文件和图片识别,群聊聊天模型转换",
16 | version="2.0.1",
17 | author="yang yang")
18 | class pictureChange(Plugin):
19 | # 定义了模型枚举类型
20 | class Model(Enum):
21 | MODEL_1 = "anything-v5-PrtRE.safetensors [7f96a1a9ca]"
22 | MODEL_2 = "absolutereality_v181.safetensors [463d6a9fe8]"
23 | MODEL_3 = "QteaMix-fp16.safetensors [0c1efcbbd6]"
24 |
25 | def __init__(self):
26 | super().__init__()
27 | cursor = os.path.dirname(__file__)
28 | config_path = os.path.join(cursor, "config.json")
29 | try:
30 | with open(config_path, "r", encoding="utf-8") as f:
31 | config = json.load(f)
32 |
33 | # 用于stable_diffusion参数
34 | self.rules = config["rules"]
35 | self.defaults = config["defaults"]
36 | self.default_params = self.defaults["params"]
37 | self.default_options = self.defaults["options"]
38 | self.role_options = [role for role in config["roles"] if role["enable"]]
39 | self.start_args = config["start"]
40 | self.host = config["start"]["host"]
41 | self.port = config["start"]["port"]
42 | self.use_https = config["start"]["use_https"]
43 |
44 | # 用于变换和放大图片操作
45 | self.file_url = config["file_url"]
46 |
47 | # 用于聊天操作
48 | self.is_group_bot_name = conf().get("group_chat_prefix", [""])[0]
49 | self.single_bot_name = conf().get("single_chat_prefix", [""])[0]
50 | self.other_user_id = config["use_group"]
51 |
52 | # 用于翻译prompt
53 | self.is_use_fanyi = config["is_use_fanyi"]
54 | self.baidu_api_key = config["baidu_api_key"]
55 | self.baidu_secret_key = config["baidu_secret_key"]
56 |
57 | # 用于音乐分析
58 | self.music_model = config["music_model"]
59 |
60 | # 用于图片和文件分析
61 | self.openai_api_key = config["openai_api_key"]
62 | self.openai_api_base = config["openai_api_base"]
63 | self.image_recognize_model = config["image_recognize_model"]
64 | self.file_recognize_model = config["file_recognize_model"]
65 | self.image_recognize_prompt = config["image_recognize_prompt"]
66 | self.file_recognize_prompt = config["file_recognize_prompt"]
67 |
68 | self.negative_prompt = ("(((nsfw))),EasyNegative,badhandv4,ng_deepnegative_v1_75t,(worst quality:2), "
69 | "(low quality:2), (normal quality:2), lowres, ((monochrome)), ((grayscale)), "
70 | "bad anatomy,DeepNegative, skin spots, acnes, skin blemishes,(fat:1.2),"
71 | "facing away, looking away,tilted head, lowres,bad anatomy,bad hands, "
72 | "missing fingers,extra digit, fewer digits,bad feet,poorly drawn hands,"
73 | "poorly drawn face,mutation,deformed,extra fingers,extra limbs,extra arms,"
74 | "extra legs,malformed limbs,fused fingers,too many fingers,long neck,"
75 | "cross-eyed,mutated hands,polar lowres,bad body,bad proportions,"
76 | "gross proportions,missing arms,missing legs,extra digit, extra arms, "
77 | "extra leg, extra foot,teethcroppe,signature, watermark, username,blurry,"
78 | "cropped,jpeg artifacts,text,error,Lower body exposure")
79 |
80 | self.bot_prompt = '''作为 Stable Diffusion Prompt 提示词专家,您将从关键词中创建提示,通常来自 Danbooru
81 | 等数据库。提示通常描述图像,使用常见词汇,按重要性排列,并用逗号分隔。避免使用"-"或".",但可以接受空格和自然语言。避免词汇重复。为了强调关键词,请将其放在括号中以增加其权重。例如,"(
82 | flowers)"将'flowers'的权重增加1.1倍,而"(((flowers)))"将其增加1.331倍。使用"(
83 | flowers:1.5)"将'flowers'的权重增加1.5倍。只为重要的标签增加权重。提示包括三个部分:前缀(质量标签+风格词+效果器)+ 主题(图像的主要焦点)+
84 | 场景(背景、环境)。前缀影响图像质量。像"masterpiece"、"best
85 | quality"、"4k"这样的标签可以提高图像的细节。像"illustration"、"lensflare"这样的风格词定义图像的风格。像"bestlighting"、"lensflare
86 | "、"depthoffield"这样的效果器会影响光照和深度。主题是图像的主要焦点,如角色或场景。对主题进行详细描述可以确保图像丰富而详细。增加主题的权重以增强
87 | 其清晰度。对于角色,描述面部、头发、身体、服装、姿势等特征。场景描述环境。没有场景,图像的背景是平淡的,主题显得过大。某些主题本身包含场景(例如建筑物
88 | 、风景)。像"花草草地"、"阳光"、"河流"这样的环境词可以丰富场景。你的任务是设计图像生成的提示。请按照以下步骤进行操作:我会发送给您一个图像场景。生成 详细的图像描述,输出 Positive
89 | Prompt ,并确保用英文回复我。示例:我发送:二战时期的护士。您回复:A WWII-era nurse in a German uniform, holding a wine bottle and
90 | stethoscope, sitting at a table in white attire,with a table in the background, masterpiece,
91 | best quality, 4k, illustration style, best lighting, depth of field, detailed character,
92 | detailed environment.'''
93 |
94 | self.suno_bot_prompt = ("现在,我需要你根据我给你的一段内容,将这段内容按照语义分成 Title(题目),Song Description(歌曲描述),Type of "
95 | "Music(音乐类型)。并根据用户的意图生成对应语言的歌曲提示词.请直接了当地输出Title(题目),Song "
96 | "Description(歌曲描述),Type of Music(音乐类型),不要超过100字。")
97 | self.suno_image_music_prompt = config["image_music_prompt"]
98 |
99 | # 管理员的配置
100 | self.max_number = int(config["max_number"])
101 | self.max_size = int(config["max_size"])
102 | self.use_pictureChange = config["use_pictureChange"]
103 | self.music_create_prefix = config["music_create_prefix"]
104 | self.image_create_prefix = config["image_create_prefix"]
105 | self.use_stable_diffusion = config["use_stable_diffusion"]
106 | self.use_music_handle = config["use_music_handle"]
107 | self.use_file_handle = config["use_file_handle"]
108 | self.use_group_handle = config.get("use_group_handle", True)
109 | self.admin = admin_service()
110 |
111 | # 判断回复类型
112 | channel_type = conf().get("channel_type", "wx")
113 | # 根据类型修改
114 | if channel_type == "wx" or channel_type == "wxy":
115 | self.is_wecom = False
116 | else:
117 | self.is_wecom = True
118 |
119 | self.handlers[Event.ON_HANDLE_CONTEXT] = self.on_handle_context
120 | logger.info("[pictureChange] inited")
121 | except Exception as e:
122 | if isinstance(e, FileNotFoundError):
123 | logger.warn(f"[SD] init failed, {config_path} not found.")
124 | else:
125 | logger.warn("[SD] init failed.")
126 | raise e
127 |
128 | @staticmethod
129 | def get_config_path(json_path: str):
130 | curdir = os.path.dirname(__file__)
131 | return os.path.join(curdir, json_path)
132 |
133 | def on_handle_context(self, e_context: EventContext):
134 | channel = e_context['channel']
135 | if ReplyType.IMAGE in channel.NOT_SUPPORT_REPLYTYPE:
136 | return
137 |
138 | # 初始化消息
139 | context = e_context['context']
140 | context.get("msg").prepare()
141 | content = context.content.strip()
142 |
143 | # 初始化画图参数
144 | check_exist = False
145 | denoising_strength = 0
146 | cfg_scale = 0
147 | prompt = ""
148 | negative_prompt = self.negative_prompt
149 | roleRule_options = {}
150 |
151 | # 初始化消息类型
152 | is_group = context["msg"].is_group
153 | """
154 | "IMAGE": "False",
155 | "FILE": "True",
156 | "MUSIC": "False",
157 | "MODEL": "GLM-4",
158 | """
159 | is_group_enable = True
160 | is_group_image = True
161 | is_group_file = True
162 | is_group_music = True
163 | is_group_model = None
164 | user = e_context["context"]["receiver"]
165 |
166 | if is_group and self.use_group_handle:
167 | group_name = context["msg"].other_user_nickname
168 | data_group_config = find_group.find_group(group_name)
169 | logger.info(data_group_config)
170 | if data_group_config and data_group_config["ENABLE"]:
171 | is_group_image = data_group_config["IMAGE"]
172 | is_group_file = data_group_config["FILE"]
173 | is_group_music = data_group_config["MUSIC"]
174 | is_group_model = data_group_config["MODEL"]
175 | else:
176 | is_group_enable = False
177 | is_group_image = False
178 | is_group_file = False
179 | is_group_music = False
180 |
181 | request_bot_name = self.is_group_bot_name if is_group else self.single_bot_name
182 | if request_bot_name != "":
183 | request_bot_name = request_bot_name + " "
184 |
185 | # 测试
186 | logger.debug(context)
187 | logger.debug(f"收到信息:{content}")
188 |
189 | title = ""
190 | # 是否存在自定义规则
191 | if self.use_stable_diffusion:
192 | for role in self.role_options:
193 | if content.startswith(role['title'] + " "):
194 | title = role['title']
195 | denoising_strength = role['denoising_strength']
196 | cfg_scale = role['cfg_scale']
197 | prompt = role['prompt']
198 | negative_prompt = role['negative_prompt']
199 | if "options" in role:
200 | for key in role["options"]:
201 | roleRule_options[key] = role["options"][key]
202 | check_exist = True
203 | break
204 |
205 | # 开启插件,否则不能正常使用(这里可以添加限制)
206 | # if self.use_pictureChange:
207 | # self.handle_image_mode(content, e_context)
208 |
209 | # 判断已经开启插件,没有开启直接跳过
210 | if self.use_pictureChange and is_group_enable:
211 | try:
212 | # 判断消息类型
213 | if (e_context['context'].type == ContextType.IMAGE and is_group_image
214 | and (self.use_music_handle or self.use_stable_diffusion)):
215 | Common.process_init_image(request_bot_name, self.role_options,
216 | self.use_stable_diffusion, self.use_music_handle, True,
217 | self.is_wecom, e_context)
218 |
219 | elif e_context['context'].type == ContextType.FILE and is_group_file and self.use_file_handle:
220 | Common.process_file(self.openai_api_base, self.openai_api_key, self.file_recognize_model,
221 | self.file_recognize_prompt, e_context)
222 |
223 | elif (any(ext in content for ext in ["jpg", "jpeg", "png", "gif", "webp"]) and (
224 | content.startswith("http://") or content.startswith("https://")) and is_group_image
225 | and (self.use_music_handle or self.use_stable_diffusion)):
226 | Common.process_init_image_url(request_bot_name, self.role_options, self.use_stable_diffusion,
227 | self.use_music_handle, True, self.is_wecom, e_context)
228 |
229 | elif (any(content.startswith(prefix) for prefix in self.image_create_prefix)
230 | and is_group_image and self.use_stable_diffusion):
231 | content = next((content.replace(prefix, "") for prefix in self.image_create_prefix
232 | if content.startswith(prefix)),
233 | content)
234 | e_context['context'].content = content
235 | Common.process_image_create(self.is_use_fanyi, self.bot_prompt, self.rules, self.Model,
236 | request_bot_name, self.start_args, self.default_params,
237 | self.default_options, self.is_wecom, e_context)
238 |
239 | # 以下是对文字消息的操作
240 | elif content.startswith("👀 暂不处理 ") and is_group_image:
241 | file_content = content.split()[2]
242 | logger.info(f"{file_content}")
243 | replyText = file_handle.delete_file(file_content)
244 | MessageReply.reply_Text_Message(True, replyText, e_context)
245 |
246 | elif content.startswith("🤖 图像修复 ") and is_group_image and self.use_stable_diffusion:
247 | Common.process_baidu_image(self.baidu_api_key, self.baidu_secret_key, e_context)
248 |
249 | elif content.startswith("🖼️ 图像描述 ") and is_group_image:
250 | Common.process_image(self.openai_api_base, self.openai_api_key, self.image_recognize_model,
251 | self.image_recognize_prompt, e_context)
252 |
253 | elif content.startswith("🎡 自定义 ") and is_group_image and self.use_stable_diffusion:
254 | message_limit = MessageLimit()
255 | if message_limit.isLimit(self.max_number, e_context):
256 | return
257 | message_limit.using()
258 | Common.process_image_custom(self.is_use_fanyi, self.bot_prompt, self.Model, request_bot_name,
259 | self.start_args, negative_prompt, self.max_size, self.is_wecom,
260 | e_context)
261 | message_limit.success(self.max_number)
262 |
263 | # 判断用户发送的消息是否在config.json预设里面
264 | elif check_exist and is_group_image and self.use_stable_diffusion:
265 | message_limit = MessageLimit()
266 | if message_limit.isLimit(self.max_number, e_context):
267 | return
268 | message_limit.using()
269 | Common.process_image_change(self.Model, request_bot_name, self.start_args, self.default_options,
270 | roleRule_options, denoising_strength, cfg_scale, prompt,
271 | negative_prompt, title, self.max_size, self.is_wecom, e_context)
272 | message_limit.success(self.max_number)
273 |
274 | elif content.startswith("🎡 变换 ") and is_group_image and self.use_stable_diffusion:
275 | Common.process_image_transform(self.Model, request_bot_name, self.start_args, self.use_https,
276 | self.host, self.port, self.file_url, prompt, negative_prompt,
277 | self.max_size, self.is_wecom, e_context)
278 |
279 | elif content.startswith("🤖 放大 ") and is_group_image and self.use_stable_diffusion:
280 | Common.process_image_large(self.use_https, self.host, self.port, self.file_url, e_context)
281 |
282 | elif content.startswith("🎧 图生音 ") and is_group_music and self.use_music_handle:
283 | Common.process_image_music(self.openai_api_base, self.openai_api_key, self.image_recognize_model,
284 | self.music_model, self.suno_image_music_prompt, self.is_wecom, e_context)
285 |
286 | elif any(content.startswith(prefix) for prefix in
287 | self.music_create_prefix) and is_group_music and self.use_music_handle:
288 | prompt = content.replace("文生音 ", "")
289 | Common.process_text_music(self.suno_bot_prompt, self.openai_api_base, self.openai_api_key,
290 | self.music_model, prompt, self.is_wecom, e_context)
291 |
292 | elif not is_group:
293 | self.admin_service(content, user, e_context)
294 |
295 | # 跳过插件,到下一个插件里面
296 | else:
297 | user_data = conf().get_user_data(user)
298 | if is_group_model:
299 | user_data["gpt_model"] = is_group_model
300 | logger.info(f"模型已经更换成为 {is_group_model}")
301 | e_context.action = EventAction.CONTINUE
302 |
303 | except Exception as e:
304 | replyText = "[😭SD画图失败] " + str(e) + "\n🧸快联系管理员解决问题吧!"
305 | logger.error("[SD画图失败] exception: %s" % e)
306 | MessageReply.reply_Error_Message(True, replyText, e_context)
307 | # util.delete_file(file_content)
308 |
309 | elif not self.use_pictureChange and self.admin.is_admin(user):
310 | self.admin_service(content, user, e_context)
311 |
312 | else:
313 | e_context.action = EventAction.CONTINUE
314 |
315 | def get_help_text(self, **kwargs):
316 | if not conf().get('image_create_prefix'):
317 | help_text = "画图功能未启用"
318 | else:
319 | trigger = conf()['image_create_prefix'][0]
320 | help_text = message_type.on_help_reply(trigger, self.rules)
321 | return help_text
322 |
323 | def admin_service(self, content, sender_id, e_context):
324 | # 认证管理员
325 | if content.startswith("认证 "):
326 | # 假设认证管理员的信息应该是:"认证 root"
327 | # 分离参数
328 | content1 = str(content).replace("认证 ", "")
329 | if self.admin.verify_admin(sender_id, content1):
330 | replyText = "🥰认证成功"
331 | else:
332 | replyText = "😭认证失败,请重新认证"
333 | MessageReply.reply_Text_Message(True, replyText, e_context)
334 | return
335 |
336 | if self.admin.is_admin(sender_id):
337 | if content.startswith("修改pictureChange参数"):
338 | content1 = content.split(" ")
339 | if len(content1) != 3:
340 | replyText = f"😭修改成失败,格式错误,应该为‘修改pictureChange参数 参数名称 参数数值’"
341 | MessageReply.reply_Text_Message(True, replyText, e_context)
342 | return
343 | name = str(content1[1])
344 | change_value = content1[2]
345 | if str(change_value).lower() == "true":
346 | change_value = True
347 | elif str(change_value).lower() == "false":
348 | change_value = False
349 |
350 | if not self.admin.update_json(sender_id, name, value=change_value):
351 | replyText = f"😭修改成失败,没有这个参数名称"
352 | MessageReply.reply_Text_Message(True, replyText, e_context)
353 | else:
354 | replyText = f"🥰修改成功,当前{name}的值为{change_value}"
355 | MessageReply.reply_Text_Message(True, replyText, e_context)
356 | return
357 |
358 | elif content.startswith("修改密码"):
359 | content1 = content.split(" ")
360 | if content1 is None or len(content1) != 2:
361 | return
362 | self.admin.update_password(sender_id, content1[1])
363 | replyText = f"🥰修改密码成功"
364 | MessageReply.reply_Text_Message(True, replyText, e_context)
365 | return
366 |
367 | elif content.startswith("修改host"):
368 | content1 = content.split(" ")
369 | if len(content1) != 2:
370 | return
371 | self.admin.update_json(sender_id, "start", "host", value=content1[1])
372 | self.host = content1[1]
373 | replyText = f"🥰修改host成功,当前host为{self.host}"
374 | MessageReply.reply_Text_Message(True, replyText, e_context)
375 | return
376 |
377 | # 清空管理员
378 | elif content.startswith("清空管理员"):
379 | self.admin.clear_admin(sender_id)
380 | replyText = "🥰清空管理员成功"
381 | MessageReply.reply_Text_Message(True, replyText, e_context)
382 | return
383 |
384 | elif content.startswith("群聊修改 "):
385 | content = content.replace("群聊修改 ", "")
386 | replyText = group_config().ins_command(content)
387 | MessageReply.reply_Text_Message(True, replyText, e_context)
388 | return
389 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | # sdwebui plugin
2 | webuiapi>=0.6.2
3 | langid
4 | oauthlib
--------------------------------------------------------------------------------
/util/__init__.py:
--------------------------------------------------------------------------------
1 | import requests
2 |
3 | import plugins.pictureChange.message.request_handle as MessageHandle
4 | from bridge.bridge import Bridge
5 | from common import const
6 | from common.log import logger
7 |
8 |
9 | # 文字生成图片
10 | def text_to_image(url: str, key: str, prompt: str, model: str, session_id: str = None):
11 | headers = {
12 | 'Authorization': f'Bearer {key}',
13 | 'Content-Type': 'application/json'
14 | }
15 | payload = MessageHandle.image_message(prompt, model)
16 | btype = Bridge().get_bot_type("chat")
17 | if btype not in [const.OPEN_AI, const.CHATGPT, const.CHATGPTONAZURE, const.LINKAI]:
18 | return
19 | bot = Bridge().get_bot("chat")
20 | bot.sessions.session_query(prompt, session_id)
21 |
22 | try:
23 | response = requests.post(url, headers=headers, json=payload)
24 | response.raise_for_status()
25 | reply = str(response.json()["data"][0]["url"]).strip()
26 | # 保存聊天记录(包含群聊和个人)
27 | # bot.sessions.session_reply(reply, session_id)
28 | return reply
29 | except requests.exceptions.RequestException as e:
30 | logger.error(f"An error occurred: {e}")
31 | return f"An error occurred: {e}"
32 |
33 |
34 | # 文字生成音乐
35 | def text_to_music(url: str, key: str, prompt: str, model: str, max_retries: int = 1,
36 | session_id: str = None):
37 | headers = {
38 | 'Authorization': f'Bearer {key}',
39 | 'Content-Type': 'application/json'
40 | }
41 |
42 | payload = MessageHandle.music_message(prompt, model)
43 | btype = Bridge().get_bot_type("chat")
44 | if btype not in [const.OPEN_AI, const.CHATGPT, const.CHATGPTONAZURE, const.LINKAI]:
45 | return
46 | bot = Bridge().get_bot("chat")
47 | bot.sessions.session_query(prompt, session_id)
48 | retries = 0
49 |
50 | while retries < max_retries:
51 | try:
52 | response = requests.post(url, headers=headers, json=payload)
53 | response.raise_for_status()
54 | reply = str(response.json()["choices"][0]["message"]["content"])
55 | # 1.提取歌曲信息(歌名,风格,歌词,歌曲图片)
56 | # 2.提取有效的url,并下载到相应MP3文件
57 |
58 | # 保存聊天记录(包含群聊和个人)
59 | # bot.sessions.session_reply(reply, session_id)
60 | return reply
61 |
62 | except requests.exceptions.RequestException:
63 | retries += 1
64 |
65 | return f"Failed to retrieve content after {max_retries} attempts due to 503 errors."
66 |
67 |
68 | # 分析文件
69 | def recognize_file(url: str, key: str, prompt: str, file_url: str, model: str, session_id: str = None):
70 | headers = {
71 | 'Authorization': f'Bearer {key}',
72 | 'Content-Type': 'application/json'
73 | }
74 |
75 | payload = MessageHandle.recognize_message(prompt, file_url, model)
76 | btype = Bridge().get_bot_type("chat")
77 | if btype not in [const.OPEN_AI, const.CHATGPT, const.CHATGPTONAZURE, const.LINKAI]:
78 | return
79 | bot = Bridge().get_bot("chat")
80 | bot.sessions.session_query(prompt, session_id)
81 | try:
82 | response = requests.post(url, headers=headers, json=payload)
83 | response.raise_for_status()
84 | reply = str(response.json()["choices"][0]["message"]["content"])
85 | # 保存聊天记录(包含群聊和个人)
86 | # bot.sessions.session_reply(reply, session_id)
87 | return reply
88 | except requests.exceptions.RequestException as e:
89 | if e.response:
90 | logger.error(f"Response content: {e.response.text}") # Print the response content for debugging
91 | return f"An error occurred: {e}"
92 |
93 |
94 | # 分析图片
95 | def recognize_image(url: str, key: str, prompt: str, image_url: str, model: str, session_id: str = None):
96 | headers = {
97 | 'Authorization': f'Bearer {key}',
98 | 'Content-Type': 'application/json'
99 | }
100 | payload = MessageHandle.recognize_message(prompt, image_url, model)
101 | btype = Bridge().get_bot_type("chat")
102 | if btype not in [const.OPEN_AI, const.CHATGPT, const.CHATGPTONAZURE, const.LINKAI]:
103 | return
104 | bot = Bridge().get_bot("chat")
105 | bot.sessions.session_query(prompt, session_id)
106 | try:
107 | response = requests.post(url, headers=headers, json=payload)
108 | response.raise_for_status()
109 | reply = str(response.json()["choices"][0]["message"]["content"])
110 | bot.sessions.session_reply(reply, session_id)
111 | return reply
112 | except requests.exceptions.RequestException as e:
113 | logger.error(f"An error occurred: {e}")
114 | return f"An error occurred: {e}"
115 |
--------------------------------------------------------------------------------
/util/__pycache__/__init__.cpython-311.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/util/__pycache__/__init__.cpython-311.pyc
--------------------------------------------------------------------------------
/util/__pycache__/__init__.cpython-312.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/util/__pycache__/__init__.cpython-312.pyc
--------------------------------------------------------------------------------
/util/__pycache__/__init__.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/util/__pycache__/__init__.cpython-38.pyc
--------------------------------------------------------------------------------
/util/__pycache__/baidu_image.cpython-311.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/util/__pycache__/baidu_image.cpython-311.pyc
--------------------------------------------------------------------------------
/util/__pycache__/baidu_image.cpython-312.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/util/__pycache__/baidu_image.cpython-312.pyc
--------------------------------------------------------------------------------
/util/__pycache__/baidu_image.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/util/__pycache__/baidu_image.cpython-38.pyc
--------------------------------------------------------------------------------
/util/__pycache__/file_handle.cpython-311.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/util/__pycache__/file_handle.cpython-311.pyc
--------------------------------------------------------------------------------
/util/__pycache__/file_handle.cpython-312.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/util/__pycache__/file_handle.cpython-312.pyc
--------------------------------------------------------------------------------
/util/__pycache__/file_handle.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/util/__pycache__/file_handle.cpython-38.pyc
--------------------------------------------------------------------------------
/util/__pycache__/image_handle.cpython-311.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/util/__pycache__/image_handle.cpython-311.pyc
--------------------------------------------------------------------------------
/util/__pycache__/image_handle.cpython-312.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/util/__pycache__/image_handle.cpython-312.pyc
--------------------------------------------------------------------------------
/util/__pycache__/image_handle.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/util/__pycache__/image_handle.cpython-38.pyc
--------------------------------------------------------------------------------
/util/__pycache__/translate_prompt.cpython-311.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/util/__pycache__/translate_prompt.cpython-311.pyc
--------------------------------------------------------------------------------
/util/__pycache__/translate_prompt.cpython-312.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/util/__pycache__/translate_prompt.cpython-312.pyc
--------------------------------------------------------------------------------
/util/__pycache__/translate_prompt.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/util/__pycache__/translate_prompt.cpython-38.pyc
--------------------------------------------------------------------------------
/util/baidu_image.py:
--------------------------------------------------------------------------------
1 | import base64
2 | import io
3 | import urllib.parse
4 |
5 | import requests
6 | from oauthlib.common import urlencoded
7 |
8 | from common.log import logger
9 | from plugins.pictureChange.message import message_reply as MessageReply
10 | from plugins.pictureChange.util import file_handle as FileHandle
11 |
12 |
13 | # 百度图片处理
14 | def read_and_encode_image(file_content):
15 | try:
16 | with open(file_content, 'rb') as file:
17 | image_data = file.read()
18 | encoded_image = base64.b64encode(image_data).decode('utf-8')
19 | if urlencoded:
20 | encoded_image = urllib.parse.quote_plus(encoded_image)
21 | return encoded_image
22 | except Exception as e:
23 | logger.error(f"处理文件数据时出现错误:{e}")
24 | return None
25 |
26 |
27 | # 回复图片
28 | def reply_image(base64_image_data, file_content, e_context):
29 | try:
30 | image_data = base64.b64decode(base64_image_data)
31 | image_storage = io.BytesIO()
32 | image_storage.write(image_data)
33 | image_storage.seek(0)
34 | MessageReply.reply_Image_Message(True, image_storage, e_context)
35 | FileHandle.delete_file(file_content)
36 | except Exception as e:
37 | logger.error(f"回复图片时出现错误:{e}")
38 |
39 |
40 | # 获取访问令牌
41 | def get_access_token(api_key, secret_key):
42 | token_url = "https://aip.baidubce.com/oauth/2.0/token"
43 | token_params = {
44 | "grant_type": "client_credentials",
45 | "client_id": api_key,
46 | "client_secret": secret_key
47 | }
48 | try:
49 | response = requests.post(token_url, params=token_params)
50 | response.raise_for_status()
51 | return response.json().get("access_token")
52 | except requests.RequestException as e:
53 | logger.error(f"获取访问令牌时出现错误:{e}")
54 | return None
55 |
56 |
57 | # 处理图片
58 | def process_image(encoded_image, access_token):
59 | process_url = f"https://aip.baidubce.com/rest/2.0/image-process/v1/image_definition_enhance"
60 | headers = {
61 | 'Content-Type': 'application/x-www-form-urlencoded',
62 | 'Accept': 'application/json'
63 | }
64 | payload = f"image={encoded_image}"
65 | # logger.debug(payload)
66 | try:
67 | response = requests.post(process_url, headers=headers, data=payload, params={"access_token": access_token})
68 | response.raise_for_status()
69 | logger.debug(response.json())
70 | return response.json().get('image')
71 | except requests.RequestException as e:
72 | logger.error(f"API请求失败:{e}")
73 | return None
74 |
--------------------------------------------------------------------------------
/util/file_handle.py:
--------------------------------------------------------------------------------
1 | import base64
2 | import json
3 | import mimetypes
4 | import os
5 |
6 | from common.log import logger
7 |
8 |
9 | # 读取配置文件
10 | def get_config_path(json_path: str):
11 | cursor = os.path.dirname(__file__)
12 | return os.path.join(cursor, json_path)
13 |
14 |
15 | # 读取配置文件
16 | def update_config(config_path, user_id, append):
17 | with open(config_path, "r", encoding="utf-8") as f:
18 | config = json.load(f)
19 | if append:
20 | config["use_group"].append(user_id)
21 | else:
22 | config["use_group"].remove(user_id)
23 | with open(config_path, "w", encoding="utf-8") as f:
24 | json.dump(config, f, indent=4, ensure_ascii=False)
25 |
26 |
27 | # 用于图片和文件转成base64
28 | def file_toBase64(file_path: str):
29 | if os.path.isfile(file_path):
30 | try:
31 | with open(file_path, 'rb') as file:
32 | image_data = file.read()
33 | base64_image = base64.b64encode(image_data).decode('utf-8')
34 | # 获取文件的MIME类型
35 | mime_type, _ = mimetypes.guess_type(file_path, strict=False)
36 | if mime_type is None:
37 | if file_path.endswith(".docx"):
38 | mime_type = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
39 | elif file_path.endswith(".xlsx"):
40 | mime_type = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
41 | else:
42 | mime_type = "application/octet-stream"
43 | logger.info(f"文件路径: {file_path}")
44 | logger.info(f"文件MIME类型: {mime_type}")
45 | if mime_type is None:
46 | mime_type = "application/octet-stream" # 默认MIME类型
47 | base64_image = f"data:{mime_type};base64,{base64_image}"
48 | return base64_image
49 | except Exception as e:
50 | logger.error(f"读取文件时出错: {e}")
51 | return None
52 | else:
53 | logger.warning(f"文件不存在: {file_path}")
54 | return None
55 |
56 |
57 | def delete_file(file_content):
58 | try:
59 | if os.path.isfile(file_content):
60 | os.remove(file_content)
61 | return "🥰图片已成功删除\n🧸感谢您的使用!"
62 | except Exception as e:
63 | logger.error(f"{str(e)}")
64 | return "😭文件不存在或已删除"
65 |
--------------------------------------------------------------------------------
/util/image_handle.py:
--------------------------------------------------------------------------------
1 | # 用于处理图片大小的工具函数
2 | def adjust_image(width, height, maxsize: int):
3 | # 确保最小尺寸为 768
4 | if width < 768 or height < 768:
5 | scale_factor = max(768 / width, 768 / height)
6 | width = int(width * scale_factor)
7 | height = int(height * scale_factor)
8 |
9 | # 确保最大尺寸不超过 maxsize
10 | if width > maxsize or height > maxsize:
11 | scale_factor = min(maxsize / width, maxsize / height)
12 | width = int(width * scale_factor)
13 | height = int(height * scale_factor)
14 |
15 | return int(width), int(height)
16 |
17 |
18 | # 用于格式化图片 URL 的工具函数
19 | def format_image_url(use_https, host, port, file_url, file_content):
20 | protocol = "https" if use_https else "http"
21 | port_part = f":{port}" if port else ""
22 | image_path = f"{file_url}{file_content}"
23 | image_url = f"{protocol}://{host}{port_part}/{image_path}"
24 | return image_url
25 |
--------------------------------------------------------------------------------
/util/translate_prompt.py:
--------------------------------------------------------------------------------
1 | import langid
2 |
3 | from bot import bot_factory
4 | from bridge.bridge import Bridge
5 | from common.log import logger
6 |
7 |
8 | # 翻译提示
9 | def translatePrompt(is_use_fanyi, bot_prompt, prompt, params, session_id):
10 | if prompt:
11 | lang = langid.classify(prompt)[0]
12 | if lang != "en":
13 | logger.info("[SD] translate prompt from {} to en".format(lang))
14 | try:
15 | if not is_use_fanyi:
16 | bot = bot_factory.create_bot(Bridge().btype['chat'])
17 | session = bot.sessions.build_session(session_id, bot_prompt)
18 | # 不带有之前的提示词
19 | # session.add_query(prompt)
20 | result = bot.reply_text(session)
21 | prompt = result['content']
22 | else:
23 | prompt = Bridge().fetch_translate(prompt, to_lang="en")
24 | except Exception as e:
25 | logger.info("[SD] translate failed: {}".format(e))
26 | logger.info("[SD] translated prompt={}".format(prompt))
27 | params["prompt"] += f", {prompt}"
28 |
29 |
30 | # 返回翻译提示
31 | def simple_translatePrompt(is_use_fanyi, bot_prompt, prompt, session_id):
32 | if prompt:
33 | lang = langid.classify(prompt)[0]
34 | if lang != "en":
35 | logger.info("[SD] translate prompt from {} to en".format(lang))
36 | try:
37 | if not is_use_fanyi:
38 | bot = bot_factory.create_bot(Bridge().btype['chat'])
39 | session = bot.sessions.build_session(session_id, bot_prompt)
40 | # 不带有之前的提示词
41 | # session.add_query(prompt)
42 | result = bot.reply_text(session)
43 | prompt = result['content']
44 | else:
45 | prompt = Bridge().fetch_translate(prompt, to_lang="en")
46 | return prompt
47 | except Exception as e:
48 | logger.info("[SD] translate failed: {}".format(e))
49 | logger.info("[SD] translated prompt={}".format(prompt))
50 | return None
51 |
--------------------------------------------------------------------------------
/work/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/work/__init__.py
--------------------------------------------------------------------------------
/work/__pycache__/__init__.cpython-311.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/work/__pycache__/__init__.cpython-311.pyc
--------------------------------------------------------------------------------
/work/__pycache__/__init__.cpython-312.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/work/__pycache__/__init__.cpython-312.pyc
--------------------------------------------------------------------------------
/work/__pycache__/__init__.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/work/__pycache__/__init__.cpython-38.pyc
--------------------------------------------------------------------------------
/work/__pycache__/common.cpython-311.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/work/__pycache__/common.cpython-311.pyc
--------------------------------------------------------------------------------
/work/__pycache__/common.cpython-312.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/work/__pycache__/common.cpython-312.pyc
--------------------------------------------------------------------------------
/work/__pycache__/common.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yanyutin753/pictureChange/9453ae4c87fc1e61dd7fa59db88bde0451fceff8/work/__pycache__/common.cpython-38.pyc
--------------------------------------------------------------------------------
/work/common.py:
--------------------------------------------------------------------------------
1 | import os
2 | import time
3 | import urllib.parse
4 |
5 | import requests
6 |
7 | import plugins.pictureChange.message.message_sd_reply as SDReply
8 | import plugins.pictureChange.util.baidu_image as Baidu_Image
9 | from bridge.context import ContextType
10 | from common.log import logger
11 | from plugins import EventAction
12 | from plugins.pictureChange import util
13 | from plugins.pictureChange.message import message_handle as MessageHandle
14 | from plugins.pictureChange.message import message_reply as MessageReply
15 | from plugins.pictureChange.message import message_type as MessageType
16 | from plugins.pictureChange.message.music_handle import music_handle
17 | from plugins.pictureChange.util import file_handle as FileHandle
18 |
19 |
20 | def process_image_music_content(openai_api_base, openai_api_key, image_recognize_model, prompt, recognize_func,
21 | reply_message_method, e_context):
22 | context = e_context['context']
23 | session_id = context.kwargs.get('session_id')
24 | file_content = context.content.strip().split()[2]
25 | if os.path.isfile(file_content):
26 | try:
27 | file_url = FileHandle.file_toBase64(file_content)
28 | reply_text = recognize_func(openai_api_base,
29 | openai_api_key, prompt, file_url,
30 | image_recognize_model, session_id)
31 | return reply_text
32 | except Exception as e:
33 | reply_text = str(e)
34 | logger.error("Processing failed: {}".format(str(e)))
35 | reply_message_method(True, reply_text, e_context)
36 | return None
37 | else:
38 | reply_text = "找不到相应的图片文件,请联系管理员!"
39 | reply_message_method(True, reply_text, e_context)
40 | return None
41 |
42 |
43 | # 描述图片信息
44 | def process_image_content(openai_api_base, openai_api_key, image_recognize_model, prompt, recognize_func,
45 | error_message, reply_message_method, e_context):
46 | context = e_context['context']
47 | session_id = context.kwargs.get('session_id')
48 | file_content = context.content.strip().split()[2]
49 | if os.path.isfile(file_content):
50 | try:
51 | file_url = FileHandle.file_toBase64(file_content)
52 | replyText = recognize_func(openai_api_base + "/chat/completions",
53 | openai_api_key, prompt, file_url,
54 | image_recognize_model, session_id)
55 | except Exception as e:
56 | replyText = error_message
57 | logger.error("Processing failed: {}".format(str(e)))
58 | else:
59 | replyText = error_message
60 | reply_message_method(True, replyText, e_context)
61 |
62 |
63 | # 描述文件信息
64 | def process_file_content(openai_api_base, openai_api_key, file_recognize_model, prompt, recognize_func,
65 | error_message,
66 | reply_message_method,
67 | e_context):
68 | context = e_context['context']
69 | session_id = context.kwargs.get('session_id')
70 | file_content = context.content.strip()
71 | if os.path.isfile(file_content):
72 | try:
73 | file_url = FileHandle.file_toBase64(file_content)
74 | replyText = recognize_func(openai_api_base + "/chat/completions",
75 | openai_api_key, prompt, file_url,
76 | file_recognize_model, session_id)
77 | except Exception as e:
78 | replyText = error_message
79 | logger.error("Processing failed: {}".format(str(e)))
80 | else:
81 | replyText = error_message
82 | reply_message_method(True, replyText, e_context)
83 |
84 |
85 | class Common:
86 |
87 | @staticmethod
88 | def process_image(openai_api_base, openai_api_key, image_recognize_model, image_recognize_prompt, e_context):
89 | process_image_content(openai_api_base, openai_api_key, image_recognize_model,
90 | image_recognize_prompt, util.recognize_image,
91 | "🥰请先发送图片给我,我将为您进行图像分析",
92 | MessageReply.reply_Text_Message, e_context)
93 |
94 | @staticmethod
95 | def process_file(openai_api_base, openai_api_key, file_recognize_model, file_recognize_prompt, e_context):
96 | process_file_content(openai_api_base, openai_api_key, file_recognize_model,
97 | file_recognize_prompt, util.recognize_file,
98 | "🥰请先发送文件给我,我将为您进行文件分析",
99 | MessageReply.reply_Text_Message, e_context)
100 |
101 | # 图片创作
102 | @staticmethod
103 | def process_image_create(is_use_fanyi, bot_prompt, rules, Model, request_bot_name, start_args, params, options,
104 | is_wecom, e_context):
105 | try:
106 | context = e_context['context']
107 | content = MessageHandle.init_content(e_context)
108 | session_id = context.kwargs.get('session_id')
109 |
110 | text = "🚀图片生成中~~~\n⏳请您耐心等待1-2分钟\n✨请稍等片刻✨✨\n❤️感谢您的耐心与支持"
111 | MessageReply.tem_reply_Text_Message(text, e_context)
112 |
113 | SDReply.create_Image(content, is_use_fanyi, bot_prompt, rules, Model, request_bot_name, start_args, params,
114 | options, session_id, is_wecom, e_context)
115 | except Exception as e:
116 | raise RuntimeError(f"图片处理发生错误: {e}") from e
117 |
118 | # 图片自定义图生图
119 | @staticmethod
120 | def process_image_custom(is_use_fanyi, bot_prompt, Model, request_bot_name, start_args,
121 | negative_prompt, maxsize, is_wecom, e_context):
122 | try:
123 | context = e_context['context']
124 | content = MessageHandle.init_content(e_context)
125 | session_id = context.kwargs.get('session_id')
126 |
127 | text = "🚀图片生成中~~~\n⏳请您耐心等待1-2分钟\n✨请稍等片刻✨✨\n❤️感谢您的耐心与支持"
128 | MessageReply.tem_reply_Text_Message(text, e_context)
129 |
130 | SDReply.custom_Image(content, is_use_fanyi, bot_prompt, Model, request_bot_name, start_args,
131 | session_id, negative_prompt, maxsize, is_wecom, e_context)
132 | except Exception as e:
133 | raise RuntimeError(f"图片处理发生错误: {e}") from e
134 |
135 | # 图片按照config配置图生图
136 | @staticmethod
137 | def process_image_change(Model, request_bot_name, start_args, default_options,
138 | roleRule_options, denoising_strength, cfg_scale,
139 | prompt, negative_prompt, title, maxsize: int, is_wecom, e_context):
140 | try:
141 | content = MessageHandle.init_content(e_context)
142 |
143 | text = "🚀图片生成中~~~\n⏳请您耐心等待1-2分钟\n✨请稍等片刻✨✨\n❤️感谢您的耐心与支持"
144 | MessageReply.tem_reply_Text_Message(text, e_context)
145 |
146 | SDReply.change_Image(content, Model, request_bot_name, start_args, default_options,
147 | roleRule_options, denoising_strength, cfg_scale,
148 | prompt, negative_prompt, title, maxsize, is_wecom, e_context)
149 | except Exception as e:
150 | raise RuntimeError(f"图片处理发生错误: {e}") from e
151 |
152 | # 图片变换
153 | @staticmethod
154 | def process_image_transform(Model, request_bot_name, start_args, use_https, host, port, file_url,
155 | prompt, negative_prompt, maxsize: int, is_wecom, e_context):
156 | try:
157 | content = MessageHandle.init_content(e_context)
158 |
159 | text = "🚀图片生成中~~~\n⏳请您耐心等待1-2分钟\n✨请稍等片刻✨✨\n❤️感谢您的耐心与支持"
160 | MessageReply.tem_reply_Text_Message(text, e_context)
161 |
162 | SDReply.transform_Image(content, Model, request_bot_name, start_args, use_https, host, port, file_url,
163 | prompt, negative_prompt, maxsize, is_wecom, e_context)
164 | except Exception as e:
165 | raise RuntimeError(f"图片处理发生错误: {e}") from e
166 |
167 | # 图片放大
168 | @staticmethod
169 | def process_image_large(use_https, host, port, file_url, e_context):
170 | content = MessageHandle.init_content(e_context)
171 |
172 | text = "🚀图片生成中~~~\n⏳请您耐心等待1-2分钟\n✨请稍等片刻✨✨\n❤️感谢您的耐心与支持"
173 | MessageReply.tem_reply_Text_Message(text, e_context)
174 | try:
175 | SDReply.large_Image(content, use_https, host, port, file_url, e_context)
176 | except Exception as e:
177 | raise RuntimeError(f"图片处理发生错误: {e}") from e
178 |
179 | # 接收图片初始化发送信息
180 | @staticmethod
181 | def process_init_image(request_bot_name, role_options, use_stable_diffusion,
182 | use_music_handle, use_file_handle, is_wecom, e_context):
183 | content = MessageHandle.init_content(e_context)
184 | file_content = urllib.parse.quote(content)
185 | if e_context['context'].type == ContextType.IMAGE:
186 | replyText = MessageType.in_image_reply(file_content, request_bot_name, role_options, use_stable_diffusion,
187 | use_music_handle, use_file_handle, is_wecom)
188 | MessageReply.reply_Text_Message(True, replyText, e_context)
189 |
190 | # 接收图片链接初始化发送信息
191 | @staticmethod
192 | def process_init_image_url(request_bot_name, role_options, use_stable_diffusion,
193 | use_music_handle, use_file_handle, is_wecom, e_context):
194 | try:
195 | content = MessageHandle.init_content(e_context)
196 | response = requests.get(content)
197 | file_content = str(int(time.time())) + ".jpg"
198 | if response.status_code == 200:
199 | with open(file_content, 'wb') as file:
200 | file.write(response.content)
201 | replyText = MessageType.in_image_reply(file_content, request_bot_name, role_options,
202 | use_stable_diffusion, use_file_handle, use_music_handle,
203 | is_wecom)
204 | MessageReply.reply_Text_Message(True, replyText, e_context)
205 | else:
206 | logger.error("下载失败")
207 | e_context.action = EventAction.BREAK_PASS
208 | except Exception as e:
209 | raise RuntimeError(f"图片处理发生错误: {e}") from e
210 |
211 | # 处理百度图片(图像修复)
212 | @staticmethod
213 | def process_baidu_image(baidu_api_key, baidu_secret_key, e_context):
214 | try:
215 | content = MessageHandle.init_content(e_context)
216 | file_content = content.split()[2]
217 |
218 | if os.path.isfile(file_content):
219 | encoded_image = Baidu_Image.read_and_encode_image(file_content)
220 | if not encoded_image:
221 | return
222 | MessageReply.tem_reply_Text_Message(
223 | "🚀图片生成中~~~\n⏳请您耐心等待1-2分钟\n✨请稍等片刻✨✨\n❤️感谢您的耐心与支持",
224 | e_context
225 | )
226 | access_token = Baidu_Image.get_access_token(baidu_api_key, baidu_secret_key)
227 | if not access_token:
228 | MessageReply.reply_Error_Message(True, "无法获取百度AI接口访问令牌", e_context)
229 | return
230 | processed_image_data = Baidu_Image.process_image(encoded_image, access_token)
231 | if processed_image_data:
232 | Baidu_Image.reply_image(processed_image_data, file_content, e_context)
233 | else:
234 | MessageReply.reply_Error_Message(True, "未找到转换后的图像数据", e_context)
235 | else:
236 | MessageReply.reply_Error_Message(True, "🥰请先发送图片给我,我将为您进行图像修复", e_context)
237 | except Exception as e:
238 | raise RuntimeError(f"图片处理发生错误: {e}") from e
239 |
240 | @staticmethod
241 | def process_text_music(bot_prompt, url, key, model, prompt, is_wecom, e_context):
242 | try:
243 | url = url + "/chat/completions"
244 | music_handle.text_to_music(bot_prompt, True, url, key, prompt, model, is_wecom, e_context)
245 | except Exception as e:
246 | raise RuntimeError(f"文生音乐发生错误: {e}") from e
247 |
248 | @staticmethod
249 | def process_image_music(url, key, image_recognize_model, suno_model, bot_prompt, is_wecom, e_context):
250 | try:
251 | url = url + "/chat/completions"
252 | image_text = process_image_music_content(url, key, image_recognize_model, bot_prompt, util.recognize_image,
253 | MessageReply.reply_Text_Message, e_context)
254 | music_handle.text_to_music(bot_prompt, False, url, key, image_text, suno_model, is_wecom, e_context)
255 | except Exception as e:
256 | raise RuntimeError(f"图生音乐发生错误: {e}") from e
257 |
--------------------------------------------------------------------------------