From f28e746652368476295fad4a9ad55bddf1568aaa 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, 27 Feb 2023 13:52:12 +0800 Subject: [PATCH] aireply add chatgpt --- go.mod | 4 +-- go.sum | 8 ++--- plugin/ai_reply/ai_tts.go | 67 ++++++++++++++++++++++++++++----------- plugin/ai_reply/main.go | 37 ++++++++++++++------- 4 files changed, 80 insertions(+), 36 deletions(-) diff --git a/go.mod b/go.mod index 26c06346..ef7881c2 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( github.com/Baidu-AIP/golang-sdk v1.1.1 - github.com/FloatTech/AnimeAPI v1.6.1-0.20230207081411-573533b18194 + github.com/FloatTech/AnimeAPI v1.6.1-0.20230225045520-b537bd7dfbfe github.com/FloatTech/floatbox v0.0.0-20230207075003-0f70b30c320d github.com/FloatTech/gg v1.1.2 github.com/FloatTech/imgfactory v0.2.2-0.20230215052637-9f7b05520ca9 @@ -12,7 +12,7 @@ require ( github.com/FloatTech/sqlite v1.5.7 github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b github.com/FloatTech/zbpctrl v1.5.3-0.20230130095145-714ad318cd52 - github.com/FloatTech/zbputils v1.6.2-0.20230215092613-4a7ebf458f16 + github.com/FloatTech/zbputils v1.6.2-0.20230217063720-e64cc4bde7c6 github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e github.com/RomiChan/websocket v1.4.3-0.20220227141055-9b2c6168c9c5 github.com/antchfx/htmlquery v1.2.5 diff --git a/go.sum b/go.sum index 3a321926..6116ff06 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ github.com/Baidu-AIP/golang-sdk v1.1.1 h1:RQsAmgDSAkiq22I6n7XJ2t3afgzFeqjY46FGhv 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/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= -github.com/FloatTech/AnimeAPI v1.6.1-0.20230207081411-573533b18194 h1:+p85V0fdZNt3UoKreBeI6S3IOPvNmU5/Fnn39ipSkVk= -github.com/FloatTech/AnimeAPI v1.6.1-0.20230207081411-573533b18194/go.mod h1:LCiKZivPVazRRCnnADQfIBFZiIPHHCFqaCpwZWsFehI= +github.com/FloatTech/AnimeAPI v1.6.1-0.20230225045520-b537bd7dfbfe h1:C2PXT21kloAiOfnkg+AHH66CZZrgccz30YjHmKdmVTw= +github.com/FloatTech/AnimeAPI v1.6.1-0.20230225045520-b537bd7dfbfe/go.mod h1:LCiKZivPVazRRCnnADQfIBFZiIPHHCFqaCpwZWsFehI= github.com/FloatTech/floatbox v0.0.0-20230207075003-0f70b30c320d h1:vVqMO5Kejt5pueuZvBxfX+psa7UwE110TpITf5eV7Zw= github.com/FloatTech/floatbox v0.0.0-20230207075003-0f70b30c320d/go.mod h1:OoZE4Ra7olpFaJSrlD6mcyT4chPLg9QBRE1pzTC8R84= github.com/FloatTech/gg v1.1.2 h1:YolgOYg3uDHc1+g0bLtt6QuRA/pvLn+b9IBCIhOOX88= @@ -18,8 +18,8 @@ github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b h1:tvciXWq2nuvTbFeJG github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b/go.mod h1:fHZFWGquNXuHttu9dUYoKuNbm3dzLETnIOnm1muSfDs= github.com/FloatTech/zbpctrl v1.5.3-0.20230130095145-714ad318cd52 h1:BrStRXeosWh8L0iA/EjPd8w6xNexDkqki39ITZko/9Q= github.com/FloatTech/zbpctrl v1.5.3-0.20230130095145-714ad318cd52/go.mod h1:qqMLUwR7tKpqnAqsgI7aZbn0hbs2FEVF4ylMXqIpBdY= -github.com/FloatTech/zbputils v1.6.2-0.20230215092613-4a7ebf458f16 h1:fOnI0V//DOW62vAhnC1a+qDMnlbJIAIiUHVX7CaUk5s= -github.com/FloatTech/zbputils v1.6.2-0.20230215092613-4a7ebf458f16/go.mod h1:Lo7y67u9EGt7l3ZBavc5bbryEIaeRYfbVy9KWIw6qk4= +github.com/FloatTech/zbputils v1.6.2-0.20230217063720-e64cc4bde7c6 h1:iHfqarofWkwwPfOG/5XbsvY7JutoEQmhxKvLxrFbiZw= +github.com/FloatTech/zbputils v1.6.2-0.20230217063720-e64cc4bde7c6/go.mod h1:Lo7y67u9EGt7l3ZBavc5bbryEIaeRYfbVy9KWIw6qk4= github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e h1:wR3MXQ3VbUlPKOOUwLOYgh/QaJThBTYtsl673O3lqSA= github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e/go.mod h1:vD7Ra3Q9onRtojoY5sMCLQ7JBgjUsrXDnDKyFxqpf9w= diff --git a/plugin/ai_reply/ai_tts.go b/plugin/ai_reply/ai_tts.go index 459a445b..1b02e5e2 100644 --- a/plugin/ai_reply/ai_tts.go +++ b/plugin/ai_reply/ai_tts.go @@ -32,20 +32,28 @@ const ( mockingbirdttsindex ) +// extrattsname is the tts other than genshin vits +var extrattsname = []string{"百度", "拟声鸟"} + const ( - defaultttsindexkey = -2905 + defaultttsindexkey = -2905 + gsapikeyextragrp = -1 + chatgptapikeyextragrp = -2 ) -var replyModes = [...]string{"青云客", "小爱"} +type replymode struct { + APIKey string // APIKey is for chatgpt + replyModes []string `json:"-"` +} -func setReplyMode(ctx *zero.Ctx, name string) error { +func (r *replymode) setReplyMode(ctx *zero.Ctx, name string) error { gid := ctx.Event.GroupID if gid == 0 { gid = -ctx.Event.UserID } var ok bool var index int64 - for i, s := range replyModes { + for i, s := range r.replyModes { if s == name { ok = true index = int64(i) @@ -62,24 +70,47 @@ func setReplyMode(ctx *zero.Ctx, name string) error { return m.SetData(gid, (m.GetData(index)&^0xff)|(index&0xff)) } -func getReplyMode(ctx *zero.Ctx) aireply.AIReply { +func (r *replymode) getReplyMode(ctx *zero.Ctx) aireply.AIReply { gid := ctx.Event.GroupID if gid == 0 { gid = -ctx.Event.UserID } m, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]) if ok { - if m.GetData(gid)&0xff == 1 { + switch m.GetData(gid) & 0xff { + case 0: + return aireply.NewQYK(aireply.QYKURL, aireply.QYKBotName) + case 1: return aireply.NewXiaoAi(aireply.XiaoAiURL, aireply.XiaoAiBotName) + case 2: + k := r.getAPIKey(ctx) + if k != "" { + return aireply.NewChatGPT(aireply.ChatGPTURL, k) + } + return aireply.NewQYK(aireply.QYKURL, aireply.QYKBotName) } - return aireply.NewQYK(aireply.QYKURL, aireply.QYKBotName) } return aireply.NewQYK(aireply.QYKURL, aireply.QYKBotName) } +func (r *replymode) getAPIKey(ctx *zero.Ctx) string { + if r.APIKey == "" { + m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]) + _ = m.Manager.GetExtra(chatgptapikeyextragrp, &r) + logrus.Debugln("[tts] get api key:", r.APIKey) + } + return r.APIKey +} + +func (r *replymode) setAPIKey(m *ctrl.Control[*zero.Ctx], key string) error { + r.APIKey = key + _ = m.Manager.Response(chatgptapikeyextragrp) + return m.Manager.SetExtra(chatgptapikeyextragrp, r) +} + var ttsins = func() map[string]tts.TTS { m := make(map[string]tts.TTS, 128) - for _, mode := range append(genshin.SoundList[:], "百度", "拟声鸟") { + for _, mode := range append(genshin.SoundList[:], extrattsname...) { m[mode] = nil } return m @@ -87,7 +118,7 @@ var ttsins = func() map[string]tts.TTS { var ttsModes = func() []string { s := append(genshin.SoundList[:], make([]string, 64-len(genshin.SoundList))...) // 0-63 - s = append(s, "百度", "拟声鸟") // 64 65 + s = append(s, extrattsname...) // 64 65 ... return s }() @@ -127,7 +158,7 @@ func newttsmode() *ttsmode { func (t *ttsmode) getAPIKey(ctx *zero.Ctx) string { if t.APIKey == "" { m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]) - _ = m.Manager.GetExtra(-1, &t) + _ = m.Manager.GetExtra(gsapikeyextragrp, &t) logrus.Debugln("[tts] get api key:", t.APIKey) } return url.QueryEscape(t.APIKey) @@ -135,8 +166,8 @@ func (t *ttsmode) getAPIKey(ctx *zero.Ctx) string { func (t *ttsmode) setAPIKey(m *ctrl.Control[*zero.Ctx], key string) error { t.APIKey = key - _ = m.Manager.Response(-1) - return m.Manager.SetExtra(-1, t) + _ = m.Manager.Response(gsapikeyextragrp) + return m.Manager.SetExtra(gsapikeyextragrp, t) } func (t *ttsmode) setSoundMode(ctx *zero.Ctx, name string, baiduper, mockingsynt int) error { @@ -157,9 +188,9 @@ func (t *ttsmode) setSoundMode(ctx *zero.Ctx, name string, baiduper, mockingsynt } if index == -1 { switch name { - case "百度": + case extrattsname[0]: index = baiduttsindex - case "拟声鸟": + case extrattsname[1]: index = mockingbirdttsindex default: return errors.New("语音人物" + name + "未注册index") @@ -189,9 +220,9 @@ func (t *ttsmode) getSoundMode(ctx *zero.Ctx) (tts.TTS, error) { ins, ok := ttsins[mode] if !ok || ins == nil { switch mode { - case "百度": + case extrattsname[0]: ins = baidutts.NewBaiduTTS(int(i&0x0f00) >> 8) - case "拟声鸟": + case extrattsname[1]: var err error ins, err = mockingbird.NewMockingBirdTTS(int(i&0xf000) >> 12) if err != nil { @@ -234,9 +265,9 @@ func (t *ttsmode) setDefaultSoundMode(name string, baiduper, mockingsynt int) er } if index == -1 { switch name { - case "百度": + case extrattsname[0]: index = baiduttsindex - case "拟声鸟": + case extrattsname[1]: index = mockingbirdttsindex default: return errors.New("语音人物" + name + "未注册index") diff --git a/plugin/ai_reply/main.go b/plugin/ai_reply/main.go index 96a88b24..7d5d6521 100644 --- a/plugin/ai_reply/main.go +++ b/plugin/ai_reply/main.go @@ -15,7 +15,11 @@ import ( "github.com/wdvxdr1123/ZeroBot/message" ) -var t = newttsmode() +var replmd = replymode{ + replyModes: []string{"青云客", "小爱", "ChatGPT"}, +} + +var ttsmd = newttsmode() func init() { // 插件主体 ent := control.Register("tts", &ctrl.Options[*zero.Ctx]{ @@ -32,13 +36,13 @@ func init() { // 插件主体 enr := control.Register("aireply", &ctrl.Options[*zero.Ctx]{ DisableOnDefault: false, Brief: "人工智能回复", - Help: "- @Bot 任意文本(任意一句话回复)\n- 设置回复模式[青云客|小爱]", + Help: "- @Bot 任意文本(任意一句话回复)\n- 设置回复模式[青云客|小爱|ChatGPT]\n- 设置 ChatGPT api key xxx", PrivateDataFolder: "aireply", }) enr.OnMessage(zero.OnlyToMe).SetBlock(true).Limit(ctxext.LimitByUser). Handle(func(ctx *zero.Ctx) { - aireply := getReplyMode(ctx) + aireply := replmd.getReplyMode(ctx) reply := message.ParseMessageFromString(aireply.Talk(ctx.Event.UserID, ctx.ExtractPlainText(), zero.BotConfig.NickName[0])) // 回复 time.Sleep(time.Second * 1) @@ -52,7 +56,7 @@ func init() { // 插件主体 enr.OnPrefix("设置回复模式", zero.AdminPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) { param := ctx.State["args"].(string) - err := setReplyMode(ctx, param) + err := replmd.setReplyMode(ctx, param) if err != nil { ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err)) return @@ -60,16 +64,25 @@ func init() { // 插件主体 ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("成功")) }) + ent.OnRegex(`^设置\s*ChatGPT\s*api\s*key\s*(.*)$`, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) { + err := replmd.setAPIKey(ctx.State["manager"].(*ctrl.Control[*zero.Ctx]), ctx.State["regex_matched"].([]string)[1]) + if err != nil { + ctx.SendChain(message.Text("ERROR: ", err)) + return + } + ctx.SendChain(message.Text("设置成功")) + }) + endpre := regexp.MustCompile(`\pP$`) ent.OnMessage(zero.OnlyToMe).SetBlock(true).Limit(ctxext.LimitByUser). Handle(func(ctx *zero.Ctx) { msg := ctx.ExtractPlainText() // 获取回复模式 - r := getReplyMode(ctx) + r := replmd.getReplyMode(ctx) // 获取回复的文本 reply := r.TalkPlain(ctx.Event.UserID, msg, zero.BotConfig.NickName[0]) // 获取语音 - speaker, err := t.getSoundMode(ctx) + speaker, err := ttsmd.getSoundMode(ctx) if err != nil { ctx.SendChain(message.Text("ERROR: ", err)) return @@ -104,7 +117,7 @@ func init() { // 插件主体 } // 保存设置 logrus.Debugln("[tts] t.setSoundMode( ctx", param, n, n, ")") - err = t.setSoundMode(ctx, param, n, n) + err = ttsmd.setSoundMode(ctx, param, n, n) if err != nil { ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err)) return @@ -112,7 +125,7 @@ func init() { // 插件主体 if banner, ok := genshin.TestRecord[param]; ok { logrus.Debugln("[tts] banner:", banner, "get sound mode...") // 设置验证 - speaker, err := t.getSoundMode(ctx) + speaker, err := ttsmd.getSoundMode(ctx) if err != nil { ctx.SendChain(message.Text("ERROR: ", err)) return @@ -146,7 +159,7 @@ func init() { // 插件主体 } } // 保存设置 - err = t.setDefaultSoundMode(param, n, n) + err = ttsmd.setDefaultSoundMode(param, n, n) if err != nil { ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err)) return @@ -155,13 +168,13 @@ func init() { // 插件主体 }) ent.OnFullMatch("恢复成默认语音模式", zero.AdminPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) { - err := t.resetSoundMode(ctx) + err := ttsmd.resetSoundMode(ctx) if err != nil { ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err)) return } // 设置验证 - speaker, err := t.getSoundMode(ctx) + speaker, err := ttsmd.getSoundMode(ctx) if err != nil { ctx.SendChain(message.Text("ERROR: ", err)) return @@ -170,7 +183,7 @@ func init() { // 插件主体 }) ent.OnRegex(`^设置原神语音\s*api\s*key\s*([0-9a-zA-Z-_]{54}==)$`, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) { - err := t.setAPIKey(ctx.State["manager"].(*ctrl.Control[*zero.Ctx]), ctx.State["regex_matched"].([]string)[1]) + err := ttsmd.setAPIKey(ctx.State["manager"].(*ctrl.Control[*zero.Ctx]), ctx.State["regex_matched"].([]string)[1]) if err != nil { ctx.SendChain(message.Text("ERROR: ", err)) return