Compare commits
No commits in common. "afa519175b83865fd2abf43c99738a66ff03d428" and "992f02ee1c8d995d0c8d21d1e7fdc6450788bd6f" have entirely different histories.
afa519175b
...
992f02ee1c
@ -280,26 +280,3 @@ func AutoClearMembers(ctx *gin.Context) {
|
|||||||
|
|
||||||
ctx.String(http.StatusOK, "操作成功")
|
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, "操作成功")
|
|
||||||
}
|
|
||||||
|
@ -25,8 +25,6 @@ system:
|
|||||||
news: true
|
news: true
|
||||||
# 热榜
|
# 热榜
|
||||||
hotTop: true
|
hotTop: true
|
||||||
# 每天免费 AI 次数限制
|
|
||||||
aiFreeLimit: 50
|
|
||||||
|
|
||||||
# 微信HOOK配置
|
# 微信HOOK配置
|
||||||
wechat:
|
wechat:
|
||||||
|
@ -16,11 +16,10 @@ type newFriendNotify struct {
|
|||||||
|
|
||||||
// 默认规则
|
// 默认规则
|
||||||
type defaultRule struct {
|
type defaultRule struct {
|
||||||
Ai bool `json:"ai" yaml:"ai"` // 是否启用AI
|
Ai bool `json:"ai" yaml:"ai"` // 是否启用AI
|
||||||
ChatRank bool `json:"chatRank" yaml:"chatRank"` // 是否启用聊天排行榜
|
ChatRank bool `json:"chatRank" yaml:"chatRank"` // 是否启用聊天排行榜
|
||||||
Summary bool `json:"summary" yaml:"summary"` // 是否启用聊天总结
|
Summary bool `json:"summary" yaml:"summary"` // 是否启用聊天总结
|
||||||
Welcome bool `json:"welcome" yaml:"welcome"` // 是否启用欢迎新成员
|
Welcome bool `json:"welcome" yaml:"welcome"` // 是否启用欢迎新成员
|
||||||
News bool `json:"news" yaml:"news"` // 是否启用每日早报
|
News bool `json:"news" yaml:"news"` // 是否启用每日早报
|
||||||
HotTop bool `json:"hotTop" yaml:"hotTop"` // 是否启用热门话题
|
HotTop bool `json:"hotTop" yaml:"hotTop"` // 是否启用热门话题
|
||||||
AiFreeLimit int `json:"aiFreeLimit" yaml:"aiFreeLimit"` // AI免费次数
|
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,6 @@ type Friend struct {
|
|||||||
ClearMember int `json:"clearMember"` // 清理成员配置(多少天未活跃的)
|
ClearMember int `json:"clearMember"` // 清理成员配置(多少天未活跃的)
|
||||||
IsOk bool `json:"isOk" gorm:"type:tinyint(1) default 0 not null"` // 是否正常
|
IsOk bool `json:"isOk" gorm:"type:tinyint(1) default 0 not null"` // 是否正常
|
||||||
UsedTokens int `json:"usedTokens"` // 已使用的AI Token数量
|
UsedTokens int `json:"usedTokens"` // 已使用的AI Token数量
|
||||||
AiFreeLimit int `json:"aiFreeLimit"` // AI免费次数
|
|
||||||
AiUsedToday int `json:"aiUsedToday"` // 今日已使用的AI次数
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Friend) TableName() string {
|
func (Friend) TableName() string {
|
||||||
|
@ -24,8 +24,6 @@ type FriendItem struct {
|
|||||||
EnableHotTop bool // 是否启用热搜
|
EnableHotTop bool // 是否启用热搜
|
||||||
ClearMember int // 清理成员配置(多少天未活跃的)
|
ClearMember int // 清理成员配置(多少天未活跃的)
|
||||||
IsOk bool // 是否还在通讯库(群聊是要还在群里也算)
|
IsOk bool // 是否还在通讯库(群聊是要还在群里也算)
|
||||||
AiFreeLimit int // AI免费次数
|
|
||||||
AiUsedToday int // 今日已使用的AI次数
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GroupUserItem
|
// GroupUserItem
|
||||||
|
@ -19,8 +19,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var notifyMap = make(map[string]bool)
|
|
||||||
|
|
||||||
// AI
|
// AI
|
||||||
// @description: AI消息
|
// @description: AI消息
|
||||||
// @param m
|
// @param m
|
||||||
@ -39,23 +37,6 @@ func AI(m *plugin.MessageContext) {
|
|||||||
if !friendInfo.EnableAi {
|
if !friendInfo.EnableAi {
|
||||||
return
|
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
|
|
||||||
defer func() {
|
|
||||||
if err == nil {
|
|
||||||
service.UpdateAiUsedToday(m.FromUser)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// 预处理一下发送的消息,用正则去掉@机器人的内容
|
// 预处理一下发送的消息,用正则去掉@机器人的内容
|
||||||
re := regexp.MustCompile(`@([^ | ]+)`)
|
re := regexp.MustCompile(`@([^ | ]+)`)
|
||||||
@ -151,17 +132,17 @@ func AI(m *plugin.MessageContext) {
|
|||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("OpenAI聊天发起失败: %v", err.Error())
|
log.Printf("OpenAI聊天发起失败: %v", err.Error())
|
||||||
_ = utils.SendMessage(m.FromUser, m.GroupUser, "AI聊天初始化失败,我已经通知我主人来修啦,请稍候一下下喔~", 0)
|
utils.SendMessage(m.FromUser, m.GroupUser, "AI聊天初始化失败,我已经通知我主人来修啦,请稍候一下下喔~", 0)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 返回消息为空
|
// 返回消息为空
|
||||||
if len(resp.Choices) == 0 || resp.Choices[0].Message.Content == "" {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 异步更新一下已使用的AI tokens
|
// 异步更新一下已使用的AI次数
|
||||||
go service.UpdateUsedAiTokens(m.FromUser, resp.Usage.TotalTokens)
|
go service.UpdateUsedAiTokens(m.FromUser, resp.Usage.TotalTokens)
|
||||||
|
|
||||||
// 保存一下AI 返回的消息,消息 Id 使用传入 Id 的负数
|
// 保存一下AI 返回的消息,消息 Id 使用传入 Id 的负数
|
||||||
@ -181,7 +162,7 @@ func AI(m *plugin.MessageContext) {
|
|||||||
if m.GroupUser != "" {
|
if m.GroupUser != "" {
|
||||||
replyMsg = "\n" + resp.Choices[0].Message.Content
|
replyMsg = "\n" + resp.Choices[0].Message.Content
|
||||||
}
|
}
|
||||||
err = utils.SendMessage(m.FromUser, m.GroupUser, replyMsg, 0)
|
utils.SendMessage(m.FromUser, m.GroupUser, replyMsg, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getGroupUserMessages
|
// getGroupUserMessages
|
||||||
|
@ -26,7 +26,6 @@ func Init(g *gin.Engine) {
|
|||||||
api := g.Group("/api")
|
api := g.Group("/api")
|
||||||
api.PUT("/ai/status", app.ChangeEnableAiStatus) // 修改是否开启AI状态
|
api.PUT("/ai/status", app.ChangeEnableAiStatus) // 修改是否开启AI状态
|
||||||
api.POST("/ai/model", app.ChangeUseAiModel) // 修改使用的AI模型
|
api.POST("/ai/model", app.ChangeUseAiModel) // 修改使用的AI模型
|
||||||
api.POST("/ai/free", app.ChangeAiFreeLimit) // 修改AI免费次数
|
|
||||||
api.POST("/ai/assistant", app.ChangeUseAiAssistant) // 修改使用的AI助手
|
api.POST("/ai/assistant", app.ChangeUseAiAssistant) // 修改使用的AI助手
|
||||||
api.PUT("/welcome/status", app.ChangeEnableWelcomeStatus) // 修改是否开启迎新状态
|
api.PUT("/welcome/status", app.ChangeEnableWelcomeStatus) // 修改是否开启迎新状态
|
||||||
api.PUT("/command/status", app.ChangeEnableCommandStatus) // 修改是否开启指令状态
|
api.PUT("/command/status", app.ChangeEnableCommandStatus) // 修改是否开启指令状态
|
||||||
|
@ -152,25 +152,3 @@ func UpdateUsedAiTokens(wxId string, tokens int) {
|
|||||||
log.Printf("更新AI使用次数失败, 错误信息: %v", err)
|
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
package friends
|
|
||||||
|
|
||||||
import "go-wechat/service"
|
|
||||||
|
|
||||||
// ClearAiUsedToday
|
|
||||||
// @description: 清空AI日使用次数
|
|
||||||
func ClearAiUsedToday() {
|
|
||||||
service.ClearAiUsedToday()
|
|
||||||
}
|
|
@ -85,7 +85,6 @@ func Sync() {
|
|||||||
EnableWelcome: config.Conf.System.DefaultRule.Welcome,
|
EnableWelcome: config.Conf.System.DefaultRule.Welcome,
|
||||||
EnableNews: config.Conf.System.DefaultRule.News,
|
EnableNews: config.Conf.System.DefaultRule.News,
|
||||||
EnableHotTop: config.Conf.System.DefaultRule.HotTop,
|
EnableHotTop: config.Conf.System.DefaultRule.HotTop,
|
||||||
AiFreeLimit: config.Conf.System.DefaultRule.AiFreeLimit,
|
|
||||||
ClearMember: 0,
|
ClearMember: 0,
|
||||||
LastActive: types.DateTime(time.Now().Local()),
|
LastActive: types.DateTime(time.Now().Local()),
|
||||||
}).Error
|
}).Error
|
||||||
|
@ -65,8 +65,6 @@ func InitTasks() {
|
|||||||
|
|
||||||
// 每天0点检查一次处理清理群成员
|
// 每天0点检查一次处理清理群成员
|
||||||
_, _ = s.Cron("0 0 * * *").Do(cleargroupuser.ClearGroupUser)
|
_, _ = s.Cron("0 0 * * *").Do(cleargroupuser.ClearGroupUser)
|
||||||
// 每天0点清空AI日使用次数
|
|
||||||
_, _ = s.Cron("0 0 * * *").Do(friends.ClearAiUsedToday)
|
|
||||||
|
|
||||||
// 开启定时任务
|
// 开启定时任务
|
||||||
s.StartAsync()
|
s.StartAsync()
|
||||||
|
@ -2,7 +2,6 @@ package utils
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/go-resty/resty/v2"
|
"github.com/go-resty/resty/v2"
|
||||||
"go-wechat/common/current"
|
"go-wechat/common/current"
|
||||||
@ -16,10 +15,9 @@ import (
|
|||||||
// @param toId
|
// @param toId
|
||||||
// @param atId
|
// @param atId
|
||||||
// @param msg
|
// @param msg
|
||||||
func SendMessage(toId, atId, msg string, retryCount int) (err error) {
|
func SendMessage(toId, atId, msg string, retryCount int) {
|
||||||
if retryCount > 5 {
|
if retryCount > 5 {
|
||||||
log.Printf("重试五次失败,停止发送")
|
log.Printf("重试五次失败,停止发送")
|
||||||
err = errors.New("重试五次失败,停止发送")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,10 +48,9 @@ func SendMessage(toId, atId, msg string, retryCount int) (err error) {
|
|||||||
log.Printf("发送文本消息失败: %s", err.Error())
|
log.Printf("发送文本消息失败: %s", err.Error())
|
||||||
// 休眠五秒后重新发送
|
// 休眠五秒后重新发送
|
||||||
time.Sleep(5 * time.Second)
|
time.Sleep(5 * time.Second)
|
||||||
return SendMessage(toId, atId, msg, retryCount+1)
|
SendMessage(toId, atId, msg, retryCount+1)
|
||||||
}
|
}
|
||||||
log.Printf("发送文本消息结果: %s", resp.String())
|
log.Printf("发送文本消息结果: %s", resp.String())
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendImage
|
// SendImage
|
||||||
|
@ -94,26 +94,6 @@
|
|||||||
</label>
|
</label>
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 每日 AI 免费次数限制 -->
|
|
||||||
<div class="flex justify-between gap-x-4 py-3 items-center">
|
|
||||||
<dt class="text-gray-500">
|
|
||||||
每日 AI 免费次数
|
|
||||||
</dt>
|
|
||||||
<dd class="flex items-start gap-x-2 items-center">
|
|
||||||
<div class="relative rounded-md">
|
|
||||||
<label>
|
|
||||||
<input type="number" id="auto-ai-{{ .Wxid }}" min="0" class="block w-1/2 float-end rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" placeholder="每日 AI 免费次数限制"
|
|
||||||
value="{{.AiFreeLimit}}"
|
|
||||||
onblur="changeAiFreeLimit({{.Wxid}}, this.value)"
|
|
||||||
>
|
|
||||||
</label>
|
|
||||||
<div class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3">
|
|
||||||
<span class="text-gray-500 sm:text-sm" id="price-currency">次</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</dd>
|
|
||||||
</div>
|
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
<div class="flex justify-between gap-x-4 py-3">
|
<div class="flex justify-between gap-x-4 py-3">
|
||||||
|
@ -73,7 +73,8 @@
|
|||||||
<select
|
<select
|
||||||
class="block w-full rounded-md border-0 py-1.5 pl-3 pr-10 text-gray-900 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-green-600 sm:text-sm sm:leading-6"
|
class="block w-full rounded-md border-0 py-1.5 pl-3 pr-10 text-gray-900 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-green-600 sm:text-sm sm:leading-6"
|
||||||
onchange="aiAssistantChange(event, {{.Wxid}})">
|
onchange="aiAssistantChange(event, {{.Wxid}})">
|
||||||
<option value="" {{ if eq .Prompt "" }}selected{{ end }}>默认</option>
|
<option value="" {{ if eq .Prompt
|
||||||
|
"" }}selected{{ end }}>默认</option>
|
||||||
|
|
||||||
{{$usePrompt := .Prompt}}
|
{{$usePrompt := .Prompt}}
|
||||||
{{ range $.assistant }}
|
{{ range $.assistant }}
|
||||||
@ -88,26 +89,6 @@
|
|||||||
{{ end }}
|
{{ end }}
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
<!-- 每日 AI 免费次数限制 -->
|
|
||||||
<div class="flex justify-between gap-x-4 py-3 items-center">
|
|
||||||
<dt class="text-gray-500">
|
|
||||||
每日 AI 免费次数限制
|
|
||||||
<span class="text-red-300">(0表示不限)</span>
|
|
||||||
</dt>
|
|
||||||
<dd class="flex items-start gap-x-2 items-center">
|
|
||||||
<div class="relative rounded-md">
|
|
||||||
<label>
|
|
||||||
<input type="number" id="auto-ai-{{ .Wxid }}" min="0" class="block w-1/2 float-end rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" placeholder="每日 AI 免费次数限制"
|
|
||||||
value="{{.AiFreeLimit}}"
|
|
||||||
onblur="changeAiFreeLimit({{.Wxid}}, this.value)"
|
|
||||||
>
|
|
||||||
</label>
|
|
||||||
<div class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3">
|
|
||||||
<span class="text-gray-500 sm:text-sm" id="price-currency">次</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</dd>
|
|
||||||
</div>
|
|
||||||
<!-- 水群排行榜 -->
|
<!-- 水群排行榜 -->
|
||||||
<div class="flex justify-between gap-x-4 py-3 items-center">
|
<div class="flex justify-between gap-x-4 py-3 items-center">
|
||||||
<dt class="text-gray-500">水群排行榜</dt>
|
<dt class="text-gray-500">水群排行榜</dt>
|
||||||
|
@ -81,13 +81,6 @@
|
|||||||
{{ end }}
|
{{ end }}
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
<!-- 今日 AI 对话已使用次数 -->
|
|
||||||
<div class="flex justify-between gap-x-4 py-3 items-center">
|
|
||||||
<dt class="text-gray-500">今日 AI 对话已使用次数</dt>
|
|
||||||
<dd class="flex items-start gap-x-2">
|
|
||||||
{{ .info.AiUsedToday }}次(限制{{ .info.AiFreeLimit }}次)
|
|
||||||
</dd>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{$isGroup := checkIsGroup .info.Wxid}}
|
{{$isGroup := checkIsGroup .info.Wxid}}
|
||||||
{{ if eq $isGroup true }}
|
{{ if eq $isGroup true }}
|
||||||
|
@ -291,29 +291,3 @@ function changeClearMember(wxid, oldVal, newVal) {
|
|||||||
window.location.reload();
|
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();
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user