mirror of
https://github.com/FloatTech/ZeroBot-Plugin.git
synced 2026-01-10 23:39:02 +08:00
194 lines
5.5 KiB
Go
194 lines
5.5 KiB
Go
// Package aichat 大模型聊天和Agent
|
||
package aichat
|
||
|
||
import (
|
||
"encoding/json"
|
||
"math/rand"
|
||
"strings"
|
||
|
||
"github.com/fumiama/deepinfra"
|
||
goba "github.com/fumiama/go-onebot-agent"
|
||
"github.com/sirupsen/logrus"
|
||
|
||
zero "github.com/wdvxdr1123/ZeroBot"
|
||
"github.com/wdvxdr1123/ZeroBot/extension/single"
|
||
"github.com/wdvxdr1123/ZeroBot/message"
|
||
|
||
"github.com/FloatTech/AnimeAPI/airecord"
|
||
"github.com/FloatTech/floatbox/process"
|
||
ctrl "github.com/FloatTech/zbpctrl"
|
||
"github.com/FloatTech/zbputils/chat"
|
||
"github.com/FloatTech/zbputils/control"
|
||
)
|
||
|
||
var (
|
||
// en data [8 temp] [8 rate] LSB
|
||
en = control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
||
DisableOnDefault: false,
|
||
Extra: control.ExtraFromString("aichat"),
|
||
Brief: "大模型聊天和Agent",
|
||
Help: "- (随意聊天, 概率匹配)",
|
||
|
||
PrivateDataFolder: "aichat",
|
||
}).ApplySingle(single.New(
|
||
single.WithKeyFn(func(ctx *zero.Ctx) int64 {
|
||
if ctx.Event.GroupID == 0 {
|
||
return -ctx.Event.UserID
|
||
}
|
||
return ctx.Event.GroupID
|
||
}),
|
||
// no post option, silently quit
|
||
))
|
||
)
|
||
|
||
var (
|
||
fastfailnorecord = false
|
||
)
|
||
|
||
func init() {
|
||
en.OnMessage(chat.EnsureConfig, func(ctx *zero.Ctx) bool {
|
||
gid := ctx.Event.GroupID
|
||
if gid == 0 {
|
||
gid = -ctx.Event.UserID
|
||
}
|
||
stor, ok := ctx.State[zero.StateKeyPrefixKeep+"aichatcfg_stor__"].(chat.Storage)
|
||
if !ok {
|
||
logrus.Warnln("ERROR: cannot get stor")
|
||
return false
|
||
}
|
||
if !(ctx.ExtractPlainText() != "" &&
|
||
(!stor.NoReplyAt() || (stor.NoReplyAt() && !ctx.Event.IsToMe))) {
|
||
return false
|
||
}
|
||
rate := stor.Rate()
|
||
if !ctx.Event.IsToMe && rand.Intn(100) >= int(rate) {
|
||
return false
|
||
}
|
||
if chat.AC.Key == "" {
|
||
logrus.Warnln("ERROR: get extra err: empty key")
|
||
return false
|
||
}
|
||
if ctx.Event.IsToMe {
|
||
ctx.Block()
|
||
}
|
||
return true
|
||
}).SetBlock(false).Handle(func(ctx *zero.Ctx) {
|
||
gid := ctx.Event.GroupID
|
||
if gid == 0 {
|
||
gid = -ctx.Event.UserID
|
||
}
|
||
stor := ctx.State[zero.StateKeyPrefixKeep+"aichatcfg_stor__"].(chat.Storage)
|
||
temperature := stor.Temp()
|
||
topp, maxn := chat.AC.MParams()
|
||
|
||
logrus.Debugln("[aichat] agent mode test: noagent", stor.NoAgent(), "hasapi", chat.AC.AgentAPI != "", "hasmodel", chat.AC.AgentModelName != "")
|
||
if !stor.NoAgent() && chat.AC.AgentAPI != "" && chat.AC.AgentModelName != "" {
|
||
logrus.Debugln("[aichat] enter agent mode")
|
||
x := deepinfra.NewAPI(chat.AC.AgentAPI, string(chat.AC.AgentKey))
|
||
mod, err := chat.AC.Type.Protocol(chat.AC.AgentModelName, temperature, topp, maxn)
|
||
if err != nil {
|
||
logrus.Warnln("ERROR: ", err)
|
||
return
|
||
}
|
||
role := goba.PermRoleUser
|
||
if zero.AdminPermission(ctx) {
|
||
role = goba.PermRoleAdmin
|
||
if zero.SuperUserPermission(ctx) {
|
||
role = goba.PermRoleOwner
|
||
}
|
||
}
|
||
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||
if !ok {
|
||
logrus.Warnln("ERROR: cannot get ctrl mamager")
|
||
}
|
||
ag := chat.AgentOf(ctx.Event.SelfID, c.Service)
|
||
logrus.Debugln("[aichat] got agent")
|
||
if chat.AC.ImageAPI != "" && !ag.CanViewImage() {
|
||
mod, err := chat.AC.ImageType.Protocol(chat.AC.ImageModelName, temperature, topp, maxn)
|
||
if err != nil {
|
||
logrus.Warnln("ERROR: ", err)
|
||
return
|
||
}
|
||
ag.SetViewImageAPI(deepinfra.NewAPI(chat.AC.ImageAPI, string(chat.AC.ImageKey)), mod)
|
||
logrus.Debugln("[aichat] agent set img")
|
||
}
|
||
ctx.NoTimeout()
|
||
logrus.Debugln("[aichat] agent set no timeout")
|
||
hasresp := false
|
||
for i := 0; i < 8; i++ { // 最大运行 8 轮因为问答上下文只有 16
|
||
reqs := chat.CallAgent(ag, zero.SuperUserPermission(ctx), x, mod, gid, role)
|
||
if len(reqs) == 0 {
|
||
logrus.Debugln("[aichat] agent call got empty response")
|
||
break
|
||
}
|
||
hasresp = true
|
||
for _, req := range reqs {
|
||
if req.Action == goba.SVM { // is a fake action
|
||
continue
|
||
}
|
||
resp := ctx.CallAction(req.Action, req.Params)
|
||
logrus.Infoln("[aichat] agent get resp:", reqs)
|
||
ag.AddResponse(gid, &goba.APIResponse{
|
||
Status: resp.Status,
|
||
Data: json.RawMessage(resp.Data.Raw),
|
||
Message: resp.Message,
|
||
Wording: resp.Wording,
|
||
RetCode: resp.RetCode,
|
||
})
|
||
}
|
||
}
|
||
if hasresp {
|
||
return
|
||
}
|
||
// no response, fall back to normal chat
|
||
logrus.Debugln("[aichat] agent fell back to normal chat")
|
||
}
|
||
|
||
x := deepinfra.NewAPI(chat.AC.API, string(chat.AC.Key))
|
||
mod, err := chat.AC.Type.Protocol(chat.AC.ModelName, temperature, topp, maxn)
|
||
if err != nil {
|
||
logrus.Warnln("ERROR: ", err)
|
||
return
|
||
}
|
||
data, err := x.Request(chat.GetChatContext(mod, gid, chat.AC.SystemP, bool(chat.AC.NoSystemP)))
|
||
if err != nil {
|
||
logrus.Warnln("[aichat] post err:", err)
|
||
return
|
||
}
|
||
|
||
txt := chat.Sanitize(strings.Trim(data, "\n "))
|
||
if len(txt) > 0 {
|
||
chat.AddChatReply(gid, txt)
|
||
nick := zero.BotConfig.NickName[rand.Intn(len(zero.BotConfig.NickName))]
|
||
txt = strings.ReplaceAll(txt, "{name}", ctx.CardOrNickName(ctx.Event.UserID))
|
||
txt = strings.ReplaceAll(txt, "{me}", nick)
|
||
id := any(nil)
|
||
if ctx.Event.IsToMe {
|
||
id = ctx.Event.MessageID
|
||
}
|
||
for _, t := range strings.Split(txt, "{segment}") {
|
||
if t == "" {
|
||
continue
|
||
}
|
||
logrus.Infoln("[aichat] 回复内容:", t)
|
||
recCfg := airecord.GetConfig()
|
||
record := ""
|
||
if !fastfailnorecord && !stor.NoRecord() {
|
||
record = ctx.GetAIRecord(recCfg.ModelID, recCfg.Customgid, t)
|
||
if record != "" {
|
||
ctx.SendChain(message.Record(record))
|
||
continue
|
||
}
|
||
fastfailnorecord = true
|
||
}
|
||
if id != nil {
|
||
id = ctx.SendChain(message.Reply(id), message.Text(t))
|
||
} else {
|
||
id = ctx.SendChain(message.Text(t))
|
||
}
|
||
process.SleepAbout1sTo2s()
|
||
}
|
||
}
|
||
})
|
||
}
|