diff --git a/README.md b/README.md index 70361326..480fb0b6 100644 --- a/README.md +++ b/README.md @@ -1633,12 +1633,12 @@ print("run[CQ:image,file="+j["img"]+"]") - [x] 设置AI聊天触发概率10 - [x] 设置AI聊天温度80 - - [x] 设置AI聊天(识图)接口类型[OpenAI|OLLaMA|GenAI] + - [x] 设置AI聊天(识图|Agent)接口类型[OpenAI|OLLaMA|GenAI] - [x] 设置AI聊天(不)使用Agent模式 - [x] 设置AI聊天(不)支持系统提示词 - - [x] 设置AI聊天(识图)接口地址https://api.siliconflow.cn/v1/chat/completions - - [x] 设置AI聊天(识图)密钥xxx - - [x] 设置AI聊天(识图)模型名Qwen/Qwen3-8B + - [x] 设置AI聊天(识图|Agent)接口地址https://api.siliconflow.cn/v1/chat/completions + - [x] 设置AI聊天(识图|Agent)密钥xxx + - [x] 设置AI聊天(识图|Agent)模型名Qwen/Qwen3-8B - [x] 查看AI聊天系统提示词 - [x] 重置AI聊天系统提示词 - [x] 设置AI聊天系统提示词xxx diff --git a/go.mod b/go.mod index fdd95de0..c06fe32e 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.20250925155009-638ed762e15e + github.com/FloatTech/zbputils v1.7.2-0.20250926153026-d616e2b87477 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 @@ -24,7 +24,7 @@ require ( github.com/fumiama/cron v1.3.0 github.com/fumiama/deepinfra v0.0.0-20250924162107-cf156d49a0fa github.com/fumiama/go-base16384 v1.7.0 - github.com/fumiama/go-onebot-agent v0.0.0-20250925171858-9c2cb926ec95 + github.com/fumiama/go-onebot-agent v0.0.0-20250926145606-37ebfa6131c8 github.com/fumiama/go-registry v0.2.7 github.com/fumiama/gotracemoe v0.0.3 github.com/fumiama/jieba v0.0.0-20221203025406-36c17a10b565 diff --git a/go.sum b/go.sum index 7d537bba..dd1a66e1 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.20250925155009-638ed762e15e h1:M+pIxQFztHqrtUVmfctSs/D5ytn0ag6twP6iJg3gdEk= -github.com/FloatTech/zbputils v1.7.2-0.20250925155009-638ed762e15e/go.mod h1:AUDxqs7liBF2H7TpSs+OXZj1Akyh0moUN/J/j8iNFxc= +github.com/FloatTech/zbputils v1.7.2-0.20250926153026-d616e2b87477 h1:T1ugPphuYnLUWvJOw0S200p2tjM2rzVdwIz76rtGt8E= +github.com/FloatTech/zbputils v1.7.2-0.20250926153026-d616e2b87477/go.mod h1:hIXcVZ3CFiL3dnM1QcZUMCjKhVryYY0EnJVN0kicB9A= 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= @@ -63,8 +63,8 @@ github.com/fumiama/deepinfra v0.0.0-20250924162107-cf156d49a0fa h1:UMMNejpPp8dn9 github.com/fumiama/deepinfra v0.0.0-20250924162107-cf156d49a0fa/go.mod h1:uqsWK/GM9OvKV0pXZOQB63rWugBbiXInY8E1JoRKhkg= 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-onebot-agent v0.0.0-20250925171858-9c2cb926ec95 h1:ZIS5BF51BkRhwfxmEVdn5mdoH1AKKFodwqpRJWl4mWs= -github.com/fumiama/go-onebot-agent v0.0.0-20250925171858-9c2cb926ec95/go.mod h1:FIhZxVeFAs201W06EgXxx/6b/l/ETSmu2sQOj10kjdk= +github.com/fumiama/go-onebot-agent v0.0.0-20250926145606-37ebfa6131c8 h1:aXk5IVXvPy2IfajL6gH+V/6ZOVV1BBVKjnFISLvyw60= +github.com/fumiama/go-onebot-agent v0.0.0-20250926145606-37ebfa6131c8/go.mod h1:oH8DGDpRPjUAu8Fd/K+RxsB+z0Yis+BHeJAh+ZkO5EM= github.com/fumiama/go-registry v0.2.7 h1:tLEqgEpsiybQMqBv0dLHm5leia/z1DhajMupwnOHeNs= github.com/fumiama/go-registry v0.2.7/go.mod h1:m+wp5fF8dYgVoFkBPZl+vlK90loymaJE0JCtocVQLEs= github.com/fumiama/go-simple-protobuf v0.2.0 h1:ACyN1MAlu7pDR3EszWgzUeNP+IRsSHwH6V9JCJA5R5o= diff --git a/plugin/aichat/cfg.go b/plugin/aichat/cfg.go index 14b2bc0f..be34967b 100644 --- a/plugin/aichat/cfg.go +++ b/plugin/aichat/cfg.go @@ -93,17 +93,20 @@ func (mk ModelKey) String() string { type config struct { ModelName string ImageModelName string + AgentModelName string Type ModelType ImageType ModelType + AgentType ModelType MaxN uint TopP float32 SystemP string API string ImageAPI string + AgentAPI string Key ModelKey ImageKey ModelKey + AgentKey ModelKey Separator string - NoReplyAT ModelBool NoSystemP ModelBool } @@ -130,7 +133,6 @@ func (c *config) String() string { sb.WriteString(fmt.Sprintf("• 密钥:%v\n", c.Key)) sb.WriteString(fmt.Sprintf("• 图像密钥:%v\n", c.ImageKey)) sb.WriteString(fmt.Sprintf("• 分隔符:%s\n", c.Separator)) - sb.WriteString(fmt.Sprintf("• 响应@:%v\n", !c.NoReplyAT)) sb.WriteString(fmt.Sprintf("• 支持系统提示词:%v\n", !c.NoSystemP)) return sb.String() } @@ -267,3 +269,30 @@ func newextrasetfloat32(ptr *float32) func(ctx *zero.Ctx) { ctx.SendChain(message.Text("成功")) } } + +func newextrasetmodeltype(ptr *ModelType) func(ctx *zero.Ctx) { + return func(ctx *zero.Ctx) { + args := strings.TrimSpace(ctx.State["args"].(string)) + if args == "" { + ctx.SendChain(message.Text("ERROR: empty args")) + return + } + c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]) + if !ok { + ctx.SendChain(message.Text("ERROR: no such plugin")) + return + } + typ, err := newModelType(args) + if err != nil { + ctx.SendChain(message.Text("ERROR: ", err)) + return + } + *ptr = typ + err = c.SetExtra(&cfg) + if err != nil { + ctx.SendChain(message.Text("ERROR: set extra err: ", err)) + return + } + ctx.SendChain(message.Text("成功")) + } +} diff --git a/plugin/aichat/main.go b/plugin/aichat/main.go index d7eead7d..49cc8a79 100644 --- a/plugin/aichat/main.go +++ b/plugin/aichat/main.go @@ -34,12 +34,12 @@ var ( Brief: "OpenAI聊天", Help: "- 设置AI聊天触发概率10\n" + "- 设置AI聊天温度80\n" + - "- 设置AI聊天(识图)接口类型[OpenAI|OLLaMA|GenAI]\n" + + "- 设置AI聊天(识图|Agent)接口类型[OpenAI|OLLaMA|GenAI]\n" + "- 设置AI聊天(不)使用Agent模式\n" + "- 设置AI聊天(不)支持系统提示词\n" + - "- 设置AI聊天(识图)接口地址https://api.siliconflow.cn/v1/chat/completions\n" + - "- 设置AI聊天(识图)密钥xxx\n" + - "- 设置AI聊天(识图)模型名Qwen/Qwen3-8B\n" + + "- 设置AI聊天(识图|Agent)接口地址https://api.siliconflow.cn/v1/chat/completions\n" + + "- 设置AI聊天(识图|Agent)密钥xxx\n" + + "- 设置AI聊天(识图|Agent)模型名Qwen/Qwen3-8B\n" + "- 查看AI聊天系统提示词\n" + "- 重置AI聊天系统提示词\n" + "- 设置AI聊天系统提示词xxx\n" + @@ -71,9 +71,6 @@ var ( func init() { en.OnMessage(ensureconfig, func(ctx *zero.Ctx) bool { - return ctx.ExtractPlainText() != "" && - (bool(!cfg.NoReplyAT) || (bool(cfg.NoReplyAT) && !ctx.Event.IsToMe)) - }).SetBlock(false).Handle(func(ctx *zero.Ctx) { gid := ctx.Event.GroupID if gid == 0 { gid = -ctx.Event.UserID @@ -81,8 +78,17 @@ func init() { stor, err := newstorage(ctx, gid) if err != nil { logrus.Warnln("ERROR: ", err) - return + return false } + ctx.State["__aichat_stor__"] = stor + return ctx.ExtractPlainText() != "" && + (bool(!stor.noreplyat()) || (bool(stor.noreplyat()) && !ctx.Event.IsToMe)) + }).SetBlock(false).Handle(func(ctx *zero.Ctx) { + gid := ctx.Event.GroupID + if gid == 0 { + gid = -ctx.Event.UserID + } + stor := ctx.State["__aichat_stor__"].(storage) rate := stor.rate() if !ctx.Event.IsToMe && rand.Intn(100) >= int(rate) { return @@ -97,14 +103,13 @@ func init() { temperature := stor.temp() topp, maxn := cfg.mparams() - x := deepinfra.NewAPI(cfg.API, string(cfg.Key)) - mod, err := cfg.Type.protocol(cfg.ModelName, temperature, topp, maxn) - if err != nil { - logrus.Warnln("ERROR: ", err) - return - } - if !stor.noagent() { + x := deepinfra.NewAPI(cfg.AgentAPI, string(cfg.AgentKey)) + mod, err := cfg.Type.protocol(cfg.AgentModelName, temperature, topp, maxn) + if err != nil { + logrus.Warnln("ERROR: ", err) + return + } role := goba.PermRoleUser if zero.AdminPermission(ctx) { role = goba.PermRoleAdmin @@ -123,15 +128,10 @@ func init() { } ctx.NoTimeout() hasresp := false - defer func() { - if hasresp { - ag.AddTerminus(gid) - } - }() for i := 0; i < 8; i++ { // 最大运行 8 轮因为问答上下文只有 16 reqs := chat.CallAgent(ag, zero.SuperUserPermission(ctx), x, mod, gid, role) if len(reqs) == 0 { - return + break } hasresp = true for _, req := range reqs { @@ -146,9 +146,19 @@ func init() { }) } } - return + if hasresp { + ag.AddTerminus(gid) + return + } + // no response, fall back to normal chat } + x := deepinfra.NewAPI(cfg.API, string(cfg.Key)) + mod, err := cfg.Type.protocol(cfg.ModelName, temperature, topp, maxn) + if err != nil { + logrus.Warnln("ERROR: ", err) + return + } data, err := x.Request(chat.GetChatContext(mod, gid, cfg.SystemP, bool(cfg.NoSystemP))) if err != nil { logrus.Warnln("[aichat] post err:", err) @@ -188,68 +198,34 @@ func init() { } } }) - en.OnPrefix("设置AI聊天触发概率", zero.AdminPermission).SetBlock(true).Handle(newstoragebitmap(bitmaprate, 0, 100)) - en.OnPrefix("设置AI聊天温度", zero.AdminPermission).SetBlock(true).Handle(newstoragebitmap(bitmaptemp, 0, 100)) - en.OnPrefix("设置AI聊天接口类型", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) { - args := strings.TrimSpace(ctx.State["args"].(string)) - if args == "" { - ctx.SendChain(message.Text("ERROR: empty args")) - return - } - c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]) - if !ok { - ctx.SendChain(message.Text("ERROR: no such plugin")) - return - } - typ, err := newModelType(args) - if err != nil { - ctx.SendChain(message.Text("ERROR: ", err)) - return - } - cfg.Type = typ - err = c.SetExtra(&cfg) - if err != nil { - ctx.SendChain(message.Text("ERROR: set extra err: ", err)) - return - } - ctx.SendChain(message.Text("成功")) - }) - en.OnPrefix("设置AI聊天识图接口类型", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) { - args := strings.TrimSpace(ctx.State["args"].(string)) - if args == "" { - ctx.SendChain(message.Text("ERROR: empty args")) - return - } - c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]) - if !ok { - ctx.SendChain(message.Text("ERROR: no such plugin")) - return - } - typ, err := newModelType(args) - if err != nil { - ctx.SendChain(message.Text("ERROR: ", err)) - return - } - cfg.ImageType = typ - err = c.SetExtra(&cfg) - if err != nil { - ctx.SendChain(message.Text("ERROR: set extra err: ", err)) - return - } - ctx.SendChain(message.Text("成功")) - }) + en.OnPrefix("设置AI聊天触发概率", zero.AdminPermission).SetBlock(true). + Handle(ctxext.NewStorageSaveBitmapHandler(bitmaprate, 0, 100)) + en.OnPrefix("设置AI聊天温度", zero.AdminPermission).SetBlock(true). + Handle(ctxext.NewStorageSaveBitmapHandler(bitmaptemp, 0, 100)) + en.OnPrefix("设置AI聊天接口类型", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). + Handle(newextrasetmodeltype(&cfg.Type)) + en.OnPrefix("设置AI聊天识图接口类型", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). + Handle(newextrasetmodeltype(&cfg.ImageType)) + en.OnPrefix("设置AI聊天Agent接口类型", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). + Handle(newextrasetmodeltype(&cfg.AgentType)) en.OnPrefix("设置AI聊天接口地址", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). Handle(newextrasetstr(&cfg.API)) en.OnPrefix("设置AI聊天识图接口地址", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). Handle(newextrasetstr(&cfg.ImageAPI)) + en.OnPrefix("设置AI聊天Agent接口地址", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). + Handle(newextrasetstr(&cfg.AgentAPI)) en.OnPrefix("设置AI聊天密钥", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). Handle(newextrasetstr(&cfg.Key)) en.OnPrefix("设置AI聊天识图密钥", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). Handle(newextrasetstr(&cfg.ImageKey)) + en.OnPrefix("设置AI聊天Agent密钥", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). + Handle(newextrasetstr(&cfg.ImageKey)) en.OnPrefix("设置AI聊天模型名", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). Handle(newextrasetstr(&cfg.ModelName)) en.OnPrefix("设置AI聊天识图模型名", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). Handle(newextrasetstr(&cfg.ImageModelName)) + en.OnPrefix("设置AI聊天Agent模型名", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). + Handle(newextrasetstr(&cfg.ImageModelName)) en.OnPrefix("设置AI聊天系统提示词", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). Handle(newextrasetstr(&cfg.SystemP)) en.OnFullMatch("查看AI聊天系统提示词", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) { @@ -272,17 +248,17 @@ func init() { en.OnPrefix("设置AI聊天分隔符", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). Handle(newextrasetstr(&cfg.Separator)) en.OnRegex("^设置AI聊天(不)?响应AT$", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). - Handle(newextrasetbool(&cfg.NoReplyAT)) + Handle(ctxext.NewStorageSaveBoolHandler(bitmapnrat)) en.OnRegex("^设置AI聊天(不)?支持系统提示词$", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). Handle(newextrasetbool(&cfg.NoSystemP)) en.OnRegex("^设置AI聊天(不)?使用Agent模式$", ensureconfig, zero.SuperUserPermission).SetBlock(true). - Handle(newstoragebool(bitmapnagt)) + Handle(ctxext.NewStorageSaveBoolHandler(bitmapnagt)) en.OnPrefix("设置AI聊天最大长度", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). Handle(newextrasetuint(&cfg.MaxN)) en.OnPrefix("设置AI聊天TopP", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). Handle(newextrasetfloat32(&cfg.TopP)) en.OnRegex("^设置AI聊天(不)?以AI语音输出$", ensureconfig, zero.AdminPermission).SetBlock(true). - Handle(newstoragebool(bitmapnrec)) + Handle(ctxext.NewStorageSaveBoolHandler(bitmapnrec)) en.OnFullMatch("查看AI聊天配置", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true). Handle(func(ctx *zero.Ctx) { gid := ctx.Event.GroupID @@ -298,6 +274,7 @@ func init() { "• 温度:", stor.temp(), "\n", "• 以AI语音输出:", ModelBool(!stor.norecord()), "\n", "• 使用Agent:", ModelBool(!stor.noagent()), "\n", + "• 响应@:", ModelBool(!stor.noreplyat()), "\n", ), message.Text("【当前AI聊天全局配置】\n", &cfg), ) diff --git a/plugin/aichat/storage.go b/plugin/aichat/storage.go index 0e7f79e2..c12a9587 100644 --- a/plugin/aichat/storage.go +++ b/plugin/aichat/storage.go @@ -1,14 +1,8 @@ package aichat import ( - "errors" - "math/bits" - "strconv" - "strings" - - ctrl "github.com/FloatTech/zbpctrl" + "github.com/FloatTech/zbputils/ctxext" zero "github.com/wdvxdr1123/ZeroBot" - "github.com/wdvxdr1123/ZeroBot/message" ) const ( @@ -16,46 +10,22 @@ const ( bitmaptemp = 0x00ff00 bitmapnagt = 0x010000 bitmapnrec = 0x020000 + bitmapnrat = 0x040000 ) -type storage int64 +type storage ctxext.Storage func newstorage(ctx *zero.Ctx, gid int64) (storage, error) { - c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]) - if !ok { - return 0, errors.New("找不到 manager") - } - x := c.GetData(gid) - return storage(x), nil -} - -func (s storage) saveto(ctx *zero.Ctx, gid int64) error { - c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]) - if !ok { - return errors.New("找不到 manager") - } - return c.SetData(int64(s), gid) -} - -func (s storage) getbybmp(bmp int64) int64 { - sft := bits.TrailingZeros64(uint64(bmp)) - return (int64(s) & bmp) >> int64(sft) -} - -func (s *storage) setbybmp(x int64, bmp int64) { - if bmp == 0 { - panic("cannot use bmp == 0") - } - sft := bits.TrailingZeros64(uint64(bmp)) - *s = storage((int64(*s) & (^bmp)) | ((x & bmp) << int64(sft))) + s, err := ctxext.NewStorage(ctx, gid) + return storage(s), err } func (s storage) rate() uint8 { - return uint8(s.getbybmp(bitmaprate)) + return uint8((ctxext.Storage)(s).Get(bitmaprate)) } func (s storage) temp() float32 { - temp := s.getbybmp(bitmaptemp) + temp := (ctxext.Storage)(s).Get(bitmaptemp) // 处理温度参数 if temp <= 0 { temp = 70 // default setting @@ -67,75 +37,13 @@ func (s storage) temp() float32 { } func (s storage) noagent() bool { - return s.getbybmp(bitmapnagt) != 0 + return (ctxext.Storage)(s).GetBool(bitmapnagt) } func (s storage) norecord() bool { - return s.getbybmp(bitmapnrec) != 0 + return (ctxext.Storage)(s).GetBool(bitmapnrec) } -func newstoragebitmap(bmp int64, minv, maxv int64) func(ctx *zero.Ctx) { - return func(ctx *zero.Ctx) { - args := strings.TrimSpace(ctx.State["args"].(string)) - if args == "" { - ctx.SendChain(message.Text("ERROR: empty args")) - return - } - r, err := strconv.ParseInt(args, 10, 64) - if err != nil { - ctx.SendChain(message.Text("ERROR: parse int64 err: ", err)) - return - } - if r > maxv { - r = maxv - } else if r < minv { - r = minv - } - gid := ctx.Event.GroupID - if gid == 0 { - gid = -ctx.Event.UserID - } - stor, err := newstorage(ctx, gid) - if err != nil { - ctx.SendChain(message.Text("ERROR: ", err)) - return - } - stor.setbybmp(r, bmp) - err = stor.saveto(ctx, gid) - if err != nil { - ctx.SendChain(message.Text("ERROR: set data err: ", err)) - return - } - ctx.SendChain(message.Text("成功")) - } -} - -func newstoragebool(bmp int64) func(ctx *zero.Ctx) { - if bits.OnesCount64(uint64(bmp)) != 1 { - panic("bool bmp must be 1-bit-long") - } - return func(ctx *zero.Ctx) { - args := ctx.State["regex_matched"].([]string) - isone := args[1] == "不" - gid := ctx.Event.GroupID - if gid == 0 { - gid = -ctx.Event.UserID - } - stor, err := newstorage(ctx, gid) - if err != nil { - ctx.SendChain(message.Text("ERROR: ", err)) - return - } - v := 0 - if isone { - v = 1 - } - stor.setbybmp(int64(v), bmp) - err = stor.saveto(ctx, gid) - if err != nil { - ctx.SendChain(message.Text("ERROR: set data err: ", err)) - return - } - ctx.SendChain(message.Text("成功")) - } +func (s storage) noreplyat() bool { + return (ctxext.Storage)(s).GetBool(bitmapnrat) }