Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
982ddef0da | ||
|
|
99447d332d | ||
|
|
3478f4f9e2 | ||
|
|
b3ed0fcc6f | ||
|
|
3da8b327d0 | ||
|
|
0262fdd9f7 | ||
|
|
f775f1d67d | ||
|
|
43f9d590b7 | ||
|
|
22c7d3683b | ||
|
|
d589a9615e | ||
|
|
13205e445f | ||
|
|
a414a98a51 | ||
|
|
d21089ab69 | ||
|
|
a274f085f8 | ||
|
|
8ddc40cc01 | ||
|
|
c0c810d02e | ||
|
|
905dab5ab8 | ||
|
|
ddb0db0b6a | ||
|
|
8bac050a02 | ||
|
|
a548af9de2 | ||
|
|
64c3c9c78b | ||
|
|
0f7cf5515d | ||
|
|
a2d84dea08 | ||
|
|
d3f8a59390 | ||
|
|
165fefdb48 | ||
|
|
22474efc57 | ||
|
|
797821e2ed |
@@ -90,6 +90,29 @@ func ChangeEnableGroupRankStatus(ctx *gin.Context) {
|
||||
ctx.String(http.StatusOK, "操作成功")
|
||||
}
|
||||
|
||||
// ChangeEnableSummaryStatus
|
||||
// @description: 修改是否开启聊天记录总结
|
||||
// @param ctx
|
||||
func ChangeEnableSummaryStatus(ctx *gin.Context) {
|
||||
var p changeStatusParam
|
||||
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("`enable_summary`", gorm.Expr(" !`enable_summary`")).Error
|
||||
if err != nil {
|
||||
log.Printf("修改开启聊天记录总结失败:%s", err)
|
||||
ctx.String(http.StatusInternalServerError, "操作失败: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.String(http.StatusOK, "操作成功")
|
||||
}
|
||||
|
||||
// ChangeEnableWelcomeStatus
|
||||
// @description: 修改是否开启迎新
|
||||
// @param ctx
|
||||
|
||||
11
config.yaml
11
config.yaml
@@ -23,12 +23,15 @@ mysql:
|
||||
schema: public # postgres 专用
|
||||
|
||||
task:
|
||||
enable: false
|
||||
enable: true
|
||||
syncFriends:
|
||||
enable: false
|
||||
cron: '*/5 * * * *' # 五分钟一次
|
||||
waterGroup:
|
||||
groupSummary:
|
||||
enable: true
|
||||
cron: '30 0 * * *' # 每天0:30
|
||||
waterGroup:
|
||||
enable: false
|
||||
cron:
|
||||
yesterday: '30 9 * * *' # 每天9:30
|
||||
week: '30 9 * * 1' # 每周一9:30
|
||||
@@ -37,6 +40,8 @@ task:
|
||||
|
||||
# MQ配置
|
||||
mq:
|
||||
# 是否启用
|
||||
enable: false
|
||||
# RabbitMQ配置
|
||||
rabbitmq:
|
||||
host: 10.0.0.247
|
||||
@@ -51,6 +56,8 @@ ai:
|
||||
enable: false
|
||||
# 模型,不填默认gpt-3.5-turbo-0613
|
||||
model: gpt-3.5-turbo-0613
|
||||
# 群聊总结模型
|
||||
summaryModel: gpt-4-0613
|
||||
# OpenAI Api key
|
||||
apiKey: sk-xxxx
|
||||
# 接口代理域名,不填默认ChatGPT官方地址
|
||||
|
||||
@@ -5,6 +5,7 @@ package config
|
||||
type ai struct {
|
||||
Enable bool `json:"enable" yaml:"enable"` // 是否启用AI
|
||||
Model string `json:"model" yaml:"model"` // 模型
|
||||
SummaryModel string `json:"summaryModel" yaml:"summaryModel"` // 总结模型
|
||||
ApiKey string `json:"apiKey" yaml:"apiKey"` // API Key
|
||||
BaseUrl string `json:"baseUrl" yaml:"baseUrl"` // API地址
|
||||
Personality string `json:"personality" yaml:"personality"` // 人设
|
||||
|
||||
@@ -5,6 +5,7 @@ import "fmt"
|
||||
// mq
|
||||
// @description: MQ配置
|
||||
type mq struct {
|
||||
Enable bool `json:"enable" yaml:"enable"` // 是否启用
|
||||
RabbitMQ rabbitMq `json:"rabbitmq" yaml:"rabbitmq"` // RabbitMQ配置
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ type task struct {
|
||||
Enable bool `json:"enable" yaml:"enable"` // 是否启用
|
||||
SyncFriends syncFriends `json:"syncFriends" yaml:"syncFriends"` // 同步好友
|
||||
WaterGroup waterGroup `json:"waterGroup" yaml:"waterGroup"` // 水群排行榜
|
||||
GroupSummary syncFriends `json:"groupSummary" yaml:"groupSummary"` // 群聊总结
|
||||
}
|
||||
|
||||
// syncFriends
|
||||
|
||||
@@ -23,9 +23,6 @@ services:
|
||||
image: mysql:8
|
||||
container_name: gw-db
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
wechat:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=wechat
|
||||
- MYSQL_USER=wechat
|
||||
@@ -41,6 +38,7 @@ services:
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- mysql
|
||||
- wechat
|
||||
volumes:
|
||||
# 配置文件请参阅项目根目录的config.yaml文件
|
||||
- ./config/config.yaml:/app/config.yaml
|
||||
|
||||
@@ -17,6 +17,7 @@ type Friend struct {
|
||||
AiModel string `json:"aiModel"` // AI模型
|
||||
EnableChatRank bool `json:"enableChatRank" gorm:"type:tinyint(1) default 0 not null"` // 是否使用聊天排行
|
||||
EnableWelcome bool `json:"enableWelcome" gorm:"type:tinyint(1) default 0 not null"` // 是否启用迎新
|
||||
EnableSummary bool `json:"enableSummary" gorm:"type:tinyint(1) default 0 not null"` // 是否启用总结
|
||||
IsOk bool `json:"isOk" gorm:"type:tinyint(1) default 0 not null"` // 是否正常
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,13 @@ func (m Message) IsRevokeMsg() bool {
|
||||
// @receiver m
|
||||
// @return bool
|
||||
func (m Message) IsNewUserJoin() bool {
|
||||
sysFlag := m.Type == types.MsgTypeSys && strings.Contains(m.Content, "\"邀请\"") && strings.Contains(m.Content, "\"加入了群聊")
|
||||
if m.Type != types.MsgTypeSys {
|
||||
return false
|
||||
}
|
||||
|
||||
isInvitation := strings.Contains(m.Content, "\"邀请\"") && strings.Contains(m.Content, "\"加入了群聊")
|
||||
isScanQrCode := strings.Contains(m.Content, "通过扫描") && strings.Contains(m.Content, "加入群聊")
|
||||
sysFlag := isInvitation || isScanQrCode
|
||||
if sysFlag {
|
||||
return true
|
||||
}
|
||||
@@ -97,7 +103,7 @@ func (m Message) IsNewUserJoin() bool {
|
||||
if err := xml.Unmarshal([]byte(m.Content), &d); err != nil {
|
||||
return false
|
||||
}
|
||||
return m.Type == types.MsgTypeSys && d.Type == "delchatroommember"
|
||||
return d.Type == "delchatroommember"
|
||||
}
|
||||
|
||||
// IsAt
|
||||
|
||||
@@ -16,6 +16,10 @@ const exchangeName = "wechat-message"
|
||||
// Init
|
||||
// @description: 初始化MQ
|
||||
func Init() {
|
||||
if !config.Conf.Mq.Enable {
|
||||
log.Println("未启用MQ")
|
||||
return
|
||||
}
|
||||
// 读取MQ连接配置
|
||||
mqUrl := config.Conf.Mq.RabbitMQ.GetURL()
|
||||
if mqUrl == "" {
|
||||
|
||||
@@ -42,6 +42,8 @@ func Command(m *plugin.MessageContext) {
|
||||
command.LeiGodCmd(m.FromUser, msgArray[1], msgArray[2:]...)
|
||||
case "/肯德基", "/kfc":
|
||||
command.KfcCrazyThursdayCmd(m.FromUser)
|
||||
case "/ai":
|
||||
command.AiCmd(m.FromUser, m.GroupUser, msgArray[1])
|
||||
default:
|
||||
utils.SendMessage(m.FromUser, m.GroupUser, "指令错误", 0)
|
||||
}
|
||||
|
||||
65
plugin/plugins/command/ai.go
Normal file
65
plugin/plugins/command/ai.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go-wechat/client"
|
||||
"go-wechat/entity"
|
||||
"go-wechat/utils"
|
||||
"log"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// AiCmd
|
||||
// @description: AI指令
|
||||
// @param userId
|
||||
// @param groupUserId
|
||||
// @param cmd
|
||||
func AiCmd(userId, groupUserId, cmd string) {
|
||||
// 判断发信人是不是群主
|
||||
can := false
|
||||
if strings.Contains(userId, "@chatroom") {
|
||||
// 判断是不是群主
|
||||
err := client.MySQL.Model(&entity.GroupUser{}).
|
||||
Where("group_id = ?", userId).
|
||||
Where("wxid = ?", groupUserId).
|
||||
Pluck("is_admin", &can).Error
|
||||
if err != nil {
|
||||
log.Printf("查询群主失败: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if !can {
|
||||
utils.SendMessage(userId, groupUserId, "您不是群主,无法使用指令", 0)
|
||||
return
|
||||
}
|
||||
|
||||
var err error
|
||||
replyMsg := "操作成功"
|
||||
|
||||
switch cmd {
|
||||
case "enable", "启用", "打开":
|
||||
err = setAiEnable(userId, true)
|
||||
case "disable", "停用", "禁用", "关闭":
|
||||
err = setAiEnable(userId, false)
|
||||
default:
|
||||
replyMsg = "指令错误"
|
||||
}
|
||||
if err != nil {
|
||||
log.Printf("AI指令执行失败: %v", err)
|
||||
replyMsg = fmt.Sprintf("指令执行错误: %v", err)
|
||||
}
|
||||
utils.SendMessage(userId, groupUserId, replyMsg, 0)
|
||||
}
|
||||
|
||||
// setAiEnable
|
||||
// @description: 设置AI启用状态
|
||||
// @param userId
|
||||
// @param enable
|
||||
// @return err
|
||||
func setAiEnable(userId string, enable bool) (err error) {
|
||||
// 更新
|
||||
err = client.MySQL.Model(&entity.Friend{}).
|
||||
Where("wxid = ?", userId).
|
||||
Update("enable_ai", enable).Error
|
||||
return
|
||||
}
|
||||
@@ -23,6 +23,13 @@ option: 指令选项,可选值:
|
||||
|
||||
#2. 肯德基疯狂星期四文案
|
||||
/kfc、/肯德基
|
||||
|
||||
#3. AI助手
|
||||
/ai option
|
||||
option: 指令选项,可选值:
|
||||
启用: '启用'、'打开'、'enable'
|
||||
停用: '停用'、'禁用'、'关闭'、'disable'
|
||||
|
||||
`
|
||||
utils.SendMessage(m.FromUser, m.GroupUser, str, 0)
|
||||
|
||||
|
||||
@@ -70,9 +70,6 @@ services:
|
||||
image: mysql:8
|
||||
container_name: gw-db
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
wechat:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=wechat
|
||||
- MYSQL_USER=wechat
|
||||
@@ -88,6 +85,7 @@ services:
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- mysql
|
||||
- wechat
|
||||
volumes:
|
||||
# 配置文件请参阅项目根目录的config.yaml文件
|
||||
- ./config/config.yaml:/app/config.yaml
|
||||
|
||||
@@ -28,4 +28,5 @@ func Init(g *gin.Engine) {
|
||||
api.PUT("/grouprank/status", app.ChangeEnableGroupRankStatus) // 修改是否开启水群排行榜状态
|
||||
api.PUT("/grouprank/skip", app.ChangeSkipGroupRankStatus) // 修改是否跳过水群排行榜状态
|
||||
api.GET("/group/users", app.GetGroupUsers) // 获取群成员列表
|
||||
api.PUT("/summary/status", app.ChangeEnableSummaryStatus) // 修改是否开启群聊总结状态
|
||||
}
|
||||
|
||||
@@ -53,6 +53,15 @@ func GetAllEnableChatRank() (records []entity.Friend, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// GetAllEnableSummary
|
||||
// @description: 取出所有启用了总结的群组
|
||||
// @return records
|
||||
// @return err
|
||||
func GetAllEnableSummary() (records []entity.Friend, err error) {
|
||||
err = client.MySQL.Where("enable_summary = ?", 1).Where("wxid LIKE '%@chatroom'").Find(&records).Error
|
||||
return
|
||||
}
|
||||
|
||||
// CheckIsEnableCommand
|
||||
// @description: 检查用户是否启用了指令
|
||||
// @param userId
|
||||
|
||||
@@ -3,6 +3,7 @@ package service
|
||||
import (
|
||||
"go-wechat/client"
|
||||
"go-wechat/entity"
|
||||
"go-wechat/vo"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
@@ -39,3 +40,22 @@ func SaveMessage(msg entity.Message) {
|
||||
go updateLastActive(msg)
|
||||
}
|
||||
}
|
||||
|
||||
// GetTextMessagesById
|
||||
// @description: 根据群id或者用户Id获取消息
|
||||
// @param id
|
||||
// @return records
|
||||
// @return err
|
||||
func GetTextMessagesById(id string) (records []vo.TextMessageItem, err error) {
|
||||
tx := client.MySQL.
|
||||
Table("`t_message` AS tm").
|
||||
Joins("LEFT JOIN t_group_user AS tgu ON tm.group_user = tgu.wxid AND tgu.group_id = tm.from_user").
|
||||
Select("tgu.nickname", "IF( tm.type = 49, EXTRACTVALUE ( tm.content, \"/msg/appmsg/title\" ), tm.content ) AS message").
|
||||
Where("tm.`from_user` = ?", id).
|
||||
Where(`(tm.type = 1 OR ( tm.type = 49 AND EXTRACTVALUE ( tm.content, "/msg/appmsg/type" ) = '57' ))`).
|
||||
Where("DATE ( tm.create_at ) = DATE ( CURDATE() - INTERVAL 1 DAY )").
|
||||
Order("tm.create_at ASC")
|
||||
|
||||
err = tx.Find(&records).Error
|
||||
return
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"go-wechat/config"
|
||||
"go-wechat/entity"
|
||||
"go-wechat/model"
|
||||
"go-wechat/utils"
|
||||
"gorm.io/gorm"
|
||||
"log"
|
||||
"slices"
|
||||
@@ -72,6 +73,8 @@ func Sync() {
|
||||
log.Printf("新增好友失败: %s", err.Error())
|
||||
continue
|
||||
}
|
||||
// 发送一条新消息
|
||||
utils.SendMessage(friend.Wxid, "", "大家好,我是一个AI机器人,可以直接@我询问你想问的问题。该功能默认未启用,请群主艾特我并发送 /ai enable 指令启用", 0)
|
||||
} else {
|
||||
pm := map[string]any{
|
||||
"nickname": friend.Nickname,
|
||||
|
||||
81
tasks/summary/summary.go
Normal file
81
tasks/summary/summary.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package summary
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/sashabaranov/go-openai"
|
||||
"go-wechat/config"
|
||||
"go-wechat/service"
|
||||
"go-wechat/utils"
|
||||
"go-wechat/vo"
|
||||
"log"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// AiSummary
|
||||
// @description: AI总结群聊记录
|
||||
func AiSummary() {
|
||||
groups, err := service.GetAllEnableSummary()
|
||||
if err != nil {
|
||||
log.Printf("获取启用了聊天排行榜的群组失败, 错误信息: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, group := range groups {
|
||||
// 获取对话记录
|
||||
var records []vo.TextMessageItem
|
||||
if records, err = service.GetTextMessagesById(group.Wxid); err != nil {
|
||||
log.Printf("获取群[%s]对话记录失败, 错误信息: %v", group.Wxid, err)
|
||||
continue
|
||||
}
|
||||
if len(records) < 100 {
|
||||
log.Printf("群[%s]对话记录不足100条,跳过总结", group.Wxid)
|
||||
continue
|
||||
}
|
||||
// 组装对话记录为字符串
|
||||
var content []string
|
||||
for _, record := range records {
|
||||
content = append(content, fmt.Sprintf("%s: %s\n-----end-----", record.Nickname, record.Message))
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf("请帮我总结一下一下的群聊内容的梗概(内容尽可能详细一些)。\n"+
|
||||
"注意,他们可能是多个话题,请仔细甄别。\n"+
|
||||
"每一行代表一个人的发言,每一行的的格式为: \n{nickname}: {content}\n-----end-----"+
|
||||
"\n\n聊天记录如下: \n%s", strings.Join(content, "\n"))
|
||||
|
||||
// AI总结
|
||||
messages := []openai.ChatCompletionMessage{
|
||||
{
|
||||
Role: openai.ChatMessageRoleUser,
|
||||
Content: msg,
|
||||
},
|
||||
}
|
||||
|
||||
// 默认使用AI回复
|
||||
conf := openai.DefaultConfig(config.Conf.Ai.ApiKey)
|
||||
if config.Conf.Ai.BaseUrl != "" {
|
||||
conf.BaseURL = fmt.Sprintf("%s/v1", config.Conf.Ai.BaseUrl)
|
||||
}
|
||||
ai := openai.NewClientWithConfig(conf)
|
||||
var resp openai.ChatCompletionResponse
|
||||
resp, err = ai.CreateChatCompletion(
|
||||
context.Background(),
|
||||
openai.ChatCompletionRequest{
|
||||
Model: config.Conf.Ai.SummaryModel,
|
||||
Messages: messages,
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("群聊记录总结失败: %v", err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
// 返回消息为空
|
||||
if resp.Choices[0].Message.Content == "" {
|
||||
continue
|
||||
}
|
||||
replyMsg := fmt.Sprintf("#昨日消息总结\n\n%s", resp.Choices[0].Message.Content)
|
||||
utils.SendMessage(group.Wxid, "", replyMsg, 0)
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"github.com/go-co-op/gocron"
|
||||
"go-wechat/config"
|
||||
"go-wechat/tasks/friends"
|
||||
"go-wechat/tasks/summary"
|
||||
"go-wechat/tasks/watergroup"
|
||||
"log"
|
||||
"time"
|
||||
@@ -37,6 +38,13 @@ func InitTasks() {
|
||||
}
|
||||
}
|
||||
|
||||
// 群聊总结
|
||||
if config.Conf.Task.GroupSummary.Enable {
|
||||
log.Printf("群聊总结任务已启用,执行表达式: %s", config.Conf.Task.GroupSummary.Cron)
|
||||
_, _ = s.Cron(config.Conf.Task.GroupSummary.Cron).Do(summary.AiSummary)
|
||||
|
||||
}
|
||||
|
||||
// 更新好友列表
|
||||
if config.Conf.Task.SyncFriends.Enable {
|
||||
log.Printf("更新好友列表任务已启用,执行表达式: %s", config.Conf.Task.SyncFriends.Cron)
|
||||
|
||||
@@ -60,27 +60,44 @@ func dealMonth(gid string) {
|
||||
|
||||
// 查询群成员总数
|
||||
var groupUsers int64
|
||||
err = client.MySQL.Model(&entity.GroupUser{}).Where("group_id = ?", gid).Count(&groupUsers).Error
|
||||
err = client.MySQL.Model(&entity.GroupUser{}).
|
||||
Where("group_id = ?", gid).
|
||||
Where("is_member IS TRUE").
|
||||
Count(&groupUsers).Error
|
||||
if err != nil {
|
||||
log.Printf("查询群成员总数失败, 错误信息: %v", err)
|
||||
}
|
||||
// 计算活跃度
|
||||
showActivity := err != nil && groupUsers > 0
|
||||
showActivity := err == nil && groupUsers > 0
|
||||
activity := "0.00"
|
||||
if groupUsers > 0 {
|
||||
activity = fmt.Sprintf("%.2f", (float64(len(records))/float64(groupUsers))*100)
|
||||
}
|
||||
|
||||
// 计算消息总数
|
||||
var msgCount int64
|
||||
for _, v := range records {
|
||||
// 计算消息总数、中位数、前十位消息总数
|
||||
var msgCount, medianCount, topTenCount int64
|
||||
for idx, v := range records {
|
||||
msgCount += v.Count
|
||||
if idx == (len(records)/2)-1 {
|
||||
medianCount = v.Count
|
||||
}
|
||||
if len(records) > 10 && idx < 10 {
|
||||
topTenCount += v.Count
|
||||
}
|
||||
}
|
||||
// 计算活跃用户人均消息条数
|
||||
avgMsgCount := int(float64(msgCount) / float64(len(records)))
|
||||
|
||||
// 组装消息总数推送信息
|
||||
notifyMsgs = append(notifyMsgs, " ")
|
||||
notifyMsgs = append(notifyMsgs, fmt.Sprintf("🗣️ %s本群 %d 位朋友共产生 %d 条发言", monthStr, len(records), msgCount))
|
||||
if showActivity {
|
||||
notifyMsgs = append(notifyMsgs, fmt.Sprintf("🎭 活跃度: %s%", activity))
|
||||
m := fmt.Sprintf("🎭 活跃度: %s%%,人均消息条数: %d,中位数: %d", activity, avgMsgCount, medianCount)
|
||||
// 计算前十占比
|
||||
if topTenCount > 0 {
|
||||
m += fmt.Sprintf(",前十名占比: %.2f%%", float64(topTenCount)/float64(msgCount)*100)
|
||||
}
|
||||
notifyMsgs = append(notifyMsgs, m)
|
||||
}
|
||||
notifyMsgs = append(notifyMsgs, "\n🏵 活跃用户排行榜 🏵")
|
||||
|
||||
|
||||
@@ -59,27 +59,44 @@ func dealWeek(gid string) {
|
||||
|
||||
// 查询群成员总数
|
||||
var groupUsers int64
|
||||
err = client.MySQL.Model(&entity.GroupUser{}).Where("group_id = ?", gid).Count(&groupUsers).Error
|
||||
err = client.MySQL.Model(&entity.GroupUser{}).
|
||||
Where("group_id = ?", gid).
|
||||
Where("is_member IS TRUE").
|
||||
Count(&groupUsers).Error
|
||||
if err != nil {
|
||||
log.Printf("查询群成员总数失败, 错误信息: %v", err)
|
||||
}
|
||||
// 计算活跃度
|
||||
showActivity := err != nil && groupUsers > 0
|
||||
showActivity := err == nil && groupUsers > 0
|
||||
activity := "0.00"
|
||||
if groupUsers > 0 {
|
||||
activity = fmt.Sprintf("%.2f", (float64(len(records))/float64(groupUsers))*100)
|
||||
}
|
||||
|
||||
// 计算消息总数
|
||||
var msgCount int64
|
||||
for _, v := range records {
|
||||
// 计算消息总数、中位数、前十位消息总数
|
||||
var msgCount, medianCount, topTenCount int64
|
||||
for idx, v := range records {
|
||||
msgCount += v.Count
|
||||
if idx == (len(records)/2)-1 {
|
||||
medianCount = v.Count
|
||||
}
|
||||
if len(records) > 10 && idx < 10 {
|
||||
topTenCount += v.Count
|
||||
}
|
||||
}
|
||||
// 计算活跃用户人均消息条数
|
||||
avgMsgCount := int(float64(msgCount) / float64(len(records)))
|
||||
|
||||
// 组装消息总数推送信息
|
||||
notifyMsgs = append(notifyMsgs, " ")
|
||||
notifyMsgs = append(notifyMsgs, fmt.Sprintf("🗣️ 上周本群 %d 位朋友共产生 %d 条发言", len(records), msgCount))
|
||||
if showActivity {
|
||||
notifyMsgs = append(notifyMsgs, fmt.Sprintf("🎭 活跃度: %s%", activity))
|
||||
m := fmt.Sprintf("🎭 活跃度: %s%%,人均消息条数: %d,中位数: %d", activity, avgMsgCount, medianCount)
|
||||
// 计算前十占比
|
||||
if topTenCount > 0 {
|
||||
m += fmt.Sprintf(",前十名占比: %.2f%%", float64(topTenCount)/float64(msgCount)*100)
|
||||
}
|
||||
notifyMsgs = append(notifyMsgs, m)
|
||||
}
|
||||
notifyMsgs = append(notifyMsgs, "\n🏵 活跃用户排行榜 🏵")
|
||||
|
||||
|
||||
@@ -59,22 +59,34 @@ func dealYear(gid string) {
|
||||
|
||||
// 查询群成员总数
|
||||
var groupUsers int64
|
||||
err = client.MySQL.Model(&entity.GroupUser{}).Where("group_id = ?", gid).Count(&groupUsers).Error
|
||||
err = client.MySQL.Model(&entity.GroupUser{}).
|
||||
Where("group_id = ?", gid).
|
||||
Where("is_member IS TRUE").
|
||||
Count(&groupUsers).Error
|
||||
if err != nil {
|
||||
log.Printf("查询群成员总数失败, 错误信息: %v", err)
|
||||
}
|
||||
// 计算活跃度
|
||||
showActivity := err != nil && groupUsers > 0
|
||||
showActivity := err == nil && groupUsers > 0
|
||||
activity := "0.00"
|
||||
if groupUsers > 0 {
|
||||
activity = fmt.Sprintf("%.2f", (float64(len(records))/float64(groupUsers))*100)
|
||||
}
|
||||
|
||||
// 计算消息总数
|
||||
var msgCount int64
|
||||
for _, v := range records {
|
||||
// 计算消息总数、中位数、前十位消息总数
|
||||
var msgCount, medianCount, topTenCount int64
|
||||
for idx, v := range records {
|
||||
msgCount += v.Count
|
||||
if idx == (len(records)/2)-1 {
|
||||
medianCount = v.Count
|
||||
}
|
||||
if len(records) > 10 && idx < 10 {
|
||||
topTenCount += v.Count
|
||||
}
|
||||
}
|
||||
// 计算活跃用户人均消息条数
|
||||
avgMsgCount := int(float64(msgCount) / float64(len(records)))
|
||||
|
||||
// 组装消息总数推送信息
|
||||
notifyMsgs = append(notifyMsgs, " ")
|
||||
notifyMsgs = append(notifyMsgs, "亲爱的群友们,新年已经悄悄来临,让我们一起迎接这充满希望和美好的时刻。在这个特殊的日子里,我要向你们致以最真挚的祝福。")
|
||||
@@ -87,7 +99,12 @@ func dealYear(gid string) {
|
||||
notifyMsgs = append(notifyMsgs, " ")
|
||||
notifyMsgs = append(notifyMsgs, fmt.Sprintf("🗣️ 去年本群 %d 位朋友共产生 %d 条发言", len(records), msgCount))
|
||||
if showActivity {
|
||||
notifyMsgs = append(notifyMsgs, fmt.Sprintf("🎭 活跃度: %s%", activity))
|
||||
m := fmt.Sprintf("🎭 活跃度: %s%%,人均消息条数: %d,中位数: %d", activity, avgMsgCount, medianCount)
|
||||
// 计算前十占比
|
||||
if topTenCount > 0 {
|
||||
m += fmt.Sprintf(",前十名占比: %.2f%%", float64(topTenCount)/float64(msgCount)*100)
|
||||
}
|
||||
notifyMsgs = append(notifyMsgs, m)
|
||||
}
|
||||
notifyMsgs = append(notifyMsgs, "\n🏵 活跃用户排行榜 🏵")
|
||||
|
||||
|
||||
@@ -61,27 +61,44 @@ func dealYesterday(gid string) {
|
||||
|
||||
// 查询群成员总数
|
||||
var groupUsers int64
|
||||
err = client.MySQL.Model(&entity.GroupUser{}).Where("group_id = ?", gid).Count(&groupUsers).Error
|
||||
err = client.MySQL.Model(&entity.GroupUser{}).
|
||||
Where("group_id = ?", gid).
|
||||
Where("is_member IS TRUE").
|
||||
Count(&groupUsers).Error
|
||||
if err != nil {
|
||||
log.Printf("查询群成员总数失败, 错误信息: %v", err)
|
||||
}
|
||||
// 计算活跃度
|
||||
showActivity := err != nil && groupUsers > 0
|
||||
showActivity := err == nil && groupUsers > 0
|
||||
activity := "0.00"
|
||||
if groupUsers > 0 {
|
||||
activity = fmt.Sprintf("%.2f", (float64(len(records))/float64(groupUsers))*100)
|
||||
}
|
||||
|
||||
// 计算消息总数
|
||||
var msgCount int64
|
||||
for _, v := range records {
|
||||
// 计算消息总数、中位数、前十位消息总数
|
||||
var msgCount, medianCount, topTenCount int64
|
||||
for idx, v := range records {
|
||||
msgCount += v.Count
|
||||
if idx == (len(records)/2)-1 {
|
||||
medianCount = v.Count
|
||||
}
|
||||
if len(records) > 10 && idx < 10 {
|
||||
topTenCount += v.Count
|
||||
}
|
||||
}
|
||||
// 计算活跃用户人均消息条数
|
||||
avgMsgCount := int(float64(msgCount) / float64(len(records)))
|
||||
|
||||
// 组装消息总数推送信息
|
||||
notifyMsgs = append(notifyMsgs, " ")
|
||||
notifyMsgs = append(notifyMsgs, fmt.Sprintf("🗣️ 昨日本群 %d 位朋友共产生 %d 条发言", len(records), msgCount))
|
||||
if showActivity {
|
||||
notifyMsgs = append(notifyMsgs, fmt.Sprintf("🎭 活跃度: %s%", activity))
|
||||
m := fmt.Sprintf("🎭 活跃度: %s%%,人均消息条数: %d,中位数: %d", activity, avgMsgCount, medianCount)
|
||||
// 计算前十占比
|
||||
if topTenCount > 0 {
|
||||
m += fmt.Sprintf(",前十名占比: %.2f%%", float64(topTenCount)/float64(msgCount)*100)
|
||||
}
|
||||
notifyMsgs = append(notifyMsgs, m)
|
||||
}
|
||||
notifyMsgs = append(notifyMsgs, "\n🏵 活跃用户排行榜 🏵")
|
||||
|
||||
|
||||
@@ -108,6 +108,7 @@
|
||||
<th>是否在通讯录</th>
|
||||
<th>是否启用AI</th>
|
||||
<th>是否启用水群排行榜</th>
|
||||
<th>是否启用聊天记录总结</th>
|
||||
<th>是否启用迎新</th>
|
||||
<th>是否启用指令</th>
|
||||
<th>操作</th>
|
||||
@@ -164,6 +165,15 @@
|
||||
<div class="swap-off">❌已禁用</div>
|
||||
</label>
|
||||
</td>
|
||||
<td>
|
||||
<!-- EnableSummary -->
|
||||
<label class="swap swap-flip {{ checkSwap .EnableSummary }}">
|
||||
<input type="checkbox" onclick="changeSummaryEnableStatus({{.Wxid}})"/>
|
||||
|
||||
<div class="swap-on">✔️已启用</div>
|
||||
<div class="swap-off">❌已禁用</div>
|
||||
</label>
|
||||
</td>
|
||||
<td>
|
||||
<label class="swap swap-flip {{ checkSwap .EnableWelcome }}">
|
||||
<input type="checkbox" onclick="changeWelcomeEnableStatus({{.Wxid}})"/>
|
||||
|
||||
@@ -12,6 +12,7 @@ function changeAiEnableStatus(wxId) {
|
||||
}
|
||||
}).then(function (response) {
|
||||
console.log(`返回结果: ${JSON.stringify(response)}`);
|
||||
alert(`${response.data}`)
|
||||
}).catch(function (error) {
|
||||
console.log(`错误信息: ${error}`);
|
||||
alert("修改失败")
|
||||
@@ -29,6 +30,25 @@ function changeGroupRankEnableStatus(wxId) {
|
||||
}
|
||||
}).then(function (response) {
|
||||
console.log(`返回结果: ${JSON.stringify(response)}`);
|
||||
alert(`${response.data}`)
|
||||
}).catch(function (error) {
|
||||
console.log(`错误信息: ${error}`);
|
||||
alert("修改失败")
|
||||
})
|
||||
}
|
||||
|
||||
// 修改水群排行榜状态
|
||||
function changeSummaryEnableStatus(wxId) {
|
||||
// console.log("修改聊天记录总结开启状态: ", wxId)
|
||||
axios({
|
||||
method: 'put',
|
||||
url: '/api/summary/status',
|
||||
data: {
|
||||
wxId: wxId
|
||||
}
|
||||
}).then(function (response) {
|
||||
console.log(`返回结果: ${JSON.stringify(response)}`);
|
||||
alert(`${response.data}`)
|
||||
}).catch(function (error) {
|
||||
console.log(`错误信息: ${error}`);
|
||||
alert("修改失败")
|
||||
@@ -45,6 +65,7 @@ function changeWelcomeEnableStatus(wxId) {
|
||||
}
|
||||
}).then(function (response) {
|
||||
console.log(`返回结果: ${JSON.stringify(response)}`);
|
||||
alert(`${response.data}`)
|
||||
}).catch(function (error) {
|
||||
console.log(`错误信息: ${error}`);
|
||||
alert("修改失败")
|
||||
@@ -61,6 +82,7 @@ function changeCommandEnableStatus(wxId) {
|
||||
}
|
||||
}).then(function (response) {
|
||||
console.log(`返回结果: ${JSON.stringify(response)}`);
|
||||
alert(`${response.data}`)
|
||||
}).catch(function (error) {
|
||||
console.log(`错误信息: ${error}`);
|
||||
alert("修改失败")
|
||||
@@ -79,6 +101,7 @@ function changeUserGroupRankSkipStatus(groupId, userId) {
|
||||
}
|
||||
}).then(function (response) {
|
||||
console.log(`返回结果: ${JSON.stringify(response)}`);
|
||||
alert(`${response.data}`)
|
||||
}).catch(function (error) {
|
||||
console.log(`错误信息: ${error}`);
|
||||
alert("修改失败")
|
||||
|
||||
@@ -18,6 +18,7 @@ type FriendItem struct {
|
||||
EnableChatRank bool // 是否使用聊天排行
|
||||
EnableWelcome bool // 是否使用迎新
|
||||
EnableCommand bool // 是否启用指令
|
||||
EnableSummary bool // 是否启用总结
|
||||
IsOk bool // 是否还在通讯库(群聊是要还在群里也算)
|
||||
}
|
||||
|
||||
|
||||
8
vo/message.go
Normal file
8
vo/message.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package vo
|
||||
|
||||
// TextMessageItem
|
||||
// @description: 文字消息
|
||||
type TextMessageItem struct {
|
||||
Nickname string `json:"nickname"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
Reference in New Issue
Block a user