From 552c1a9a3527be6478c2f57e401b17c1708e594c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=BA=90=E6=96=87=E9=9B=A8?=
<41315874+fumiama@users.noreply.github.com>
Date: Mon, 17 Feb 2025 23:12:23 +0900
Subject: [PATCH] optimize(chat): avoid conflicts
---
README.md | 3 +-
go.mod | 2 +-
go.sum | 4 +-
plugin/aichat/main.go | 25 ++++-
plugin/thesaurus/chat.go | 192 ++++++---------------------------------
5 files changed, 54 insertions(+), 172 deletions(-)
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))]