diff --git a/airecord/record.go b/airecord/record.go new file mode 100644 index 0000000..ac841d6 --- /dev/null +++ b/airecord/record.go @@ -0,0 +1,127 @@ +// Package airecord 群应用:AI声聊 +package airecord + +import ( + "strconv" + "strings" + "time" + + "github.com/sirupsen/logrus" + "github.com/tidwall/gjson" + + zero "github.com/wdvxdr1123/ZeroBot" + "github.com/wdvxdr1123/ZeroBot/message" + + ctrl "github.com/FloatTech/zbpctrl" + "github.com/FloatTech/zbputils/control" +) + +func init() { + if err := loadConfig(); err != nil { + logrus.Warnln("WARN: 加载配置文件失败,使用默认配置:", err) + } else { + logrus.Infoln("成功从文件加载语音记录配置") + } + en := control.AutoRegister(&ctrl.Options[*zero.Ctx]{ + DisableOnDefault: false, + Extra: control.ExtraFromString("airecord"), + Brief: "群应用:AI声聊", + Help: "- 设置AI语音群号1048452984(tips:机器人任意所在群聊即可)\n" + + "- 设置AI语音模型\n" + + "- 查看AI语音配置\n" + + "- 发送AI语音xxx", + PrivateDataFolder: "airecord", + }) + + en.OnPrefix("设置AI语音群号", zero.SuperUserPermission).SetBlock(true). + Handle(func(ctx *zero.Ctx) { + u := strings.TrimSpace(ctx.State["args"].(string)) + num, err := strconv.ParseInt(u, 10, 64) + if err != nil { + ctx.SendChain(message.Text("ERROR: parse gid err: ", err)) + return + } + setCustomGID(num) + ctx.SendChain(message.Text("设置AI语音群号为", num)) + }) + en.OnFullMatch("设置AI语音模型", zero.SuperUserPermission).SetBlock(true). + Handle(func(ctx *zero.Ctx) { + next := zero.NewFutureEvent("message", 999, false, ctx.CheckSession()) + recv, cancel := next.Repeat() + defer cancel() + jsonData := ctx.GetAICharacters(0, 1) + + // 转换为字符串数组 + var names []string + // 初始化两个映射表 + nameToID := make(map[string]string) + nameToURL := make(map[string]string) + characters := jsonData.Get("#.characters") + + // 遍历每个角色对象 + characters.ForEach(func(_, group gjson.Result) bool { + group.ForEach(func(_, character gjson.Result) bool { + // 提取当前角色的三个字段 + name := character.Get("character_name").String() + names = append(names, name) + // 存入映射表(重复名称会覆盖,保留最后出现的条目) + nameToID[name] = character.Get("character_id").String() + nameToURL[name] = character.Get("preview_url").String() + return true // 继续遍历 + }) + return true // 继续遍历 + }) + var builder strings.Builder + // 写入开头文本 + builder.WriteString("请选择语音模型序号:\n") + + // 遍历names数组,拼接序号和名称 + for i, v := range names { + // 将数字转换为字符串(不依赖fmt) + numStr := strconv.Itoa(i) + // 拼接格式:"序号. 名称\n" + builder.WriteString(numStr) + builder.WriteString(". ") + builder.WriteString(v) + builder.WriteString("\n") + } + // 获取最终字符串 + ctx.SendChain(message.Text(builder.String())) + for { + select { + case <-time.After(time.Second * 120): + ctx.SendChain(message.Text("设置AI语音模型指令过期")) + return + case ct := <-recv: + msg := ct.Event.Message.ExtractPlainText() + num, err := strconv.Atoi(msg) + if err != nil { + ctx.SendChain(message.Text("请输入数字!")) + continue + } + if num < 0 || num >= len(names) { + ctx.SendChain(message.Text("序号非法!")) + continue + } + setRecordModel(names[num], nameToID[names[num]]) + ctx.SendChain(message.Text("已选择语音模型: ", names[num])) + ctx.SendChain(message.Record(nameToURL[names[num]])) + return + } + } + }) + en.OnFullMatch("查看AI语音配置").SetBlock(true). + Handle(func(ctx *zero.Ctx) { + ctx.SendChain(message.Text(printRecordConfig(recordcfg))) + }) + en.OnPrefix("发送AI语音").SetBlock(true). + Handle(func(ctx *zero.Ctx) { + u := strings.TrimSpace(ctx.State["args"].(string)) + record := ctx.GetAIRecord(recordcfg.ModelID, recordcfg.Customgid, u).String() + if record == "" { + ctx.SendChain(message.Text("ERROR: get record err: empty record")) + return + } + ctx.SendChain(message.Record(record)) + }) +} diff --git a/airecord/recordcfg.go b/airecord/recordcfg.go new file mode 100644 index 0000000..247d241 --- /dev/null +++ b/airecord/recordcfg.go @@ -0,0 +1,79 @@ +package airecord + +import ( + "encoding/json" + "fmt" + "os" + "strings" + + "github.com/sirupsen/logrus" +) + +var ( + recordcfg recordconfig + configPath = "data/airecord/recordconfig.json" // 配置文件路径 +) + +// recordconfig 存储语音记录相关配置 +type recordconfig struct { + ModelName string `json:"modelName"` // 语音模型名称 + ModelID string `json:"modelID"` // 语音模型ID + Customgid int64 `json:"customgid"` // 自定义群ID +} + +// GetRecordConfig 返回当前语音记录配置信息 +func GetRecordConfig() recordconfig { + return recordcfg +} + +// setRecordModel 设置语音记录模型 +func setRecordModel(modelName, modelID string) { + recordcfg.ModelName = modelName + recordcfg.ModelID = modelID + saveConfig() // 保存配置 +} + +// setCustomGID 设置自定义群ID +func setCustomGID(gid int64) { + recordcfg.Customgid = gid + saveConfig() // 保存配置 +} + +// printRecordConfig 生成格式化的语音记录配置信息字符串 +func printRecordConfig(recCfg recordconfig) string { + var builder strings.Builder + builder.WriteString("当前语音记录配置:\n") + builder.WriteString(fmt.Sprintf("• 语音模型名称:%s\n", recCfg.ModelName)) + builder.WriteString(fmt.Sprintf("• 语音模型ID:%s\n", recCfg.ModelID)) + builder.WriteString(fmt.Sprintf("• 自定义群ID:%d\n", recCfg.Customgid)) + return builder.String() +} + +// saveConfig 将配置保存到JSON文件 +func saveConfig() error { + data, err := json.MarshalIndent(recordcfg, "", " ") + if err != nil { + logrus.Warnln("ERROR: 序列化配置失败:", err) + return err + } + err = os.WriteFile(configPath, data, 0644) + if err != nil { + logrus.Warnln("ERROR: 写入配置文件失败:", err) + return err + } + return nil +} + +// loadConfig 从JSON文件加载配置 +func loadConfig() error { + data, err := os.ReadFile(configPath) + if err != nil { + return err + } + err = json.Unmarshal(data, &recordcfg) + if err != nil { + logrus.Warnln("ERROR: 解析配置文件失败:", err) + return err + } + return nil +} diff --git a/driver/funcall.go b/driver/funcall.go index 2043f05..0b9454e 100644 --- a/driver/funcall.go +++ b/driver/funcall.go @@ -162,7 +162,7 @@ func (f *FCClient) handleRequest(req *zero.APIRequest) (r *zero.APIResponse, err r = &zero.APIResponse{ // 发送api调用响应 Status: s, Data: data.Get("data"), - Msg: m, + Message: m, Wording: w, RetCode: c, Echo: req.Echo,