ZeroBot-Plugin/plugin/baiduaudit/audit.go
2023-03-05 00:46:53 +08:00

293 lines
9.1 KiB
Go

// Package baiduaudit 百度内容审核
package baiduaudit
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"github.com/Baidu-AIP/golang-sdk/aip/censor"
"github.com/sirupsen/logrus"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
"github.com/FloatTech/floatbox/binary"
ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control"
"github.com/FloatTech/zbputils/img/text"
)
var (
bdcli *censor.ContentCensorClient // 百度云审核服务Client
txttyp = [...]string{
0: "默认违禁词库",
1: "违禁违规",
2: "文本色情",
3: "敏感信息",
4: "恶意推广",
5: "低俗辱骂",
6: "恶意推广-联系方式",
7: "恶意推广-软文推广",
} // 文本类型
config = newconfig() // 插件配置
)
func init() {
engine := control.Register("baiduaudit", &ctrl.Options[*zero.Ctx]{
DisableOnDefault: false,
Brief: "百度内容审核",
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"
err := config.load(configpath)
if err != nil {
logrus.Warnln("[baiduaudit] 加载配置错误:", err)
} else if config.Key1 != "" && config.Key2 != "" {
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, hasinit).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
// 获取群配置
group := config.groupof(ctx.Event.GroupID)
msg := ""
k1 := ctx.State["regex_matched"].([]string)[1]
if k1 == "类型" {
sb := strings.Builder{}
sb.WriteString("本群检测类型:")
found := false
// 遍历群检测类型名单
for i, v := range group.copyWhiteListType() {
if !v {
found = true
sb.WriteByte('\n')
sb.WriteString(strconv.Itoa(i))
sb.WriteByte('.')
sb.WriteString(txttyp[i])
}
}
if !found {
sb.WriteString("无")
}
msg = sb.String()
} else {
// 生成配置文本
msg = 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(msg, text.FontFile, 300, 20)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(message.Image("base64://" + binary.BytesToString(b)))
})
engine.OnRegex("^设置(不)?检测类型([0-7])$", zero.AdminPermission, hasinit).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
k1 := ctx.State["regex_matched"].([]string)[1]
k2 := ctx.State["regex_matched"].([]string)[2]
group := config.groupof(ctx.Event.GroupID)
inputType, _ := strconv.Atoi(k2)
group.setWhiteListType(inputType, k1 == "不")
err := config.saveto(configpath)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(message.At(ctx.Event.UserID), message.Text(fmt.Sprintf("本群将%s检测%s类型内容", k1, txttyp[inputType])))
})
engine.OnRegex("^设置(最大|每次|撤回)(累加|禁言)时间(\\d{1,5})$", zero.AdminPermission, hasinit).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
k1 := ctx.State["regex_matched"].([]string)[1]
k3 := ctx.State["regex_matched"].([]string)[3]
time, _ := strconv.ParseInt(k1, 10, 64)
config.groupof(ctx.Event.GroupID).set(func(g *group) {
switch k1 {
case "最大":
g.MaxBANTimeAddRange = time
case "每次":
g.BANTimeAddTime = time
case "撤回":
g.BANTime = time
}
})
err := config.saveto(configpath)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(message.At(ctx.Event.UserID), message.Text(fmt.Sprintf("本群%s禁言累加时间已设置为%s", k3, k1)))
})
engine.OnRegex("^(开启|关闭)(内容审核|撤回提示|撤回禁言|禁言累加|详细提示|文本检测|图像检测)$", zero.AdminPermission, hasinit).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
k1 := ctx.State["regex_matched"].([]string)[1]
k2 := ctx.State["regex_matched"].([]string)[2]
isEnable := mark(k1 == "开启")
config.groupof(ctx.Event.GroupID).set(func(g *group) {
switch k2 {
case "内容审核":
g.Enable = isEnable
case "撤回提示":
g.DMRemind = isEnable
case "撤回禁言":
g.DMBAN = isEnable
case "禁言累加":
g.BANTimeAddEnable = isEnable
case "详细提示":
g.MoreRemind = isEnable
case "文本检测":
g.TextAudit = isEnable
case "图像检测":
g.ImageAudit = isEnable
}
})
err := config.saveto(configpath)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
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.setkey(k1, k2)
if bdcli != nil {
err := config.saveto(configpath)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(message.Text("配置成功"))
}
})
engine.OnMessage(config.isgroupexist).SetBlock(false).Handle(func(ctx *zero.Ctx) {
group := config.groupof(ctx.Event.GroupID)
if !bool(group.Enable) {
return
}
var bdres baiduRes
var err error
for _, elem := range ctx.Event.Message {
switch elem.Type {
case "image":
if !group.ImageAudit || elem.Data["url"] == "" {
continue
}
res := bdcli.ImgCensorUrl(elem.Data["url"], nil)
bdres, err = parse2BaiduRes(res)
if err != nil {
continue
}
case "text":
if !group.TextAudit || elem.Data["text"] == "" {
continue
}
bdres, err = parse2BaiduRes(bdcli.TextCensor(elem.Data["text"]))
if err != nil {
continue
}
default:
continue
}
}
bdres.audit(ctx, configpath)
})
engine.OnPrefix("^文本检测", hasinit).SetBlock(false).
Handle(func(ctx *zero.Ctx) {
args := ctx.ExtractPlainText()
res := bdcli.TextCensor(args)
bdres, err := parse2BaiduRes(res)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", bdres.ErrorMsg, "(", bdres.ErrorCode, ")"))
return
}
ctx.Send(config.groupof(ctx.Event.GroupID).reply(&bdres))
})
engine.OnPrefix("^图像检测", hasinit).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 := parse2BaiduRes(res)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", bdres.ErrorMsg, "(", bdres.ErrorCode, ")"))
return
}
ctx.Send(config.groupof(ctx.Event.GroupID).reply(&bdres))
})
}
// 客户端是否初始化检测
func hasinit(ctx *zero.Ctx) bool {
if bdcli == nil {
ctx.SendChain(message.Text("Key未配置"))
return false
}
return true
}
func parse2BaiduRes(resjson string) (bdres baiduRes, err error) {
err = json.Unmarshal(binary.StringToBytes(resjson), &bdres)
return
}