NovelAi安装

NovelAI下载压缩包,启动就行。它自带前后端,本地输入标签就可AI绘图,不再赘述

值得一提的是,使用标签超市里面的标签画出来的图片更优雅。

可参考此文档

  1. 需要使用python3.8及以上
  2. 电脑太差不行,显存4G以上

QQ机器人

QQ机器人框架极多,例如小栗子等等

但由于我注册不上小栗子,而且好像这个框架需要付费,所以我不再折腾它了

由于我们想实现的仅仅只是几个关键词读取,推送回去几条消息而已,我们自己写完全可以实现

Go-cqhttp可以模拟登陆一个QQ手表版,以此实现读取所有的QQ消息,并可以通过CQ码等发送消息出去。

安装(树莓派)

版本很多,请一定下载符合自己系统的版本

release中下载符合自己系统版本的包

GO-cqhttp部分系统支持一键运行,但树莓派不支持,所以我下载了符合树莓派系统的linux-armV7

下载完成解压,初次运行将自动生成配置文件,所以,请先运行一次。

  • 第一次运行选择http链路即可

  • 在解压目录下运行./go-cqhttp启动服务

由于AI项目在win10上运行,所以我们需要上报数据链到局域网端口中

config.yml中填写上报IP地址及端口

重启服务

不出意外的话,你的服务已经运行起来了

1
2
3
4
5
6
7
# 私聊消息发送
http://192.168.2.199:5700/send_private_msg?user_id=对方QQ&message=消息内容

# 群聊消息发送
http://192.168.2.199:5700/send_group_msg?group_id=群id&message=消息内容&message_type=group&auto_escape=false

# 在局域网内使用IP加端口,跟上参数,(QQ需要已添加好友),get一次就能顺利发出消息。

win10监听

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from flask import Flask, request
import json
import requests

app = Flask(__name__)

# 获取QQ消息
@app.route('/', methods=["POST"])
def post_data():
if request.get_json().get('message_type') == 'private': # 私聊信息
uid = request.get_json().get('sender').get('user_id') # 获取信息发送者的 QQ号码
message = request.get_json().get('raw_message') # 获取原始信息
print(message, uid)

if request.get_json().get('message_type') == 'group': # 如果是群聊信息
gid = request.get_json().get('group_id') # 获取群号
uid = request.get_json().get('sender').get('user_id') # 获取信息发送者的 QQ号码
message = request.get_json().get('raw_message') # 获取原始信息
print(message, gid, uid)
send(message, gid, uid) # 检测发送消息函数
return 'OK'

if __name__ == '__main__':
app.run(host='192.168.2.191', port=1234) # 此处的 host和 port对应上面 yml文件的设置

win10监听1234端口,当树莓派端获取到消息,将上报到此端口

指令处理

当检测到某个关键词时,将处理对应的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# 发送消息
def send(message, gid, uid):
put = 'http://192.168.2.199:5700/send_group_msg?group_id={0}&message={1}&message_type=group&auto_escape=false'

# 推送到QQ
def send_qq_msg(path, gid):
path = quote(path, 'utf-8')
pic_path = f'[CQ:image,file=http://frp1.freefrp.net:13389/{path}]'
data = {
"message_type": "group",
"group_id": gid,
"message": pic_path
}
print(pic_path, gid)
response = requests.post('http://192.168.2.199:5700/send_group_msg', json=data)

if not message.find("画了个画"):
key = message[5:].split(',')
# 关键词转换
m = []
for ii in range(len(key)):
m.append(tanslate(key[ii]))
time.sleep(1)
yu = ",".join(m)

# 如果没被画过,开始绘画
if yu not in over_send_msg:
message = "开始绘画\n关键词:" + message[5:] + "[" + yu + "]\n预计时间:1m..."
over_send_msg.append(",".join(m))
requests.get(url=put.format(gid, message))
print("画图\n关键词:" + message[5:] + "\n==>" + yu)
print(over_send_msg)
paint_state = True
requests.get(url=put.format(gid, "来自:%d的绘图完成\n%s" % (uid, start_piant(yu))))
send_qq = input("是否允许推送QQ?(y推送):")
if send_qq != "y":
send_qq_msg(key_qq_msg, gid)
else:
requests.get(url=put.format(gid, "你的绘图,太刺激了吧.....不给你看"))

elif not message.find("画了个画"):
yu = message[5:].replace(",", ",")
if yu not in over_send_msg:
message = "开始绘画\n关键词:[" + yu + "]\n预计时间:1m..."
over_send_msg.append(yu)
requests.get(url=put.format(gid, message))
print("画图\n关键词:\n==>" + yu)
print(over_send_msg)
paint_state = True
requests.get(url=put.format(gid, "来自:%d的绘图完成\n%s" % (uid, start_piant(yu))))
send_qq = input("是否允许推送QQ?(y推送):")
if send_qq != "y":
send_qq_msg(key_qq_msg, gid)
else:
requests.get(url=put.format(gid, "你的绘图,太刺激了吧.....不给你看"))

在侦测到”高级画画”,”画了个画”时,将触发函数

完整py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
import requests
from flask import Flask, request
from urllib.parse import quote
import http.client
import hashlib
import urllib
import random
import json
import time


app = Flask(__name__)

over_send_msg = []
key_msg = []
--------------------------------------------------------------
# 请求绘图
# 拿到处理完成后的用户关键词后,post请求本地AI,画完后返回图片消息
def start_piant(key_new):
cookies = {
}

# 随机数取值
value = (random.uniform(100236542, 875987458))
value = int(value)
key = "masterpiece, best quality, " + key_new
print(key, "绘图中")

headers = {
'Accept': '*/*',
'Accept-Language': 'en,zh-CN;q=0.9,zh;q=0.8',
'Authorization': 'Bearer',
'Connection': 'keep-alive',
'Origin': 'http://localhost:6969',
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Site': 'same-origin',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36',
'sec-ch-ua': '"Google Chrome";v="107", "Chromium";v="107", "Not=A?Brand";v="24"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
}

# 数据内容提交
json_data = {
'prompt': key,
'width': 512,
'height': 768,
'scale': 12,
'sampler': 'k_euler_ancestral',
'steps': 28,
'seed': value,
'n_samples': 1,
'ucPreset': 0,
'uc': 'lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry',
}

response = requests.post('http://localhost:6969/generate-stream', cookies=cookies, headers=headers, json=json_data)

# 定义全局变量方便拿值

global key_qq_msg
key_qq_msg = key_new + " s-" + str(value) + ".png"

return key_new + " s-" + str(value) + ".png"

--------------------------------------------------------------
# 百度通用翻译API,详见官方文档,请使用自己的参数
# 将用户输入的中文关键词翻译成英文关键词,ai处理效果更好

# coding=utf-8
def tanslate(q):
appid = '' # 填写你的appid
secretKey = '' # 填写你的密钥
httpClient = None
myurl = '/api/trans/vip/translate'
fromLang = 'zh' # 原文语种
toLang = 'en' # 译文语种
salt = random.randint(32768, 65536)
sign = appid + q + str(salt) + secretKey
sign = hashlib.md5(sign.encode()).hexdigest()
myurl = myurl + '?appid=' + appid + '&q=' + urllib.parse.quote(
q) + '&from=' + fromLang + '&to=' + toLang + '&salt=' + str(
salt) + '&sign=' + sign

try:
httpClient = http.client.HTTPConnection('api.fanyi.baidu.com')
httpClient.request('GET', myurl)

# response是HTTPResponse对象
response = httpClient.getresponse()
result_all = response.read().decode("utf-8")
result = json.loads(result_all)
return result["trans_result"][0]["dst"]

except Exception as e:
print(e)
finally:
if httpClient:
httpClient.close()

--------------------------------------------------------------
# 发送消息
# 由于服务部署于不同设备,推送QQ图片时不方便。使用内网穿透,直接映射文件出去。
def send(message, gid, uid):

推送到的地址,需要改变ip
put = 'http://192.168.2.199:5700/send_group_msg?group_id={0}&message={1}&message_type=group&auto_escape=false'
# 图片推送到QQ,使用CQ消息 https://docs.go-cqhttp.org/cqcode/#%E5%9B%BE%E7%89%87
def send_qq_msg(path, gid):
path = quote(path, 'utf-8')
pic_path = f'[CQ:image,file=http://frp1.freefrp.net:13389/{path}]'
data = {
"message_type": "group",
"group_id": gid,
"message": pic_path
}
print(pic_path, gid)
response = requests.post('http://192.168.2.199:5700/send_group_msg', json=data)

# 判断关键词
if not message.find("画了个画"):
key = message[5:].split(',')
# 关键词转换,百度翻译而已
m = []
for ii in range(len(key)):
m.append(tanslate(key[ii]))
time.sleep(1)
yu = ",".join(m)

# 如果没被画过,开始绘画
if yu not in over_send_msg:
message = "开始绘画\n关键词:" + message[5:] + "[" + yu + "]\n预计时间:1m..."
over_send_msg.append(",".join(m))
requests.get(url=put.format(gid, message))
print("画图\n关键词:" + message[5:] + "\n==>" + yu)
print(over_send_msg)
paint_state = True
requests.get(url=put.format(gid, "来自:%d的绘图完成\n%s" % (uid, start_piant(yu))))
send_qq = input("是否允许推送QQ图片?(y表示不推送):")
if send_qq != "y":
send_qq_msg(key_qq_msg, gid)
else:
requests.get(url=put.format(gid, "你的绘图,太刺激了吧.....不给你看"))

elif not message.find("高级画画"):
# 高级绘画时,将不处理关键词,即直接推送标签。
yu = message[5:].replace(",", ",")
if yu not in over_send_msg:
message = "开始绘画\n关键词:[" + yu + "]\n预计时间:1m..."
over_send_msg.append(yu)
requests.get(url=put.format(gid, message))
print("画图\n关键词:\n==>" + yu)
print(over_send_msg)
paint_state = True
requests.get(url=put.format(gid, "来自:%d的绘图完成\n%s" % (uid, start_piant(yu))))
send_qq = input("是否允许推送QQ图片?(y表示不推送):")
if send_qq != "y":
send_qq_msg(key_qq_msg, gid)
else:
requests.get(url=put.format(gid, "你的绘图,太刺激了吧.....不给你看"))


""" else:
requests.get(url=put.format(gid, "喂,已经画过了喂,GPU很烫的!"))"""


# 获取QQ消息
@app.route('/', methods=["POST"])
def post_data():
if request.get_json().get('message_type') == 'private': # 私聊信息
uid = request.get_json().get('sender').get('user_id') # 获取信息发送者的 QQ号码
message = request.get_json().get('raw_message') # 获取原始信息
print(message, uid)

if request.get_json().get('message_type') == 'group': # 如果是群聊信息
gid = request.get_json().get('group_id') # 获取群号
uid = request.get_json().get('sender').get('user_id') # 获取信息发送者的 QQ号码
message = request.get_json().get('raw_message') # 获取原始信息
print(message, gid, uid)
send(message, gid, uid)

return 'OK'

if __name__ == '__main__':
app.run(host='192.168.2.191', port=1234) # 此处的 host和 port对应上面 yml文件的设置

frp端口映射

使用了开源FrpClient项目进行映射

至于免费frp服务,网络上太多了afrpsfreefrp等等

建立服务后,更改python代码中的ip与端口,浏览器中带端口测试,不出意外的话,你就已经映射了文件。

效果预览

完成啦