mirror of
https://github.com/FloatTech/ZeroBot-Plugin.git
synced 2026-02-07 15:40:26 +00:00
Compare commits
19 Commits
v1.5.1
...
v1.5.2-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fce75a9475 | ||
|
|
7616d5759f | ||
|
|
ea2c81a9c7 | ||
|
|
37cff9ff31 | ||
|
|
b8d3d6af9b | ||
|
|
fdf90a72cc | ||
|
|
ba0c05a774 | ||
|
|
3250ec14ac | ||
|
|
ce2f390361 | ||
|
|
71434232fe | ||
|
|
852629fa2e | ||
|
|
f10676d16d | ||
|
|
d43ea7df1d | ||
|
|
21712c6299 | ||
|
|
2fc47a38fa | ||
|
|
cbb4408668 | ||
|
|
a0df41b859 | ||
|
|
494c1b33b4 | ||
|
|
2034d91912 |
109
README.md
109
README.md
@@ -26,7 +26,7 @@
|
||||
| [Mrs4s/go-cqhttp](https://github.com/Mrs4s/go-cqhttp) | [MiraiGo](https://github.com/Mrs4s/MiraiGo) | Mrs4s |
|
||||
| [yyuueexxiinngg/cqhttp-mirai](https://github.com/yyuueexxiinngg/cqhttp-mirai) | [Mirai](https://github.com/mamoe/mirai) | yyuueexxiinngg |
|
||||
| [takayama-lily/onebot](https://github.com/takayama-lily/onebot) | [OICQ](https://github.com/takayama-lily/oicq) | takayama |
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
> 如果您不知道什么是 [OneBot](https://github.com/howmanybots/onebot) 或不希望运行多个程序,还可以直接前往 [gocqzbp](https://github.com/FloatTech/gocqzbp) 的 [Release](https://github.com/FloatTech/gocqzbp/releases) 页面下载单一可执行文件或前往 [Packages](https://github.com/FloatTech/gocqzbp/pkgs/container/gocqzbp) 页面使用`docker`,运行后按提示登录即可。
|
||||
@@ -354,13 +354,15 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] [ ai绘图 | 生成色图 | 生成涩图 | ai画图 ] xxx
|
||||
|
||||
- [x] [ ai高级绘图 | 高级生成色图 | 高级生成涩图 | ai高级画图 ] xxx
|
||||
|
||||
- [x] [ 以图绘图 | 以图生图 | 以图画图 ] xxx [图片]|@xxx|[qq号]
|
||||
|
||||
- [ ] 设置ai绘图配置 [server] [token]
|
||||
- [x] 设置ai绘图配置 [server] [token]
|
||||
|
||||
例1: 设置ai绘图配置 http://91.216.169.75:5010 abc
|
||||
例: 设置ai绘图配置 http://91.216.169.75:5010 abc
|
||||
|
||||
例2: 设置ai绘图配置 http://91.217.139.190:5010 abc
|
||||
参考服务器 http://91.217.139.190:5010, http://91.216.169.75:5010, http://185.80.202.180:5010
|
||||
|
||||
通过 http://91.217.139.190:5010/token 获取token
|
||||
|
||||
@@ -403,6 +405,51 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
- [x] 百度下[xxx]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>百度内容审核</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/baiduaudit"`
|
||||
|
||||
- [x] 获取BDAkey
|
||||
|
||||
- [x] 配置BDAKey [API Key] [Secret Key]
|
||||
|
||||
- [x] 获取BDAkey
|
||||
|
||||
- [x] [开启|关闭]内容审核
|
||||
|
||||
- [x] [开启|关闭]撤回提示
|
||||
|
||||
- [x] [开启|关闭]详细提示
|
||||
|
||||
- [x] [开启|关闭]撤回禁言
|
||||
|
||||
- [x] [开启|关闭]禁言累加
|
||||
|
||||
- [x] [开启|关闭]文本检测
|
||||
|
||||
- [x] [开启|关闭]图像检测
|
||||
|
||||
- [x] 设置最大禁言时间[分钟,默认:60,最大43200]
|
||||
|
||||
- [x] 设置每次累加时间[分钟,默认:1]
|
||||
|
||||
- [x] 设置撤回禁言时间[分钟,默认:1]
|
||||
|
||||
- [x] 查看检测类型
|
||||
|
||||
- [x] 查看检测配置
|
||||
|
||||
- [x] 测试文本检测[文本内容]
|
||||
|
||||
- [x] 测试图像检测[图片]
|
||||
|
||||
- [x] 设置检测类型[类型编号]
|
||||
|
||||
- [x] 设置不检测类型[类型编号]
|
||||
|
||||
检测类型编号列表:[1:违禁违规|2:文本色情|3:敏感信息|4:恶意推广|5:低俗辱骂|6:恶意推广-联系方式|7:恶意推广-软文推广]
|
||||
</details>
|
||||
<details>
|
||||
<summary>base64卦加解密</summary>
|
||||
|
||||
@@ -572,15 +619,9 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/drift_bottle"`
|
||||
|
||||
- [x] (在群xxx)丢漂流瓶(到频道xxx) [消息]
|
||||
- [x] @Bot pick (随机捞一个漂流瓶)
|
||||
|
||||
- [x] (从频道xxx)捡漂流瓶
|
||||
|
||||
- [x] @BOT 创建频道 xxx
|
||||
|
||||
- [x] 跳入(频道)海中
|
||||
|
||||
- [x] 注:不显式限制时,私聊发送可在所有群抽到,群聊发送仅可在本群抽到,默认频道为 global
|
||||
- [x] @Bot throw xxx (投递内容xxx,支持图片文字,投递内容需要大于10个字符或者带有图片)
|
||||
|
||||
</details>
|
||||
<details>
|
||||
@@ -962,6 +1003,8 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/nihongo"`
|
||||
|
||||
- [x] 日语语法 [xxx] (使用tag随机)
|
||||
|
||||
- [x] 搜索日语语法 [xxx]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
@@ -1135,21 +1178,45 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>百度文心AI画图</summary>
|
||||
<summary>百度文心AI</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wenxinAI"`
|
||||
|
||||
- 基于百度文心的免费AI画图插件(因为是免费的,图片质量你懂的)
|
||||
基于百度文心API的一些功能
|
||||
|
||||
- key申请链接:https://wenxin.baidu.com/moduleApi/key
|
||||
|
||||
- [x] 为[自己/本群/QQ号/群+群号]设置AI画图key [API Key] [Secret Key]
|
||||
|
||||
- 例:“为10086设置AI画图key 123 456”;“为群10010设置AI画图key 789 101”
|
||||
key申请链接:https://wenxin.baidu.com/moduleApi/key
|
||||
|
||||
- [x] 为[自己/本群/QQ号/群+群号]设置文心key [API Key] [Secret Key]
|
||||
|
||||
- [x] 为[自己/本群/QQ号/群+群号]设置画图key [API Key] [Secret Key]
|
||||
|
||||
例:“为10086设置画图key 123 456”;“为群10010设置画图key 789 101”
|
||||
|
||||
文心key和画图key的API key 可以是相同的,只是文心key日限为200,画图日限为50,以此作区别。
|
||||
|
||||
- [x] 文心作文 (x字的)[作文题目]
|
||||
|
||||
- [x] 文心提案 (x字的)[文案标题]
|
||||
|
||||
- [x] 文心摘要 (x字的)[文章内容]
|
||||
|
||||
- [x] 文心小说 (x字的)[小说上文]
|
||||
|
||||
- [x] 文心对联 [上联]
|
||||
|
||||
- [x] 文心问答 [问题]
|
||||
|
||||
- [x] 文心补全 [带“_”的填空题]
|
||||
|
||||
- [x] 文心自定义 [prompt]
|
||||
|
||||
- [x] [bot名称]画几张[图片描述]的[图片类型][图片尺寸]
|
||||
|
||||
- 指令示例:
|
||||
指令示例:
|
||||
|
||||
- 文心作文 我的椛椛机器人
|
||||
|
||||
- 文心作文 300字的我的椛椛机器人
|
||||
|
||||
- 椛椛帮我画几张金凤凰,背景绚烂,高饱和,古风,仙境,高清,4K,古风的油画方图
|
||||
|
||||
@@ -1219,9 +1286,7 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
- [x] @Bot 任意文本(任意一句话回复)
|
||||
|
||||
- [x] 设置回复模式[青云客 | 小爱]
|
||||
|
||||
</details>
|
||||
|
||||
## 三种使用方法,推荐第一种
|
||||
|
||||
### 1. 使用稳定版/测试版 (推荐)
|
||||
|
||||
10
go.mod
10
go.mod
@@ -3,20 +3,21 @@ module github.com/FloatTech/ZeroBot-Plugin
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/Baidu-AIP/golang-sdk v1.1.1
|
||||
github.com/Coloured-glaze/gg v1.3.4
|
||||
github.com/FloatTech/AnimeAPI v1.5.2-0.20221015060924-fe2f85a3cf45
|
||||
github.com/FloatTech/floatbox v0.0.0-20221011153549-68005767c531
|
||||
github.com/FloatTech/AnimeAPI v1.5.2-0.20221028033300-a9293e7eecb8
|
||||
github.com/FloatTech/floatbox v0.0.0-20221028033104-a243fca6f2a3
|
||||
github.com/FloatTech/sqlite v0.5.0
|
||||
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b
|
||||
github.com/FloatTech/zbpctrl v1.5.2-0.20221011153929-4834c6911511
|
||||
github.com/FloatTech/zbputils v1.5.1-0.20221011154037-734498125e07
|
||||
github.com/FloatTech/zbputils v1.5.1-0.20221028033223-1fdfaf978116
|
||||
github.com/RomiChan/syncx v0.0.0-20220404072119-d7ea0ae15a4c
|
||||
github.com/antchfx/htmlquery v1.2.5
|
||||
github.com/corona10/goimagehash v1.1.0
|
||||
github.com/fumiama/ahsai v0.1.0
|
||||
github.com/fumiama/cron v1.3.0
|
||||
github.com/fumiama/go-base16384 v1.6.1
|
||||
github.com/fumiama/go-registry v0.1.6
|
||||
github.com/fumiama/go-registry v0.2.1
|
||||
github.com/fumiama/gotracemoe v0.0.3
|
||||
github.com/fumiama/sqlite3 v1.14.6
|
||||
github.com/fumiama/unibase2n v0.0.0-20221003115227-e7db987de949
|
||||
@@ -43,6 +44,7 @@ require (
|
||||
github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4 // indirect
|
||||
github.com/faiface/beep v1.1.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||
github.com/fumiama/go-simple-protobuf v0.1.0 // indirect
|
||||
github.com/fumiama/gofastTEA v0.0.10 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.0.4 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
|
||||
20
go.sum
20
go.sum
@@ -1,19 +1,21 @@
|
||||
github.com/Baidu-AIP/golang-sdk v1.1.1 h1:RQsAmgDSAkiq22I6n7XJ2t3afgzFeqjY46FGhvrx4cw=
|
||||
github.com/Baidu-AIP/golang-sdk v1.1.1/go.mod h1:bXnGw7xPeKt8aF7UCELKrV6UZ/46spItONK1RQBQj1Y=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Coloured-glaze/gg v1.3.4 h1:l31zIF/HaVwkzjrj+A56RGQoSKyKuR1IWtIrqXGFStI=
|
||||
github.com/Coloured-glaze/gg v1.3.4/go.mod h1:Ih5NLNNDHOy3RJbB0EPqGTreIzq/H02TGThIagh8HJg=
|
||||
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/FloatTech/AnimeAPI v1.5.2-0.20221015060924-fe2f85a3cf45 h1:XbNlD0irJELgdR304TvqmFrxdH7hsxA/Ah9xLHFP3eQ=
|
||||
github.com/FloatTech/AnimeAPI v1.5.2-0.20221015060924-fe2f85a3cf45/go.mod h1:RgcMDA1S7C81bq7HQjygMEEo+EXwAlsutvKMv7DafgY=
|
||||
github.com/FloatTech/floatbox v0.0.0-20221011153549-68005767c531 h1:Z0yn6LFhEyC12hj+TBXc2P7/kWlCd/jlwv4JFndgpnw=
|
||||
github.com/FloatTech/floatbox v0.0.0-20221011153549-68005767c531/go.mod h1:4tfIeB74L1RzhNp3nNjaTw8m3IEnc+q/k6k/MhL07ks=
|
||||
github.com/FloatTech/AnimeAPI v1.5.2-0.20221028033300-a9293e7eecb8 h1:W+Gb+NGv6RJZI4BSJHHADzYC9YeDfftFGphP8aMUvbg=
|
||||
github.com/FloatTech/AnimeAPI v1.5.2-0.20221028033300-a9293e7eecb8/go.mod h1:2RjLcJ67OxRebKTrxBKy4P/8wPdcVhci8a/HALVUAQQ=
|
||||
github.com/FloatTech/floatbox v0.0.0-20221028033104-a243fca6f2a3 h1:yiq5kEr51FTfz7xxDY+xjbcdgDWyvZ6U93cf1xSsGs4=
|
||||
github.com/FloatTech/floatbox v0.0.0-20221028033104-a243fca6f2a3/go.mod h1:GVbLqexg8XJGuZs2zBZHO7jswCAPkZ9M/IKBYD0I/L0=
|
||||
github.com/FloatTech/sqlite v0.5.0 h1:U7J5Omc534PqmH6csfu+ypCo3DS8L91l5lTsxUu3b/U=
|
||||
github.com/FloatTech/sqlite v0.5.0/go.mod h1:i33d92OtR8jcp5fBUvQtospf27+MkfUxnGwnZ95E/dA=
|
||||
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b h1:tvciXWq2nuvTbFeJGLDNIdRX3BI546D3O7k7vrVueZw=
|
||||
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b/go.mod h1:fHZFWGquNXuHttu9dUYoKuNbm3dzLETnIOnm1muSfDs=
|
||||
github.com/FloatTech/zbpctrl v1.5.2-0.20221011153929-4834c6911511 h1:i2+JjTRR7gW8n1KivMKj3NEsCEEllYp8jneeOyg1Lz0=
|
||||
github.com/FloatTech/zbpctrl v1.5.2-0.20221011153929-4834c6911511/go.mod h1:TC5RkmSwKJvkDV+7vlTpcY+rnviB5gBq6JNOKnfZXHc=
|
||||
github.com/FloatTech/zbputils v1.5.1-0.20221011154037-734498125e07 h1:nG1q2NJZPehyV0xk88WHtqgwsOohkEDMFu/8v9rN1/o=
|
||||
github.com/FloatTech/zbputils v1.5.1-0.20221011154037-734498125e07/go.mod h1:UYuWZBInYdGZOXxEazrvaJE8nYGRB4xxoaacX6nKosk=
|
||||
github.com/FloatTech/zbputils v1.5.1-0.20221028033223-1fdfaf978116 h1:ZHAMbLbSkirxV3/Z7FKaiF9TiMRCavCYsIbYDIYbSGc=
|
||||
github.com/FloatTech/zbputils v1.5.1-0.20221028033223-1fdfaf978116/go.mod h1:nxTBx0YX8Ewq8oef2em4aJ5RH/5ZiG4PizK8v/csm7w=
|
||||
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||
github.com/RomiChan/syncx v0.0.0-20220404072119-d7ea0ae15a4c h1:cNPOdTNiVwxLpROLjXCgbIPvdkE+BwvxDvgmdYmWx6Q=
|
||||
github.com/RomiChan/syncx v0.0.0-20220404072119-d7ea0ae15a4c/go.mod h1:KqZzu7slNKROh3TSYEH/IUMG6f4M+1qubZ5e52QypsE=
|
||||
@@ -50,8 +52,10 @@ github.com/fumiama/cron v1.3.0 h1:ZWlwuexF+HQHl3cYytEE5HNwD99q+3vNZF1GrEiXCFo=
|
||||
github.com/fumiama/cron v1.3.0/go.mod h1:bz5Izvgi/xEUI8tlBN8BI2jr9Moo8N4or0KV8xXuPDY=
|
||||
github.com/fumiama/go-base16384 v1.6.1 h1:4yb4JgmBJDnQtq3XGXXdLrVwEnRpjhMUt4eAcsNeA30=
|
||||
github.com/fumiama/go-base16384 v1.6.1/go.mod h1:OEn+947GV5gsbTAnyuUW/SrfxJYUdYupSIQXOuGOcXM=
|
||||
github.com/fumiama/go-registry v0.1.6 h1:Ee/tXCCIR/xt8celhbbw0W/xDMdhAXLwy2YFBB/LWFk=
|
||||
github.com/fumiama/go-registry v0.1.6/go.mod h1:dIUVbiOgfk9oZcsgwDvNLC72i+ctibVukSXR/9bLviI=
|
||||
github.com/fumiama/go-registry v0.2.1 h1:PCu4d1OIYkLmoSufyxov3QXRul4lXrAfXfK1pVS2wrQ=
|
||||
github.com/fumiama/go-registry v0.2.1/go.mod h1:GP45kejHuDLFxcWdksrt75r5rHBqYwtfeUl3JzGWxfQ=
|
||||
github.com/fumiama/go-simple-protobuf v0.1.0 h1:rLzJgNqB6LHNDVMl81yyNt6ZKziWtVfu+ioF0edlEVw=
|
||||
github.com/fumiama/go-simple-protobuf v0.1.0/go.mod h1:5yYNapXq1tQMOZg9bOIVhQlZk9pQqpuFIO4DZLbsdy4=
|
||||
github.com/fumiama/gofastTEA v0.0.10 h1:JJJ+brWD4kie+mmK2TkspDXKzqq0IjXm89aGYfoGhhQ=
|
||||
github.com/fumiama/gofastTEA v0.0.10/go.mod h1:RIdbYZyB4MbH6ZBlPymRaXn3cD6SedlCu5W/HHfMPBk=
|
||||
github.com/fumiama/gotracemoe v0.0.3 h1:iI5EbE9A3UUbfukG6+/soYPjp1S31eCNYf4tw7s6/Jc=
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
var (
|
||||
// Banner ...
|
||||
Banner = "* OneBot + ZeroBot + Golang\n" +
|
||||
"* Version 1.5.1 - 2022-10-16 12:58:18 +0800 CST\n" +
|
||||
"* Version 1.5.2-beta2 - 2022-10-28 12:49:51 +0800 CST\n" +
|
||||
"* Copyright © 2020 - 2022 FloatTech. All Rights Reserved.\n" +
|
||||
"* Project: https://github.com/FloatTech/ZeroBot-Plugin"
|
||||
reg = registry.NewRegReader("reilia.fumiama.top:32664", "fumiama")
|
||||
|
||||
1
main.go
1
main.go
@@ -65,6 +65,7 @@ import (
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/alipayvoice" // 支付宝到账语音
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/b14" // base16384加解密
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/baidu" // 百度一下
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/baiduaudit" // 百度内容审核
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/base64gua" // base64卦加解密
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/baseamasiro" // base天城文加解密
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili" // b站相关
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
@@ -52,11 +53,15 @@ func init() { // 插件主体
|
||||
DisableOnDefault: false,
|
||||
Help: "ai绘图\n" +
|
||||
"- [ ai绘图 | 生成色图 | 生成涩图 | ai画图 ] xxx\n" +
|
||||
"- [ ai高级绘图 | 高级生成色图 | 高级生成涩图 | ai高级画图 ] [prompt]\n" +
|
||||
"- [ 以图绘图 | 以图生图 | 以图画图 ] xxx [图片]|@xxx|[qq号]\n" +
|
||||
"- 设置ai绘图配置 [server] [token]\n" +
|
||||
"例1: 设置ai绘图配置 http://91.216.169.75:5010 abc\n" +
|
||||
"例2: 设置ai绘图配置 http://91.217.139.190:5010 abc\n" +
|
||||
"通过 http://91.217.139.190:5010/token 获取token",
|
||||
"例: 设置ai绘图配置 http://91.217.139.190:5010 abc\n" +
|
||||
"参考服务器 http://91.217.139.190:5010, http://91.216.169.75:5010, http://185.80.202.180:5010\n" +
|
||||
"通过 http://91.217.139.190:5010/token 获取token\n" +
|
||||
"[prompt]参数如下\n" +
|
||||
"tags:tag词条\nntags:ntag词条\nshape:[Portrait|Landscape|Square]\nscale:[6:20]\nseed:种子\n" +
|
||||
"参数与参数内容用:连接,每个参数之间用回车或者&分割",
|
||||
PrivateDataFolder: "aipaint",
|
||||
})
|
||||
datapath = file.BOTPATH + "/" + engine.DataFolder()
|
||||
@@ -133,6 +138,56 @@ func init() { // 插件主体
|
||||
}
|
||||
sendAiImg(ctx, data)
|
||||
})
|
||||
engine.OnPrefixGroup([]string{`ai高级绘图`, `高级生成色图`, `高级生成涩图`, `ai高级画图`}).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
server, token, err := cfg.load()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
tags := make(map[string]string)
|
||||
args := strings.Split(ctx.State["args"].(string), "\n")
|
||||
if len(args) < 1 {
|
||||
ctx.SendChain(message.Text("ERROR: 请输入正确的参数"))
|
||||
return
|
||||
}
|
||||
for _, info := range args {
|
||||
value := strings.Split(info, ":")
|
||||
if len(value) > 1 {
|
||||
if value[0] == "R18" && value[1] == "1" {
|
||||
value[1] = "0"
|
||||
ctx.SendChain(message.Text("不准涩涩!已将R18设置为0。"))
|
||||
}
|
||||
tags[value[0]] = strings.Join(value[1:], ":")
|
||||
}
|
||||
}
|
||||
ctx.SendChain(message.Text("少女祈祷中..."))
|
||||
apiurl := "/got_image?token=" + token
|
||||
if _, ok := tags["tags"]; ok {
|
||||
apiurl += "&tags=" + url.QueryEscape(strings.ReplaceAll(strings.TrimSpace(tags["tags"]), " ", "%20"))
|
||||
}
|
||||
if _, ok := tags["ntags"]; ok {
|
||||
apiurl += "&ntags=" + url.QueryEscape(strings.ReplaceAll(strings.TrimSpace(tags["ntags"]), " ", "%20"))
|
||||
}
|
||||
if _, ok := tags["R18"]; ok {
|
||||
apiurl += "&R18=" + url.QueryEscape(strings.TrimSpace(tags["R18"]))
|
||||
}
|
||||
if _, ok := tags["shape"]; ok {
|
||||
apiurl += "&shape=" + url.QueryEscape(strings.TrimSpace(tags["shape"]))
|
||||
}
|
||||
if _, ok := tags["scale"]; ok {
|
||||
apiurl += "&scale=" + url.QueryEscape(strings.TrimSpace(tags["scale"]))
|
||||
}
|
||||
if _, ok := tags["seed"]; ok {
|
||||
apiurl += "&seed=" + url.QueryEscape(strings.TrimSpace(tags["seed"]))
|
||||
}
|
||||
data, err := web.GetData(server + apiurl)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
sendAiImg(ctx, data)
|
||||
})
|
||||
engine.OnRegex(`^设置ai绘图配置\s(.*[^\s$])\s(.+)$`, zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
regexMatched := ctx.State["regex_matched"].([]string)
|
||||
@@ -157,11 +212,22 @@ func sendAiImg(ctx *zero.Ctx, data []byte) {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
r.Uc, err = url.QueryUnescape(r.Uc)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
}
|
||||
encodeStr := base64.StdEncoding.EncodeToString(data)
|
||||
m := message.Message{ctxext.FakeSenderForwardNode(ctx, message.Image("base64://"+encodeStr))}
|
||||
m = append(m, ctxext.FakeSenderForwardNode(ctx, message.Text(r.String())))
|
||||
if id := ctx.Send(m).ID(); id == 0 {
|
||||
if mid := ctx.Send(m); mid.ID() == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控或下载图片用时过长,请耐心等待"))
|
||||
} else {
|
||||
go func(i message.MessageID) {
|
||||
time.Sleep(90 * time.Second)
|
||||
ctx.DeleteMessage(i)
|
||||
}(mid)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
500
plugin/baiduaudit/audit.go
Normal file
500
plugin/baiduaudit/audit.go
Normal file
@@ -0,0 +1,500 @@
|
||||
// Package baiduaudit 百度内容审核
|
||||
package baiduaudit
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/Baidu-AIP/golang-sdk/aip/censor"
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// 服务网址:https://console.bce.baidu.com/ai/?_=1665977657185#/ai/antiporn/overview/index
|
||||
// 返回参数说明:https://cloud.baidu.com/doc/ANTIPORN/s/Nk3h6xbb2
|
||||
type baiduRes struct {
|
||||
LogID int `json:"log_id"` // 请求唯一id
|
||||
Conclusion string `json:"conclusion"` // 审核结果,可取值:合规、不合规、疑似、审核失败
|
||||
ConclusionType int `json:"conclusionType"` // 审核结果类型,可取值1.合规,2.不合规,3.疑似,4.审核失败
|
||||
Data []auditData `json:"data"`
|
||||
ErrorCode int `json:"error_code"` // 错误提示码,失败才返回,成功不返回
|
||||
ErrorMsg string `json:"error_msg"` // 错误提示信息,失败才返回,成功不返回
|
||||
}
|
||||
|
||||
type auditData struct {
|
||||
Type int `json:"type"` // 审核主类型,11:百度官方违禁词库、12:文本反作弊、13:自定义文本黑名单、14:自定义文本白名单
|
||||
SubType int `json:"subType"` // 审核子类型,0:含多种类型,具体看官方链接,1:违禁违规、2:文本色情、3:敏感信息、4:恶意推广、5:低俗辱骂 6:恶意推广-联系方式、7:恶意推广-软文推广
|
||||
Conclusion string `json:"conclusion"` // 审核结果,可取值:合规、不合规、疑似、审核失败
|
||||
ConclusionType int `json:"conclusionType"` // 审核结果类型,可取值1.合规,2.不合规,3.疑似,4.审核失败
|
||||
Msg string `json:"msg"` // 不合规项描述信息
|
||||
Hits []hit `json:"hits"`
|
||||
} // 不合规/疑似/命中白名单项详细信息。响应成功并且conclusion为疑似或不合规或命中白名单时才返回,响应失败或conclusion为合规且未命中白名单时不返回。
|
||||
|
||||
type hit struct {
|
||||
DatasetName string `json:"datasetName"` // 违规项目所属数据集名称
|
||||
Words []string `json:"words"` // 送检文本命中词库的关键词(备注:建议参考新字段“wordHitPositions”,包含信息更丰富:关键词以及对应的位置及标签信息)
|
||||
Probability float64 `json:"probability,omitempty"` // 不合规项置信度
|
||||
} // 送检文本违规原因的详细信息
|
||||
type keyConfig struct {
|
||||
Key1 string `json:"key1"` // 百度云服务内容审核key存储
|
||||
Key2 string `json:"key2"` // 百度云服务内容审核key存储
|
||||
Groups map[int64]group `json:"groups"` // 群配置存储
|
||||
}
|
||||
|
||||
type group struct {
|
||||
Enable EnableMark // 是否启用内容审核
|
||||
TextAudit EnableMark // 文本检测
|
||||
ImageAudit EnableMark // 图像检测
|
||||
DMRemind EnableMark // 撤回提示
|
||||
MoreRemind EnableMark // 详细违规提示
|
||||
DMBAN EnableMark // 撤回后禁言
|
||||
BANTimeAddEnable EnableMark // 禁言累加
|
||||
BANTime int64 // 标准禁言时间,禁用累加,但开启禁言的的情况下采用该值
|
||||
MaxBANTimeAddRange int64 // 最大禁言时间累加范围,最高禁言时间
|
||||
BANTimeAddTime int64 // 禁言累加时间,该值是开启禁累加功能后,再次触发时,根据被禁次数X该值计算出的禁言时间
|
||||
WhiteListType [8]bool // 类型白名单,处于白名单类型的违规,不会被触发 0:含多种类型,具体看官方链接,1:违禁违规、2:文本色情、3:敏感信息、4:恶意推广、5:低俗辱骂 6:恶意推广-联系方式、7:恶意推广-软文推广
|
||||
AuditHistory map[int64]auditHistory // 被封禁用户列表
|
||||
}
|
||||
|
||||
// EnableMark 启用:●,禁用:○
|
||||
type EnableMark bool
|
||||
|
||||
// String 打印启用状态
|
||||
func (em EnableMark) String() string {
|
||||
if em {
|
||||
return "开启"
|
||||
}
|
||||
return "关闭"
|
||||
}
|
||||
|
||||
type auditHistory struct {
|
||||
Count int64 `json:"key2"` // 被禁次数
|
||||
ResList []baiduRes `json:"reslist"` // 禁言原因
|
||||
}
|
||||
|
||||
var bdcli *censor.ContentCensorClient // 百度云审核服务Client
|
||||
var typetext = [8]string{
|
||||
0: "默认违禁词库",
|
||||
1: "违禁违规",
|
||||
2: "文本色情",
|
||||
3: "敏感信息",
|
||||
4: "恶意推广",
|
||||
5: "低俗辱骂",
|
||||
6: "恶意推广-联系方式",
|
||||
7: "恶意推广-软文推广",
|
||||
} // 文本类型
|
||||
|
||||
var (
|
||||
config keyConfig // 插件配置
|
||||
configinit bool // 配置初始化
|
||||
configpath string // 配置路径
|
||||
)
|
||||
|
||||
func init() {
|
||||
engine := control.Register("baiduaudit", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "##该功能来自百度内容审核,需购买相关服务,并创建app##\n" +
|
||||
"- 获取BDAKey\n" +
|
||||
"- 配置BDAKey [API key] [Secret Key]\n" +
|
||||
"- 开启/关闭内容审核\n" +
|
||||
"- 开启/关闭撤回提示\n" +
|
||||
"- 开启/关闭详细提示\n" +
|
||||
"- 开启/关闭撤回禁言\n" +
|
||||
"##禁言时间设置## 禁言时间计算方式为:禁言次数*每次禁言累加时间,当达到最大禁言时间时,再次触发按最大禁言时间计算\n" +
|
||||
"- 开启/关闭禁言累加\n" +
|
||||
"- 设置撤回禁言时间[分钟,默认:1]\n" +
|
||||
"- 设置最大禁言时间[分钟,默认:60,最大43200]\n" +
|
||||
"- 设置每次累加时间[分钟,默认:1]\n" +
|
||||
"##检测类型设置## 类型编号列表:[1:违禁违规、2:文本色情、3:敏感信息、4:恶意推广、5:低俗辱骂 6:恶意推广-联系方式、7:恶意推广-软文推广]\n" +
|
||||
"- 查看检测类型\n" +
|
||||
"- 查看检测配置\n" +
|
||||
"- 设置检测类型[类型编号]\n" +
|
||||
"- 设置不检测类型[类型编号]\n" +
|
||||
"- 开启/关闭文本检测\n" +
|
||||
"- 开启/关闭图像检测\n" +
|
||||
"##测试功能##\n" +
|
||||
"- 测试文本检测[文本内容]\n" +
|
||||
"- 测试图像检测[图片]\n",
|
||||
PrivateDataFolder: "baiduaudit",
|
||||
})
|
||||
configpath = engine.DataFolder() + "config.json"
|
||||
loadConfig()
|
||||
if configinit {
|
||||
bdcli = censor.NewClient(config.Key1, config.Key2)
|
||||
}
|
||||
engine.OnFullMatch("获取BDAKey", zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SendChain(message.Text("接口key创建网址:\n" +
|
||||
"https://console.bce.baidu.com/ai/?_=1665977657185#/ai/antiporn/overview/index\n" +
|
||||
"免费8w次数领取地址:\n" +
|
||||
"https://console.bce.baidu.com/ai/?_=1665977657185#/ai/antiporn/overview/resource/getFree"))
|
||||
})
|
||||
|
||||
engine.OnRegex("^查看检测(类型|配置)$", zero.AdminPermission, clientCheck).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
// 获取群配置
|
||||
group := getGroup(ctx.Event.GroupID)
|
||||
var msgs string
|
||||
k1 := ctx.State["regex_matched"].([]string)[1]
|
||||
if k1 == "类型" {
|
||||
msgs += "本群检测类型:"
|
||||
find := false
|
||||
// 遍历群检测类型名单
|
||||
for i, v := range group.WhiteListType {
|
||||
if !v {
|
||||
find = true
|
||||
msgs += fmt.Sprint("\n", i, ".", typetext[i])
|
||||
}
|
||||
}
|
||||
if !find {
|
||||
msgs += "无"
|
||||
}
|
||||
|
||||
} else {
|
||||
// 生成配置文本
|
||||
msgs = fmt.Sprintf("本群配置:\n"+
|
||||
"内容审核:%s\n"+
|
||||
"-文本:%s\n"+
|
||||
"-图像:%s\n"+
|
||||
"撤回提示:%s\n"+
|
||||
"-详细提示:%s\n"+
|
||||
"撤回禁言:%s\n"+
|
||||
"-禁言累加:%s\n"+
|
||||
"-撤回禁言时间:%v分钟\n"+
|
||||
"-每次累加时间:%v分钟\n"+
|
||||
"-最大禁言时间:%v分钟", group.Enable, group.TextAudit, group.ImageAudit, group.DMRemind, group.MoreRemind, group.DMBAN, group.BANTimeAddEnable, group.BANTime, group.BANTimeAddTime, group.MaxBANTimeAddRange)
|
||||
}
|
||||
b, err := text.RenderToBase64(msgs, text.FontFile, 300, 20)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Image("base64://" + binary.BytesToString(b)))
|
||||
})
|
||||
engine.OnRegex("^设置(不)?检测类型([01234567])$", zero.AdminPermission, clientCheck).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
defer jsonSave(config, configpath)
|
||||
k1 := ctx.State["regex_matched"].([]string)[1]
|
||||
k2 := ctx.State["regex_matched"].([]string)[2]
|
||||
group := getGroup(ctx.Event.GroupID)
|
||||
inputType, _ := strconv.Atoi(k2)
|
||||
if k1 == "不" {
|
||||
group.WhiteListType[inputType] = true //不检测:则进入类型白名单
|
||||
} else {
|
||||
group.WhiteListType[inputType] = false //检测:则退出白名单
|
||||
}
|
||||
config.Groups[ctx.Event.GroupID] = group
|
||||
ctx.SendChain(message.At(ctx.Event.UserID), message.Text(fmt.Sprintf("本群将%s检测%s类型内容", k1, typetext[inputType])))
|
||||
})
|
||||
engine.OnRegex("^设置(最大|每次|撤回)(累加|禁言)时间(\\d{1,5})$", zero.AdminPermission, clientCheck).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
defer jsonSave(config, configpath)
|
||||
k1 := ctx.State["regex_matched"].([]string)[1]
|
||||
k3 := ctx.State["regex_matched"].([]string)[3]
|
||||
group := getGroup(ctx.Event.GroupID)
|
||||
time, _ := strconv.ParseInt(k1, 10, 64)
|
||||
switch k1 {
|
||||
case "最大":
|
||||
group.MaxBANTimeAddRange = time
|
||||
case "每次":
|
||||
group.BANTimeAddTime = time
|
||||
case "撤回":
|
||||
group.BANTime = time
|
||||
}
|
||||
config.Groups[ctx.Event.GroupID] = group
|
||||
ctx.SendChain(message.At(ctx.Event.UserID), message.Text(fmt.Sprintf("本群%s禁言累加时间已设置为%s", k3, k1)))
|
||||
})
|
||||
engine.OnRegex("^(开启|关闭)(内容审核|撤回提示|撤回禁言|禁言累加|详细提示|文本检测|图像检测)$", zero.AdminPermission, clientCheck).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
defer jsonSave(config, configpath)
|
||||
k1 := ctx.State["regex_matched"].([]string)[1]
|
||||
k2 := ctx.State["regex_matched"].([]string)[2]
|
||||
isEnable := EnableMark(false)
|
||||
group := getGroup(ctx.Event.GroupID)
|
||||
if k1 == "开启" {
|
||||
isEnable = true
|
||||
}
|
||||
switch k2 {
|
||||
case "内容审核":
|
||||
group.Enable = isEnable
|
||||
case "撤回提示":
|
||||
group.DMRemind = isEnable
|
||||
case "撤回禁言":
|
||||
group.DMBAN = isEnable
|
||||
case "禁言累加":
|
||||
group.BANTimeAddEnable = isEnable
|
||||
case "详细提示":
|
||||
group.MoreRemind = isEnable
|
||||
case "文本检测":
|
||||
group.TextAudit = isEnable
|
||||
case "图像检测":
|
||||
group.ImageAudit = isEnable
|
||||
}
|
||||
config.Groups[ctx.Event.GroupID] = group
|
||||
ctx.SendChain(message.At(ctx.Event.UserID), message.Text(fmt.Sprintf("本群%s已%s", k2, k1)))
|
||||
})
|
||||
engine.OnRegex(`^配置BDAKey\s*(.*)\s*(.*)$`, zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
k1 := ctx.State["regex_matched"].([]string)[1]
|
||||
k2 := ctx.State["regex_matched"].([]string)[2]
|
||||
bdcli = censor.NewClient(k1, k2)
|
||||
config.Key1 = k1
|
||||
config.Key2 = k2
|
||||
if bdcli != nil {
|
||||
jsonSave(config, configpath)
|
||||
ctx.SendChain(message.Text("配置成功"))
|
||||
}
|
||||
})
|
||||
engine.OnMessage().SetBlock(false).Handle(func(ctx *zero.Ctx) {
|
||||
group, ok := config.Groups[ctx.Event.GroupID]
|
||||
// 如果没该配置,或者审核功能未开启直接跳过
|
||||
if !ok || !bool(group.Enable) {
|
||||
return
|
||||
}
|
||||
for _, elem := range ctx.Event.Message {
|
||||
switch elem.Type {
|
||||
case "image":
|
||||
if !group.ImageAudit {
|
||||
return
|
||||
}
|
||||
res := bdcli.ImgCensorUrl(elem.Data["url"], nil)
|
||||
bdres, err := jsonToBaiduRes(res)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("Error:", bdres.ErrorMsg, "(", bdres.ErrorCode, ")"))
|
||||
return
|
||||
}
|
||||
banCheck(ctx, bdres)
|
||||
|
||||
case "text":
|
||||
if !group.TextAudit {
|
||||
return
|
||||
}
|
||||
res := bdcli.TextCensor(elem.Data["text"])
|
||||
bdres, err := jsonToBaiduRes(res)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("Error:", bdres.ErrorMsg, "(", bdres.ErrorCode, ")"))
|
||||
return
|
||||
}
|
||||
banCheck(ctx, bdres)
|
||||
}
|
||||
}
|
||||
})
|
||||
engine.OnPrefix("文本检测", clientCheck).SetBlock(false).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
if bdcli == nil {
|
||||
ctx.SendChain(message.Text("Key未配置"))
|
||||
return
|
||||
}
|
||||
args := ctx.ExtractPlainText()
|
||||
res := bdcli.TextCensor(args)
|
||||
bdres, err := jsonToBaiduRes(res)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("Error:", bdres.ErrorMsg, "(", bdres.ErrorCode, ")"))
|
||||
return
|
||||
}
|
||||
group := getGroup(ctx.Event.GroupID)
|
||||
ctx.SendChain(buildResp(bdres, group)...)
|
||||
})
|
||||
engine.OnPrefix("^图像检测", clientCheck).SetBlock(false).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
var urls []string
|
||||
for _, elem := range ctx.Event.Message {
|
||||
if elem.Type == "image" {
|
||||
if elem.Data["url"] != "" {
|
||||
urls = append(urls, elem.Data["url"])
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(urls) == 0 {
|
||||
return
|
||||
}
|
||||
res := bdcli.ImgCensorUrl(urls[0], nil)
|
||||
bdres, err := jsonToBaiduRes(res)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("Error:", bdres.ErrorMsg, "(", bdres.ErrorCode, ")"))
|
||||
return
|
||||
}
|
||||
group := getGroup(ctx.Event.GroupID)
|
||||
ctx.SendChain(buildResp(bdres, group)...)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
// 禁言检测
|
||||
func banCheck(ctx *zero.Ctx, bdres baiduRes) {
|
||||
// 如果返回类型为2(不合规),0为合规,3为疑似
|
||||
if bdres.ConclusionType == 2 {
|
||||
// 创建消息ID
|
||||
mid := message.NewMessageIDFromInteger(ctx.Event.MessageID.(int64))
|
||||
// 获取群配置
|
||||
group := getGroup(ctx.Event.GroupID)
|
||||
// 检测群配置里的不检测类型白名单,忽略掉不检测的违规类型
|
||||
for i, b := range group.WhiteListType {
|
||||
if i == bdres.Data[0].SubType && b {
|
||||
return
|
||||
}
|
||||
}
|
||||
// 生成回复文本
|
||||
res := buildResp(bdres, group)
|
||||
// 撤回消息
|
||||
ctx.DeleteMessage(mid)
|
||||
// 查看是否启用撤回后禁言
|
||||
if group.DMBAN {
|
||||
// 从历史违规记录中获取指定用户
|
||||
user := group.getUser(ctx.Event.UserID)
|
||||
// 用户违规次数自增
|
||||
user.Count++
|
||||
// 用户违规原因记录
|
||||
user.ResList = append(user.ResList, bdres)
|
||||
// 覆写该用户到群违规记录中
|
||||
group.AuditHistory[ctx.Event.UserID] = user
|
||||
// 覆写该群信息
|
||||
config.Groups[ctx.Event.GroupID] = group
|
||||
// 保存到json
|
||||
jsonSave(config, configpath)
|
||||
var bantime int64
|
||||
// 查看是否开启禁言累加功能,并计算禁言时间
|
||||
if group.BANTimeAddEnable {
|
||||
bantime = user.Count * group.BANTimeAddTime * 60
|
||||
} else {
|
||||
bantime = group.BANTime * 60
|
||||
}
|
||||
//执行禁言
|
||||
ctx.SetGroupBan(ctx.Event.GroupID, ctx.Event.UserID, bantime)
|
||||
}
|
||||
//查看是否开启撤回提示
|
||||
if group.DMRemind {
|
||||
res = append(res, message.At(ctx.Event.Sender.ID))
|
||||
ctx.SendChain(res...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取群配置
|
||||
func getGroup(groupID int64) group {
|
||||
g, ok := config.Groups[groupID]
|
||||
if ok {
|
||||
return g
|
||||
}
|
||||
if config.Groups == nil {
|
||||
config.Groups = make(map[int64]group)
|
||||
}
|
||||
g = group{
|
||||
TextAudit: true,
|
||||
ImageAudit: true,
|
||||
BANTime: 1,
|
||||
MaxBANTimeAddRange: 60,
|
||||
BANTimeAddTime: 1,
|
||||
WhiteListType: [8]bool{},
|
||||
AuditHistory: map[int64]auditHistory{},
|
||||
}
|
||||
config.Groups[groupID] = g
|
||||
return g
|
||||
}
|
||||
|
||||
// 从群历史违规记录中获取用户
|
||||
func (group *group) getUser(userID int64) auditHistory {
|
||||
audit, ok := group.AuditHistory[userID]
|
||||
if ok {
|
||||
return audit
|
||||
}
|
||||
// 如果没有用户,则创建一个并返回
|
||||
if group.AuditHistory == nil {
|
||||
group.AuditHistory = make(map[int64]auditHistory)
|
||||
}
|
||||
audit = auditHistory{0, []baiduRes{}}
|
||||
group.AuditHistory[userID] = audit
|
||||
return audit
|
||||
}
|
||||
|
||||
// 客户端是否初始化检测
|
||||
func clientCheck(ctx *zero.Ctx) bool {
|
||||
if bdcli == nil {
|
||||
ctx.SendChain(message.Text("Key未配置"))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 加载JSON配置文件
|
||||
func loadConfig() {
|
||||
if file.IsExist(configpath) {
|
||||
data, err := os.OpenFile(configpath, os.O_RDONLY, 0755)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = json.NewDecoder(data).Decode(&config)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
configinit = true
|
||||
} else {
|
||||
config = keyConfig{}
|
||||
configinit = false
|
||||
}
|
||||
}
|
||||
|
||||
// 保存配置文件
|
||||
func jsonSave(v keyConfig, path string) {
|
||||
jsf, _ := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
|
||||
defer func(file *os.File) {
|
||||
err := file.Close()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}(jsf) // 结束时关闭句柄,释放资源
|
||||
err := json.NewEncoder(jsf).Encode(v)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
// JSON反序列化
|
||||
func jsonToBaiduRes(resjson string) (baiduRes, error) {
|
||||
var bdres baiduRes
|
||||
err := json.Unmarshal(binary.StringToBytes(resjson), &bdres)
|
||||
return bdres, err
|
||||
}
|
||||
|
||||
// 生成回复文本
|
||||
func buildResp(bdres baiduRes, group group) []message.MessageSegment {
|
||||
// 建立消息段
|
||||
msgs := make([]message.MessageSegment, 0, 8)
|
||||
// 生成简略审核结果回复
|
||||
msgs = append(msgs, message.Text(bdres.Conclusion, "\n"))
|
||||
// 查看是否开启详细审核内容提示,并确定审核内容值为疑似,或者不合规
|
||||
if !group.MoreRemind {
|
||||
return msgs
|
||||
}
|
||||
// 遍历返回的不合规数据,生成详细违规内容
|
||||
for i, datum := range bdres.Data {
|
||||
msgs = append(msgs, message.Text("[", i, "]:", datum.Msg, "\n"))
|
||||
// 检查命中词条是否大于0
|
||||
if len(datum.Hits) == 0 {
|
||||
return msgs
|
||||
}
|
||||
// 遍历打印命中的违规词条
|
||||
for _, hit := range datum.Hits {
|
||||
if len(datum.Hits) == 0 {
|
||||
return msgs
|
||||
}
|
||||
msgs = append(msgs, message.Text("("))
|
||||
for i4, i3 := range hit.Words {
|
||||
// 检查是否是最后一个要打印的词条,如果是则不加上逗号
|
||||
if i4 != len(hit.Words)-1 {
|
||||
msgs = append(msgs, message.Text(i3, ","))
|
||||
} else {
|
||||
msgs = append(msgs, message.Text(i3))
|
||||
}
|
||||
}
|
||||
msgs = append(msgs, message.Text(")"))
|
||||
}
|
||||
}
|
||||
return msgs
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package driftbottle
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"hash/crc64"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
sql "github.com/FloatTech/sqlite"
|
||||
)
|
||||
|
||||
type bottle struct {
|
||||
ID int64 `db:"id"` // ID qq_grp_name_msg 的 crc64
|
||||
QQ int64 `db:"qq"` // QQ 发送者 qq
|
||||
Grp int64 `db:"grp"` // Grp 限制抽出的群 / 人(负数)
|
||||
Name string `db:"name"` // Name 发送者 昵称
|
||||
Msg string `db:"msg"` // Msg 消息,纯文本
|
||||
}
|
||||
|
||||
var sea = &sql.Sqlite{}
|
||||
var seamu sync.RWMutex
|
||||
|
||||
func newBottle(qq, grp int64, name, msg string) *bottle {
|
||||
id := int64(crc64.Checksum(binary.StringToBytes(fmt.Sprintf("%d_%d_%s_%s", qq, grp, name, msg)), crc64.MakeTable(crc64.ISO)))
|
||||
return &bottle{ID: id, QQ: qq, Grp: grp, Name: name, Msg: msg}
|
||||
}
|
||||
|
||||
func (b *bottle) throw(db *sql.Sqlite, channel string) error {
|
||||
seamu.Lock()
|
||||
defer seamu.Unlock()
|
||||
return db.Insert(channel, b)
|
||||
}
|
||||
|
||||
func (b *bottle) destroy(db *sql.Sqlite, channel string) error {
|
||||
seamu.Lock()
|
||||
defer seamu.Unlock()
|
||||
return db.Del(channel, "WHERE id="+strconv.FormatInt(b.ID, 10))
|
||||
}
|
||||
|
||||
// fetchBottle grp != 0
|
||||
func fetchBottle(db *sql.Sqlite, channel string, grp int64) (*bottle, error) {
|
||||
seamu.RLock()
|
||||
defer seamu.RUnlock()
|
||||
b := new(bottle)
|
||||
return b, db.Find(channel, b, "WHERE grp=0 or grp="+strconv.FormatInt(grp, 10)+" ORDER BY RANDOM() limit 1")
|
||||
}
|
||||
|
||||
func createChannel(db *sql.Sqlite, channel string) error {
|
||||
seamu.Lock()
|
||||
defer seamu.Unlock()
|
||||
return db.Create(channel, &bottle{})
|
||||
}
|
||||
@@ -2,132 +2,107 @@
|
||||
package driftbottle
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"hash/crc64"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
sql "github.com/FloatTech/sqlite"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
type sea struct {
|
||||
ID int64 `db:"id"` // ID qq_grp_name_msg 的 crc64 hashCheck.
|
||||
QQ int64 `db:"qq"` // Get current user(Who sends this)
|
||||
Name string `db:"Name"` // his or her name at that time:P
|
||||
Msg string `db:"msg"` // What he or she sent to bot?
|
||||
Grp int64 `db:"grp"` // which group sends this msg?
|
||||
Time string `db:"time"` // we need to know the current time,master>
|
||||
}
|
||||
|
||||
var seaSide = &sql.Sqlite{}
|
||||
var seaLocker sync.RWMutex
|
||||
|
||||
// We need a container to inject what we need :(
|
||||
|
||||
func init() {
|
||||
en := control.Register("driftbottle", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "漂流瓶\n- (在群xxx)丢漂流瓶(到频道xxx) [消息]\n- (从频道xxx)捡漂流瓶\n- @BOT 创建频道 xxx\n- 跳入(频道)海中\n- 注:不显式限制时,私聊发送可在所有群抽到,群聊发送仅可在本群抽到,默认频道为 global",
|
||||
Help: "简单的漂流瓶\n" + "- @bot pick" + "- @bot throw xxx (xxx为投递内容)",
|
||||
PrivateDataFolder: "driftbottle",
|
||||
})
|
||||
sea.DBPath = en.DataFolder() + "sea.db"
|
||||
err := sea.Open(time.Hour * 24)
|
||||
seaSide.DBPath = en.DataFolder() + "sea.db"
|
||||
err := seaSide.Open(time.Hour * 24)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_ = createChannel(sea, "global")
|
||||
en.OnRegex(`^(在群\d+)?丢漂流瓶(到频道\w+)?\s+(.*)$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
msgs := ctx.State["regex_matched"].([]string)
|
||||
grp := ctx.Event.GroupID
|
||||
channel := "global"
|
||||
msg := msgs[3]
|
||||
var err error
|
||||
if msgs[1] != "" {
|
||||
grp, err = strconv.ParseInt(msgs[1][6:], 10, 64)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("群号非法!"))
|
||||
return
|
||||
}
|
||||
}
|
||||
if msgs[2] != "" {
|
||||
channel = msgs[2][9:]
|
||||
}
|
||||
if msg == "" {
|
||||
ctx.SendChain(message.Text("消息为空!"))
|
||||
return
|
||||
}
|
||||
logrus.Debugln("[driftbottle]", grp, channel, msg)
|
||||
err = newBottle(
|
||||
ctx.Event.UserID,
|
||||
grp,
|
||||
ctx.CardOrNickName(ctx.Event.UserID),
|
||||
msg,
|
||||
).throw(sea, channel)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("你将它扔进大海,希望有人捞到吧~")))
|
||||
})
|
||||
en.OnRegex(`^(从频道\w+)?捡漂流瓶$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
msgs := ctx.State["regex_matched"].([]string)
|
||||
grp := ctx.Event.GroupID
|
||||
if grp == 0 {
|
||||
grp = -ctx.Event.UserID
|
||||
}
|
||||
if grp == 0 {
|
||||
ctx.SendChain(message.Text("找不到对象!"))
|
||||
return
|
||||
}
|
||||
channel := "global"
|
||||
if msgs[1] != "" {
|
||||
channel = msgs[1][9:]
|
||||
}
|
||||
logrus.Debugln("[driftbottle]", grp, channel)
|
||||
b, err := fetchBottle(sea, channel, grp)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
err = b.destroy(sea, channel)
|
||||
wg.Done()
|
||||
}()
|
||||
ctx.Send(
|
||||
message.ReplyWithMessage(
|
||||
ctx.Event.MessageID,
|
||||
message.Text("你在海边捡到了一个来自 ", b.Name, " 的漂流瓶,打开瓶子,里面有一张纸条,写着:"),
|
||||
message.Text(b.Msg),
|
||||
),
|
||||
)
|
||||
wg.Wait()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
})
|
||||
en.OnPrefix("创建频道", zero.SuperUserPermission, zero.OnlyToMe).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
channel := strings.TrimRight(ctx.State["args"].(string), " ")
|
||||
if channel == "" {
|
||||
ctx.SendChain(message.Text("频道名为空!"))
|
||||
return
|
||||
}
|
||||
err := createChannel(sea, channel)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("成功~")))
|
||||
})
|
||||
en.OnRegex(`^跳入(\w+)?海中$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
msgs := ctx.State["regex_matched"].([]string)
|
||||
channel := "global"
|
||||
if msgs[1] != "" {
|
||||
channel = msgs[1]
|
||||
}
|
||||
seamu.RLock()
|
||||
c, err := sea.Count(channel)
|
||||
seamu.RUnlock()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("你缓缓走入大海,感受着海浪轻柔地拍打着你的小腿,膝盖……\n波浪卷着你的腰腹,你感觉有些把握不住平衡了……\n……\n你沉入海中,", c, " 个物体与你一同沉浮。\n不知何处涌来一股暗流,你失去了意识。")))
|
||||
})
|
||||
|
||||
_ = createChannel(seaSide)
|
||||
en.OnFullMatch("pick", zero.OnlyToMe, zero.OnlyGroup).Limit(ctxext.LimitByGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
be, err := fetchBottle(seaSide)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERR:", err))
|
||||
}
|
||||
idstr := strconv.Itoa(int(be.ID))
|
||||
qqstr := strconv.Itoa(int(be.QQ))
|
||||
grpstr := strconv.Itoa(int(be.Grp))
|
||||
botname := zero.BotConfig.NickName[0]
|
||||
msg := message.Message{message.CustomNode(botname, ctx.Event.SelfID, botname+"试着帮你捞出来了这个~\nID:"+idstr+"\n投递人: "+be.Name+"("+qqstr+")"+"\n群号: "+grpstr+"\n时间: "+be.Time+"\n内容: \n"+be.Msg)}
|
||||
ctx.Send(msg)
|
||||
})
|
||||
|
||||
en.OnRegex(`throw.*?(.*)`, zero.OnlyToMe, zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
senderFormatTime := time.Unix(ctx.Event.Time, 0).Format("2006-01-02 15:04:05")
|
||||
rawSenderMessage := ctx.State["regex_matched"].([]string)[1]
|
||||
rawMessageCallBack := message.UnescapeCQCodeText(rawSenderMessage)
|
||||
keyWordsNum := utf8.RuneCountInString(rawMessageCallBack)
|
||||
if keyWordsNum < 10 {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("需要投递的内容过少( "))
|
||||
return
|
||||
}
|
||||
// check current needs and prepare to throw drift_bottle.
|
||||
err = globalbottle(
|
||||
ctx.Event.UserID,
|
||||
ctx.Event.GroupID,
|
||||
senderFormatTime,
|
||||
ctx.CardOrNickName(ctx.Event.UserID),
|
||||
rawMessageCallBack,
|
||||
).throw(seaSide)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("已经帮你丢出去了哦~")))
|
||||
})
|
||||
}
|
||||
|
||||
func globalbottle(qq, grp int64, time, name, msg string) *sea { // Check as if the User is available and collect information to store.
|
||||
id := int64(crc64.Checksum(binary.StringToBytes(fmt.Sprintf("%d_%d_%s_%s_%s", grp, qq, time, name, msg)), crc64.MakeTable(crc64.ISO)))
|
||||
return &sea{ID: id, Grp: grp, Time: time, QQ: qq, Name: name, Msg: msg}
|
||||
}
|
||||
|
||||
func (be *sea) throw(db *sql.Sqlite) error {
|
||||
seaLocker.Lock()
|
||||
defer seaLocker.Unlock()
|
||||
return db.Insert("global", be)
|
||||
}
|
||||
|
||||
func fetchBottle(db *sql.Sqlite) (*sea, error) {
|
||||
seaLocker.Lock()
|
||||
defer seaLocker.Unlock()
|
||||
be := new(sea)
|
||||
return be, db.Pick("global", be)
|
||||
}
|
||||
|
||||
func createChannel(db *sql.Sqlite) error {
|
||||
seaLocker.Lock()
|
||||
defer seaLocker.Unlock()
|
||||
return db.Create("global", &sea{})
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ func init() { // 插件主体
|
||||
ctx.SendChain(message.Text(serviceErr, "ERROR:\n", err))
|
||||
}
|
||||
})
|
||||
engine.OnRegex(`^猜歌(开启|关闭)(歌单|歌词)自动下载`).SetBlock(true).
|
||||
engine.OnRegex(`^猜歌(开启|关闭)(歌单|歌词)自动下载`, zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
swtich := ctx.State["regex_matched"].([]string)[1]
|
||||
option := ctx.State["regex_matched"].([]string)[1]
|
||||
|
||||
@@ -43,11 +43,11 @@ func TestSetHoliday(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = SetHoliday("中秋节", 1, 2022, 9, 10)
|
||||
err = SetHoliday("中秋节", 1, 2023, 9, 29)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = SetHoliday("国庆节", 7, 2022, 10, 1)
|
||||
err = SetHoliday("国庆节", 7, 2023, 10, 1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -95,7 +95,8 @@ func init() {
|
||||
})
|
||||
engine.OnFullMatch("所有本地setu分类").SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
msg := "所有本地setu分类"
|
||||
msg := "本地setu分类一览"
|
||||
hasnotchange := true
|
||||
ns.mu.RLock()
|
||||
for i, c := range ns.List() {
|
||||
n, err := ns.db.Count(c)
|
||||
@@ -105,8 +106,12 @@ func init() {
|
||||
msg += fmt.Sprintf("\n%02d. %s(error)", i, c)
|
||||
logrus.Errorln("[nsetu]", err)
|
||||
}
|
||||
hasnotchange = false
|
||||
}
|
||||
ns.mu.RUnlock()
|
||||
if hasnotchange {
|
||||
msg += "\n空"
|
||||
}
|
||||
ctx.SendChain(message.Text(msg))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -25,6 +25,11 @@ func (g *grammar) string() string {
|
||||
var db = &sql.Sqlite{}
|
||||
|
||||
func getRandomGrammarByTag(tag string) (g grammar) {
|
||||
_ = db.Find("grammar", &g, "where tag LIKE '%"+tag+"%' ORDER BY RANDOM() limit 1")
|
||||
_ = db.Find("grammar", &g, "WHERE tag LIKE '%"+tag+"%' ORDER BY RANDOM() limit 1")
|
||||
return
|
||||
}
|
||||
|
||||
func getRandomGrammarByKeyword(keyword string) (g grammar) {
|
||||
_ = db.Find("grammar", &g, "WHERE (name LIKE '%"+keyword+"%' or pronunciation LIKE '%"+keyword+"%') ORDER BY RANDOM() limit 1")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -17,7 +17,8 @@ import (
|
||||
func init() {
|
||||
engine := control.Register("nihongo", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "日语学习\n- 日语语法[xxx](使用tag随机)",
|
||||
Help: "日语学习\n- 日语语法[xxx](使用tag随机)\n" +
|
||||
"搜索日语语法[xxx]",
|
||||
PublicDataFolder: "Nihongo",
|
||||
})
|
||||
|
||||
@@ -47,7 +48,7 @@ func init() {
|
||||
return true
|
||||
})
|
||||
|
||||
engine.OnRegex(`^日语语法\s?([0-9A-Za-zぁ-んァ-ヶ]{1,6})$`, getdb).SetBlock(true).
|
||||
engine.OnRegex(`^日语语法\s?([0-9A-Za-zぁ-んァ-ヶ~]{1,6})$`, getdb).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
g := getRandomGrammarByTag(ctx.State["regex_matched"].([]string)[1])
|
||||
if g.ID == 0 {
|
||||
@@ -63,4 +64,20 @@ func init() {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
})
|
||||
engine.OnRegex(`^搜索日语语法\s?([0-9A-Za-zぁ-んァ-ヶ~]{1,25})$`, getdb).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
g := getRandomGrammarByKeyword(ctx.State["regex_matched"].([]string)[1])
|
||||
if g.ID == 0 {
|
||||
ctx.SendChain(message.Text("未能找到", ctx.State["regex_matched"].([]string)[1], "相关标签的语法"))
|
||||
return
|
||||
}
|
||||
data, err := text.RenderToBase64(g.string(), text.FontFile, 400, 20)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
if id := ctx.SendChain(message.Image("base64://" + binary.BytesToString(data))); id.ID() == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ func init() {
|
||||
DisableOnDefault: false,
|
||||
PrivateDataFolder: "qqwife",
|
||||
Help: "一群一天一夫一妻制群老婆\n(每天凌晨刷新CP)\n" +
|
||||
"- 娶群友\n- 群老婆列表\n- 允许/禁止自由恋爱\n- 允许/禁止牛头人\n- 设置CD为xx小时 →(默认12小时)\n- 重置花名册\n- 重置所有花名册(用于清除所有群数据及其设置)\n" +
|
||||
"- 娶群友\n- 群老婆列表\n- [允许|禁止]自由恋爱\n- [允许|禁止]牛头人\n- 设置CD为xx小时 →(默认12小时)\n- 重置花名册\n- 重置所有花名册(用于清除所有群数据及其设置)\n" +
|
||||
"--------------------------------\n以下指令存在CD,不跨天刷新,前两个受指令开关\n--------------------------------\n" +
|
||||
"- (娶|嫁)@对方QQ\n自由选择对象,自由恋爱(好感度越高成功率越高,保底30%概率)\n" +
|
||||
"- 当[对方Q号|@对方QQ]的小三\n我和你才是真爱,为了你我愿意付出一切(好感度越高成功率越高,保底10%概率)\n" +
|
||||
|
||||
@@ -147,7 +147,7 @@ func init() { // 插件主体
|
||||
msg = append(msg, message.Image(pic))
|
||||
}
|
||||
msg = append(msg, message.Text("\n图源: ", result.Header.IndexName, binary.BytesToString(b)))
|
||||
ctx.Send(ctxext.FakeSenderForwardNode(ctx, msg...))
|
||||
ctx.Send(message.Message{ctxext.FakeSenderForwardNode(ctx, msg...)})
|
||||
if s > 80.0 {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -12,15 +12,16 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
chpURL = "https://api.shadiao.app/chp"
|
||||
duURL = "https://api.shadiao.app/du"
|
||||
pyqURL = "https://api.shadiao.app/pyq"
|
||||
shadiaoURL = "https://api.shadiao.pro"
|
||||
chpURL = shadiaoURL + "/chp"
|
||||
duURL = shadiaoURL + "/du"
|
||||
pyqURL = shadiaoURL + "/pyq"
|
||||
yduanziURL = "http://www.yduanzi.com/duanzi/getduanzi"
|
||||
chayiURL = "https://api.lovelive.tools/api/SweetNothings/Web/0"
|
||||
ganhaiURL = "https://api.lovelive.tools/api/SweetNothings/Web/1"
|
||||
ergofabulousURL = "https://ergofabulous.org/luther/?"
|
||||
ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"
|
||||
sdReferer = "https://api.shadiao.app/"
|
||||
sdReferer = shadiaoURL
|
||||
yduanziReferer = "http://www.yduanzi.com/?utm_source=shadiao.app"
|
||||
loveliveReferer = "https://lovelive.tools/"
|
||||
)
|
||||
|
||||
@@ -4,14 +4,19 @@ package tarot
|
||||
import (
|
||||
"encoding/json"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/process"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/img/pool"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
"github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
@@ -37,12 +42,13 @@ type formation struct {
|
||||
}
|
||||
type cardSet = map[string]card
|
||||
|
||||
var cardMap = make(cardSet, 80)
|
||||
var infoMap = make(map[string]cardInfo, 80)
|
||||
var formationMap = make(map[string]formation, 10)
|
||||
|
||||
var majorArcanaName = make([]string, 0, 80)
|
||||
var formationName = make([]string, 0, 10)
|
||||
var (
|
||||
cardMap = make(cardSet, 80)
|
||||
infoMap = make(map[string]cardInfo, 80)
|
||||
formationMap = make(map[string]formation, 10)
|
||||
majorArcanaName = make([]string, 0, 80)
|
||||
formationName = make([]string, 0, 10)
|
||||
)
|
||||
|
||||
func init() {
|
||||
engine := control.Register("tarot", &ctrl.Options[*zero.Ctx]{
|
||||
@@ -55,6 +61,13 @@ func init() {
|
||||
PublicDataFolder: "Tarot",
|
||||
}).ApplySingle(ctxext.DefaultSingle)
|
||||
|
||||
cache := engine.DataFolder() + "cache"
|
||||
_ = os.RemoveAll(cache)
|
||||
err := os.MkdirAll(cache, 0755)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
getTarot := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
data, err := engine.GetLazyData("tarots.json", true)
|
||||
if err != nil {
|
||||
@@ -131,12 +144,32 @@ func init() {
|
||||
if p == 1 {
|
||||
description = card.ReverseDescription
|
||||
}
|
||||
if id := ctx.SendChain(
|
||||
message.Text(reasons[rand.Intn(len(reasons))], position[p], "的『", name, "』\n"),
|
||||
message.Image(bed+reverse[p]+card.ImgURL),
|
||||
message.Text("\n其释义为: ", description)); id.ID() == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
imgurl := bed + reverse[p] + card.ImgURL
|
||||
imgname := ""
|
||||
if p == 1 {
|
||||
imgname = reverse[p][:len(reverse[p])-1] + name
|
||||
} else {
|
||||
imgname = name
|
||||
}
|
||||
imgpath := cache + "/" + imgname + ".png"
|
||||
err := pool.SendImageFromPool("pool"+imgname, imgpath, func() error {
|
||||
data, err := web.RequestDataWith(web.NewTLS12Client(), imgurl, "GET", "gitcode.net", web.RandUA())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f, err := os.Create(imgpath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
return os.WriteFile(f.Name(), data, 0755)
|
||||
}, ctxext.Send(ctx), ctxext.GetMessage(ctx))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
process.SleepAbout1sTo2s()
|
||||
ctx.SendChain(message.Text(reasons[rand.Intn(len(reasons))], position[p], "的『", name, "』\n其释义为: ", description))
|
||||
return
|
||||
}
|
||||
msg := make(message.Message, n)
|
||||
@@ -156,41 +189,61 @@ func init() {
|
||||
if p == 1 {
|
||||
description = card.ReverseDescription
|
||||
}
|
||||
tarotMsg := message.Message{
|
||||
message.Text(position[p], "的『", name, "』\n"),
|
||||
message.Image(bed + reverse[p] + card.ImgURL),
|
||||
message.Text("\n其释义为: ", description)}
|
||||
msg[i] = ctxext.FakeSenderForwardNode(ctx, tarotMsg...)
|
||||
imgurl := bed + reverse[p] + card.ImgURL
|
||||
tarotmsg := message.Message{message.Text(reasons[rand.Intn(len(reasons))], position[p], "的『", name, "』\n")}
|
||||
var imgmsg message.MessageSegment
|
||||
var err error
|
||||
if p == 1 {
|
||||
imgmsg, err = poolimg(ctx, imgurl, reverse[p][:len(reverse[p])-1]+name, cache)
|
||||
} else {
|
||||
imgmsg, err = poolimg(ctx, imgurl, name, cache)
|
||||
}
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
tarotmsg = append(tarotmsg, imgmsg)
|
||||
tarotmsg = append(tarotmsg, message.Text("\n其释义为: ", description))
|
||||
msg[i] = ctxext.FakeSenderForwardNode(ctx, tarotmsg...)
|
||||
}
|
||||
if id := ctx.Send(msg).ID(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
ctx.Send(msg)
|
||||
})
|
||||
|
||||
engine.OnRegex(`^解塔罗牌\s?(.*)`, getTarot).SetBlock(true).Limit(ctxext.LimitByGroup).Handle(func(ctx *zero.Ctx) {
|
||||
match := ctx.State["regex_matched"].([]string)[1]
|
||||
info, ok := infoMap[match]
|
||||
if ok {
|
||||
ctx.SendChain(
|
||||
message.Image(bed+info.ImgURL),
|
||||
message.Text("\n", match, "的含义是~"),
|
||||
message.Text("\n『正位』:", info.Description),
|
||||
message.Text("\n『逆位』:", info.ReverseDescription))
|
||||
} else {
|
||||
var build strings.Builder
|
||||
build.WriteString("塔罗牌列表\n大阿尔卡纳:\n")
|
||||
build.WriteString(strings.Join(majorArcanaName[:7], " "))
|
||||
build.WriteString("\n")
|
||||
build.WriteString(strings.Join(majorArcanaName[7:14], " "))
|
||||
build.WriteString("\n")
|
||||
build.WriteString(strings.Join(majorArcanaName[14:22], " "))
|
||||
build.WriteString("\n小阿尔卡纳:\n[圣杯|星币|宝剑|权杖] [0-10|侍从|骑士|王后|国王]")
|
||||
txt := build.String()
|
||||
cardList, err := text.RenderToBase64(txt, text.FontFile, 420, 20)
|
||||
imgurl := bed + info.ImgURL
|
||||
var tarotmsg message.Message
|
||||
imgmsg, err := poolimg(ctx, imgurl, match, cache)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("没有找到", match, "噢~"))
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("没有找到", match, "噢~"), message.Image("base64://"+binary.BytesToString(cardList)))
|
||||
tarotmsg = append(tarotmsg, imgmsg)
|
||||
tarotmsg = append(tarotmsg, message.Text("\n", match, "的含义是~\n『正位』:", info.Description, "\n『逆位』:", info.ReverseDescription))
|
||||
if id := ctx.Send(tarotmsg).ID(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
return
|
||||
}
|
||||
var build strings.Builder
|
||||
build.WriteString("塔罗牌列表\n大阿尔卡纳:\n")
|
||||
build.WriteString(strings.Join(majorArcanaName[:7], " "))
|
||||
build.WriteString("\n")
|
||||
build.WriteString(strings.Join(majorArcanaName[7:14], " "))
|
||||
build.WriteString("\n")
|
||||
build.WriteString(strings.Join(majorArcanaName[14:22], " "))
|
||||
build.WriteString("\n小阿尔卡纳:\n[圣杯|星币|宝剑|权杖] [0-10|侍从|骑士|王后|国王]")
|
||||
txt := build.String()
|
||||
cardList, err := text.RenderToBase64(txt, text.FontFile, 420, 20)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("没有找到", match, "噢~"), message.Image("base64://"+binary.BytesToString(cardList)))
|
||||
})
|
||||
engine.OnRegex(`^((塔罗|大阿(尔)?卡纳)|小阿(尔)?卡纳|混合)牌阵\s?(.*)`, getTarot).SetBlock(true).Limit(ctxext.LimitByGroup).Handle(func(ctx *zero.Ctx) {
|
||||
cardType := ctx.State["regex_matched"].([]string)[1]
|
||||
@@ -230,7 +283,20 @@ func init() {
|
||||
if p == 1 {
|
||||
description = card.ReverseDescription
|
||||
}
|
||||
tarotMsg := message.Message{message.Image(bed + reverse[p] + card.ImgURL)}
|
||||
var tarotmsg message.Message
|
||||
imgurl := bed + reverse[p] + card.ImgURL
|
||||
var imgmsg message.MessageSegment
|
||||
var err error
|
||||
if p == 1 {
|
||||
imgmsg, err = poolimg(ctx, imgurl, reverse[p][:len(reverse[p])-1]+name, cache)
|
||||
} else {
|
||||
imgmsg, err = poolimg(ctx, imgurl, name, cache)
|
||||
}
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
tarotmsg = append(tarotmsg, imgmsg)
|
||||
build.WriteString(info.Represent[0][i])
|
||||
build.WriteString(":")
|
||||
build.WriteString(position[p])
|
||||
@@ -239,18 +305,54 @@ func init() {
|
||||
build.WriteString("』\n其释义为: \n")
|
||||
build.WriteString(description)
|
||||
build.WriteString("\n")
|
||||
msg[i] = ctxext.FakeSenderForwardNode(ctx, tarotMsg...)
|
||||
msg[i] = ctxext.FakeSenderForwardNode(ctx, tarotmsg...)
|
||||
}
|
||||
txt := build.String()
|
||||
formation, err := text.RenderToBase64(txt, text.FontFile, 400, 20)
|
||||
formation, err := text.RenderToBase64(txt, text.FontFile, 420, 20)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
msg[info.CardsNum] = ctxext.FakeSenderForwardNode(ctx, message.Message{message.Image("base64://" + binary.BytesToString(formation))}...)
|
||||
ctx.Send(msg)
|
||||
if id := ctx.Send(msg).ID(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||
}
|
||||
} else {
|
||||
ctx.SendChain(message.Text("没有找到", match, "噢~\n现有牌阵列表: \n", strings.Join(formationName, "\n")))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func poolimg(ctx *zero.Ctx, imgurl, imgname, cache string) (msg message.MessageSegment, err error) {
|
||||
imgfile := cache + "/" + imgname + ".png"
|
||||
aimgfile := file.BOTPATH + "/" + imgfile
|
||||
m, err := pool.GetImage("pool" + imgname)
|
||||
if err == nil {
|
||||
msg = message.Image(m.String())
|
||||
if ctxext.SendToSelf(ctx)(msg) == 0 {
|
||||
msg = msg.Add("cache", "0")
|
||||
}
|
||||
return
|
||||
}
|
||||
if file.IsNotExist(aimgfile) {
|
||||
var data []byte
|
||||
data, err = web.RequestDataWith(web.NewTLS12Client(), imgurl, "GET", "gitcode.net", web.RandUA())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var f *os.File
|
||||
f, err = os.Create(imgfile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
err = os.WriteFile(f.Name(), data, 0755)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
m.SetFile(aimgfile)
|
||||
_, _ = m.Push(ctxext.SendToSelf(ctx), ctxext.GetMessage(ctx))
|
||||
msg = message.Image("file:///" + aimgfile)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Package ernie AI画图
|
||||
package ernie
|
||||
// Package wenxin 百度文心AI
|
||||
package wenxin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -19,13 +19,17 @@ import (
|
||||
|
||||
// 数据库
|
||||
sql "github.com/FloatTech/sqlite"
|
||||
// 百度文心大模型
|
||||
model "github.com/FloatTech/AnimeAPI/wenxinAI/erniemodle"
|
||||
// 百度文心AI画图API
|
||||
wenxin "github.com/FloatTech/AnimeAPI/wenxinAI/ernievilg"
|
||||
)
|
||||
|
||||
const (
|
||||
serviceName = "AIdraw"
|
||||
serviceName = "wenxinvilg"
|
||||
serviceErr = "[" + serviceName + "]ERROR:\n"
|
||||
modelName = "wenxinmodel"
|
||||
modelErr = "[" + modelName + "]ERROR:\n"
|
||||
)
|
||||
|
||||
type keydb struct {
|
||||
@@ -46,24 +50,34 @@ type apikey struct {
|
||||
}
|
||||
|
||||
var (
|
||||
groupinfo = &keydb{
|
||||
name = "椛椛"
|
||||
limit int
|
||||
vilginfo = &keydb{
|
||||
db: &sql.Sqlite{},
|
||||
}
|
||||
modelinfo = &keydb{
|
||||
db: &sql.Sqlite{},
|
||||
}
|
||||
limit = 50
|
||||
dtype = [...]string{
|
||||
"古风", "油画", "水彩画", "卡通画", "二次元", "浮世绘", "蒸汽波艺术", "low poly", "像素风格", "概念艺术", "未来主义", "赛博朋克", "写实风格", "洛丽塔风格", "巴洛克风格", "超现实主义",
|
||||
}
|
||||
)
|
||||
|
||||
func init() { // 插件主体
|
||||
go func() {
|
||||
process.GlobalInitMutex.Lock()
|
||||
defer process.GlobalInitMutex.Unlock()
|
||||
name = zero.BotConfig.NickName[0]
|
||||
}()
|
||||
engine := control.Register(serviceName, &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "AI画图\n" +
|
||||
Help: "文心AI画图\n" +
|
||||
"基于百度文心的免费AI画图插件,\n因为是免费的,图片质量你懂的。\n" +
|
||||
"key申请链接:https://wenxin.baidu.com/moduleApi/key\n" +
|
||||
"注意:每个apikey每日上限50次,总上限500次请求。次数超过了请自行更新apikey\n" +
|
||||
"- 为[自己/本群/QQ号/群+群号]设置AI画图key [API Key] [Secret Key]\n" +
|
||||
"例:\n[为10086设置AI画图key 123 456]\n[为群10010设置AI画图key 789 101]\n" +
|
||||
"key申请链接:https://wenxin.baidu.com/moduleApi/key\n" +
|
||||
"key和erniemodel插件的key相同。\n" +
|
||||
"注意:每个apikey每日上限50次,总上限500次请求。次数超过了请自行更新apikey\n" +
|
||||
"- 为[自己/本群/QQ号/群+群号]设置画图key [API Key] [Secret Key]\n" +
|
||||
"例:\n为自己设置画图key 123 456\n为10086设置画图key 123 456\n为群10010设置画图key 789 101\n" +
|
||||
"- [bot名称]画几张[图片描述]的[图片类型][图片尺寸]\n" +
|
||||
"————————————————————\n" +
|
||||
"图片描述指南:\n图片主体,细节词(请用逗号连接)\n官方prompt指南:https://wenxin.baidu.com/wenxin/docs#Ol7ece95m\n" +
|
||||
@@ -73,8 +87,8 @@ func init() { // 插件主体
|
||||
"图片尺寸当前只支持:方图/长图/横图\n" +
|
||||
"————————————————————\n" +
|
||||
"指令示例:\n" +
|
||||
"椛椛帮我画几张金凤凰,背景绚烂,高饱和,古风,仙境,高清,4K,古风的油画方图",
|
||||
PrivateDataFolder: "ernievilg",
|
||||
name + "帮我画几张金凤凰,背景绚烂,高饱和,古风,仙境,高清,4K,古风的油画方图",
|
||||
PrivateDataFolder: "wenxinAI",
|
||||
}).ApplySingle(single.New(
|
||||
single.WithKeyFn(func(ctx *zero.Ctx) int64 { return ctx.Event.GroupID }),
|
||||
single.WithPostFn[int64](func(ctx *zero.Ctx) {
|
||||
@@ -87,8 +101,8 @@ func init() { // 插件主体
|
||||
}),
|
||||
))
|
||||
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
groupinfo.db.DBPath = engine.DataFolder() + "keydb.db"
|
||||
err := groupinfo.db.Open(time.Hour * 24)
|
||||
vilginfo.db.DBPath = engine.DataFolder() + "ernieVilg.db"
|
||||
err := vilginfo.db.Open(time.Hour * 24)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(serviceErr, err))
|
||||
return false
|
||||
@@ -101,8 +115,8 @@ func init() { // 插件主体
|
||||
uid := -ctx.Event.UserID
|
||||
gid := ctx.Event.GroupID
|
||||
// 获取个人和群的key
|
||||
userinfo, err1 := groupinfo.checkGroup(uid)
|
||||
info, err2 := groupinfo.checkGroup(gid)
|
||||
userinfo, err1 := vilginfo.checkGroup(uid, "vilg")
|
||||
info, err2 := vilginfo.checkGroup(gid, "vilg")
|
||||
switch {
|
||||
// 如果是个人请求且报错
|
||||
case gid == 0 && err1 != nil:
|
||||
@@ -189,7 +203,8 @@ func init() { // 插件主体
|
||||
return
|
||||
}
|
||||
if status == "0" {
|
||||
msg := message.Message{ctxext.FakeSenderForwardNode(ctx, message.Text("我画好了!"))}
|
||||
lastTime := time.Duration(i * 10 * int(time.Second))
|
||||
msg := message.Message{ctxext.FakeSenderForwardNode(ctx, message.Text("我画好了!\n本次绘画用了", lastTime))}
|
||||
for _, imginfo := range picURL {
|
||||
msg = append(msg,
|
||||
ctxext.FakeSenderForwardNode(ctx,
|
||||
@@ -201,14 +216,14 @@ func init() { // 插件主体
|
||||
break
|
||||
}
|
||||
}
|
||||
err = groupinfo.update(gid)
|
||||
err = vilginfo.update(gid, 1)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(serviceErr, err))
|
||||
}
|
||||
process.SleepAbout1sTo2s()
|
||||
ctx.SendChain(message.Text("累死了,今天我最多只能画", info.DayLimit-1, "张图哦"))
|
||||
})
|
||||
engine.OnRegex(`^为(群)?(自己|本群|\d+)设置AI画图key\s(.*[^\s$])\s(.+)$`, getdb).SetBlock(true).
|
||||
engine.OnRegex(`^为(群)?(自己|本群|\d+)设置画图key\s(.*[^\s$])\s(.+)$`, getdb).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
mode := ctx.State["regex_matched"].([]string)[1]
|
||||
user := ctx.State["regex_matched"].([]string)[2]
|
||||
@@ -238,17 +253,267 @@ func init() { // 插件主体
|
||||
}
|
||||
dbID = -uid
|
||||
}
|
||||
err := groupinfo.insert(dbID, aKey, sKey)
|
||||
err := vilginfo.insert(dbID, "vilg", aKey, sKey)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(serviceErr, err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("成功!"))
|
||||
})
|
||||
/*********************************************************/
|
||||
en := control.Register(modelName, &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "文心AI文本处理\n" +
|
||||
"基于百度文心AI的API文本处理\n" +
|
||||
"key申请链接:https://wenxin.baidu.com/moduleApi/key\n" +
|
||||
"key和ernievilg插件的key相同。\n" +
|
||||
"注意:每个apikey每日上限200条,总上限2000条。次数超过了请自行更新apikey\n" +
|
||||
"- 为[自己/本群/QQ号/群+群号]设置文心key [API Key] [Secret Key]\n" +
|
||||
"例:\n为自己设置文心key 123 456\n为10086设置文心key 123 456\n为群10010设置文心key 789 101\n" +
|
||||
"————————————————————\n" +
|
||||
"- 文心作文 (x字的)[作文题目]\n" +
|
||||
"————————————————————\n" +
|
||||
"- 文心提案 (x字的)[文案标题]\n" +
|
||||
"————————————————————\n" +
|
||||
"- 文心摘要 (x字的)[文章内容]\n" +
|
||||
"————————————————————\n" +
|
||||
"- 文心小说 (x字的)[小说上文]\n" +
|
||||
"————————————————————\n" +
|
||||
"- 文心对联 [上联]\n" +
|
||||
"————————————————————\n" +
|
||||
"- 文心问答 [问题]" +
|
||||
"————————————————————\n" +
|
||||
"- 文心补全 [带“_”的填空题]\n" +
|
||||
"————————————————————\n" +
|
||||
"- 文心自定义 [prompt]\n" +
|
||||
"prompt: [问题描述] [问题类型]:[题目] [解答类型]:[解题必带内容]\n" +
|
||||
"指令示例:\n" +
|
||||
"文心自定义 请写出下面这道题的解题过程。\\n题目:养殖场养鸭376只,养鸡的只数比鸭多258只,这个养殖场一共养鸭和鸡多少只?\\n解:\n" +
|
||||
"文心自定义 1+1=?\n" +
|
||||
"文心自定义 歌曲名:大风车转啊转\\n歌词:",
|
||||
}).ApplySingle(single.New(
|
||||
single.WithKeyFn(func(ctx *zero.Ctx) int64 { return ctx.Event.GroupID }),
|
||||
single.WithPostFn[int64](func(ctx *zero.Ctx) {
|
||||
ctx.Break()
|
||||
ctx.Send(
|
||||
message.ReplyWithMessage(ctx.Event.MessageID,
|
||||
message.Text(zero.BotConfig.NickName[0], "正在给别人编辑,请不要打扰哦"),
|
||||
),
|
||||
)
|
||||
}),
|
||||
))
|
||||
getmodeldb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
modelinfo.db.DBPath = engine.DataFolder() + "ernieModel.db"
|
||||
err := modelinfo.db.Open(time.Hour * 24)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(modelErr, err))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
en.OnRegex(`^为(群)?(自己|本群|\d+)设置文心key\s(.*[^\s$])\s(.+)$`, getmodeldb).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
mode := ctx.State["regex_matched"].([]string)[1]
|
||||
user := ctx.State["regex_matched"].([]string)[2]
|
||||
aKey := ctx.State["regex_matched"].([]string)[3]
|
||||
sKey := ctx.State["regex_matched"].([]string)[4]
|
||||
dbID := -ctx.Event.UserID // 默认给自己
|
||||
switch {
|
||||
case mode != "": // 指定群的话
|
||||
gid, err := strconv.ParseInt(user, 10, 64)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(modelErr, err))
|
||||
return
|
||||
}
|
||||
dbID = gid
|
||||
case user == "本群": // 用于本群
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 {
|
||||
ctx.SendChain(message.Text(modelErr, "请指定群聊,或者使用指令;\n为群xxx设置AI画图key xxx xxx"))
|
||||
return
|
||||
}
|
||||
dbID = gid
|
||||
case user != "自己": // 给别人开key
|
||||
uid, err := strconv.ParseInt(user, 10, 64)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(modelErr, err))
|
||||
return
|
||||
}
|
||||
dbID = -uid
|
||||
}
|
||||
err := modelinfo.insert(dbID, "model", aKey, sKey)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(modelErr, err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("成功!"))
|
||||
})
|
||||
|
||||
var erniemodel = map[string]int{
|
||||
"作文": 1,
|
||||
"提案": 2,
|
||||
"摘要": 3,
|
||||
"对联": 4,
|
||||
"问答": 5,
|
||||
"小说": 6,
|
||||
"补全": 7,
|
||||
"自定义": 8}
|
||||
var erniePrompt = map[string]string{
|
||||
"作文": "zuowen",
|
||||
"提案": "adtext",
|
||||
"摘要": "Summarization",
|
||||
"对联": "couplet",
|
||||
"问答": "Dialogue",
|
||||
"小说": "novel",
|
||||
"补全": "cloze"}
|
||||
en.OnRegex(`^文心(作文|提案|摘要|小说)\s?((\d+)字的)?(.*)$`, getmodeldb).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
uid := -ctx.Event.UserID
|
||||
gid := ctx.Event.GroupID
|
||||
// 获取个人和群的key
|
||||
userinfo, err1 := modelinfo.checkGroup(uid, "model")
|
||||
info, err2 := modelinfo.checkGroup(gid, "model")
|
||||
switch {
|
||||
// 如果是个人请求且报错
|
||||
case gid == 0 && err1 != nil:
|
||||
ctx.SendChain(message.Text(modelErr, err1))
|
||||
return
|
||||
// 如果群报错而个人没有,就切换成个人的
|
||||
case err2 != nil && err1 == nil:
|
||||
gid = uid
|
||||
info = userinfo
|
||||
// 如果都报错就以群为优先级
|
||||
case err1 != nil && err2 != nil:
|
||||
ctx.SendChain(message.Text(modelErr, err2))
|
||||
return
|
||||
}
|
||||
// 判断使用次数
|
||||
check := false
|
||||
switch {
|
||||
// 群和个人都没有次数了
|
||||
case info.DayLimit == 0 && userinfo.DayLimit == 0:
|
||||
ctx.SendChain(message.Text("今日请求次数已到200次了,明天在玩吧"))
|
||||
return
|
||||
// 个人还有次数的话
|
||||
case info.DayLimit == 0 && userinfo.DayLimit != 0:
|
||||
check = true
|
||||
}
|
||||
switch {
|
||||
// 群和个人都没有总次数了
|
||||
case info.MaxLimit == 0 && userinfo.MaxLimit == 0:
|
||||
ctx.SendChain(message.Text("设置的key使用次数超过了限额,请更换key。"))
|
||||
return
|
||||
// 个人还有总次数的话
|
||||
case info.MaxLimit == 0 && userinfo.MaxLimit != 0:
|
||||
check = true
|
||||
}
|
||||
if check { // 如果只有个人有次数就切换回个人key
|
||||
gid = uid
|
||||
info = userinfo
|
||||
}
|
||||
// 调用API
|
||||
modelStr := ctx.State["regex_matched"].([]string)[1]
|
||||
mun := ctx.State["regex_matched"].([]string)[3]
|
||||
minlen := 1
|
||||
maxlen := 128
|
||||
if mun != "" {
|
||||
max, err := strconv.Atoi(mun)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(modelErr, err))
|
||||
return
|
||||
}
|
||||
minlen = max
|
||||
if max > 128 {
|
||||
maxlen = max
|
||||
}
|
||||
}
|
||||
keyword := ctx.State["regex_matched"].([]string)[4]
|
||||
if len([]rune(keyword)) >= 1000 { // 描述不能超过1000
|
||||
ctx.SendChain(message.Text("是你写作文还是我写?减少点!"))
|
||||
return
|
||||
}
|
||||
result, err := model.GetResult(info.Token, erniemodel[modelStr], keyword, minlen, maxlen, erniePrompt[modelStr])
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(modelErr, err))
|
||||
return
|
||||
}
|
||||
if id := ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text(keyword, ",", result))); id.ID() == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 请求超时!"))
|
||||
}
|
||||
err = modelinfo.update(gid, 1)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(modelErr, err))
|
||||
}
|
||||
})
|
||||
en.OnRegex(`^文心(对联|问答|补全|自定义)\s?(.*)$`, getmodeldb).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
uid := -ctx.Event.UserID
|
||||
gid := ctx.Event.GroupID
|
||||
// 获取个人和群的key
|
||||
userinfo, err1 := modelinfo.checkGroup(uid, "model")
|
||||
info, err2 := modelinfo.checkGroup(gid, "model")
|
||||
switch {
|
||||
// 如果是个人请求且报错
|
||||
case gid == 0 && err1 != nil:
|
||||
ctx.SendChain(message.Text(modelErr, err1))
|
||||
return
|
||||
// 如果群报错而个人没有,就切换成个人的
|
||||
case err2 != nil && err1 == nil:
|
||||
gid = uid
|
||||
info = userinfo
|
||||
// 如果都报错就以群为优先级
|
||||
case err1 != nil && err2 != nil:
|
||||
ctx.SendChain(message.Text(modelErr, err2))
|
||||
return
|
||||
}
|
||||
// 判断使用次数
|
||||
check := false
|
||||
switch {
|
||||
// 群和个人都没有次数了
|
||||
case info.DayLimit == 0 && userinfo.DayLimit == 0:
|
||||
ctx.SendChain(message.Text("今日请求次数已到200次了,明天在玩吧"))
|
||||
return
|
||||
// 个人还有次数的话
|
||||
case info.DayLimit == 0 && userinfo.DayLimit != 0:
|
||||
check = true
|
||||
}
|
||||
switch {
|
||||
// 群和个人都没有总次数了
|
||||
case info.MaxLimit == 0 && userinfo.MaxLimit == 0:
|
||||
ctx.SendChain(message.Text("设置的key使用次数超过了限额,请更换key。"))
|
||||
return
|
||||
// 个人还有总次数的话
|
||||
case info.MaxLimit == 0 && userinfo.MaxLimit != 0:
|
||||
check = true
|
||||
}
|
||||
if check { // 如果只有个人有次数就切换回个人key
|
||||
gid = uid
|
||||
info = userinfo
|
||||
}
|
||||
// 创建任务
|
||||
modelStr := ctx.State["regex_matched"].([]string)[1]
|
||||
keyword := ctx.State["regex_matched"].([]string)[2]
|
||||
if len([]rune(keyword)) >= 1000 { // 描述不能超过1000
|
||||
ctx.SendChain(message.Text("你在写作文吗?减少点!"))
|
||||
return
|
||||
}
|
||||
result, err := model.GetResult(info.Token, erniemodel[modelStr], keyword, 1, 128, erniePrompt[modelStr])
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(modelErr, err))
|
||||
return
|
||||
}
|
||||
if id := ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text(result))); id.ID() == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 请求超时!"))
|
||||
}
|
||||
err = modelinfo.update(gid, 1)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text(modelErr, err))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 登记group的key
|
||||
func (sql *keydb) insert(gid int64, akey, skey string) error {
|
||||
func (sql *keydb) insert(gid int64, model, akey, skey string) error {
|
||||
sql.Lock()
|
||||
defer sql.Unlock()
|
||||
// 给db文件创建表格(没有才创建),表格名称groupinfo,表格结构apikey
|
||||
@@ -270,7 +535,12 @@ func (sql *keydb) insert(gid int64, akey, skey string) error {
|
||||
ID: gid,
|
||||
APIKey: akey,
|
||||
SecretKey: skey,
|
||||
MaxLimit: 500,
|
||||
}
|
||||
switch model {
|
||||
case "vilg":
|
||||
groupinfo.MaxLimit = 500
|
||||
case "model":
|
||||
groupinfo.MaxLimit = 2000
|
||||
}
|
||||
}
|
||||
return sql.db.Insert("groupinfo", &groupinfo)
|
||||
@@ -278,12 +548,19 @@ func (sql *keydb) insert(gid int64, akey, skey string) error {
|
||||
// 进行更新
|
||||
groupinfo.APIKey = akey
|
||||
groupinfo.SecretKey = skey
|
||||
groupinfo.MaxLimit = 500
|
||||
groupinfo.Token = ""
|
||||
groupinfo.Updatetime = 0
|
||||
switch model {
|
||||
case "vilg":
|
||||
groupinfo.MaxLimit = 500
|
||||
case "model":
|
||||
groupinfo.MaxLimit = 2000
|
||||
}
|
||||
return sql.db.Insert("groupinfo", &groupinfo)
|
||||
}
|
||||
|
||||
// 获取group信息
|
||||
func (sql *keydb) checkGroup(gid int64) (groupinfo apikey, err error) {
|
||||
func (sql *keydb) checkGroup(gid int64, model string) (groupinfo apikey, err error) {
|
||||
sql.Lock()
|
||||
defer sql.Unlock()
|
||||
// 给db文件创建表格(没有才创建),表格名称groupinfo,表格结构apikey
|
||||
@@ -291,12 +568,20 @@ func (sql *keydb) checkGroup(gid int64) (groupinfo apikey, err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
switch model {
|
||||
case "vilg":
|
||||
limit = 50
|
||||
model = "画图"
|
||||
case "model":
|
||||
limit = 200
|
||||
model = "文心"
|
||||
}
|
||||
// 先判断该群是否已经设置过key了
|
||||
if ok := sql.db.CanFind("groupinfo", "where ID is "+strconv.FormatInt(gid, 10)); !ok {
|
||||
if gid > 0 {
|
||||
err = errors.New("该群没有设置过apikey,请前往https://wenxin.baidu.com/moduleApi/key获取key值后,发送指令:\n为本群设置AI画图key [API Key] [Secret Key]")
|
||||
err = errors.New("该群没有设置过apikey,请前往https://wenxin.baidu.com/moduleApi/key获取key值后,发送指令:\n为本群设置" + model + "key [API Key] [Secret Key]\n或\n为自己设置" + model + "key [API Key] [Secret Key]")
|
||||
} else {
|
||||
err = errors.New("你没有设置过apikey,请前往https://wenxin.baidu.com/moduleApi/key获取key值后,发送指令:\n为自己设置AI画图key [API Key] [Secret Key]")
|
||||
err = errors.New("你没有设置过apikey,请前往https://wenxin.baidu.com/moduleApi/key获取key值后,发送指令:\n为自己设置" + model + "key [API Key] [Secret Key]")
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -314,7 +599,7 @@ func (sql *keydb) checkGroup(gid int64) (groupinfo apikey, err error) {
|
||||
return
|
||||
}
|
||||
// 如果token有效期过期
|
||||
if time.Since(time.Unix(groupinfo.Updatetime, 0)).Hours() > 24 {
|
||||
if time.Since(time.Unix(groupinfo.Updatetime, 0)).Hours() > 24 || groupinfo.Token == "" {
|
||||
token, err1 := wenxin.GetToken(groupinfo.APIKey, groupinfo.SecretKey)
|
||||
if err1 != nil {
|
||||
err = err1
|
||||
@@ -350,8 +635,8 @@ func (sql *keydb) checkGroup(gid int64) (groupinfo apikey, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// 记录次数(-1)
|
||||
func (sql *keydb) update(gid int64) error {
|
||||
// 记录次数(-sub)
|
||||
func (sql *keydb) update(gid int64, sub int) error {
|
||||
sql.Lock()
|
||||
defer sql.Unlock()
|
||||
// 给db文件创建表格(没有才创建),表格名称groupinfo,表格结构apikey
|
||||
@@ -365,8 +650,8 @@ func (sql *keydb) update(gid int64) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
groupinfo.MaxLimit--
|
||||
groupinfo.DayLimit--
|
||||
groupinfo.MaxLimit -= sub
|
||||
groupinfo.DayLimit -= sub
|
||||
err = sql.db.Insert("groupinfo", &groupinfo)
|
||||
if err != nil {
|
||||
return err
|
||||
Reference in New Issue
Block a user