From 8d2dffba3a874faf7a61d79b1342ca5e2f107d80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=94=85=E9=A5=AD?= <1156544355@qq.com> Date: Wed, 30 Jul 2025 20:52:19 +0800 Subject: [PATCH 01/14] =?UTF-8?q?=E2=9C=A8=20=E6=B7=BB=E5=8A=A0=E9=87=8D?= =?UTF-8?q?=E7=BD=AE=E8=81=8A=E5=A4=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugin/aichat/main.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugin/aichat/main.go b/plugin/aichat/main.go index c8ac1df646..5331cad234 100644 --- a/plugin/aichat/main.go +++ b/plugin/aichat/main.go @@ -41,7 +41,8 @@ var ( "- 设置AI聊天最大长度4096\n" + "- 设置AI聊天TopP 0.9\n" + "- 设置AI聊天(不)以AI语音输出\n" + - "- 查看AI聊天配置\n", + "- 查看AI聊天配置\n" + + "- 重置AI聊天\n", PrivateDataFolder: "aichat", }) ) @@ -305,4 +306,8 @@ func init() { } ctx.SendChain(message.Text(printConfig(rate, temp, cfg))) }) + en.OnFullMatch("重置AI聊天", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) { + chat.Reset() + ctx.SendChain(message.Text("成功")) + }) } From 8feca47d46976c810a2525450bf7f87f3ff4ca70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=94=85=E9=A5=AD?= <1156544355@qq.com> Date: Wed, 30 Jul 2025 21:01:07 +0800 Subject: [PATCH 02/14] =?UTF-8?q?=F0=9F=8E=A8=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 5 +++-- plugin/aichat/main.go | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1442aad6ff..3e46929e5e 100644 --- a/README.md +++ b/README.md @@ -1612,9 +1612,9 @@ print("run[CQ:image,file="+j["img"]+"]") - [x] 设置AI聊天温度80 - [x] 设置AI聊天接口类型[OpenAI|OLLaMA|GenAI] - [x] 设置AI聊天(不)支持系统提示词 - - [x] 设置AI聊天接口地址https://api.deepseek.com/chat/completions + - [x] 设置AI聊天接口地址https://api.siliconflow.cn/v1/chat/completions - [x] 设置AI聊天密钥xxx - - [x] 设置AI聊天模型名xxx + - [x] 设置AI聊天模型名Qwen/Qwen3-8B - [x] 查看AI聊天系统提示词 - [x] 重置AI聊天系统提示词 - [x] 设置AI聊天系统提示词xxx @@ -1624,6 +1624,7 @@ print("run[CQ:image,file="+j["img"]+"]") - [x] 设置AI聊天TopP 0.9 - [x] 设置AI聊天(不)以AI语音输出 - [x] 查看AI聊天配置 + - [x] 重置AI聊天
diff --git a/plugin/aichat/main.go b/plugin/aichat/main.go index 5331cad234..bc851ac919 100644 --- a/plugin/aichat/main.go +++ b/plugin/aichat/main.go @@ -30,9 +30,9 @@ var ( "- 设置AI聊天温度80\n" + "- 设置AI聊天接口类型[OpenAI|OLLaMA|GenAI]\n" + "- 设置AI聊天(不)支持系统提示词\n" + - "- 设置AI聊天接口地址https://api.deepseek.com/chat/completions\n" + + "- 设置AI聊天接口地址https://api.siliconflow.cn/v1/chat/completions\n" + "- 设置AI聊天密钥xxx\n" + - "- 设置AI聊天模型名xxx\n" + + "- 设置AI聊天模型名Qwen/Qwen3-8B\n" + "- 查看AI聊天系统提示词\n" + "- 重置AI聊天系统提示词\n" + "- 设置AI聊天系统提示词xxx\n" + From e5a7c30f494337717fd795889da0860e120ecef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=94=85=E9=A5=AD?= <1156544355@qq.com> Date: Thu, 31 Jul 2025 00:33:56 +0800 Subject: [PATCH 03/14] =?UTF-8?q?=E2=9C=A8=20=E6=B7=BB=E5=8A=A0=E7=BE=A4?= =?UTF-8?q?=E8=81=8A=E6=91=98=E8=A6=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugin/aichat/main.go | 89 +++++++++++++++++++++++++++++++++++++++- plugin/wordcount/main.go | 2 +- 2 files changed, 88 insertions(+), 3 deletions(-) diff --git a/plugin/aichat/main.go b/plugin/aichat/main.go index bc851ac919..c00419ead5 100644 --- a/plugin/aichat/main.go +++ b/plugin/aichat/main.go @@ -1,14 +1,17 @@ -// Package aichat OpenAI聊天 +// Package aichat OpenAI聊天和群聊摘要 package aichat import ( + "fmt" "math/rand" "strconv" "strings" + "unicode" "github.com/fumiama/deepinfra" "github.com/fumiama/deepinfra/model" "github.com/sirupsen/logrus" + "github.com/tidwall/gjson" zero "github.com/wdvxdr1123/ZeroBot" "github.com/wdvxdr1123/ZeroBot/message" @@ -42,7 +45,8 @@ var ( "- 设置AI聊天TopP 0.9\n" + "- 设置AI聊天(不)以AI语音输出\n" + "- 查看AI聊天配置\n" + - "- 重置AI聊天\n", + "- 重置AI聊天\n" + + "- 群聊摘要 [群号] [消息数目]|群聊摘要 123456 1000\n", PrivateDataFolder: "aichat", }) ) @@ -310,4 +314,85 @@ func init() { chat.Reset() ctx.SendChain(message.Text("成功")) }) + + // 添加群聊摘要功能 + en.OnRegex(`^群聊摘要\s?(\d*)\s?(\d*)$`, zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) { + ctx.SendChain(message.Text("少女思考中...")) + gid, _ := strconv.ParseInt(ctx.State["regex_matched"].([]string)[1], 10, 64) + p, _ := strconv.ParseInt(ctx.State["regex_matched"].([]string)[2], 10, 64) + if p > 1000 { + p = 1000 + } + if p == 0 { + p = 200 + } + if gid == 0 { + gid = ctx.Event.GroupID + } + group := ctx.GetGroupInfo(gid, false) + if group.MemberCount == 0 { + ctx.SendChain(message.Text(zero.BotConfig.NickName[0], "未加入", group.Name, "(", gid, "),无法获取摘要")) + return + } + + var messages []string + + h := ctx.GetGroupMessageHistory(gid, 0, p, false) + h.Get("messages").ForEach(func(_, msgObj gjson.Result) bool { + nickname := removeControlChars(msgObj.Get("sender.nickname").Str) + text := strings.TrimSpace(message.ParseMessageFromString(msgObj.Get("raw_message").Str).ExtractPlainText()) + if text != "" { + messages = append(messages, nickname+": "+text) + } + return true + }) + + if len(messages) == 0 { + ctx.SendChain(message.Text("ERROR: 历史消息为空或者无法获得历史消息")) + return + } + + // 调用大模型API进行摘要 + summary, err := summarizeMessages(messages) + if err != nil { + ctx.SendChain(message.Text("ERROR: ", err)) + return + } + + ctx.SendChain(message.Text( + fmt.Sprintf("群 %s(%d) 的 %d 条消息摘要:\n\n", group.Name, gid, p), + summary, + )) + }) +} + +// summarizeMessages 调用大模型API进行消息摘要 +func summarizeMessages(messages []string) (string, error) { + // 使用现有的AI配置进行摘要 + x := deepinfra.NewAPI(cfg.API, cfg.Key) + mod := model.NewOpenAI( + cfg.ModelName, cfg.Separator, + float32(70)/100, 0.9, 4096, + ) + + // 构造摘要请求提示 + summaryPrompt := "请将以下群聊消息总结成一段简洁的摘要,保留每个用户主要话题和关键信息:\n\n" + + strings.Join(messages, "\n") + "\n\n群聊摘要:" + + data, err := x.Request(mod.User(summaryPrompt)) + if err != nil { + return "", err + } + + return strings.TrimSpace(data), nil +} + +func removeControlChars(s string) string { + var builder strings.Builder + for _, r := range s { + if !unicode.IsControl(r) { // 保留非控制字符 + builder.WriteRune(r) + } + } + return builder.String() } diff --git a/plugin/wordcount/main.go b/plugin/wordcount/main.go index 5e58069fa3..2ffbf78d57 100644 --- a/plugin/wordcount/main.go +++ b/plugin/wordcount/main.go @@ -114,7 +114,7 @@ func init() { messageSeq := h.Get("messages.0.message_seq").Int() msghists <- &h for i := 1; i < int(p/20) && messageSeq != 0; i++ { - h := ctx.GetGroupMessageHistory(gid, messageSeq) + h := ctx.GetGroupMessageHistory(gid, messageSeq, 20, false) msghists <- &h messageSeq = h.Get("messages.0.message_seq").Int() } From eae8383b130e7339470f5f58f23ae584ba346a8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=94=85=E9=A5=AD?= <1156544355@qq.com> Date: Thu, 31 Jul 2025 11:21:26 +0800 Subject: [PATCH 04/14] =?UTF-8?q?=F0=9F=90=9B=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E8=AF=BB=E9=85=8D=E7=BD=AEbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugin/aichat/main.go | 37 +++++++++++++------------------------ 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/plugin/aichat/main.go b/plugin/aichat/main.go index c00419ead5..7474263045 100644 --- a/plugin/aichat/main.go +++ b/plugin/aichat/main.go @@ -1,4 +1,4 @@ -// Package aichat OpenAI聊天和群聊摘要 +// Package aichat OpenAI聊天和群聊总结 package aichat import ( @@ -6,7 +6,7 @@ import ( "math/rand" "strconv" "strings" - "unicode" + "time" "github.com/fumiama/deepinfra" "github.com/fumiama/deepinfra/model" @@ -21,6 +21,7 @@ import ( ctrl "github.com/FloatTech/zbpctrl" "github.com/FloatTech/zbputils/chat" "github.com/FloatTech/zbputils/control" + "github.com/FloatTech/zbputils/ctxext" ) var ( @@ -46,7 +47,7 @@ var ( "- 设置AI聊天(不)以AI语音输出\n" + "- 查看AI聊天配置\n" + "- 重置AI聊天\n" + - "- 群聊摘要 [群号] [消息数目]|群聊摘要 123456 1000\n", + "- 群聊总结 [消息数目]|群聊总结 1000\n", PrivateDataFolder: "aichat", }) ) @@ -58,6 +59,7 @@ var ( "GenAI": 2, } apilist = [3]string{"OpenAI", "OLLaMA", "GenAI"} + limit = ctxext.NewLimiterManager(time.Second*60, 1) ) func init() { @@ -315,20 +317,17 @@ func init() { ctx.SendChain(message.Text("成功")) }) - // 添加群聊摘要功能 - en.OnRegex(`^群聊摘要\s?(\d*)\s?(\d*)$`, zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) { + // 添加群聊总结功能 + en.OnRegex(`^群聊总结\s?(\d*)$`, ensureconfig, zero.OnlyGroup).SetBlock(true).Limit(limit.LimitByGroup).Handle(func(ctx *zero.Ctx) { ctx.SendChain(message.Text("少女思考中...")) - gid, _ := strconv.ParseInt(ctx.State["regex_matched"].([]string)[1], 10, 64) - p, _ := strconv.ParseInt(ctx.State["regex_matched"].([]string)[2], 10, 64) + p, _ := strconv.ParseInt(ctx.State["regex_matched"].([]string)[1], 10, 64) if p > 1000 { p = 1000 } if p == 0 { p = 200 } - if gid == 0 { - gid = ctx.Event.GroupID - } + gid := ctx.Event.GroupID group := ctx.GetGroupInfo(gid, false) if group.MemberCount == 0 { ctx.SendChain(message.Text(zero.BotConfig.NickName[0], "未加入", group.Name, "(", gid, "),无法获取摘要")) @@ -339,7 +338,7 @@ func init() { h := ctx.GetGroupMessageHistory(gid, 0, p, false) h.Get("messages").ForEach(func(_, msgObj gjson.Result) bool { - nickname := removeControlChars(msgObj.Get("sender.nickname").Str) + nickname := msgObj.Get("sender.nickname").Str text := strings.TrimSpace(message.ParseMessageFromString(msgObj.Get("raw_message").Str).ExtractPlainText()) if text != "" { messages = append(messages, nickname+": "+text) @@ -360,7 +359,7 @@ func init() { } ctx.SendChain(message.Text( - fmt.Sprintf("群 %s(%d) 的 %d 条消息摘要:\n\n", group.Name, gid, p), + fmt.Sprintf("群 %s(%d) 的 %d 条消息总结:\n\n", group.Name, gid, p), summary, )) }) @@ -376,8 +375,8 @@ func summarizeMessages(messages []string) (string, error) { ) // 构造摘要请求提示 - summaryPrompt := "请将以下群聊消息总结成一段简洁的摘要,保留每个用户主要话题和关键信息:\n\n" + - strings.Join(messages, "\n") + "\n\n群聊摘要:" + summaryPrompt := "请总结这个群聊内容,要求按发言顺序梳理,明确标注每个发言者的昵称,并完整呈现其核心观点、提出的问题、发表的看法或做出的回应,确保不遗漏关键信息,且能体现成员间的对话逻辑和互动关系:\n\n" + + strings.Join(messages, "\n---\n") data, err := x.Request(mod.User(summaryPrompt)) if err != nil { @@ -386,13 +385,3 @@ func summarizeMessages(messages []string) (string, error) { return strings.TrimSpace(data), nil } - -func removeControlChars(s string) string { - var builder strings.Builder - for _, r := range s { - if !unicode.IsControl(r) { // 保留非控制字符 - builder.WriteRune(r) - } - } - return builder.String() -} From 3eadcc3a49e91076bd00af86a0b5f6c25ca08c5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=94=85=E9=A5=AD?= <1156544355@qq.com> Date: Thu, 31 Jul 2025 11:40:05 +0800 Subject: [PATCH 05/14] =?UTF-8?q?=F0=9F=90=9B=20=E4=BF=AE=E6=94=B9wordcoun?= =?UTF-8?q?t=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + plugin/aichat/main.go | 17 +++++++++----- plugin/wordcount/main.go | 51 +++++++++++----------------------------- 3 files changed, 26 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 3e46929e5e..d8dc09a404 100644 --- a/README.md +++ b/README.md @@ -1625,6 +1625,7 @@ print("run[CQ:image,file="+j["img"]+"]") - [x] 设置AI聊天(不)以AI语音输出 - [x] 查看AI聊天配置 - [x] 重置AI聊天 + - [x] 群聊总结 [消息数目]|群聊总结 1000
diff --git a/plugin/aichat/main.go b/plugin/aichat/main.go index 7474263045..7f6bda37c6 100644 --- a/plugin/aichat/main.go +++ b/plugin/aichat/main.go @@ -2,7 +2,6 @@ package aichat import ( - "fmt" "math/rand" "strconv" "strings" @@ -59,7 +58,7 @@ var ( "GenAI": 2, } apilist = [3]string{"OpenAI", "OLLaMA", "GenAI"} - limit = ctxext.NewLimiterManager(time.Second*60, 1) + limit = ctxext.NewLimiterManager(time.Second*30, 1) ) func init() { @@ -358,10 +357,16 @@ func init() { return } - ctx.SendChain(message.Text( - fmt.Sprintf("群 %s(%d) 的 %d 条消息总结:\n\n", group.Name, gid, p), - summary, - )) + var b strings.Builder + b.WriteString("群 ") + b.WriteString(group.Name) + b.WriteByte('(') + b.WriteString(strconv.FormatInt(gid, 10)) + b.WriteString(") 的 ") + b.WriteString(strconv.FormatInt(p, 10)) + b.WriteString(" 条消息总结:\n\n") + b.WriteString(summary) + ctx.SendChain(message.Text(b.String())) }) } diff --git a/plugin/wordcount/main.go b/plugin/wordcount/main.go index 2ffbf78d57..2b713263d2 100644 --- a/plugin/wordcount/main.go +++ b/plugin/wordcount/main.go @@ -8,7 +8,6 @@ import ( "sort" "strconv" "strings" - "sync" "time" "github.com/go-ego/gse" @@ -108,44 +107,22 @@ func init() { return } messageMap := make(map[string]int, 256) - msghists := make(chan *gjson.Result, 256) - go func() { - h := ctx.GetLatestGroupMessageHistory(gid) - messageSeq := h.Get("messages.0.message_seq").Int() - msghists <- &h - for i := 1; i < int(p/20) && messageSeq != 0; i++ { - h := ctx.GetGroupMessageHistory(gid, messageSeq, 20, false) - msghists <- &h - messageSeq = h.Get("messages.0.message_seq").Int() - } - close(msghists) - }() - var wg sync.WaitGroup - var mapmu sync.Mutex - for h := range msghists { - wg.Add(1) - go func(h *gjson.Result) { - for _, v := range h.Get("messages.#.message").Array() { - tex := strings.TrimSpace(message.ParseMessageFromString(v.Str).ExtractPlainText()) - if tex == "" { - continue - } - segments := seg.Segment(helper.StringToBytes(tex)) - words := gse.ToSlice(segments, true) - for _, word := range words { - word = strings.TrimSpace(word) - i := sort.SearchStrings(stopwords, word) - if re.MatchString(word) && (i >= len(stopwords) || stopwords[i] != word) { - mapmu.Lock() - messageMap[word]++ - mapmu.Unlock() - } + h := ctx.GetGroupMessageHistory(gid, 0, p, false) + h.Get("messages").ForEach(func(_, msgObj gjson.Result) bool { + tex := strings.TrimSpace(message.ParseMessageFromString(msgObj.Get("raw_message").Str).ExtractPlainText()) + if tex != "" { + segments := seg.Segment(helper.StringToBytes(tex)) + words := gse.ToSlice(segments, true) + for _, word := range words { + word = strings.TrimSpace(word) + i := sort.SearchStrings(stopwords, word) + if re.MatchString(word) && (i >= len(stopwords) || stopwords[i] != word) { + messageMap[word]++ } } - wg.Done() - }(h) - } - wg.Wait() + } + return true + }) wc := rankByWordCount(messageMap) if len(wc) > 20 { From 9e98b8fe3017ecb1c006b4da0ae83ca846db8906 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=94=85=E9=A5=AD?= <1156544355@qq.com> Date: Thu, 31 Jul 2025 15:04:14 +0800 Subject: [PATCH 06/14] =?UTF-8?q?=F0=9F=90=9B=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E6=B0=B4=E7=BE=A4bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugin/chatcount/chatcount.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/plugin/chatcount/chatcount.go b/plugin/chatcount/chatcount.go index a4e1bb41a8..caf88ebeed 100644 --- a/plugin/chatcount/chatcount.go +++ b/plugin/chatcount/chatcount.go @@ -43,8 +43,15 @@ func init() { }) engine.OnPrefix(`查询水群`, zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) { + param := ctx.State["args"].(string) + var uid int64 + if len(ctx.Event.Message) > 1 && ctx.Event.Message[1].Type == "at" { + uid, _ = strconv.ParseInt(ctx.Event.Message[1].Data["qq"], 10, 64) + } else if param == "" { + uid = ctx.Event.UserID + } name := ctx.NickName() - todayTime, todayMessage, totalTime, totalMessage := ctdb.getChatTime(ctx.Event.GroupID, ctx.Event.UserID) + todayTime, todayMessage, totalTime, totalMessage := ctdb.getChatTime(ctx.Event.GroupID, uid) ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(fmt.Sprintf("%s今天水了%d分%d秒,发了%d条消息;总计水了%d分%d秒,发了%d条消息。", name, todayTime/60, todayTime%60, todayMessage, totalTime/60, totalTime%60, totalMessage))) }) engine.OnFullMatch("查看水群排名", zero.OnlyGroup).Limit(ctxext.LimitByGroup).SetBlock(true). From c72a5d2e8783e2191295e605359368c4a5aafd71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=94=85=E9=A5=AD?= <1156544355@qq.com> Date: Thu, 31 Jul 2025 15:09:05 +0800 Subject: [PATCH 07/14] =?UTF-8?q?=F0=9F=8E=A8=20=E7=83=AD=E8=AF=8D?= =?UTF-8?q?=E9=99=90=E5=88=B6=E5=BD=93=E5=89=8D=E7=BE=A4=E8=81=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- plugin/wordcount/main.go | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index d8dc09a404..69e1b47378 100644 --- a/README.md +++ b/README.md @@ -1496,7 +1496,7 @@ print("run[CQ:image,file="+j["img"]+"]") `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/word_count"` - - [x] 热词 [群号] [消息数目]|热词 123456 1000 + - [x] 热词 [消息数目]|热词 1000
diff --git a/plugin/wordcount/main.go b/plugin/wordcount/main.go index 2b713263d2..127c7da8db 100644 --- a/plugin/wordcount/main.go +++ b/plugin/wordcount/main.go @@ -39,7 +39,7 @@ func init() { engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{ DisableOnDefault: false, Brief: "聊天热词", - Help: "- 热词 [群号] [消息数目]|热词 123456 1000", + Help: "- 热词 [消息数目]|热词 1000", PublicDataFolder: "WordCount", }) cachePath := engine.DataFolder() + "cache/" @@ -50,7 +50,7 @@ func init() { } _ = os.RemoveAll(cachePath) _ = os.MkdirAll(cachePath, 0755) - engine.OnRegex(`^热词\s?(\d*)\s?(\d*)$`, zero.OnlyGroup, fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool { + engine.OnRegex(`^热词\s?(\d*)$`, zero.OnlyGroup, fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool { _, err := engine.GetLazyData("stopwords.txt", false) if err != nil { ctx.SendChain(message.Text("ERROR: ", err)) @@ -84,17 +84,14 @@ func init() { } ctx.SendChain(message.Text("少女祈祷中...")) - gid, _ := strconv.ParseInt(ctx.State["regex_matched"].([]string)[1], 10, 64) - p, _ := strconv.ParseInt(ctx.State["regex_matched"].([]string)[2], 10, 64) + p, _ := strconv.ParseInt(ctx.State["regex_matched"].([]string)[1], 10, 64) if p > 10000 { p = 10000 } if p == 0 { p = 1000 } - if gid == 0 { - gid = ctx.Event.GroupID - } + gid := ctx.Event.GroupID group := ctx.GetGroupInfo(gid, false) if group.MemberCount == 0 { ctx.SendChain(message.Text(zero.BotConfig.NickName[0], "未加入", group.Name, "(", gid, "),无法获得热词呢")) From 0ec648093b541c25e93a5e2211a4d4e3b0b126f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=94=85=E9=A5=AD?= <1156544355@qq.com> Date: Thu, 31 Jul 2025 15:18:35 +0800 Subject: [PATCH 08/14] =?UTF-8?q?=F0=9F=8E=A8=20token=E6=B6=88=E8=80=97?= =?UTF-8?q?=E5=A4=A7=EF=BC=8C=E6=B7=BB=E5=8A=A0admin=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugin/aichat/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/aichat/main.go b/plugin/aichat/main.go index 7f6bda37c6..412b4cda97 100644 --- a/plugin/aichat/main.go +++ b/plugin/aichat/main.go @@ -317,7 +317,7 @@ func init() { }) // 添加群聊总结功能 - en.OnRegex(`^群聊总结\s?(\d*)$`, ensureconfig, zero.OnlyGroup).SetBlock(true).Limit(limit.LimitByGroup).Handle(func(ctx *zero.Ctx) { + en.OnRegex(`^群聊总结\s?(\d*)$`, ensureconfig, zero.OnlyGroup, zero.AdminPermission).SetBlock(true).Limit(limit.LimitByGroup).Handle(func(ctx *zero.Ctx) { ctx.SendChain(message.Text("少女思考中...")) p, _ := strconv.ParseInt(ctx.State["regex_matched"].([]string)[1], 10, 64) if p > 1000 { From c690405d65caa8c7bec3fa35421a292e7308f581 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=94=85=E9=A5=AD?= <1156544355@qq.com> Date: Thu, 31 Jul 2025 15:28:28 +0800 Subject: [PATCH 09/14] =?UTF-8?q?=F0=9F=8E=A8=20=E8=BD=AC=E5=8F=91?= =?UTF-8?q?=E5=88=86=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugin/aichat/main.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/plugin/aichat/main.go b/plugin/aichat/main.go index 412b4cda97..dbb9e9aa80 100644 --- a/plugin/aichat/main.go +++ b/plugin/aichat/main.go @@ -366,7 +366,18 @@ func init() { b.WriteString(strconv.FormatInt(p, 10)) b.WriteString(" 条消息总结:\n\n") b.WriteString(summary) - ctx.SendChain(message.Text(b.String())) + + // 分割总结内容为多段 + parts := strings.Split(b.String(), "\n\n") + msg := make(message.Message, 0, len(parts)) + for _, part := range parts { + if part != "" { + msg = append(msg, ctxext.FakeSenderForwardNode(ctx, message.Text(part))) + } + } + if len(msg) > 0 { + ctx.Send(msg) + } }) } From 307f66ffe39ec805b3d8f02233507cb56b1c28c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=94=85=E9=A5=AD?= <1156544355@qq.com> Date: Thu, 31 Jul 2025 17:32:40 +0800 Subject: [PATCH 10/14] =?UTF-8?q?=E2=9C=A8=20=E6=B7=BB=E5=8A=A0ai=E7=94=BB?= =?UTF-8?q?=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.go | 1 + plugin/aiimage/config.go | 76 ++++++++++++++++++++ plugin/aiimage/main.go | 150 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 227 insertions(+) create mode 100644 plugin/aiimage/config.go create mode 100644 plugin/aiimage/main.go diff --git a/main.go b/main.go index 5e9b13e577..117b111aa1 100644 --- a/main.go +++ b/main.go @@ -67,6 +67,7 @@ import ( _ "github.com/FloatTech/ZeroBot-Plugin/custom" // 自定义插件合集 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/ahsai" // ahsai tts _ "github.com/FloatTech/ZeroBot-Plugin/plugin/aifalse" // 服务器监控 + _ "github.com/FloatTech/ZeroBot-Plugin/plugin/aiimage" // AI画图 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/aiwife" // 随机老婆 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/alipayvoice" // 支付宝到账语音 _ "github.com/FloatTech/ZeroBot-Plugin/plugin/animetrace" // AnimeTrace 动画/Galgame识别 diff --git a/plugin/aiimage/config.go b/plugin/aiimage/config.go new file mode 100644 index 0000000000..d1111f9eaa --- /dev/null +++ b/plugin/aiimage/config.go @@ -0,0 +1,76 @@ +// Package aiimage 提供AI画图功能配置 +package aiimage + +import ( + "fmt" + "os" + "strings" + "sync" + "time" + + sql "github.com/FloatTech/sqlite" +) + +// Storage 管理画图配置存储 +type Storage struct { + sync.RWMutex + db sql.Sqlite +} + +var ( + sdb = &Storage{ + db: sql.New("data/aiimage/config.db"), + } +) + +func init() { + if err := os.MkdirAll("data/aiimage", 0755); err != nil { + panic(err) + } + if err := sdb.db.Open(time.Hour * 24); err != nil { + panic(err) + } + if err := sdb.db.Create("config", &ImageConfig{}); err != nil { + panic(err) + } +} + +// ImageConfig 存储AI画图配置信息 +type ImageConfig struct { + ID int64 `db:"id"` // 主键ID + APIKey string `db:"apiKey"` // API密钥 + APIURL string `db:"apiUrl"` // API地址 + ModelName string `db:"modelName"` // 画图模型名称 +} + +// GetConfig 获取当前配置 +func GetConfig() ImageConfig { + sdb.RLock() + defer sdb.RUnlock() + cfg := ImageConfig{} + _ = sdb.db.Find("config", &cfg, "WHERE id = 1") + return cfg +} + +// SetConfig 设置AI画图配置 +func SetConfig(apiKey, apiURL, modelName string) error { + sdb.Lock() + defer sdb.Unlock() + return sdb.db.Insert("config", &ImageConfig{ + ID: 1, + APIKey: apiKey, + APIURL: apiURL, + ModelName: modelName, + }) +} + +// PrintConfig 返回格式化后的配置信息 +func PrintConfig() string { + cfg := GetConfig() + var builder strings.Builder + builder.WriteString("当前AI画图配置:\n") + builder.WriteString(fmt.Sprintf("• 密钥: %s\n", cfg.APIKey)) + builder.WriteString(fmt.Sprintf("• 接口地址: %s\n", cfg.APIURL)) + builder.WriteString(fmt.Sprintf("• 模型名: %s\n", cfg.ModelName)) + return builder.String() +} diff --git a/plugin/aiimage/main.go b/plugin/aiimage/main.go new file mode 100644 index 0000000000..e9461c48a7 --- /dev/null +++ b/plugin/aiimage/main.go @@ -0,0 +1,150 @@ +// Package aiimage AI画图 +package aiimage + +import ( + "bytes" + "encoding/json" + "net/http" + "strings" + + "github.com/FloatTech/floatbox/web" + "github.com/tidwall/gjson" + zero "github.com/wdvxdr1123/ZeroBot" + "github.com/wdvxdr1123/ZeroBot/message" + + ctrl "github.com/FloatTech/zbpctrl" + "github.com/FloatTech/zbputils/control" + "github.com/FloatTech/zbputils/ctxext" +) + +func init() { + en := control.AutoRegister(&ctrl.Options[*zero.Ctx]{ + DisableOnDefault: false, + Extra: control.ExtraFromString("aiimage"), + Brief: "AI画图", + Help: "- 设置AI画图密钥\n" + + "- 设置AI画图接口地址https://api.siliconflow.cn/v1/images/generations\n" + + "- 设置AI画图模型名Kwai-Kolors/Kolors\n" + + "- 查看AI画图配置\n" + + "- AI画图 [描述]", + PrivateDataFolder: "aiimage", + }) + + en.OnPrefix("设置AI画图密钥", zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). + Handle(func(ctx *zero.Ctx) { + apiKey := strings.TrimSpace(ctx.State["args"].(string)) + cfg := GetConfig() + err := SetConfig(apiKey, cfg.APIURL, cfg.ModelName) + if err != nil { + ctx.SendChain(message.Text("ERROR: 设置API密钥失败: ", err)) + return + } + ctx.SendChain(message.Text("成功设置API密钥")) + }) + + en.OnPrefix("设置AI画图接口地址", zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). + Handle(func(ctx *zero.Ctx) { + apiURL := strings.TrimSpace(ctx.State["args"].(string)) + cfg := GetConfig() + err := SetConfig(cfg.APIKey, apiURL, cfg.ModelName) + if err != nil { + ctx.SendChain(message.Text("ERROR: 设置API地址失败: ", err)) + return + } + ctx.SendChain(message.Text("成功设置API地址")) + }) + + en.OnPrefix("设置AI画图模型名", zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). + Handle(func(ctx *zero.Ctx) { + modelName := strings.TrimSpace(ctx.State["args"].(string)) + cfg := GetConfig() + err := SetConfig(cfg.APIKey, cfg.APIURL, modelName) + if err != nil { + ctx.SendChain(message.Text("ERROR: 设置模型失败: ", err)) + return + } + ctx.SendChain(message.Text("成功设置模型: ", modelName)) + }) + + en.OnFullMatch("查看AI画图配置", zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). + Handle(func(ctx *zero.Ctx) { + ctx.SendChain(message.Text(PrintConfig())) + }) + + en.OnPrefix("AI画图").SetBlock(true). + Handle(func(ctx *zero.Ctx) { + prompt := strings.TrimSpace(ctx.State["args"].(string)) + if prompt == "" { + ctx.SendChain(message.Text("请输入图片描述")) + return + } + + cfg := GetConfig() + if cfg.APIKey == "" || cfg.APIURL == "" { + ctx.SendChain(message.Text("请先配置API密钥和地址")) + return + } + + // 准备请求数据 + reqData := map[string]interface{}{ + "model": cfg.ModelName, + "prompt": prompt, + "image_size": "1024x1024", + "batch_size": 4, + "num_inference_steps": 20, + "guidance_scale": 7.5, + } + reqBytes, _ := json.Marshal(reqData) + + // 发送API请求 + data, err := web.RequestDataWithHeaders( + web.NewDefaultClient(), + cfg.APIURL, + "POST", + func(req *http.Request) error { + req.Header.Set("Authorization", "Bearer "+cfg.APIKey) + req.Header.Set("Content-Type", "application/json") + return nil + }, + bytes.NewReader(reqBytes), + ) + if err != nil { + ctx.SendChain(message.Text("API请求失败: ", err)) + return + } + + // 解析API响应 + jsonData := gjson.ParseBytes(data) + images := jsonData.Get("images") + if !images.Exists() { + images = jsonData.Get("data") + if !images.Exists() { + ctx.SendChain(message.Text("未获取到图片URL")) + return + } + } + + // 发送生成的图片和相关信息 + inferenceTime := jsonData.Get("timings.inference").Float() + seed := jsonData.Get("seed").Int() + msg := make(message.Message, 0, 1) + msg = append(msg, ctxext.FakeSenderForwardNode(ctx, message.Text("图片生成成功!\n", + "提示词: ", prompt, "\n", + "模型: ", cfg.ModelName, "\n", + "推理时间: ", inferenceTime, "秒\n", + "种子: ", seed))) + + // 添加所有图片 + images.ForEach(func(_, value gjson.Result) bool { + url := value.Get("url").String() + if url != "" { + msg = append(msg, ctxext.FakeSenderForwardNode(ctx, message.Image(url))) + } + return true + }) + + if len(msg) > 0 { + ctx.Send(msg) + } + }) +} From 334363c2dc50078edd331cdb3f666f1602838303 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=94=85=E9=A5=AD?= <1156544355@qq.com> Date: Thu, 31 Jul 2025 18:37:25 +0800 Subject: [PATCH 11/14] =?UTF-8?q?=F0=9F=8E=A8=20readme=E6=B7=BB=E5=8A=A0ai?= =?UTF-8?q?=E7=94=BB=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 12 ++++++++++++ plugin/aiimage/main.go | 1 + 2 files changed, 13 insertions(+) diff --git a/README.md b/README.md index 69e1b47378..7126c5cf65 100644 --- a/README.md +++ b/README.md @@ -412,6 +412,18 @@ print("run[CQ:image,file="+j["img"]+"]") - [x] 设置默认限速为每 m [分钟 | 秒] n 次触发 +
+
+ aiimage + + `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/aiimage"` + + - [x] 设置AI画图密钥 + - [x] 设置AI画图接口地址https://api.siliconflow.cn/v1/images/generations + - [x] 设置AI画图模型名Kwai-Kolors/Kolors + - [x] 查看AI画图配置 + - [x] AI画图 [描述] +
AIWife diff --git a/plugin/aiimage/main.go b/plugin/aiimage/main.go index e9461c48a7..0c4fa7c81f 100644 --- a/plugin/aiimage/main.go +++ b/plugin/aiimage/main.go @@ -73,6 +73,7 @@ func init() { en.OnPrefix("AI画图").SetBlock(true). Handle(func(ctx *zero.Ctx) { + ctx.SendChain(message.Text("少女思考中...")) prompt := strings.TrimSpace(ctx.State["args"].(string)) if prompt == "" { ctx.SendChain(message.Text("请输入图片描述")) From 958be34780758dc633bcf200c71fbecf7fea9af5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=94=85=E9=A5=AD?= <1156544355@qq.com> Date: Thu, 31 Jul 2025 18:51:04 +0800 Subject: [PATCH 12/14] =?UTF-8?q?=E2=9C=A8=20=E6=B7=BB=E5=8A=A0=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugin/aiimage/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin/aiimage/main.go b/plugin/aiimage/main.go index 0c4fa7c81f..bb52ad86ef 100644 --- a/plugin/aiimage/main.go +++ b/plugin/aiimage/main.go @@ -81,8 +81,8 @@ func init() { } cfg := GetConfig() - if cfg.APIKey == "" || cfg.APIURL == "" { - ctx.SendChain(message.Text("请先配置API密钥和地址")) + if cfg.APIKey == "" || cfg.APIURL == "" || cfg.ModelName == "" { + ctx.SendChain(message.Text("请先配置API密钥、地址和模型")) return } From bd53c190b4cea95c83c3944bb4c5b63a50cf4118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=94=85=E9=A5=AD?= <1156544355@qq.com> Date: Tue, 12 Aug 2025 17:01:43 +0800 Subject: [PATCH 13/14] =?UTF-8?q?=F0=9F=8E=A8=20=E6=9B=B4=E6=96=B0zbputils?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index c319db1c9e..3e7cd6dc5d 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/FloatTech/sqlite v1.7.1 github.com/FloatTech/ttl v0.0.0-20240716161252-965925764562 github.com/FloatTech/zbpctrl v1.7.0 - github.com/FloatTech/zbputils v1.7.2-0.20250614165821-95cf57cf2434 + github.com/FloatTech/zbputils v1.7.2-0.20250812085410-2741050f465f github.com/RomiChan/syncx v0.0.0-20240418144900-b7402ffdebc7 github.com/RomiChan/websocket v1.4.3-0.20220227141055-9b2c6168c9c5 github.com/Tnze/go-mc v1.20.2 @@ -22,7 +22,7 @@ require ( github.com/disintegration/imaging v1.6.2 github.com/fumiama/ahsai v0.1.0 github.com/fumiama/cron v1.3.0 - github.com/fumiama/deepinfra v0.0.0-20250601112706-0175c95164c1 + github.com/fumiama/deepinfra v0.0.0-20250812083039-f1b27f21d8c9 github.com/fumiama/go-base16384 v1.7.0 github.com/fumiama/go-registry v0.2.7 github.com/fumiama/gotracemoe v0.0.3 @@ -45,7 +45,7 @@ require ( github.com/sirupsen/logrus v1.9.3 github.com/tidwall/gjson v1.18.0 github.com/wcharczuk/go-chart/v2 v2.1.2 - github.com/wdvxdr1123/ZeroBot v1.8.2-0.20250707133321-6197b8ee5df7 + github.com/wdvxdr1123/ZeroBot v1.8.2-0.20250804063440-ccc03e33ac20 gitlab.com/gomidi/midi/v2 v2.1.7 golang.org/x/image v0.24.0 golang.org/x/sys v0.30.0 diff --git a/go.sum b/go.sum index d4b9a61146..31ada71b36 100644 --- a/go.sum +++ b/go.sum @@ -17,8 +17,8 @@ github.com/FloatTech/ttl v0.0.0-20240716161252-965925764562 h1:snfw7FNFym1eNnLrQ github.com/FloatTech/ttl v0.0.0-20240716161252-965925764562/go.mod h1:fHZFWGquNXuHttu9dUYoKuNbm3dzLETnIOnm1muSfDs= github.com/FloatTech/zbpctrl v1.7.0 h1:Hxo6EIhJo+pHjcQP9QgIJgluaT1pHH99zkk3njqTNMo= github.com/FloatTech/zbpctrl v1.7.0/go.mod h1:xmM4dSwHA02Gei3ogCRiG+RTrw/7Z69PfrN5NYf8BPE= -github.com/FloatTech/zbputils v1.7.2-0.20250614165821-95cf57cf2434 h1:oEYQFQ2/qx10FtZKCNbW3Ohj/Iw71aM4RWpIu+LMmf8= -github.com/FloatTech/zbputils v1.7.2-0.20250614165821-95cf57cf2434/go.mod h1:ArZ0fMAcmPEIXOqDmfzbSx+oYH8sssApQnbCu694iS8= +github.com/FloatTech/zbputils v1.7.2-0.20250812085410-2741050f465f h1:5jnrFe9FTydb/pcUhxkWHuQVCwmYIZmneOkvmgHOwGI= +github.com/FloatTech/zbputils v1.7.2-0.20250812085410-2741050f465f/go.mod h1:HG/yZwExV3b1Vqu4chbqwhfX4hx7gDS07QO436JkwIg= github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= github.com/RomiChan/syncx v0.0.0-20240418144900-b7402ffdebc7 h1:S/ferNiehVjNaBMNNBxUjLtVmP/YWD6Yh79RfPv4ehU= github.com/RomiChan/syncx v0.0.0-20240418144900-b7402ffdebc7/go.mod h1:vD7Ra3Q9onRtojoY5sMCLQ7JBgjUsrXDnDKyFxqpf9w= @@ -59,8 +59,8 @@ github.com/fumiama/ahsai v0.1.0 h1:LXD61Kaj6kJHa3AEGsLIfKNzcgaVxg7JB72OR4yNNZ4= github.com/fumiama/ahsai v0.1.0/go.mod h1:fFeNnqgo44i8FIaguK659aQryuZeFy+4klYLQu/rfdk= 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/deepinfra v0.0.0-20250601112706-0175c95164c1 h1:qE3l/y4Y1gMD2NokQ5Nw4NIUjL8ZwYLPIHOExQNu4hM= -github.com/fumiama/deepinfra v0.0.0-20250601112706-0175c95164c1/go.mod h1:wW05PQSn8mo1mZIoa6LBUE+3xIBjkoONvnfPTV5ZOhY= +github.com/fumiama/deepinfra v0.0.0-20250812083039-f1b27f21d8c9 h1:X2h8RnCgC04LmwBoizYbFawXh/h6CouXmhYtaVuUn7k= +github.com/fumiama/deepinfra v0.0.0-20250812083039-f1b27f21d8c9/go.mod h1:wW05PQSn8mo1mZIoa6LBUE+3xIBjkoONvnfPTV5ZOhY= github.com/fumiama/go-base16384 v1.7.0 h1:6fep7XPQWxRlh4Hu+KsdH+6+YdUp+w6CwRXtMWSsXCA= github.com/fumiama/go-base16384 v1.7.0/go.mod h1:OEn+947GV5gsbTAnyuUW/SrfxJYUdYupSIQXOuGOcXM= github.com/fumiama/go-registry v0.2.7 h1:tLEqgEpsiybQMqBv0dLHm5leia/z1DhajMupwnOHeNs= @@ -199,8 +199,8 @@ github.com/vcaesar/cedar v0.20.2/go.mod h1:lyuGvALuZZDPNXwpzv/9LyxW+8Y6faN7zauFe github.com/vcaesar/tt v0.20.1 h1:D/jUeeVCNbq3ad8M7hhtB3J9x5RZ6I1n1eZ0BJp7M+4= github.com/wcharczuk/go-chart/v2 v2.1.2 h1:Y17/oYNuXwZg6TFag06qe8sBajwwsuvPiJJXcUcLL6E= github.com/wcharczuk/go-chart/v2 v2.1.2/go.mod h1:Zi4hbaqlWpYajnXB2K22IUYVXRXaLfSGNNR7P4ukyyQ= -github.com/wdvxdr1123/ZeroBot v1.8.2-0.20250707133321-6197b8ee5df7 h1:ya+lVbCC/EN5JumpQDDlVCSrWzLwHl4CHzlTANKDvrU= -github.com/wdvxdr1123/ZeroBot v1.8.2-0.20250707133321-6197b8ee5df7/go.mod h1:C86nQ0gIdAri4K2vg8IIQIslt08zzrKMcqYt8zhkx1M= +github.com/wdvxdr1123/ZeroBot v1.8.2-0.20250804063440-ccc03e33ac20 h1:Yzd+cbiJQYtf6cZDP5ZB/LqjNWiV752+5P6Eua+wnic= +github.com/wdvxdr1123/ZeroBot v1.8.2-0.20250804063440-ccc03e33ac20/go.mod h1:C86nQ0gIdAri4K2vg8IIQIslt08zzrKMcqYt8zhkx1M= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= From 2b6a08cfb92013e8562b1c162e1c850ae533b965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E9=94=85=E9=A5=AD?= <1156544355@qq.com> Date: Fri, 15 Aug 2025 23:10:02 +0800 Subject: [PATCH 14/14] =?UTF-8?q?=F0=9F=8E=A8=20=E4=BC=98=E5=8C=96ai?= =?UTF-8?q?=E7=94=BB=E5=9B=BE=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- plugin/aiimage/config.go | 44 +++++++++----------------------- plugin/aiimage/main.go | 54 +++++++++++++++++++++++++++------------- 3 files changed, 50 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 7126c5cf65..f7535e4ae7 100644 --- a/README.md +++ b/README.md @@ -418,7 +418,7 @@ print("run[CQ:image,file="+j["img"]+"]") `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/aiimage"` - - [x] 设置AI画图密钥 + - [x] 设置AI画图密钥xxx - [x] 设置AI画图接口地址https://api.siliconflow.cn/v1/images/generations - [x] 设置AI画图模型名Kwai-Kolors/Kolors - [x] 查看AI画图配置 diff --git a/plugin/aiimage/config.go b/plugin/aiimage/config.go index d1111f9eaa..e48ec5c926 100644 --- a/plugin/aiimage/config.go +++ b/plugin/aiimage/config.go @@ -3,60 +3,40 @@ package aiimage import ( "fmt" - "os" "strings" "sync" - "time" sql "github.com/FloatTech/sqlite" ) -// Storage 管理画图配置存储 -type Storage struct { +// storage 管理画图配置存储 +type storage struct { sync.RWMutex db sql.Sqlite } -var ( - sdb = &Storage{ - db: sql.New("data/aiimage/config.db"), - } -) - -func init() { - if err := os.MkdirAll("data/aiimage", 0755); err != nil { - panic(err) - } - if err := sdb.db.Open(time.Hour * 24); err != nil { - panic(err) - } - if err := sdb.db.Create("config", &ImageConfig{}); err != nil { - panic(err) - } -} - -// ImageConfig 存储AI画图配置信息 -type ImageConfig struct { +// imageConfig 存储AI画图配置信息 +type imageConfig struct { ID int64 `db:"id"` // 主键ID APIKey string `db:"apiKey"` // API密钥 APIURL string `db:"apiUrl"` // API地址 ModelName string `db:"modelName"` // 画图模型名称 } -// GetConfig 获取当前配置 -func GetConfig() ImageConfig { +// getConfig 获取当前配置 +func (sdb *storage) getConfig() imageConfig { sdb.RLock() defer sdb.RUnlock() - cfg := ImageConfig{} + cfg := imageConfig{} _ = sdb.db.Find("config", &cfg, "WHERE id = 1") return cfg } -// SetConfig 设置AI画图配置 -func SetConfig(apiKey, apiURL, modelName string) error { +// setConfig 设置AI画图配置 +func (sdb *storage) setConfig(apiKey, apiURL, modelName string) error { sdb.Lock() defer sdb.Unlock() - return sdb.db.Insert("config", &ImageConfig{ + return sdb.db.Insert("config", &imageConfig{ ID: 1, APIKey: apiKey, APIURL: apiURL, @@ -65,8 +45,8 @@ func SetConfig(apiKey, apiURL, modelName string) error { } // PrintConfig 返回格式化后的配置信息 -func PrintConfig() string { - cfg := GetConfig() +func (sdb *storage) PrintConfig() string { + cfg := sdb.getConfig() var builder strings.Builder builder.WriteString("当前AI画图配置:\n") builder.WriteString(fmt.Sprintf("• 密钥: %s\n", cfg.APIKey)) diff --git a/plugin/aiimage/main.go b/plugin/aiimage/main.go index bb52ad86ef..519065e92a 100644 --- a/plugin/aiimage/main.go +++ b/plugin/aiimage/main.go @@ -6,8 +6,11 @@ import ( "encoding/json" "net/http" "strings" + "time" + fcext "github.com/FloatTech/floatbox/ctxext" "github.com/FloatTech/floatbox/web" + sql "github.com/FloatTech/sqlite" "github.com/tidwall/gjson" zero "github.com/wdvxdr1123/ZeroBot" "github.com/wdvxdr1123/ZeroBot/message" @@ -18,11 +21,13 @@ import ( ) func init() { + var sdb = &storage{} + en := control.AutoRegister(&ctrl.Options[*zero.Ctx]{ DisableOnDefault: false, Extra: control.ExtraFromString("aiimage"), Brief: "AI画图", - Help: "- 设置AI画图密钥\n" + + Help: "- 设置AI画图密钥xxx\n" + "- 设置AI画图接口地址https://api.siliconflow.cn/v1/images/generations\n" + "- 设置AI画图模型名Kwai-Kolors/Kolors\n" + "- 查看AI画图配置\n" + @@ -30,11 +35,27 @@ func init() { PrivateDataFolder: "aiimage", }) - en.OnPrefix("设置AI画图密钥", zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). + getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool { + sdb.db = sql.New(en.DataFolder() + "aiimage.db") + err := sdb.db.Open(time.Hour) + if err == nil { + // 创建配置表 + err = sdb.db.Create("config", &imageConfig{}) + if err != nil { + ctx.SendChain(message.Text("[ERROR]:", err)) + return false + } + return true + } + ctx.SendChain(message.Text("[ERROR]:", err)) + return false + }) + + en.OnPrefix("设置AI画图密钥", getdb, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). Handle(func(ctx *zero.Ctx) { apiKey := strings.TrimSpace(ctx.State["args"].(string)) - cfg := GetConfig() - err := SetConfig(apiKey, cfg.APIURL, cfg.ModelName) + cfg := sdb.getConfig() + err := sdb.setConfig(apiKey, cfg.APIURL, cfg.ModelName) if err != nil { ctx.SendChain(message.Text("ERROR: 设置API密钥失败: ", err)) return @@ -42,11 +63,11 @@ func init() { ctx.SendChain(message.Text("成功设置API密钥")) }) - en.OnPrefix("设置AI画图接口地址", zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). + en.OnPrefix("设置AI画图接口地址", getdb, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). Handle(func(ctx *zero.Ctx) { apiURL := strings.TrimSpace(ctx.State["args"].(string)) - cfg := GetConfig() - err := SetConfig(cfg.APIKey, apiURL, cfg.ModelName) + cfg := sdb.getConfig() + err := sdb.setConfig(cfg.APIKey, apiURL, cfg.ModelName) if err != nil { ctx.SendChain(message.Text("ERROR: 设置API地址失败: ", err)) return @@ -54,11 +75,11 @@ func init() { ctx.SendChain(message.Text("成功设置API地址")) }) - en.OnPrefix("设置AI画图模型名", zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). + en.OnPrefix("设置AI画图模型名", getdb, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). Handle(func(ctx *zero.Ctx) { modelName := strings.TrimSpace(ctx.State["args"].(string)) - cfg := GetConfig() - err := SetConfig(cfg.APIKey, cfg.APIURL, modelName) + cfg := sdb.getConfig() + err := sdb.setConfig(cfg.APIKey, cfg.APIURL, modelName) if err != nil { ctx.SendChain(message.Text("ERROR: 设置模型失败: ", err)) return @@ -66,12 +87,12 @@ func init() { ctx.SendChain(message.Text("成功设置模型: ", modelName)) }) - en.OnFullMatch("查看AI画图配置", zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). + en.OnFullMatch("查看AI画图配置", getdb, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). Handle(func(ctx *zero.Ctx) { - ctx.SendChain(message.Text(PrintConfig())) + ctx.SendChain(message.Text(sdb.PrintConfig())) }) - en.OnPrefix("AI画图").SetBlock(true). + en.OnPrefix("AI画图", getdb).SetBlock(true). Handle(func(ctx *zero.Ctx) { ctx.SendChain(message.Text("少女思考中...")) prompt := strings.TrimSpace(ctx.State["args"].(string)) @@ -80,22 +101,21 @@ func init() { return } - cfg := GetConfig() + cfg := sdb.getConfig() if cfg.APIKey == "" || cfg.APIURL == "" || cfg.ModelName == "" { ctx.SendChain(message.Text("请先配置API密钥、地址和模型")) return } // 准备请求数据 - reqData := map[string]interface{}{ + reqBytes, _ := json.Marshal(map[string]interface{}{ "model": cfg.ModelName, "prompt": prompt, "image_size": "1024x1024", "batch_size": 4, "num_inference_steps": 20, "guidance_scale": 7.5, - } - reqBytes, _ := json.Marshal(reqData) + }) // 发送API请求 data, err := web.RequestDataWithHeaders(