From cf1be44c9ea3091840c1b72e839b69b85d428b5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=AF=BB=E6=AC=A2?= Date: Sat, 17 Aug 2024 13:10:31 +0800 Subject: [PATCH 1/3] =?UTF-8?q?:new:=20=E6=96=B0=E5=A2=9E`=E6=AF=8F?= =?UTF-8?q?=E6=97=A5=E5=85=8D=E8=B4=B9AI=E5=AF=B9=E8=AF=9D=E6=AC=A1?= =?UTF-8?q?=E6=95=B0=E9=99=90=E5=88=B6`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/friend.go | 23 +++++++++++++++++++++++ config.yaml | 2 ++ config/system.go | 13 +++++++------ model/entity/friend.go | 2 ++ model/vo/friend.go | 2 ++ plugin/plugins/ai.go | 19 +++++++++++++++---- router/router.go | 1 + service/friend.go | 22 ++++++++++++++++++++++ tasks/friends/ai.go | 9 +++++++++ tasks/friends/friends.go | 1 + tasks/tasks.go | 2 ++ utils/send.go | 7 +++++-- views/friend.html | 20 ++++++++++++++++++++ views/group.html | 23 +++++++++++++++++++++-- views/static/js/index.js | 26 ++++++++++++++++++++++++++ 15 files changed, 158 insertions(+), 14 deletions(-) create mode 100644 tasks/friends/ai.go diff --git a/app/friend.go b/app/friend.go index 42b549c..52040a9 100644 --- a/app/friend.go +++ b/app/friend.go @@ -280,3 +280,26 @@ func AutoClearMembers(ctx *gin.Context) { ctx.String(http.StatusOK, "操作成功") } + +// ChangeAiFreeLimit +// @description: 修改AI免费次数 +// @param ctx +func ChangeAiFreeLimit(ctx *gin.Context) { + var p autoClearMembers + if err := ctx.ShouldBindJSON(&p); err != nil { + ctx.String(http.StatusBadRequest, "参数错误") + return + } + log.Printf("待修改的Id:%s", p.WxId) + + err := client.MySQL.Model(&entity.Friend{}). + Where("wxid = ?", p.WxId). + Update("`ai_free_limit`", p.Days).Error + if err != nil { + log.Printf("修改AI免费次数失败:%s", err) + ctx.String(http.StatusInternalServerError, "操作失败: %s", err) + return + } + + ctx.String(http.StatusOK, "操作成功") +} diff --git a/config.yaml b/config.yaml index 2c02051..47e6274 100644 --- a/config.yaml +++ b/config.yaml @@ -25,6 +25,8 @@ system: news: true # 热榜 hotTop: true + # 每天免费 AI 次数限制 + aiFreeLimit: 50 # 微信HOOK配置 wechat: diff --git a/config/system.go b/config/system.go index d9475e4..f6d9656 100644 --- a/config/system.go +++ b/config/system.go @@ -16,10 +16,11 @@ type newFriendNotify struct { // 默认规则 type defaultRule struct { - Ai bool `json:"ai" yaml:"ai"` // 是否启用AI - ChatRank bool `json:"chatRank" yaml:"chatRank"` // 是否启用聊天排行榜 - Summary bool `json:"summary" yaml:"summary"` // 是否启用聊天总结 - Welcome bool `json:"welcome" yaml:"welcome"` // 是否启用欢迎新成员 - News bool `json:"news" yaml:"news"` // 是否启用每日早报 - HotTop bool `json:"hotTop" yaml:"hotTop"` // 是否启用热门话题 + Ai bool `json:"ai" yaml:"ai"` // 是否启用AI + ChatRank bool `json:"chatRank" yaml:"chatRank"` // 是否启用聊天排行榜 + Summary bool `json:"summary" yaml:"summary"` // 是否启用聊天总结 + Welcome bool `json:"welcome" yaml:"welcome"` // 是否启用欢迎新成员 + News bool `json:"news" yaml:"news"` // 是否启用每日早报 + HotTop bool `json:"hotTop" yaml:"hotTop"` // 是否启用热门话题 + AiFreeLimit int `json:"aiFreeLimit" yaml:"aiFreeLimit"` // AI免费次数 } diff --git a/model/entity/friend.go b/model/entity/friend.go index 95a0fc5..f892b1d 100644 --- a/model/entity/friend.go +++ b/model/entity/friend.go @@ -25,6 +25,8 @@ type Friend struct { ClearMember int `json:"clearMember"` // 清理成员配置(多少天未活跃的) IsOk bool `json:"isOk" gorm:"type:tinyint(1) default 0 not null"` // 是否正常 UsedTokens int `json:"usedTokens"` // 已使用的AI Token数量 + AiFreeLimit int `json:"aiFreeLimit"` // AI免费次数 + AiUsedToday int `json:"aiUsedToday"` // 今日已使用的AI次数 } func (Friend) TableName() string { diff --git a/model/vo/friend.go b/model/vo/friend.go index d51420d..280b7c1 100644 --- a/model/vo/friend.go +++ b/model/vo/friend.go @@ -24,6 +24,8 @@ type FriendItem struct { EnableHotTop bool // 是否启用热搜 ClearMember int // 清理成员配置(多少天未活跃的) IsOk bool // 是否还在通讯库(群聊是要还在群里也算) + AiFreeLimit int // AI免费次数 + AiUsedToday int // 今日已使用的AI次数 } // GroupUserItem diff --git a/plugin/plugins/ai.go b/plugin/plugins/ai.go index 7ab5ee6..7d907b0 100644 --- a/plugin/plugins/ai.go +++ b/plugin/plugins/ai.go @@ -37,6 +37,17 @@ func AI(m *plugin.MessageContext) { if !friendInfo.EnableAi { return } + if friendInfo.AiUsedToday > 0 && friendInfo.AiUsedToday >= friendInfo.AiFreeLimit { + _ = utils.SendMessage(m.FromUser, "", fmt.Sprintf("本群今天的免费次数已经用完啦,明天再来找我聊天吧~\n每天限制%d次,0点自动重置", friendInfo.AiFreeLimit), 0) + return + } + + var err error + defer func() { + if err == nil { + service.UpdateAiUsedToday(m.FromUser) + } + }() // 预处理一下发送的消息,用正则去掉@机器人的内容 re := regexp.MustCompile(`@([^ | ]+)`) @@ -132,17 +143,17 @@ func AI(m *plugin.MessageContext) { if err != nil { log.Printf("OpenAI聊天发起失败: %v", err.Error()) - utils.SendMessage(m.FromUser, m.GroupUser, "AI聊天初始化失败,我已经通知我主人来修啦,请稍候一下下喔~", 0) + _ = utils.SendMessage(m.FromUser, m.GroupUser, "AI聊天初始化失败,我已经通知我主人来修啦,请稍候一下下喔~", 0) return } // 返回消息为空 if len(resp.Choices) == 0 || resp.Choices[0].Message.Content == "" { - utils.SendMessage(m.FromUser, m.GroupUser, "AI似乎抽风了,没有告诉我你需要的回答~", 0) + _ = utils.SendMessage(m.FromUser, m.GroupUser, "AI似乎抽风了,没有告诉我你需要的回答~", 0) return } - // 异步更新一下已使用的AI次数 + // 异步更新一下已使用的AI tokens go service.UpdateUsedAiTokens(m.FromUser, resp.Usage.TotalTokens) // 保存一下AI 返回的消息,消息 Id 使用传入 Id 的负数 @@ -162,7 +173,7 @@ func AI(m *plugin.MessageContext) { if m.GroupUser != "" { replyMsg = "\n" + resp.Choices[0].Message.Content } - utils.SendMessage(m.FromUser, m.GroupUser, replyMsg, 0) + err = utils.SendMessage(m.FromUser, m.GroupUser, replyMsg, 0) } // getGroupUserMessages diff --git a/router/router.go b/router/router.go index 90a05a9..a88367d 100644 --- a/router/router.go +++ b/router/router.go @@ -26,6 +26,7 @@ func Init(g *gin.Engine) { api := g.Group("/api") api.PUT("/ai/status", app.ChangeEnableAiStatus) // 修改是否开启AI状态 api.POST("/ai/model", app.ChangeUseAiModel) // 修改使用的AI模型 + api.POST("/ai/free", app.ChangeAiFreeLimit) // 修改AI免费次数 api.POST("/ai/assistant", app.ChangeUseAiAssistant) // 修改使用的AI助手 api.PUT("/welcome/status", app.ChangeEnableWelcomeStatus) // 修改是否开启迎新状态 api.PUT("/command/status", app.ChangeEnableCommandStatus) // 修改是否开启指令状态 diff --git a/service/friend.go b/service/friend.go index d02b2ee..fc18892 100644 --- a/service/friend.go +++ b/service/friend.go @@ -152,3 +152,25 @@ func UpdateUsedAiTokens(wxId string, tokens int) { log.Printf("更新AI使用次数失败, 错误信息: %v", err) } } + +// UpdateAiUsedToday +// @description: 更新AI今日使用次数 +// @param wxId +func UpdateAiUsedToday(wxId string) { + err := client.MySQL.Model(&entity.Friend{}). + Where("wxid = ?", wxId). + Update("`ai_used_today`", gorm.Expr(" `ai_used_today` + 1")).Error + if err != nil { + log.Printf("更新AI今日使用次数失败, 错误信息: %v", err) + } +} + +// ClearAiUsedToday +// @description: 清空AI今日使用次数 +func ClearAiUsedToday() { + err := client.MySQL.Model(&entity.Friend{}). + Update("`ai_used_today`", 0).Error + if err != nil { + log.Printf("清空AI今日使用次数失败, 错误信息: %v", err) + } +} diff --git a/tasks/friends/ai.go b/tasks/friends/ai.go new file mode 100644 index 0000000..77acff4 --- /dev/null +++ b/tasks/friends/ai.go @@ -0,0 +1,9 @@ +package friends + +import "go-wechat/service" + +// ClearAiUsedToday +// @description: 清空AI日使用次数 +func ClearAiUsedToday() { + service.ClearAiUsedToday() +} diff --git a/tasks/friends/friends.go b/tasks/friends/friends.go index a371f7c..5db7af0 100644 --- a/tasks/friends/friends.go +++ b/tasks/friends/friends.go @@ -85,6 +85,7 @@ func Sync() { EnableWelcome: config.Conf.System.DefaultRule.Welcome, EnableNews: config.Conf.System.DefaultRule.News, EnableHotTop: config.Conf.System.DefaultRule.HotTop, + AiFreeLimit: config.Conf.System.DefaultRule.AiFreeLimit, ClearMember: 0, LastActive: types.DateTime(time.Now().Local()), }).Error diff --git a/tasks/tasks.go b/tasks/tasks.go index f441b32..d9c5cb9 100644 --- a/tasks/tasks.go +++ b/tasks/tasks.go @@ -65,6 +65,8 @@ func InitTasks() { // 每天0点检查一次处理清理群成员 _, _ = s.Cron("0 0 * * *").Do(cleargroupuser.ClearGroupUser) + // 每天0点清空AI日使用次数 + _, _ = s.Cron("0 0 * * *").Do(friends.ClearAiUsedToday) // 开启定时任务 s.StartAsync() diff --git a/utils/send.go b/utils/send.go index 5a4652b..6318072 100644 --- a/utils/send.go +++ b/utils/send.go @@ -2,6 +2,7 @@ package utils import ( "encoding/json" + "errors" "fmt" "github.com/go-resty/resty/v2" "go-wechat/common/current" @@ -15,9 +16,10 @@ import ( // @param toId // @param atId // @param msg -func SendMessage(toId, atId, msg string, retryCount int) { +func SendMessage(toId, atId, msg string, retryCount int) (err error) { if retryCount > 5 { log.Printf("重试五次失败,停止发送") + err = errors.New("重试五次失败,停止发送") return } @@ -48,9 +50,10 @@ func SendMessage(toId, atId, msg string, retryCount int) { log.Printf("发送文本消息失败: %s", err.Error()) // 休眠五秒后重新发送 time.Sleep(5 * time.Second) - SendMessage(toId, atId, msg, retryCount+1) + return SendMessage(toId, atId, msg, retryCount+1) } log.Printf("发送文本消息结果: %s", resp.String()) + return } // SendImage diff --git a/views/friend.html b/views/friend.html index 04c660d..7ec3c11 100644 --- a/views/friend.html +++ b/views/friend.html @@ -94,6 +94,26 @@ + + +
+
+ 每日 AI 免费次数 +
+
+
+ +
+ +
+
+
+
{{ end }}
diff --git a/views/group.html b/views/group.html index 3407bfc..a58ea39 100644 --- a/views/group.html +++ b/views/group.html @@ -73,8 +73,7 @@ + +
+ +
+
+ +
水群排行榜
diff --git a/views/static/js/index.js b/views/static/js/index.js index aad9170..02f8039 100644 --- a/views/static/js/index.js +++ b/views/static/js/index.js @@ -291,3 +291,29 @@ function changeClearMember(wxid, oldVal, newVal) { window.location.reload(); }) } + +// 修改每日免费 AI 对话次数 +function changeAiFreeLimit(wxid, limitNumber) { + limitNumber = Number(limitNumber) + + if (limitNumber < 0) { + alert('值不能小于0') + } + // 请求接口 + axios({ + method: 'post', + url: '/api/ai/free', + data: { + wxid: wxid, + days: Number(limitNumber) + } + }).then(function (response) { + console.log(`返回结果: ${JSON.stringify(response)}`); + alert(`${response.data}`) + }).catch(function (error) { + console.log(`错误信息: ${error}`); + alert("修改失败") + }).finally(function () { + window.location.reload(); + }) +} From e08ad4b438d10bb01af9276e1b16f048a57ecf13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=AF=BB=E6=AC=A2?= Date: Sat, 17 Aug 2024 13:14:10 +0800 Subject: [PATCH 2/3] =?UTF-8?q?:new:=20=E6=96=B0=E5=A2=9E`=E6=AF=8F?= =?UTF-8?q?=E6=97=A5=E5=85=8D=E8=B4=B9AI=E5=AF=B9=E8=AF=9D=E6=AC=A1?= =?UTF-8?q?=E6=95=B0=E9=99=90=E5=88=B6`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- views/manager-one.html | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/views/manager-one.html b/views/manager-one.html index a7b6340..c8d2b05 100644 --- a/views/manager-one.html +++ b/views/manager-one.html @@ -81,6 +81,13 @@ {{ end }}
+ +
+
今日 AI 对话已使用次数
+
+ {{ .info.AiUsedToday }}次(限制{{ .info.AiFreeLimit }}次) +
+
{{$isGroup := checkIsGroup .info.Wxid}} {{ if eq $isGroup true }} From 88f4069c8e342e6e28e178dafc1aae964df89eab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=AF=BB=E6=AC=A2?= Date: Sat, 17 Aug 2024 13:16:05 +0800 Subject: [PATCH 3/3] =?UTF-8?q?:new:=20=E6=96=B0=E5=A2=9E`=E6=AF=8F?= =?UTF-8?q?=E6=97=A5=E5=85=8D=E8=B4=B9AI=E5=AF=B9=E8=AF=9D=E6=AC=A1?= =?UTF-8?q?=E6=95=B0=E9=99=90=E5=88=B6`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugin/plugins/ai.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/plugin/plugins/ai.go b/plugin/plugins/ai.go index 7d907b0..814a307 100644 --- a/plugin/plugins/ai.go +++ b/plugin/plugins/ai.go @@ -19,6 +19,8 @@ import ( "time" ) +var notifyMap = make(map[string]bool) + // AI // @description: AI消息 // @param m @@ -38,8 +40,14 @@ func AI(m *plugin.MessageContext) { return } if friendInfo.AiUsedToday > 0 && friendInfo.AiUsedToday >= friendInfo.AiFreeLimit { + if notifyMap[m.FromUser] { + return + } _ = utils.SendMessage(m.FromUser, "", fmt.Sprintf("本群今天的免费次数已经用完啦,明天再来找我聊天吧~\n每天限制%d次,0点自动重置", friendInfo.AiFreeLimit), 0) + notifyMap[m.FromUser] = true return + } else { + notifyMap[m.FromUser] = false } var err error