Compare commits

...

11 Commits

Author SHA1 Message Date
1d62e95910 fix: 聊天消息增加角色 2025-06-16 18:28:16 +08:00
980880533c fix: 重构规则 2025-06-16 17:58:15 +08:00
58eb0d0b52 Update dto.go 2025-06-16 16:18:06 +08:00
cee0d67de1 fix: 更新配置 2025-06-16 16:10:48 +08:00
55c74ea17c fix: 修复卡片类型内容不展示 2025-06-16 15:51:52 +08:00
31d401e213 fix: 优化机器人监听事件的逻辑 2025-06-16 15:22:42 +08:00
c1dc0821e9 fix: 完成关键字回复 2025-06-16 15:04:11 +08:00
eb99e251bf fix: 修复部分聊天机器人相关问题 2025-06-16 14:02:55 +08:00
cde4488548 Update wsMessageHandle.go 2025-06-16 09:58:43 +08:00
aac5d05d13 Update wsMessageHandle.go 2025-06-16 09:55:13 +08:00
d415621631 Update wsMessageHandle.go 2025-06-16 09:52:07 +08:00
15 changed files with 271 additions and 122 deletions

View File

@ -45,7 +45,7 @@ const (
MsgType_ImageMsgType MsgType = 2 //图片
MsgType_AudioMsgType MsgType = 3 //音频
MsgType_VideoMsgType MsgType = 4 //视频
MsgType_FileType MsgType = 5 //文件
MsgType_CardType MsgType = 5 //卡片
)
// Enum value maps for MsgType.
@ -56,7 +56,7 @@ var (
2: "ImageMsgType",
3: "AudioMsgType",
4: "VideoMsgType",
5: "FileType",
5: "CardType",
}
MsgType_value = map[string]int32{
"UnknownMsgType": 0,
@ -64,7 +64,7 @@ var (
"ImageMsgType": 2,
"AudioMsgType": 3,
"VideoMsgType": 4,
"FileType": 5,
"CardType": 5,
}
)
@ -11421,7 +11421,7 @@ var file_accountFiee_proto_rawDesc = []byte{
0x01, 0x12, 0x10, 0x0a, 0x0c, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x4d, 0x73, 0x67, 0x54, 0x79, 0x70,
0x65, 0x10, 0x02, 0x12, 0x10, 0x0a, 0x0c, 0x41, 0x75, 0x64, 0x69, 0x6f, 0x4d, 0x73, 0x67, 0x54,
0x79, 0x70, 0x65, 0x10, 0x03, 0x12, 0x10, 0x0a, 0x0c, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x4d, 0x73,
0x67, 0x54, 0x79, 0x70, 0x65, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x54,
0x67, 0x54, 0x79, 0x70, 0x65, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x61, 0x72, 0x64, 0x54,
0x79, 0x70, 0x65, 0x10, 0x05, 0x32, 0xeb, 0x2b, 0x0a, 0x0b, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e,
0x74, 0x46, 0x69, 0x65, 0x65, 0x12, 0x3c, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x19,
0x2e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x46, 0x69, 0x65, 0x65, 0x2e, 0x4c, 0x6f, 0x67,

View File

@ -869,7 +869,7 @@ enum MsgType{
ImageMsgType = 2 ;//
AudioMsgType = 3 ;//
VideoMsgType = 4 ;//
FileType = 5 ;//
CardType = 5 ;//
}
message ChatRecordData{
int64 ID=1;

View File

@ -1,5 +1,5 @@
[system]
Domain = "fiee"
Domain = "app"
AppMode = "debug"
HttpPort = ":8085"
Host = "http://127.0.0.1:8085"
@ -14,12 +14,12 @@ BosBaseDir = "fonchain-main"
BosHttp = "https://"
BosDomain = "cdns.fontree.cn"
[oss]
AccessKeyId = "LTAI5tLz1fSK53FQAEC9uNSb"
AccessKeySecret = "oGB9chrQzQzITXR2IGv37Ji5WxZh4j"
Endpoint = "oss-cn-hangzhou.aliyuncs.com"
BucketName = "fontree-test"
BaseDir = "fonchain-main"
CdnHost = "https://cdn-test.szjixun.cn"
AccessKeyId = "LTAI5tHfjSmWXHqfWgaL7Uo5"
AccessKeySecret = "kOPctFZ3DHsbdSSym1fLyDK39hkzPI"
Endpoint = "oss-cn-hangzhou-internal.aliyuncs.com"
BucketName = "erp-k8s-store"
BaseDir = "fiee"
CdnHost = "https://e-cdn.fontree.cn"
[redis]
RedisDB = "2"
RedisAddr = "127.0.0.1:6379"

View File

@ -27,7 +27,7 @@ Password = "Gy.123456"
[oss]
AccessKeyId = "LTAI5tHfjSmWXHqfWgaL7Uo5"
AccessKeySecret = "kOPctFZ3DHsbdSSym1fLyDK39hkzPI"
Endpoint = "oss-cn-hangzhou.aliyuncs.com"
Endpoint = "oss-cn-hangzhou-internal.aliyuncs.com"
BucketName = "erp-k8s-store"
BaseDir = "fiee"
CdnHost = "https://e-cdn.fontree.cn"

View File

@ -12,7 +12,13 @@ BucketName = "dci-file-new"
BosUrl = ".bj.bcebos.com"
BosBaseDir = "fonchain-main"
BosHttp = "https://"
[oss]
AccessKeyId = "LTAI5tHfjSmWXHqfWgaL7Uo5"
AccessKeySecret = "kOPctFZ3DHsbdSSym1fLyDK39hkzPI"
Endpoint = "oss-cn-hangzhou-internal.aliyuncs.com"
BucketName = "erp-k8s-store"
BaseDir = "fiee"
CdnHost = "https://e-cdn.fontree.cn"
[redis]
RedisDB = "2"
RedisAddr = "redis:6379"

View File

@ -136,11 +136,11 @@ func (o *ChatRoom) Run() {
}
}
}
o.clientsRwLocker.Unlock()
//再把自己的客户端加入会话
o.Session[newClient.SessionId] = append(o.Session[newClient.SessionId], newClient)
}
o.pushEvent(EventUserJoin, EventProgressAfter, nil, newClient)
o.clientsRwLocker.Unlock()
//注销事件
case client := <-o.UnRegister:
o.pushEvent(EventUserLeave, EventProgressBefore, nil, client)
@ -190,10 +190,10 @@ func (o *ChatRoom) Register(c *Client) (sessionId string) {
// sessionId 会话id
// msgType 消息类型
// message: 消息内容
func (o *ChatRoom) SendSessionMessage(chatUser *accountFiee.ChatUserData, sessionId string, msgType WsType, message any) (userIdInSession []int64, err error) {
func (o *ChatRoom) SendSessionMessage(sender *accountFiee.ChatUserData, sessionId string, msgType WsType, message any) (userIdInSession []int64, err error) {
fmt.Println("ChatRoom.SendSessionMessage ------------------1")
o.clientsRwLocker.Lock()
defer o.clientsRwLocker.Unlock()
//o.clientsRwLocker.Lock()
//defer o.clientsRwLocker.Unlock()
var msg = WsSessionInfo{
Type: msgType,
Content: message,
@ -204,7 +204,7 @@ func (o *ChatRoom) SendSessionMessage(chatUser *accountFiee.ChatUserData, sessio
err = fmt.Errorf("该会话不存在或已失效")
return
}
fmt.Println("ChatRoom.SendSessionMessage - 1")
fmt.Println("ChatRoom.SendSessionMessage ------------------3")
usableClients := []*Client{}
fmt.Printf("sessionId:[%s],客户端数量%d\n", sessionId, len(o.Session[sessionId]))
for i, client := range o.Session[sessionId] {
@ -212,13 +212,13 @@ func (o *ChatRoom) SendSessionMessage(chatUser *accountFiee.ChatUserData, sessio
_, exist := o.clients[client.UserId][client.ClientId]
if exist {
usableClients = append(usableClients, o.Session[sessionId][i])
o.pushEvent(EventChatMessage, EventProgressBefore, chatUser, o.Session[sessionId][i], message)
go o.pushEvent(EventChatMessage, EventProgressBefore, sender, o.Session[sessionId][i], message)
}
}
fmt.Printf("client:%+v\n", client)
if client != nil && client.UserId != chatUser.ID {
if client != nil && (client.UserId != sender.ID || sender.Role == 3) {
client.Send <- msgBytes
o.pushEvent(EventChatMessage, EventProgressAfter, chatUser, o.Session[sessionId][i], message)
go o.pushEvent(EventChatMessage, EventProgressAfter, sender, o.Session[sessionId][i], message)
userIdInSession = append(userIdInSession, client.UserId)
}
//client.Send <- msgBytes
@ -230,8 +230,6 @@ func (o *ChatRoom) SendSessionMessage(chatUser *accountFiee.ChatUserData, sessio
}
func (o *ChatRoom) GetUserIdInSession(sessionId string, withoutUserId ...int64) (userIds []int64) {
fmt.Printf("sessionId:%s withoutUserId:%d\n", sessionId, withoutUserId)
//o.clientsRwLocker.RLock()
//defer o.clientsRwLocker.RUnlock()
fmt.Println("GetUserIdInSession 1")
if o.Session[sessionId] != nil {
fmt.Printf("GetUserIdInSession 2,o.Session[sessionId]:%+v", o.Session[sessionId])
@ -345,8 +343,8 @@ func (o *ChatRoom) UnRegisterEventListener(listenerChan *EventListener) {
// pushEvent 推送聊天室事件
func (o *ChatRoom) pushEvent(eventType EventType, progress EventProgress, chatUser *accountFiee.ChatUserData, client *Client, data ...any) {
o.EventRwLocker.Lock()
defer o.EventRwLocker.Unlock()
//o.EventRwLocker.Lock()
//defer o.EventRwLocker.Unlock()
for _, listener := range o.eventBus {
hit := false
for _, need := range listener.ListenEvents {
@ -358,13 +356,20 @@ func (o *ChatRoom) pushEvent(eventType EventType, progress EventProgress, chatUs
if hit == false {
continue
}
msg := ""
if data != nil {
msg = fmt.Sprintf("%v", data[0])
}
listener.Chan <- ListenEventData{
ListenEvent: ListenEvent{
EventType: eventType,
ProgressType: progress,
},
Client: client,
Data: data,
ChatUser: chatUser,
Client: client,
Msg: msg,
Data: data,
}
fmt.Printf("chatRooom 推送事件给%s eventType:%v progress:%v", listener.Name, eventType, progress)
}
}

View File

@ -6,6 +6,8 @@
// -------------------------------------------
package ws
import "fonchain-fiee/api/accountFiee"
// websocket 消息类型
type WsType int
@ -42,8 +44,10 @@ type ListenEvent struct {
}
type ListenEventData struct {
ListenEvent
Client *Client
Data any
Client *Client
ChatUser *accountFiee.ChatUserData
Msg string
Data any
}
type ListenEventChan chan ListenEventData
type EventListener struct {

View File

@ -80,6 +80,7 @@ func AuthorizationVerify(sourceData []byte) (userInfo *accountFiee.ChatUserData,
if err != nil || fontreeJwtInfo.IsOffline {
check = false
} else {
check = true
fmt.Printf("fontreeJwtInfo is %#v\n", fontreeJwtInfo)
accountInfo.Origin = e.ErpDomain
accountInfo.OriginId = int64(fontreeJwtInfo.ID)
@ -147,6 +148,7 @@ func HandleMessage(sourceData []byte, cli *Client) {
switch msg.Type {
default:
cli.Send <- WsErrorUnknownMessageType(msg.From)
//fmt.Printf("不支持的ws业务消息%#v\n", msg)
case TestType:
var newMsg = WsInfo{
Type: TestType,

View File

@ -55,19 +55,37 @@ type MessageListType struct {
ID int64 `json:"ID"`
CreatedAt string `json:"createdAt"`
UserId int64 `json:"userId"`
Role int32 `json:"role,omitempty"`
Name string `json:"name"`
Message Message `json:"message"`
}
func (m *MessageListType) BuildMessage(data *accountFiee.ChatRecordData) {
func (m *MessageListType) BuildMessage(data *accountFiee.ChatRecordData, role int32) {
m.ID = data.ID
m.CreatedAt = data.CreatedAt
m.UserId = data.UserId
m.Name = data.Name
m.Role = role
switch data.MsgType {
default:
m.Message.MsgType = data.MsgType
m.Message.Text = data.Content
m.Message.LocalStamp = data.LocalStamp
if data.Medias != nil {
for _, media := range data.Medias {
m.Message.Media = append(m.Message.Media, MessageMedia{
MediaId: media.ID,
MediaSize: media.Size,
Ext: media.Ext,
Url: media.Url,
ConvText: media.ConvText,
Duration: media.Duration,
})
}
}
case accountFiee.MsgType_TextMsgType:
m.Message = Message{
MsgType: accountFiee.MsgType_TextMsgType,
MsgType: data.MsgType,
Text: data.Content,
Media: []MessageMedia{},
LocalStamp: data.LocalStamp,

View File

@ -42,9 +42,14 @@ import (
"go.uber.org/zap"
)
var ChatHandlerIns = ChatHandler{
cache: chatCache.ChatCache{NewMessageStatExpireAfter: 10 * time.Minute},
robot: robot.NewRobot(),
var ChatHandlerIns = NewChatHandler()
func NewChatHandler() ChatHandler {
c := ChatHandler{
cache: chatCache.ChatCache{NewMessageStatExpireAfter: 10 * time.Minute},
}
c.robot = robot.NewRobot(&c.cache)
return c
}
type ChatHandler struct {
@ -317,7 +322,7 @@ func (cr ChatHandler) MessageList(c *gin.Context) {
}
returnDataIdList = append(returnDataIdList, message.ID)
var msg = &dto.MessageListType{}
msg.BuildMessage(message)
msg.BuildMessage(message, 0)
resp = append(resp, msg)
}
} else {
@ -349,7 +354,7 @@ func (cr ChatHandler) MessageList(c *gin.Context) {
total++
returnDataIdList = append(returnDataIdList, message.ID)
var msg = &dto.MessageListType{}
msg.BuildMessage(message)
msg.BuildMessage(message, 0)
resp = append(resp, msg)
}
}
@ -429,7 +434,7 @@ func (cr ChatHandler) Upload(c *gin.Context) {
defer tmp.Close()
fileBuffer := bytes.NewBuffer(fileContent)
var bosUrl string
bosUrl, err = upload.UploadWithBuffer(fileBuffer, fmt.Sprintf("fiee/%d/%v%v", chatUser.ID, filename, fileExt))
bosUrl, err = upload.UploadWithBuffer(fileBuffer, fmt.Sprintf("%d/%v%v", chatUser.ID, filename, fileExt))
if err != nil {
service.Error(c, err)
return

View File

@ -75,7 +75,7 @@ func NewMessage(ctx context.Context, cache *chatCache.ChatCache, chatUser *accou
fmt.Println("NewMessage 6")
//发送websocket消息提醒通知
var notice = dto.MessageListType{}
notice.BuildMessage(resp.Data)
notice.BuildMessage(resp.Data, chatUser.Role)
fmt.Printf("ws消息提醒:%+v\n", notice)
_, err = consts.ChatRoom.SendSessionMessage(chatUser, request.SessionId, ws.NewChatMsgType, notice)
if err != nil {

View File

@ -11,20 +11,22 @@ import (
"fonchain-fiee/api/accountFiee"
"fonchain-fiee/pkg/common/ws"
"fonchain-fiee/pkg/service"
"fonchain-fiee/pkg/service/asChat/consts"
"fonchain-fiee/pkg/service/asChat/chatCache"
"fonchain-fiee/pkg/service/asChat/dto"
"fonchain-fiee/pkg/service/asChat/logic"
"strings"
"time"
)
// 回复规则
type Reply struct {
Response string
Rules []IRule
}
func (r *Reply) Hit(eventType ws.EventType, chatUser *accountFiee.ChatUserData, wsClient *ws.Client, msg *accountFiee.ChatRecordData, robotInfo *accountFiee.ChatUserData) (hit bool, runTime time.Time, logic func(msg string) error) {
func (r *Reply) Hit(event ws.ListenEventData, robotInfo *accountFiee.ChatUserData) (hit bool, task RobotTask) {
for _, rule := range r.Rules {
hit, runTime, logic = rule.Hit(eventType, chatUser, wsClient, msg, robotInfo)
hit, task = rule.Hit(event, robotInfo)
if hit {
return
}
@ -32,12 +34,9 @@ func (r *Reply) Hit(eventType ws.EventType, chatUser *accountFiee.ChatUserData,
return
}
// 规则接口
type IRule interface {
Hit(eventType ws.EventType, chatUser *accountFiee.ChatUserData, wsClient *ws.Client, msg *accountFiee.ChatRecordData, robotInfo *accountFiee.ChatUserData) (hit bool, runTime time.Time, logic func(msg string) error)
}
func NewReplyWhenHitKeywords(keywords []string) IRule {
return &ReplyWhenHitKeywords{Keywords: keywords}
Hit(event ws.ListenEventData, robotInfo *accountFiee.ChatUserData) (hit bool, task RobotTask)
}
// KeywordsRuleChecker 关键字回复
@ -45,44 +44,80 @@ type ReplyWhenHitKeywords struct {
Keywords []string `json:"keywords"`
}
func (k ReplyWhenHitKeywords) Hit(eventType ws.EventType, chatUser *accountFiee.ChatUserData, wsClient *ws.Client, record *accountFiee.ChatRecordData, robotInfo *accountFiee.ChatUserData) (hit bool, runTime time.Time, logic func(msg string) error) {
if record == nil {
func NewReplyWhenHitKeywords(keywords []string) IRule {
return &ReplyWhenHitKeywords{Keywords: keywords}
}
func (k ReplyWhenHitKeywords) Hit(event ws.ListenEventData, robotInfo *accountFiee.ChatUserData) (hit bool, task RobotTask) {
if event.EventType != ws.EventChatMessage || event.Msg == "" || event.Client == nil || event.ChatUser == nil {
return
}
for _, v := range k.Keywords {
if strings.Contains(record.Content, v) {
if strings.Contains(event.Msg, v) {
hit = true
break
}
}
logic = func(msg string) error {
var notice = dto.MessageListType{}
notice.BuildMessage(record)
_, err := consts.ChatRoom.SendSessionMessage(robotInfo, record.SessionId, ws.NewChatMsgType, notice)
return err
task = RobotTask{
ChatUser: event.ChatUser,
Run: func(msg string, cache *chatCache.ChatCache, Sender *accountFiee.ChatUserData) error {
return logic.NewMessage(context.Background(), cache, Sender, dto.NewMessageRequest{
Waiter: true,
SessionId: event.Client.SessionId,
Message: dto.Message{
MsgType: 1,
Text: msg,
LocalStamp: time.Now().Unix(),
},
})
},
}
//logicFunc = func(content string, cache *chatCache.ChatCache, chatUser *accountFiee.ChatUserData) error {
// //var notice = dto.MessageListType{}
// //newRecord := &accountFiee.ChatRecordData{
// // SessionId: wsClient.SessionId,
// // UserId: wsClient.UserId,
// // Name: chatUser.NickName,
// // Avatar: robotInfo.Avatar,
// // MsgType: 1,
// // Content: content,
// //}
// //notice.BuildMessage(newRecord)
// //_, err := consts.ChatRoom.SendSessionMessage(robotInfo, wsClient.SessionId, ws.NewChatMsgType, notice)
// //return err
// err := logic.NewMessage(context.Background(), cache, chatUser, dto.NewMessageRequest{
// Waiter: true,
// SessionId: wsClient.SessionId,
// Message: dto.Message{
// MsgType: 1,
// Text: msg,
// LocalStamp: time.Now().Unix(),
// },
// })
// return err
//}
return
}
// 用户打开聊天会话直接发送
type ReplyWhenUserJoinSession struct {
}
func NewReplyWhenUserJoinSession() IRule {
return &ReplyWhenUserJoinSession{}
}
type ReplyWhenUserJoinSession struct {
}
func (k ReplyWhenUserJoinSession) Hit(eventType ws.EventType, chatUser *accountFiee.ChatUserData, wsClient *ws.Client, record *accountFiee.ChatRecordData, robotInfo *accountFiee.ChatUserData) (hit bool, runTime time.Time, logic func(msg string) error) {
if eventType != ws.EventUserJoin {
func (k ReplyWhenUserJoinSession) Hit(event ws.ListenEventData, robotInfo *accountFiee.ChatUserData) (hit bool, task RobotTask) {
if event.EventType != ws.EventUserJoin {
return
}
if wsClient == nil {
if event.Client == nil {
return
}
ctx := context.Background()
queryRes, err := service.AccountFieeProvider.GetChatRecordList(ctx, &accountFiee.GetChatRecordListRequest{
Query: &accountFiee.ChatRecordData{
SessionId: wsClient.SessionId,
SessionId: event.Client.SessionId,
},
Page: 1,
PageSize: 1,
@ -102,41 +137,115 @@ func (k ReplyWhenUserJoinSession) Hit(eventType ws.EventType, chatUser *accountF
}
}
hit = true
logic = func(msg string) error {
var notice = dto.MessageListType{}
newRecord := &accountFiee.ChatRecordData{
SessionId: wsClient.SessionId,
UserId: wsClient.UserId,
Name: wsClient.SessionId,
Avatar: robotInfo.Avatar,
MsgType: 1,
Content: msg,
if event.ChatUser == nil {
event.ChatUser, err = service.AccountFieeProvider.GetChatUserDetail(context.Background(), &accountFiee.GetChatUserByIdRequest{Id: event.Client.UserId})
if err != nil {
return
}
notice.BuildMessage(newRecord)
_, err = consts.ChatRoom.SendSessionMessage(robotInfo, wsClient.SessionId, ws.NewChatMsgType, notice)
return err
}
task = RobotTask{
ChatUser: event.ChatUser,
Run: func(msg string, cache *chatCache.ChatCache, Sender *accountFiee.ChatUserData) error {
return logic.NewMessage(ctx, cache, Sender, dto.NewMessageRequest{
Waiter: true,
SessionId: event.Client.SessionId,
Message: dto.Message{
MsgType: 1,
Text: msg,
LocalStamp: time.Now().Unix(),
},
})
},
}
//logicFunc = func(msg string, cache *chatCache.ChatCache, chatUser *accountFiee.ChatUserData) error {
// //var notice = dto.MessageListType{}
// //newRecord := &accountFiee.ChatRecordData{
// // SessionId: wsClient.SessionId,
// // UserId: wsClient.UserId,
// // Name: wsClient.SessionId,
// // Avatar: robotInfo.Avatar,
// // MsgType: 1,
// // Content: msg,
// //}
// //notice.BuildMessage(newRecord)
// //_, err = consts.ChatRoom.SendSessionMessage(robotInfo, wsClient.SessionId, ws.NewChatMsgType, notice)
// err = logic.NewMessage(ctx, cache, chatUser, dto.NewMessageRequest{
// Waiter: true,
// SessionId: wsClient.SessionId,
// Message: dto.Message{
// MsgType: 1,
// Text: msg,
// LocalStamp: time.Now().Unix(),
// },
// })
// return err
//}
return
}
// 客服
// 客服指定时间不回复则自动回复
type ReplyWhenWaiterNoAction struct {
DelaySecond time.Duration
}
func NewReplyWhenWaiterNoAction(delaySecond time.Duration) *ReplyWhenWaiterNoAction {
return &ReplyWhenWaiterNoAction{
DelaySecond: delaySecond,
}
}
type ReplyWhenWaiterNoAction struct {
DelaySecond time.Duration
}
func (k *ReplyWhenWaiterNoAction) Hit(event ws.ListenEventData, chatUser *accountFiee.ChatUserData) (hit bool, task RobotTask) {
if event.Client == nil || event.EventType != ws.EventChatMessage {
return
}
task = RobotTask{
RunTime: time.Now().Add(k.DelaySecond * time.Second),
Run: func(content string, cache *chatCache.ChatCache, Sender *accountFiee.ChatUserData) error {
//如果客服已经回复则不发送消息
chatRecordListRes, err := service.AccountFieeProvider.GetChatRecordList(context.Background(), &accountFiee.GetChatRecordListRequest{
Query: &accountFiee.ChatRecordData{
SessionId: event.Client.SessionId,
},
Page: 1,
PageSize: 1,
Order: "created_at desc",
})
if err != nil || chatRecordListRes.Total == 0 {
return err
}
checkUserId := chatRecordListRes.List[0].UserId
checkChatUser, err := service.AccountFieeProvider.GetChatUserDetail(context.Background(), &accountFiee.GetChatUserByIdRequest{Id: checkUserId})
if err != nil || checkChatUser.Role != 1 {
return err
}
func (k *ReplyWhenWaiterNoAction) Hit(eventType ws.EventType, chatUser *accountFiee.ChatUserData, wsClient *ws.Client, record *accountFiee.ChatRecordData, robotInfo *accountFiee.ChatUserData) (hit bool, runTime time.Time, logic func(msg string) error) {
runTime = time.Now().Add(k.DelaySecond * time.Second)
logic = func(msg string) error {
var notice = dto.MessageListType{}
notice.BuildMessage(record)
_, err := consts.ChatRoom.SendSessionMessage(robotInfo, record.SessionId, ws.NewChatMsgType, notice)
return err
//var notice = dto.MessageListType{}
//newRecord := &accountFiee.ChatRecordData{
// SessionId: wsClient.SessionId,
// UserId: wsClient.UserId,
// Name: chatUser.NickName,
// Avatar: robotInfo.Avatar,
// MsgType: 1,
// Content: content,
//}
//notice.BuildMessage(newRecord)
//_, err = consts.ChatRoom.SendSessionMessage(robotInfo, wsClient.SessionId, ws.NewChatMsgType, notice)
//return err
err = logic.NewMessage(context.Background(), cache, chatUser, dto.NewMessageRequest{
Waiter: true,
SessionId: event.Client.SessionId,
Message: dto.Message{
MsgType: 1,
Text: event.Msg,
LocalStamp: time.Now().Unix(),
},
})
return err
},
Response: "",
ChatUser: event.ChatUser,
}
return

View File

@ -12,6 +12,7 @@ import (
"fonchain-fiee/api/accountFiee"
"fonchain-fiee/pkg/common/ws"
"fonchain-fiee/pkg/service"
"fonchain-fiee/pkg/service/asChat/chatCache"
"fonchain-fiee/pkg/service/asChat/consts"
"fonchain-fiee/pkg/service/asChat/dto"
"log"
@ -19,7 +20,7 @@ import (
"time"
)
func NewRobot() *Robot {
func NewRobot(cache *chatCache.ChatCache) *Robot {
ctx := context.Background()
robotQuery, err := service.AccountFieeProvider.GetChatUserList(ctx, &accountFiee.GetChatUserListRequest{
Query: &accountFiee.ChatUserData{Role: 3},
@ -49,10 +50,11 @@ func NewRobot() *Robot {
Name: "robot1",
ListenEvents: []ws.ListenEvent{ //只监听消息推送事件
{ws.EventUserJoin, ws.EventProgressAfter},
{ws.EventChatMessage, ws.EventProgressAfter},
{ws.EventChatMessage, ws.EventProgressBefore},
},
Chan: make(ws.ListenEventChan),
},
cache: cache,
}
ruleListRes, err := service.AccountFieeProvider.GetChatAutoReplyRulerList(ctx, &accountFiee.GetChatAutoReplyRulerListRequest{
Query: &accountFiee.ChatAutoReplyRulerData{Status: 1},
@ -87,6 +89,7 @@ type Robot struct {
isRunning bool //运行状态
mu sync.Mutex
*ws.EventListener
cache *chatCache.ChatCache
}
//func (r *Robot) Listen(record *accountFiee.ChatRecordData) {
@ -144,6 +147,8 @@ func (r *Robot) Run() {
for {
select {
default:
time.Sleep(200 * time.Millisecond)
case <-r.ticker.C:
r.mu.Lock()
if len(r.DelayTask) == 0 {
@ -157,7 +162,7 @@ func (r *Robot) Run() {
if now.After(task.RunTime) {
// 执行任务
go func() {
err := task.Run(task.Response)
err := task.Run(task.Response, r.cache, task.ChatUser)
if err != nil {
log.Printf("聊天机器人[%d]回复消息失败:%v", r.Info.ID, err)
}
@ -172,39 +177,21 @@ func (r *Robot) Run() {
case <-r.stopChan:
return
case event := <-r.EventListener.Chan:
fmt.Printf("listen event:%#v\n", event)
switch event.EventType {
case ws.EventUserJoin: //用户加入聊天室
for _, ruleResponse := range r.Rules {
hit, runtime, logic := ruleResponse.Hit(ws.EventUserJoin, nil, event.Client, nil, r.Info)
if hit {
if runtime.IsZero() {
err := logic(ruleResponse.Response)
if err != nil {
log.Printf("robot 执行任务失败:%v\n", err)
}
} else {
r.DelayTask = append(r.DelayTask, RobotTask{
RunTime: runtime,
Run: logic,
Response: ruleResponse.Response,
})
fmt.Printf("robot listen event:%#v\n", event)
for _, ruleResponse := range r.Rules {
hit, task := ruleResponse.Hit(event, r.Info)
if hit {
if task.RunTime.IsZero() {
err := task.Run(ruleResponse.Response, r.cache, r.Info)
if err != nil {
log.Printf("robot 执行任务失败:%v\n", err)
}
break
}
}
case ws.EventChatMessage:
for _, ruleResponse := range r.Rules {
hit, runtime, logic := ruleResponse.Hit(ws.EventUserJoin, nil, event.Client, nil, r.Info)
if hit {
if !runtime.IsZero() {
err := logic(ruleResponse.Response)
if err != nil {
log.Printf("robot 执行任务失败:%v\n", err)
}
}
break
} else {
task.Response = ruleResponse.Response
r.RegisterDelayTask(task)
}
break
}
}
}
@ -219,3 +206,11 @@ func (r *Robot) Stop() {
}
r.mu.Unlock()
}
func (r *Robot) RegisterDelayTask(task RobotTask) {
r.mu.Lock()
defer r.mu.Unlock()
if task.Run == nil {
return
}
r.DelayTask = append(r.DelayTask, task)
}

View File

@ -21,7 +21,7 @@ func ParseReplyRule(data *dto.ChatAutoReplyData) (r Reply) {
switch ruleName {
case "keywords": //关键字回复
var keywords []string
if v.Content != "" {
if v.Content == "" {
continue
} else {
keywords = strings.Split(v.Content, ",")

View File

@ -6,10 +6,15 @@
// -------------------------------------------
package robot
import "time"
import (
"fonchain-fiee/api/accountFiee"
"fonchain-fiee/pkg/service/asChat/chatCache"
"time"
)
type RobotTask struct {
RunTime time.Time
Run func(msg string) error
Run func(msg string, cache *chatCache.ChatCache, Sender *accountFiee.ChatUserData) error
Response string
ChatUser *accountFiee.ChatUserData
}