chore: remove aireply due to 没人用

This commit is contained in:
源文雨 2024-11-07 14:48:43 +09:00
parent 9470977092
commit 4ba0b36be1
5 changed files with 0 additions and 535 deletions

View File

@ -1542,18 +1542,6 @@ print("run[CQ:image,file="+j["img"]+"]")
- [x] 大力骂我
</details>
<details>
<summary>人工智能回复</summary>
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/aireply"`
- [x] @Bot 任意文本(任意一句话回复)
- [x] 设置文字回复模式[婧枫|沫沫|青云客|小爱|ChatGPT]
- [x] 设置 ChatGPT api key xxx
</details>
<details>
<summary>词典匹配回复</summary>

View File

@ -169,8 +169,6 @@ import (
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/curse" // 骂人
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/aireply" // 人工智能回复
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/thesaurus" // 词典匹配回复
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/breakrepeat" // 打断复读

View File

@ -1,263 +0,0 @@
package aireply
import (
"errors"
"strings"
"github.com/RomiChan/syncx"
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/lolimi"
"github.com/FloatTech/AnimeAPI/tts/ttscn"
ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control"
)
// 数据结构: [8 bits] [8 bits] [8 bits]
// [具体人物] [tts模式] [回复模式]
// defaultttsindexkey
// 数据结构: [8 bits] [8 bits]
// [具体人物] [tts模式]
// [tts模式]: 0~200 genshin 201 baidu 202 ttscn 203 lolimi
const (
baiduttsindex = 201 + iota
ttscnttsindex
lolimittsindex
)
// extrattsname is the tts other than genshin vits
var extrattsname = []string{"百度", "TTSCN", "桑帛云"}
var ttscnspeakers = [...]string{
"晓晓(女 - 年轻人)",
"云扬(男 - 年轻人)",
"晓辰(女 - 年轻人 - 抖音热门)",
"晓涵(女 - 年轻人)",
"晓墨(女 - 年轻人)",
"晓秋(女 - 中年人)",
"晓睿(女 - 老年)",
"晓双(女 - 儿童)",
"晓萱(女 - 年轻人)",
"晓颜(女 - 年轻人)",
"晓悠(女 - 儿童)",
"云希(男 - 年轻人 - 抖音热门)",
"云野(男 - 中年人)",
"晓梦(女 - 年轻人)",
"晓伊(女 - 儿童)",
"晓甄(女 - 年轻人)",
}
const defaultttsindexkey = -2905
var (
= newapikeystore("./data/tts/o.txt")
ཆཏ = newapikeystore("./data/tts/c.txt")
= newapikeystore("./data/tts/b.txt")
= newapikeystore("./data/tts/s.txt")
)
type replymode []string
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 r {
if s == name {
ok = true
index = int64(i)
break
}
}
if !ok {
return errors.New("no such mode")
}
m, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
if !ok {
return errors.New("no such plugin")
}
return m.SetData(gid, (m.GetData(gid)&^0xff)|(index&0xff))
}
func (r replymode) getReplyMode(ctx *zero.Ctx) aireply.AIReply {
k := .k
gid := ctx.Event.GroupID
if gid == 0 {
gid = -ctx.Event.UserID
}
m, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
if ok {
switch m.GetData(gid) & 0xff {
case 0:
return aireply.NewLolimiAi(aireply.JingfengURL, aireply.JingfengBotName, k, false, 0)
case 1:
return aireply.NewLolimiAi(aireply.MomoURL, aireply.MomoBotName, k, false, 0)
case 2:
return aireply.NewQYK(aireply.QYKURL, aireply.QYKBotName)
case 3:
return aireply.NewXiaoAi(aireply.XiaoAiURL, aireply.XiaoAiBotName)
case 4:
if ཆཏ.k != "" {
return aireply.NewChatGPT(aireply.ChatGPTURL, ཆཏ.k)
}
return aireply.NewLolimiAi(aireply.JingfengURL, aireply.JingfengBotName, k, false, 0)
}
}
return aireply.NewLolimiAi(aireply.JingfengURL, aireply.JingfengBotName, k, false, 0)
}
var ttsins = func() map[string]tts.TTS {
m := make(map[string]tts.TTS, 512)
for _, mode := range extrattsname {
m[mode] = nil
}
return m
}()
var ttsModes = func() []string {
s := make([]string, baiduttsindex) // 0-200
s = append(s, extrattsname...) // 201 202 ...
return s
}()
type ttsmode syncx.Map[int64, int64]
func list(list []string, num int) string {
s := ""
for i, value := range list {
s += value
if (i+1)%num == 0 {
s += "\n"
} else {
s += " | "
}
}
return s
}
func newttsmode() *ttsmode {
t := &ttsmode{}
m, ok := control.Lookup("tts")
(*syncx.Map[int64, int64])(t).Store(defaultttsindexkey, 0)
if ok {
index := m.GetData(defaultttsindexkey)
msk := index & 0xff
if msk >= 0 && (msk < int64(len(ttsModes))) {
(*syncx.Map[int64, int64])(t).Store(defaultttsindexkey, index)
}
}
return t
}
func (t *ttsmode) setSoundMode(ctx *zero.Ctx, name string, character int) error {
gid := ctx.Event.GroupID
if gid == 0 {
gid = -ctx.Event.UserID
}
_, ok := ttsins[name]
if !ok {
return errors.New("不支持设置语音人物" + name)
}
var index = int64(-1)
switch name {
case extrattsname[0]:
index = baiduttsindex
case extrattsname[1]:
index = ttscnttsindex
case extrattsname[2]:
index = lolimittsindex
default:
return errors.New("语音人物" + name + "未注册index")
}
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
// 按原来的逻辑map存的是前16位
storeIndex := (m.GetData(gid) &^ 0xffff00) | ((index << 8) & 0xff00) | ((int64(character) << 16) & 0xff0000)
(*syncx.Map[int64, int64])(t).Store(gid, (storeIndex>>8)&0xffff)
return m.SetData(gid, storeIndex)
}
func (t *ttsmode) getSoundMode(ctx *zero.Ctx) (tts.TTS, error) {
gid := ctx.Event.GroupID
if gid == 0 {
gid = -ctx.Event.UserID
}
i, ok := (*syncx.Map[int64, int64])(t).Load(gid)
if !ok {
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
i = m.GetData(gid) >> 8
}
m := i & 0xff
if m <= 0 || (m >= int64(len(ttsModes))) {
i, _ = (*syncx.Map[int64, int64])(t).Load(defaultttsindexkey)
if i == 0 {
i = ctx.State["manager"].(*ctrl.Control[*zero.Ctx]).GetData(defaultttsindexkey)
(*syncx.Map[int64, int64])(t).Store(defaultttsindexkey, i)
}
m = i & 0xff
}
mode := ttsModes[m]
ins, ok := ttsins[mode]
if !ok || ins == nil {
switch mode {
case extrattsname[0]:
id, sec, _ := strings.Cut(.k, ",")
ins = baidutts.NewBaiduTTS(int(i&0xff00)>>8, id, sec)
case extrattsname[1]:
var err error
ins, err = ttscn.NewTTSCN("中文(普通话,简体)", ttscnspeakers[int(i&0xff00)>>8], ttscn.KBRates[0])
if err != nil {
return nil, err
}
case extrattsname[2]:
ins = lolimi.NewLolimi(int(i&0xff00) >> 8)
default: // 原神
return nil, errors.New("no such mode")
}
}
return ins, nil
}
func (t *ttsmode) resetSoundMode(ctx *zero.Ctx) error {
gid := ctx.Event.GroupID
if gid == 0 {
gid = -ctx.Event.UserID
}
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
// 只保留后面8位
(*syncx.Map[int64, int64])(t).Delete(gid)
return m.SetData(gid, (m.GetData(gid) & 0xff)) // 重置数据
}
func (t *ttsmode) setDefaultSoundMode(name string, character int) error {
_, ok := ttsins[name]
if !ok {
return errors.New("不支持设置语音人物" + name)
}
index := int64(-1)
switch name {
case extrattsname[0]:
index = baiduttsindex
case extrattsname[1]:
index = ttscnttsindex
case extrattsname[2]:
index = lolimittsindex
default:
return errors.New("语音人物" + name + "未注册index")
}
m, ok := control.Lookup("tts")
if !ok {
return errors.New("[tts] service not found")
}
storeIndex := (index & 0xff) | ((int64(character) << 8) & 0xff00)
(*syncx.Map[int64, int64])(t).Store(defaultttsindexkey, storeIndex)
return m.SetData(defaultttsindexkey, storeIndex)
}

View File

@ -1,229 +0,0 @@
// Package aireply AI 回复
package aireply
import (
"os"
"regexp"
"strconv"
"strings"
"time"
ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control"
"github.com/FloatTech/zbputils/ctxext"
"github.com/sirupsen/logrus"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
)
var replmd = replymode([]string{"婧枫", "沫沫", "青云客", "小爱", "ChatGPT"})
var ttsmd = newttsmode()
func init() { // 插件主体
ent := control.Register("tts", &ctrl.Options[*zero.Ctx]{
DisableOnDefault: true,
Brief: "人工智能语音回复",
Help: "- @Bot 任意文本(任意一句话回复)\n" +
"- 设置语音模式[百度/TTSCN/桑帛云] 数字(百度/TTSCN说话人/桑帛云)\n" +
"- 设置默认语音模式[百度/TTSCN/桑帛云] 数字(百度/TTSCN说话人/桑帛云)\n" +
"- 恢复成默认语音模式\n" +
"- 设置语音回复模式[沫沫|婧枫|青云客|小爱|ChatGPT]\n" +
"- 设置百度语音 api id xxxxxx secret xxxxxx (请自行获得)\n" +
"\n当前适用的TTSCN人物含有以下(以数字顺序代表): \n" + list(ttscnspeakers[:], 5),
PrivateDataFolder: "tts",
})
enr := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
DisableOnDefault: false,
Brief: "人工智能回复",
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 := replmd.getReplyMode(ctx)
reply := message.ParseMessageFromString(aireply.Talk(ctx.Event.UserID, ctx.ExtractPlainText(), zero.BotConfig.NickName[0]))
// 回复
time.Sleep(time.Second * 1)
reply = append(reply, message.Reply(ctx.Event.MessageID))
ctx.Send(reply)
})
setReplyMode := func(ctx *zero.Ctx) {
param := ctx.State["args"].(string)
err := replmd.setReplyMode(ctx, param)
if err != nil {
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err))
return
}
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("成功"))
}
enr.OnPrefix("设置文字回复模式", zero.AdminPermission).SetBlock(true).Handle(setReplyMode)
enr.OnRegex(`^设置\s*桑帛云\s*api\s*key\s*(.*)$`, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
err := .set(ctx.State["regex_matched"].([]string)[1])
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(message.Text("设置成功"))
})
enr.OnRegex(`^设置\s*ChatGPT\s*api\s*key\s*(.*)$`, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
err := ཆཏ.set(ctx.State["regex_matched"].([]string)[1])
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(message.Text("设置成功"))
})
endpre := regexp.MustCompile(`\pP$`)
ttscachedir := ent.DataFolder() + "cache/"
_ = os.RemoveAll(ttscachedir)
err := os.MkdirAll(ttscachedir, 0755)
if err != nil {
panic(err)
}
ent.OnMessage(zero.OnlyToMe).SetBlock(true).Limit(ctxext.LimitByUser).
Handle(func(ctx *zero.Ctx) {
msg := ctx.ExtractPlainText()
// 获取回复模式
r := replmd.getReplyMode(ctx)
// 获取回复的文本
reply := message.ParseMessageFromString(r.TalkPlain(ctx.Event.UserID, msg, zero.BotConfig.NickName[0]))
// 过滤掉文字消息
filterMsg := make([]message.Segment, 0, len(reply))
sb := strings.Builder{}
for _, v := range reply {
if v.Type != "text" {
filterMsg = append(filterMsg, v)
} else {
sb.WriteString(v.Data["text"])
}
}
// 纯文本
plainReply := sb.String()
plainReply = strings.ReplaceAll(plainReply, "\n", "")
// 获取语音
speaker, err := ttsmd.getSoundMode(ctx)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
rec, err := speaker.Speak(ctx.Event.UserID, func() string {
if !endpre.MatchString(plainReply) {
return plainReply + "。"
}
return plainReply
})
// 发送前面的图片
if len(filterMsg) != 0 {
filterMsg = append(filterMsg, message.Reply(ctx.Event.MessageID))
ctx.Send(filterMsg)
}
if err != nil {
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(plainReply))
return
}
// 发送语音
if id := ctx.SendChain(message.Record(rec)); id.ID() == 0 {
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(plainReply))
}
})
ent.OnPrefix("设置语音回复模式", zero.AdminPermission).SetBlock(true).Handle(setReplyMode)
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
}
}
// 保存设置
logrus.Debugln("[tts] t.setSoundMode( ctx", param, n, ")")
err = ttsmd.setSoundMode(ctx, param, n)
if err != nil {
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err))
return
}
banner := "这是一段测试语音"
logrus.Debugln("[tts] banner:", banner, "get sound mode...")
// 设置验证
speaker, err := ttsmd.getSoundMode(ctx)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
logrus.Debugln("[tts] got sound mode, speaking...")
rec, err := speaker.Speak(ctx.Event.UserID, func() string { return banner })
if err != nil {
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("无法发送测试语音,请重试。"))
return
}
logrus.Debugln("[tts] sending...")
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("设置成功,当前为", speaker))
})
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 = ttsmd.setDefaultSoundMode(param, 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 := ttsmd.resetSoundMode(ctx)
if err != nil {
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err))
return
}
// 设置验证
speaker, err := ttsmd.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*api\s*key\s*([0-9a-zA-Z-_]{54}==)$`, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
err := .set(ctx.State["regex_matched"].([]string)[1])
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(message.Text("设置成功"))
})
ent.OnRegex(`^设置百度语音\s*api\s*id\s*(.*)\s*secret\s*(.*)\s*$`, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
err := .set(ctx.State["regex_matched"].([]string)[1] + "," + ctx.State["regex_matched"].([]string)[2])
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(message.Text("设置成功"))
})
}

View File

@ -1,29 +0,0 @@
package aireply
import (
"os"
"github.com/FloatTech/floatbox/binary"
"github.com/FloatTech/floatbox/file"
)
type apikeystore struct {
k string
p string
}
func newapikeystore(p string) (s apikeystore) {
s.p = p
if file.IsExist(p) {
data, err := os.ReadFile(p)
if err == nil {
s.k = binary.BytesToString(data)
}
}
return
}
func (s *apikeystore) set(k string) error {
s.k = k
return os.WriteFile(s.p, binary.StringToBytes(k), 0644)
}