diff --git a/README.md b/README.md index 75eba94a..d6306f2b 100644 --- a/README.md +++ b/README.md @@ -1548,6 +1548,7 @@ print("run[CQ:image,file="+j["img"]+"]") - [x] 设置AI聊天模型名xxx - [x] 设置AI聊天系统提示词xxx - [x] 设置AI聊天分隔符``(留空则清除) + - [x] 设置AI聊天(不)响应AT
@@ -1561,7 +1562,7 @@ print("run[CQ:image,file="+j["img"]+"]")
- 词典匹配回复 + 词典匹配回复, 仅@触发 `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/thesaurus"` diff --git a/go.mod b/go.mod index c7057430..d9570eea 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.20 require ( github.com/Baidu-AIP/golang-sdk v1.1.1 - github.com/FloatTech/AnimeAPI v1.7.1-0.20250214133017-28762c8262a6 + github.com/FloatTech/AnimeAPI v1.7.1-0.20250217140215-4856397458c9 github.com/FloatTech/floatbox v0.0.0-20241106130736-5aea0a935024 github.com/FloatTech/gg v1.1.3 github.com/FloatTech/imgfactory v0.2.2-0.20230413152719-e101cc3606ef diff --git a/go.sum b/go.sum index 257518c6..381fc71a 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,8 @@ 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/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= -github.com/FloatTech/AnimeAPI v1.7.1-0.20250214133017-28762c8262a6 h1:LxCcLzXCMUJ67I1sDaW1fOFlTxabLR29g+qpSExrGzk= -github.com/FloatTech/AnimeAPI v1.7.1-0.20250214133017-28762c8262a6/go.mod h1:XXG1eBJf+eeWacQx5azsQKL5Gg7jDYTFyyZGIa/56js= +github.com/FloatTech/AnimeAPI v1.7.1-0.20250217140215-4856397458c9 h1:tI9GgG8fdMK2WazFiEbMXAXjwMCckIfDaXbig9B6DdA= +github.com/FloatTech/AnimeAPI v1.7.1-0.20250217140215-4856397458c9/go.mod h1:XXG1eBJf+eeWacQx5azsQKL5Gg7jDYTFyyZGIa/56js= github.com/FloatTech/floatbox v0.0.0-20241106130736-5aea0a935024 h1:mrvWpiwfRklt9AyiQjKgDGJjf4YL6FZ3yC+ydbkuF2o= github.com/FloatTech/floatbox v0.0.0-20241106130736-5aea0a935024/go.mod h1:+P3hs+Cvl10/Aj3SNE96TuBvKAXCe+XD1pKphTZyiwk= github.com/FloatTech/gg v1.1.3 h1:+GlL02lTKsxJQr4WCuNwVxC1/eBZrCvypCIBtxuOFb4= diff --git a/plugin/aichat/main.go b/plugin/aichat/main.go index 543ffb00..04e297d3 100644 --- a/plugin/aichat/main.go +++ b/plugin/aichat/main.go @@ -33,7 +33,8 @@ var ( "- 设置AI聊天密钥xxx\n" + "- 设置AI聊天模型名xxx\n" + "- 设置AI聊天系统提示词xxx\n" + - "- 设置AI聊天分隔符(留空则清除)", + "- 设置AI聊天分隔符(留空则清除)\n" + + "- 设置AI聊天(不)响应AT", PrivateDataFolder: "aichat", }) ) @@ -42,6 +43,7 @@ var ( modelname = "deepseek-ai/DeepSeek-R1" systemprompt = "你正在QQ群与用户聊天,用户发送了消息。按自己的心情简短思考后条理清晰地回复。" sepstr = "" + noreplyat = false ) func init() { @@ -74,7 +76,7 @@ func init() { } en.OnMessage(func(ctx *zero.Ctx) bool { - return ctx.ExtractPlainText() != "" + return ctx.ExtractPlainText() != "" && (!noreplyat || (noreplyat && !ctx.Event.IsToMe)) }).SetBlock(false).Handle(func(ctx *zero.Ctx) { gid := ctx.Event.GroupID if gid == 0 { @@ -270,4 +272,23 @@ func init() { } ctx.SendChain(message.Text("设置成功")) }) + en.OnRegex("^设置AI聊天(不)?响应AT$", zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) { + args := ctx.State["regex_matched"].([]string) + isno := args[1] == "不" + fp := en.DataFolder() + "NoReplyAT" + if isno { + f, err := os.Create(fp) + if err != nil { + ctx.SendChain(message.Text("ERROR: ", err)) + return + } + defer f.Close() + f.WriteString("PLACEHOLDER") + noreplyat = true + } else { + _ = os.Remove(fp) + noreplyat = false + } + ctx.SendChain(message.Text("成功")) + }) } diff --git a/plugin/thesaurus/chat.go b/plugin/thesaurus/chat.go index ee2dc1fa..69b2051e 100644 --- a/plugin/thesaurus/chat.go +++ b/plugin/thesaurus/chat.go @@ -1,61 +1,33 @@ -// Package thesaurus 修改过的单纯回复插件 +// Package thesaurus 修改过的单纯回复插件, 仅@触发 package thesaurus import ( "bytes" - "encoding/json" "math/rand" - "net/http" - "os" - "strconv" "strings" - "time" - "github.com/FloatTech/floatbox/binary" - "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/fumiama/jieba" "github.com/sirupsen/logrus" + "gopkg.in/yaml.v3" + zero "github.com/wdvxdr1123/ZeroBot" "github.com/wdvxdr1123/ZeroBot/message" - "gopkg.in/yaml.v3" + + "github.com/FloatTech/AnimeAPI/kimoi" + "github.com/FloatTech/floatbox/ctxext" + "github.com/FloatTech/floatbox/process" + ctrl "github.com/FloatTech/zbpctrl" + "github.com/FloatTech/zbputils/control" ) func init() { engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{ DisableOnDefault: false, - Brief: "词典匹配回复", - Help: "- 切换[kimo|傲娇|可爱|🦙]词库\n- 设置词库触发概率0.x (0= 9 { - ctx.SendChain(message.Text("ERROR: 概率越界")) - return - } - n-- // 0~7 - gid := ctx.Event.GroupID - if gid == 0 { - gid = -ctx.Event.UserID - } - d := c.GetData(gid) - err := c.SetData(gid, (d&3)|(int64(n)<<59)) - if err != nil { - ctx.SendChain(message.Text("ERROR: ", err)) - return - } - ctx.SendChain(message.Text("成功!")) - }) - engine.OnRegex(`^设置🦙API地址\s*(http.*)\s*$`, zero.SuperUserPermission, zero.OnlyPrivate).SetBlock(true).Handle(func(ctx *zero.Ctx) { - alpacapiurl = ctx.State["regex_matched"].([]string)[1] - err := os.WriteFile(alpacapifile, binary.StringToBytes(alpacapiurl), 0644) - if err != nil { - ctx.SendChain(message.Text("ERROR: ", err)) - return - } - ctx.SendChain(message.Text("成功!")) - }) - engine.OnRegex(`^设置🦙token\s*([0-9a-f]{112})\s*$`, zero.SuperUserPermission, zero.OnlyPrivate).SetBlock(true).Handle(func(ctx *zero.Ctx) { - alpacatoken = ctx.State["regex_matched"].([]string)[1] - err := os.WriteFile(alpacatokenfile, binary.StringToBytes(alpacatoken), 0644) - if err != nil { - ctx.SendChain(message.Text("ERROR: ", err)) - return - } - ctx.SendChain(message.Text("成功!")) - }) go func() { data, err := engine.GetLazyData("dict.txt", false) if err != nil { @@ -144,21 +72,6 @@ func init() { if err != nil { panic(err) } - data, err = engine.GetLazyData("kimoi.json", false) - if err != nil { - panic(err) - } - kimomap := make(kimo, 256) - err = json.Unmarshal(data, &kimomap) - if err != nil { - panic(err) - } - chatList := make([]string, 0, len(kimomap)) - for k := range kimomap { - chatList = append(chatList, k) - } - logrus.Infoln("[thesaurus]加载", len(chatList), "条kimoi") - chatListD := make([]string, 0, len(sm.D)) for k := range sm.D { chatListD = append(chatListD, k) @@ -169,86 +82,32 @@ func init() { } logrus.Infoln("[thesaurus]加载", len(chatListD), "条傲娇词库", len(chatListK), "条可爱词库") - engine.OnMessage(canmatch(tKIMO), match(chatList, seg)). - SetBlock(false). - Handle(randreply(kimomap)) - engine.OnMessage(canmatch(tDERE), match(chatListD, seg)). - SetBlock(false). - Handle(randreply(sm.D)) - engine.OnMessage(canmatch(tKAWA), match(chatListK, seg)). - SetBlock(false). - Handle(randreply(sm.K)) - engine.OnMessage(canmatch(tALPACA), func(_ *zero.Ctx) bool { - return alpacapiurl != "" && alpacatoken != "" - }).SetBlock(false).Handle(func(ctx *zero.Ctx) { - msg := ctx.ExtractPlainText() - if msg != "" { - data, err := web.RequestDataWithHeaders(http.DefaultClient, alpacapiurl+"/reply", "POST", - func(r *http.Request) error { - r.Header.Set("Authorization", alpacatoken) - return nil - }, bytes.NewReader(binary.NewWriterF(func(writer *binary.Writer) { - _ = json.NewEncoder(writer).Encode(&[]alpacamsg{{ - Name: ctx.CardOrNickName(ctx.Event.UserID), - Message: msg, - }}) - }))) - if err != nil { - logrus.Warnln("[chat] 🦙 err:", err) - return - } - type reply struct { - ID int - Msg string - } - m := reply{} - err = json.Unmarshal(data, &m) - if err != nil { - logrus.Warnln("[chat] 🦙 unmarshal err:", err) - return - } - for i := 0; i < 60; i++ { - time.Sleep(time.Second * 4) - data, err := web.RequestDataWithHeaders(http.DefaultClient, alpacapiurl+"/get?id="+strconv.Itoa(m.ID), "GET", - func(r *http.Request) error { - r.Header.Set("Authorization", alpacatoken) - return nil - }, nil) - if err != nil { - continue - } - err = json.Unmarshal(data, &m) - if err != nil { - logrus.Warnln("[chat] 🦙 unmarshal err:", err) - return - } - if len(m.Msg) > 0 { - ctx.Send(message.Text(m.Msg)) - } - return - } + engine.OnMessage(zero.OnlyToMe, canmatch(tKIMO)). + SetBlock(false).Handle(func(ctx *zero.Ctx) { + r, err := kimoi.Chat(ctx.ExtractPlainText()) + if err == nil && r.Confidence > 0.5 && r.Confidence < 0.95 { + ctx.Block() + ctx.SendChain(message.Text(r.Reply)) } }) + engine.OnMessage(zero.OnlyToMe, canmatch(tDERE), match(chatListD, seg)). + SetBlock(false). + Handle(randreply(sm.D)) + engine.OnMessage(zero.OnlyToMe, canmatch(tKAWA), match(chatListK, seg)). + SetBlock(false). + Handle(randreply(sm.K)) }() } -type kimo = map[string][]string - type simai struct { D map[string][]string `yaml:"傲娇"` K map[string][]string `yaml:"可爱"` } -type alpacamsg struct { - Name string - Message string -} - const ( tKIMO = iota tDERE tKAWA - tALPACA ) func match(l []string, seg *jieba.Segmenter) zero.Rule { @@ -273,12 +132,13 @@ func canmatch(typ int64) zero.Rule { gid = -ctx.Event.UserID } d := c.GetData(gid) - return d&3 == typ && rand.Int63n(10) <= d>>59 + return ctx.ExtractPlainText() != "" && d&3 == typ } } func randreply(m map[string][]string) zero.Handler { return func(ctx *zero.Ctx) { + ctx.Block() key := ctx.State["matched"].(string) val := m[key] nick := zero.BotConfig.NickName[rand.Intn(len(zero.BotConfig.NickName))]