diff --git a/go.mod b/go.mod index 5624f923..25cba580 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( github.com/Baidu-AIP/golang-sdk v1.1.1 github.com/Coloured-glaze/gg v1.3.4 - github.com/FloatTech/AnimeAPI v1.6.1-0.20221210053102-a9b76da3c119 + github.com/FloatTech/AnimeAPI v1.6.1-0.20221211044824-a4c95321af15 github.com/FloatTech/floatbox v0.0.0-20221210051813-4bd44af40c60 github.com/FloatTech/sqlite v1.5.7 github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b @@ -28,7 +28,6 @@ require ( github.com/lucas-clemente/quic-go v0.31.0 github.com/mroth/weightedrand v1.0.0 github.com/pkg/errors v0.9.1 - github.com/pkumza/numcn v1.0.0 github.com/shirou/gopsutil/v3 v3.22.11 github.com/sirupsen/logrus v1.9.0 github.com/tidwall/gjson v1.14.4 @@ -66,6 +65,7 @@ require ( github.com/mattn/go-isatty v0.0.16 // indirect github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect github.com/onsi/ginkgo/v2 v2.2.0 // indirect + github.com/pkumza/numcn v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect github.com/tidwall/match v1.1.1 // indirect diff --git a/go.sum b/go.sum index 251bf625..a380d128 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym github.com/Coloured-glaze/gg v1.3.4 h1:l31zIF/HaVwkzjrj+A56RGQoSKyKuR1IWtIrqXGFStI= github.com/Coloured-glaze/gg v1.3.4/go.mod h1:Ih5NLNNDHOy3RJbB0EPqGTreIzq/H02TGThIagh8HJg= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= -github.com/FloatTech/AnimeAPI v1.6.1-0.20221210053102-a9b76da3c119 h1:8uBYj/4UTX4mGxcY/C22NIaQvHe+B0LTxZh8eC/331k= -github.com/FloatTech/AnimeAPI v1.6.1-0.20221210053102-a9b76da3c119/go.mod h1:N5+P+xQlmn/qNfvFO4ZLR0/OXQC298pp5o6kOPkBN1M= +github.com/FloatTech/AnimeAPI v1.6.1-0.20221211044824-a4c95321af15 h1:/AMRe7SDCqrE0674bz6FakI/UqaxTUbBjbDs+p/ARh8= +github.com/FloatTech/AnimeAPI v1.6.1-0.20221211044824-a4c95321af15/go.mod h1:Sp8rOoJkMq/X0XIqrhcH9fuFTF/HuLDBL26NkA1FEGA= github.com/FloatTech/floatbox v0.0.0-20221210051813-4bd44af40c60 h1:S4KfcdK6LdOa0+TTyacHYOZ8aWkR6YbvlnI6GWe66Jc= github.com/FloatTech/floatbox v0.0.0-20221210051813-4bd44af40c60/go.mod h1:/k2zxRJtAJ17w9fSpc7xf2QjPDTUBmqhBsOGyHVyX0U= github.com/FloatTech/rendercard v0.0.2-0.20221128165614-a41216d2422e h1:7bF01RHsYS99Zp+OWfob1W/Cymho6fcggoRSpiuiYB8= diff --git a/plugin/ai_reply/ai_tts.go b/plugin/ai_reply/ai_tts.go index 7b7a10ce..104ec15f 100644 --- a/plugin/ai_reply/ai_tts.go +++ b/plugin/ai_reply/ai_tts.go @@ -3,93 +3,40 @@ package aireply import ( "errors" "net/url" - "regexp" "sync" zero "github.com/wdvxdr1123/ZeroBot" "github.com/FloatTech/AnimeAPI/aireply" + "github.com/FloatTech/AnimeAPI/tts" + "github.com/FloatTech/AnimeAPI/tts/baidutts" + "github.com/FloatTech/AnimeAPI/tts/genshin" + "github.com/FloatTech/AnimeAPI/tts/mockingbird" ctrl "github.com/FloatTech/zbpctrl" "github.com/FloatTech/zbputils/control" ) +// 数据结构: [4 bits] [4 bits] [8 bits] [8 bits] +// [拟声鸟模式] [百度模式] [tts模式] [回复模式] + +// defaultttsindexkey +// 数据结构: [4 bits] [4 bits] [8 bits] +// [拟声鸟模式] [百度模式] [tts模式] + +// [tts模式]: 0~63 genshin 64 baidu 65 mockingbird + const ( - cnapi = "https://genshin.azurewebsites.net/api/speak?format=mp3&id=%d&text=%s&code=%s" + lastgsttsindex = 63 + iota + baiduttsindex + mockingbirdttsindex ) -// 每个角色的测试文案 -var testRecord = map[string]string{ - "派蒙": "哎,又是看不懂的东西。我完全不知道这些奇怪的问题和实验,能得到什么结果…", - "凯亚": "真是个急性子啊你。", - "安柏": "最初的鸟儿是不会飞翔的,飞翔是它们勇敢跃入峡谷的奖励。", - "丽莎": "嗨,小可爱,你是新来的助理吗?", - "琴": "蒲公英骑士,琴,申请入队。", - "香菱": "我是来自璃月的厨师香菱,最擅长的是做各种捞…捞,料理…哎呀,练了那么多次,还是会紧张,嘿。", - "枫原万叶": "飘摇风雨中,带刀归来赤脚行。", - "迪卢克": "在黎明来临之前,总要有人照亮黑暗。", - "温迪": "若你困于无风之地,我将为你奏响高天之歌。", - "可莉": "西风骑士团,火花骑士,可莉,前来报到!…呃—后面该说什么词来着?可莉背不下来啦...", - "早柚": "终末番,早柚,参上。 呼——", - "托马": "初次见面,异乡的旅人,你的名字我可是早就听说了。只要你不嫌弃,我托马,从今天起就是你的朋友了。", - "芭芭拉": "芭芭拉,闪耀登场~治疗就交给我吧,不会让你失望的!", - "优菈": "沉沦是很容易的一件事,但我仍想冻住这股潮流。", - "云堇": "曲高未必人不识,自有知音和清词。", - "钟离": "人间归离复归离,借一浮生逃浮生。", - "魈": "三眼五显仙人,魈,听召,前来守护", - "凝光": "就算古玩价值连城,给人的快乐,也只有刚拥有的一瞬", - "雷电将军": "浮世千百年来风景依旧,人之在世却如白露与泡影。", - "北斗": "不知道如何向前的话,总之先迈出第一步,后面的道路就会自然而然地展开了。", - "甘雨": "这项工作,该划掉了。", - "七七": "椰羊的奶,好喝!比一般的羊奶,好喝!", - "刻晴": "劳逸结合是不错,但也别放松过头。", - "神里绫华": "若知是梦何须醒,不比真如一相会。", - "雷泽": "你是朋友。我和你一起狩猎。", - "神里绫人": "此前听绫华屡次提起阁下,不料公务繁忙,直至今日才有机会相见。", - "罗莎莉亚": "哪怕如今你已经走上截然不同的道路,也不要否认从前的自己,从前的每一个你都是你脚下的基石,不要害怕过去,不要畏惧与它抗衡。", - "阿贝多": "用自己的双脚丈量土地,将未知变为知识。", - "八重神子": "我的神明,就托付给你了。", - "宵宫": "即使只是片刻的火花,也能在仰望黑夜的人心中留下久久不灭的美丽光芒。", - "荒泷一斗": "更好地活下去,绝不该靠牺牲同类换取,应该是,一起更好地活着,才对。", - "九条裟罗": "想要留住雪花。但在手心里,它只会融化的更快。", - "夜兰": "线人来信了,嗯,看来又出现了新的变数。", - "珊瑚宫心海": "成为了现任人神巫女之后,我也慢慢习惯了这样的生活,更重要的是我也因此和你相遇了,不是吗?", - "五郎": "海祇岛反抗军大将,五郎,前来助阵!", - "达达利亚": "许下的诺言就好好遵守,做错了事情就承担责任,这才是家人应有的样子吧。", - "莫娜": "正是因为无法更改,无可违逆,只能接受,命运才会被称之为命运。", - "班尼特": "只要有大家在,伤口就不会痛!", - "申鹤": "不知道你是喜欢人间的灯火,还是山林的月光?", - "行秋": "有时明月无人夜,独向昭潭制恶龙。", - "烟绯": "律法即是约束,也是工具。", - "久岐忍": "有麻烦事要处理的话,直接告诉我就好,我来摆平。", - "辛焱": "马上就要演出了,你也一起来嗨吗?", - "砂糖": "我是砂糖,炼金术的…研究员。", - "胡桃": "阴阳有序,命运无常,死亡难以预测,却也有它的规矩。", - "重云": "我名重云,家族久居璃月,世代以驱邪除魔为业。", - "菲谢尔": "我即断罪之皇女,真名为菲谢尔。应命运的召唤降临在此间——哎?你也是,异世界的旅人吗…?", - "诺艾尔": "我是诺艾尔,西风骑士团的女仆,从今天起会陪你一起去冒险。", - "迪奥娜": "猫尾酒馆的招牌调酒师,迪奥娜,我的出场费可是很贵的。", - "鹿野院平藏": "我叫鹿野院平藏,是天领奉行里破案最多最快的侦探……", -} - -var ( - re = regexp.MustCompile(`(\-|\+)?\d+(\.\d+)?`) - soundList = [...]string{ - "派蒙", "凯亚", "安柏", "丽莎", "琴", - "香菱", "枫原万叶", "迪卢克", "温迪", "可莉", - "早柚", "托马", "芭芭拉", "优菈", "云堇", - "钟离", "魈", "凝光", "雷电将军", "北斗", - "甘雨", "七七", "刻晴", "神里绫华", "雷泽", - "神里绫人", "罗莎莉亚", "阿贝多", "八重神子", "宵宫", - "荒泷一斗", "九条裟罗", "夜兰", "珊瑚宫心海", "五郎", - "达达利亚", "莫娜", "班尼特", "申鹤", "行秋", - "烟绯", "久岐忍", "辛焱", "砂糖", "胡桃", - "重云", "菲谢尔", "诺艾尔", "迪奥娜", "鹿野院平藏", - } +const ( + defaultttsindexkey = -2905 ) -/************************************************************* -*******************************AIreply************************ -*************************************************************/ +var replyModes = [...]string{"青云客", "小爱", "ChatGPT"} + func setReplyMode(ctx *zero.Ctx, name string) error { gid := ctx.Event.GroupID if gid == 0 { @@ -111,7 +58,7 @@ func setReplyMode(ctx *zero.Ctx, name string) error { if !ok { return errors.New("no such plugin") } - return m.SetData(gid, index) + return m.SetData((m.GetData(gid)&^0xff)|(gid&0xff), index) } var chats *aireply.ChatGPT @@ -123,7 +70,7 @@ func getReplyMode(ctx *zero.Ctx) aireply.AIReply { } m, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]) if ok { - switch m.GetData(gid) { + switch m.GetData(gid) & 0xff { case 0: return aireply.NewQYK(aireply.QYKURL, aireply.QYKBotName) case 1: @@ -137,13 +84,24 @@ func getReplyMode(ctx *zero.Ctx) aireply.AIReply { return aireply.NewQYK(aireply.QYKURL, aireply.QYKBotName) } -/************************************************************* -***********************tts************************************ -*************************************************************/ +var ttsins = func() map[string]tts.TTS { + m := make(map[string]tts.TTS, 128) + for _, mode := range append(genshin.SoundList[:], "百度", "拟声鸟") { + m[mode] = nil + } + return m +}() + +var ttsModes = func() []string { + s := append(genshin.SoundList[:], make([]string, 64-len(genshin.SoundList))...) // 0-63 + s = append(s, "百度", "拟声鸟") // 64 65 + return s +}() + type ttsmode struct { - sync.RWMutex `json:"-"` - APIKey string - mode map[int64]int64 + sync.Mutex `json:"-"` + APIKey string // APIKey is for genshin vits + mode map[int64]int64 `json:"-"` // mode grp index } func list(list []string, num int) string { @@ -160,111 +118,157 @@ func list(list []string, num int) string { } func newttsmode() *ttsmode { - tts := &ttsmode{} - tts.Lock() - defer tts.Unlock() + t := &ttsmode{} + t.Lock() + defer t.Unlock() m, ok := control.Lookup("tts") - tts.mode = make(map[int64]int64, 2*len(soundList)) - tts.mode[-2905] = 1 + t.mode = make(map[int64]int64, 2*len(genshin.SoundList)) + t.mode[defaultttsindexkey] = 0 if ok { - index := m.GetData(-2905) - if index > 0 && index < int64(len(soundList)) { - tts.mode[-2905] = index + index := m.GetData(defaultttsindexkey) + msk := index & 0xff + if msk >= 0 && (msk < int64(len(genshin.SoundList)) || msk == baiduttsindex || msk == mockingbirdttsindex) { + t.mode[defaultttsindexkey] = index } } - return tts + return t } -func (tts *ttsmode) getAPIKey(ctx *zero.Ctx) string { - if tts.APIKey == "" { +func (t *ttsmode) getAPIKey(ctx *zero.Ctx) string { + if t.APIKey == "" { + t.Lock() m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]) gid := ctx.Event.GroupID if gid == 0 { gid = -ctx.Event.UserID } - _ = m.Manager.GetExtra(gid, &tts) + _ = m.Manager.GetExtra(gid, &t) + t.Unlock() } - return url.QueryEscape(tts.APIKey) + return url.QueryEscape(t.APIKey) } -func (tts *ttsmode) setAPIKey(m *ctrl.Control[*zero.Ctx], grp int64, key string) error { +func (t *ttsmode) setAPIKey(m *ctrl.Control[*zero.Ctx], grp int64, key string) error { + t.Lock() + defer t.Unlock() err := m.Manager.SetExtra(grp, &key) if err != nil { return err } - tts.APIKey = key + t.APIKey = key return nil } -func (tts *ttsmode) setSoundMode(ctx *zero.Ctx, name string) error { +func (t *ttsmode) setSoundMode(ctx *zero.Ctx, name string, baiduper, mockingsynt int) error { gid := ctx.Event.GroupID if gid == 0 { gid = -ctx.Event.UserID } - var index int64 - for i, s := range soundList { + _, ok := ttsins[name] + if !ok { + return errors.New("不支持设置语音人物" + name) + } + var index = int64(-1) + for i, s := range genshin.SoundList { if s == name { - index = int64(i + 1) + index = int64(i) break } } - if index == 0 { - return errors.New("不支持设置语音人物" + name) + if index == -1 { + switch name { + case "百度": + index = baiduttsindex + case "拟声鸟": + index = mockingbirdttsindex + default: + return errors.New("语音人物" + name + "未注册index") + } } m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]) - tts.Lock() - defer tts.Unlock() - tts.mode[gid] = index - return m.SetData(gid, index) + t.Lock() + defer t.Unlock() + t.mode[gid] = index + return m.SetData(gid, (m.GetData(gid)&^0xffff00)|((index<<8)&0xff00)|((int64(baiduper)<<16)&0x0f0000)|((int64(mockingsynt)<<20)&0xf00000)) } -func (tts *ttsmode) getSoundMode(ctx *zero.Ctx) int64 { +func (t *ttsmode) getSoundMode(ctx *zero.Ctx) (tts.TTS, error) { gid := ctx.Event.GroupID if gid == 0 { gid = -ctx.Event.UserID } - tts.Lock() - defer tts.Unlock() - i, ok := tts.mode[gid] + t.Lock() + defer t.Unlock() + i, ok := t.mode[gid] if !ok { m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]) - i = m.GetData(gid) + i = m.GetData(gid) >> 8 } - if i <= 0 || i >= int64(len(soundList)) { - i = tts.mode[-2905] + m := i & 0xff + if m < 0 || (m >= int64(len(genshin.SoundList)) && m != baiduttsindex && m != mockingbirdttsindex) { + i = t.mode[defaultttsindexkey] + m = i & 0xff } - return i - 1 + mode := ttsModes[m] + ins, ok := ttsins[mode] + if !ok { + switch mode { + case "百度": + ins = baidutts.NewBaiduTTS(int(i&0x0f00) >> 8) + case "拟声鸟": + var err error + ins, err = mockingbird.NewMockingBirdTTS(int(i&0xf000) >> 12) + if err != nil { + return nil, err + } + default: // 原神 + ins = genshin.NewGenshin(int(m), t.getAPIKey(ctx)) + ttsins[mode] = ins + } + } + return ins, nil } -func (tts *ttsmode) resetSoundMode(ctx *zero.Ctx) error { +func (t *ttsmode) resetSoundMode(ctx *zero.Ctx) error { gid := ctx.Event.GroupID if gid == 0 { gid = -ctx.Event.UserID } - tts.Lock() - defer tts.Unlock() + t.Lock() + defer t.Unlock() m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]) - tts.mode[gid] = 0 - return m.SetData(gid, 0) // 重置数据 + index := m.GetData(defaultttsindexkey) + return m.SetData(gid, (m.GetData(gid)&0xff)|((index&^0xff)<<8)) // 重置数据 } -func (tts *ttsmode) setDefaultSoundMode(name string) error { - var index int64 - for i, s := range soundList { +func (t *ttsmode) setDefaultSoundMode(name string, baiduper, mockingsynt int) error { + _, ok := ttsins[name] + if !ok { + return errors.New("不支持设置语音人物" + name) + } + index := int64(-1) + for i, s := range genshin.SoundList { if s == name { - index = int64(i + 1) + index = int64(i) break } } - if index == 0 { - return errors.New("不支持设置语音人物" + name) + if index == -1 { + switch name { + case "百度": + index = baiduttsindex + case "拟声鸟": + index = mockingbirdttsindex + default: + return errors.New("语音人物" + name + "未注册index") + } } - tts.Lock() - defer tts.Unlock() + t.Lock() + defer t.Unlock() m, ok := control.Lookup("tts") if !ok { return errors.New("[tts] service not found") } - tts.mode[-2905] = index - return m.SetData(-2905, index) + t.mode[defaultttsindexkey] = index + return m.SetData(defaultttsindexkey, (index&0xff)|((int64(baiduper)<<8)&0x0f00)|((int64(mockingsynt)<<12)&0xf000)) } diff --git a/plugin/ai_reply/main.go b/plugin/ai_reply/main.go index b74ebb56..f7a308b5 100644 --- a/plugin/ai_reply/main.go +++ b/plugin/ai_reply/main.go @@ -2,47 +2,43 @@ package aireply import ( - "fmt" - "net/url" "os" "strconv" "time" "github.com/FloatTech/AnimeAPI/aireply" "github.com/FloatTech/AnimeAPI/chatgpt" + "github.com/FloatTech/AnimeAPI/tts/genshin" "github.com/FloatTech/floatbox/binary" ctrl "github.com/FloatTech/zbpctrl" "github.com/FloatTech/zbputils/control" "github.com/FloatTech/zbputils/ctxext" - "github.com/pkumza/numcn" "github.com/sirupsen/logrus" zero "github.com/wdvxdr1123/ZeroBot" "github.com/wdvxdr1123/ZeroBot/message" ) -var replyModes = [...]string{"青云客", "小爱", "ChatGPT"} +var t = newttsmode() func init() { // 插件主体 ent := control.Register("tts", &ctrl.Options[*zero.Ctx]{ DisableOnDefault: true, Brief: "人工智能语音回复", Help: "- @Bot 任意文本(任意一句话回复)\n" + - "- 设置语音模式[原神人物]\n" + - "- 设置默认语音模式[原神人物]\n" + + "- 设置语音模式[原神人物/百度/拟声鸟] 数字(百度/拟声鸟模式)\n" + + "- 设置默认语音模式[原神人物/百度/拟声鸟] 数字(百度/拟声鸟模式)\n" + "- 恢复成默认语音模式\n" + "- 为群 xxx 设置原神语音 api key xxxxxx (key请加开发群获得)\n" + - "当前适用的原神人物含有以下:\n" + list(soundList[:], 5), + "当前适用的原神人物含有以下:\n" + list(genshin.SoundList[:], 5), }) - tts := newttsmode() + enr := control.Register("aireply", &ctrl.Options[*zero.Ctx]{ DisableOnDefault: false, Brief: "人工智能回复", Help: "- @Bot 任意文本(任意一句话回复)\n- 设置回复模式[青云客|小爱|ChatGPT]\n- 设置 ChatGPT SessionToken xxx", PrivateDataFolder: "aireply", }) - /************************************************************* - *******************************AIreply************************ - *************************************************************/ + enr.OnMessage(zero.OnlyToMe).SetBlock(true).Limit(ctxext.LimitByUser). Handle(func(ctx *zero.Ctx) { aireply := getReplyMode(ctx) @@ -56,6 +52,7 @@ func init() { // 插件主体 } ctx.Send(reply) }) + enr.OnPrefix("设置回复模式", zero.AdminPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) { param := ctx.State["args"].(string) err := setReplyMode(ctx, param) @@ -65,97 +62,7 @@ func init() { // 插件主体 } ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("成功")) }) - /************************************************************* - ***********************tts************************************ - *************************************************************/ - ent.OnMessage(zero.OnlyToMe).SetBlock(true).Limit(ctxext.LimitByUser). - Handle(func(ctx *zero.Ctx) { - msg := ctx.ExtractPlainText() - // 获取回复模式 - r := getReplyMode(ctx) - // 获取回复的文本 - reply := r.TalkPlain(ctx.Event.UserID, msg, zero.BotConfig.NickName[0]) - // 获取语音 - index := tts.getSoundMode(ctx) - record := message.Record(fmt.Sprintf(cnapi, index, url.QueryEscape( - // 将数字转文字 - re.ReplaceAllStringFunc(reply, func(s string) string { - f, err := strconv.ParseFloat(s, 64) - if err != nil { - logrus.Errorln("[tts]", err) - return s - } - return numcn.EncodeFromFloat64(f) - }), - ), tts.getAPIKey(ctx))) - // 发送语音 - if ID := ctx.SendChain(record); ID.ID() == 0 { - ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(reply)) - } - }) - ent.OnRegex(`^设置语音模式(.*)$`, zero.AdminPermission, func(ctx *zero.Ctx) bool { - param := ctx.State["regex_matched"].([]string)[1] - if _, ok := testRecord[param]; !ok { - return false - } - return true - }).SetBlock(true).Handle(func(ctx *zero.Ctx) { - param := ctx.State["regex_matched"].([]string)[1] - // 保存设置 - err := tts.setSoundMode(ctx, param) - if err != nil { - ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err)) - return - } - // 设置验证 - i := tts.getSoundMode(ctx) - if _, ok := testRecord[soundList[i]]; !ok { - ctx.SendChain(message.Text("配置的语音人物数据丢失!请重新设置语音人物。")) - return - } - record := message.Record(fmt.Sprintf(cnapi, i, url.QueryEscape(testRecord[soundList[i]]), tts.getAPIKey(ctx))).Add("cache", 0) - if ID := ctx.SendChain(record); ID.ID() == 0 { - ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("设置失败!无法发送测试语音,请重试。")) - return - } - time.Sleep(time.Second * 2) - ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("设置成功")) - }) - ent.OnRegex(`^设置默认语音模式(.*)$`, zero.SuperUserPermission, func(ctx *zero.Ctx) bool { - param := ctx.State["regex_matched"].([]string)[1] - if _, ok := testRecord[param]; !ok { - return false - } - return true - }).SetBlock(true).Handle(func(ctx *zero.Ctx) { - param := ctx.State["regex_matched"].([]string)[1] - // 保存设置 - err := tts.setDefaultSoundMode(param) - if err != nil { - ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err)) - return - } - ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("设置成功")) - }) - ent.OnFullMatch("恢复成默认语音模式", zero.AdminPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) { - err := tts.resetSoundMode(ctx) - if err != nil { - ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err)) - return - } - // 设置验证 - index := tts.getSoundMode(ctx) - ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("设置成功,当前为", soundList[index])) - }) - ent.OnRegex(`^为群\s*(-?\d+)\s*设置原神语音\s*api\s*key\s*([0-9a-zA-Z-_]{54}==)$`, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) { - grp, _ := strconv.ParseInt(ctx.State["regex_matched"].([]string)[1], 10, 64) - err := tts.setAPIKey(ctx.State["manager"].(*ctrl.Control[*zero.Ctx]), grp, ctx.State["regex_matched"].([]string)[2]) - if err != nil { - ctx.SendChain(message.Text("ERROR: ", err)) - return - } - ctx.SendChain(message.Text("设置成功")) - }) + chatgptfile := enr.DataFolder() + "chatgpt.txt" cfg := &chatgpt.Config{ UA: chatgpt.UA, @@ -178,6 +85,7 @@ func init() { // 插件主体 } } }() + enr.OnRegex(`^设置\s*ChatGPT\s*SessionToken\s*(.*)$`, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) { token := ctx.State["regex_matched"].([]string)[1] f, err := os.Create(chatgptfile) @@ -199,8 +107,118 @@ func init() { // 插件主体 }) ctx.SendChain(message.Text("设置成功")) }) + enr.OnFullMatch("重置ChatGPT连接").SetBlock(true).Handle(func(ctx *zero.Ctx) { chats.Reset(ctx.Event.UserID) ctx.SendChain(message.Text("成功")) }) + + ent.OnMessage(zero.OnlyToMe).SetBlock(true).Limit(ctxext.LimitByUser). + Handle(func(ctx *zero.Ctx) { + msg := ctx.ExtractPlainText() + // 获取回复模式 + r := getReplyMode(ctx) + // 获取回复的文本 + reply := r.TalkPlain(ctx.Event.UserID, msg, zero.BotConfig.NickName[0]) + // 获取语音 + speaker, err := t.getSoundMode(ctx) + if err != nil { + ctx.SendChain(message.Text("ERROR: ", err)) + return + } + rec, err := speaker.Speak(ctx.Event.UserID, func() string { return reply }) + if err != nil { + ctx.SendChain(message.Text("ERROR: ", err)) + return + } + // 发送语音 + if id := ctx.SendChain(message.Record(rec)); id.ID() == 0 { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(reply)) + } + }) + + ent.OnRegex(`^设置语音模式\s*([\S\D]*)\s*(\d*)$`, zero.AdminPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) { + param := ctx.State["regex_matched"].([]string)[1] + num := ctx.State["regex_matched"].([]string)[2] + n := 0 + var err error + if num != "" { + n, err = strconv.Atoi(num) + if err != nil { + ctx.SendChain(message.Text("ERROR: ", err)) + return + } + } + // 保存设置 + err = t.setSoundMode(ctx, param, n, n) + if err != nil { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err)) + return + } + if banner, ok := genshin.TestRecord[param]; ok { + // 设置验证 + speaker, err := t.getSoundMode(ctx) + if err != nil { + ctx.SendChain(message.Text("ERROR: ", err)) + return + } + rec, err := speaker.Speak(ctx.Event.UserID, func() string { return banner }) + if err != nil { + ctx.SendChain(message.Text("ERROR: ", err)) + return + } + if id := ctx.SendChain(message.Record(rec).Add("cache", 0)); id.ID() == 0 { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("无法发送测试语音,请重试。")) + return + } + time.Sleep(time.Second * 2) + } + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("设置成功")) + }) + + ent.OnRegex(`^设置默认语音模式\s*([\S\D]*)\s*(\d*)$`, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) { + param := ctx.State["regex_matched"].([]string)[1] + num := ctx.State["regex_matched"].([]string)[2] + n := 0 + var err error + if num != "" { + n, err = strconv.Atoi(num) + if err != nil { + ctx.SendChain(message.Text("ERROR: ", err)) + return + } + } + // 保存设置 + err = t.setDefaultSoundMode(param, n, n) + if err != nil { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err)) + return + } + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("设置成功")) + }) + + ent.OnFullMatch("恢复成默认语音模式", zero.AdminPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) { + err := t.resetSoundMode(ctx) + if err != nil { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err)) + return + } + // 设置验证 + speaker, err := t.getSoundMode(ctx) + if err != nil { + ctx.SendChain(message.Text("ERROR: ", err)) + return + } + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("设置成功,当前为", speaker)) + }) + + ent.OnRegex(`^为群\s*(-?\d+)\s*设置原神语音\s*api\s*key\s*([0-9a-zA-Z-_]{54}==)$`, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) { + grp, _ := strconv.ParseInt(ctx.State["regex_matched"].([]string)[1], 10, 64) + err := t.setAPIKey(ctx.State["manager"].(*ctrl.Control[*zero.Ctx]), grp, ctx.State["regex_matched"].([]string)[2]) + if err != nil { + ctx.SendChain(message.Text("ERROR: ", err)) + return + } + ctx.SendChain(message.Text("设置成功")) + }) } diff --git a/plugin/score/sign_in.go b/plugin/score/sign_in.go index 0c0d32ad..ad225277 100644 --- a/plugin/score/sign_in.go +++ b/plugin/score/sign_in.go @@ -286,12 +286,12 @@ func init() { } // 无缓存获取群员列表 temp := ctx.GetThisGroupMemberListNoCache().Array() - var usergroup []int64 - for _, info := range temp { - usergroup = append(usergroup, info.Get("user_id").Int()) + usergroup := make([]int64, len(temp)) + for i, info := range temp { + usergroup[i] = info.Get("user_id").Int() } // 获取钱包信息 - st, err := wallet.GetGroupWalletOf(usergroup, true) + st, err := wallet.GetGroupWalletOf(true, usergroup...) if err != nil { ctx.SendChain(message.Text("ERROR: ", err)) return