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_ImageMsgType MsgType = 2 //图片
MsgType_AudioMsgType MsgType = 3 //音频 MsgType_AudioMsgType MsgType = 3 //音频
MsgType_VideoMsgType MsgType = 4 //视频 MsgType_VideoMsgType MsgType = 4 //视频
MsgType_FileType MsgType = 5 //文件 MsgType_CardType MsgType = 5 //卡片
) )
// Enum value maps for MsgType. // Enum value maps for MsgType.
@ -56,7 +56,7 @@ var (
2: "ImageMsgType", 2: "ImageMsgType",
3: "AudioMsgType", 3: "AudioMsgType",
4: "VideoMsgType", 4: "VideoMsgType",
5: "FileType", 5: "CardType",
} }
MsgType_value = map[string]int32{ MsgType_value = map[string]int32{
"UnknownMsgType": 0, "UnknownMsgType": 0,
@ -64,7 +64,7 @@ var (
"ImageMsgType": 2, "ImageMsgType": 2,
"AudioMsgType": 3, "AudioMsgType": 3,
"VideoMsgType": 4, "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, 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, 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, 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, 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, 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, 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 ;// ImageMsgType = 2 ;//
AudioMsgType = 3 ;// AudioMsgType = 3 ;//
VideoMsgType = 4 ;// VideoMsgType = 4 ;//
FileType = 5 ;// CardType = 5 ;//
} }
message ChatRecordData{ message ChatRecordData{
int64 ID=1; int64 ID=1;

View File

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

View File

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

View File

@ -12,7 +12,13 @@ BucketName = "dci-file-new"
BosUrl = ".bj.bcebos.com" BosUrl = ".bj.bcebos.com"
BosBaseDir = "fonchain-main" BosBaseDir = "fonchain-main"
BosHttp = "https://" 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] [redis]
RedisDB = "2" RedisDB = "2"
RedisAddr = "redis:6379" 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.Session[newClient.SessionId] = append(o.Session[newClient.SessionId], newClient)
} }
o.pushEvent(EventUserJoin, EventProgressAfter, nil, newClient) o.pushEvent(EventUserJoin, EventProgressAfter, nil, newClient)
o.clientsRwLocker.Unlock()
//注销事件 //注销事件
case client := <-o.UnRegister: case client := <-o.UnRegister:
o.pushEvent(EventUserLeave, EventProgressBefore, nil, client) o.pushEvent(EventUserLeave, EventProgressBefore, nil, client)
@ -190,10 +190,10 @@ func (o *ChatRoom) Register(c *Client) (sessionId string) {
// sessionId 会话id // sessionId 会话id
// msgType 消息类型 // msgType 消息类型
// message: 消息内容 // 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") fmt.Println("ChatRoom.SendSessionMessage ------------------1")
o.clientsRwLocker.Lock() //o.clientsRwLocker.Lock()
defer o.clientsRwLocker.Unlock() //defer o.clientsRwLocker.Unlock()
var msg = WsSessionInfo{ var msg = WsSessionInfo{
Type: msgType, Type: msgType,
Content: message, Content: message,
@ -204,7 +204,7 @@ func (o *ChatRoom) SendSessionMessage(chatUser *accountFiee.ChatUserData, sessio
err = fmt.Errorf("该会话不存在或已失效") err = fmt.Errorf("该会话不存在或已失效")
return return
} }
fmt.Println("ChatRoom.SendSessionMessage - 1") fmt.Println("ChatRoom.SendSessionMessage ------------------3")
usableClients := []*Client{} usableClients := []*Client{}
fmt.Printf("sessionId:[%s],客户端数量%d\n", sessionId, len(o.Session[sessionId])) fmt.Printf("sessionId:[%s],客户端数量%d\n", sessionId, len(o.Session[sessionId]))
for i, client := range 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] _, exist := o.clients[client.UserId][client.ClientId]
if exist { if exist {
usableClients = append(usableClients, o.Session[sessionId][i]) 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) 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 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) userIdInSession = append(userIdInSession, client.UserId)
} }
//client.Send <- msgBytes //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) { func (o *ChatRoom) GetUserIdInSession(sessionId string, withoutUserId ...int64) (userIds []int64) {
fmt.Printf("sessionId:%s withoutUserId:%d\n", sessionId, withoutUserId) fmt.Printf("sessionId:%s withoutUserId:%d\n", sessionId, withoutUserId)
//o.clientsRwLocker.RLock()
//defer o.clientsRwLocker.RUnlock()
fmt.Println("GetUserIdInSession 1") fmt.Println("GetUserIdInSession 1")
if o.Session[sessionId] != nil { if o.Session[sessionId] != nil {
fmt.Printf("GetUserIdInSession 2,o.Session[sessionId]:%+v", o.Session[sessionId]) fmt.Printf("GetUserIdInSession 2,o.Session[sessionId]:%+v", o.Session[sessionId])
@ -345,8 +343,8 @@ func (o *ChatRoom) UnRegisterEventListener(listenerChan *EventListener) {
// pushEvent 推送聊天室事件 // pushEvent 推送聊天室事件
func (o *ChatRoom) pushEvent(eventType EventType, progress EventProgress, chatUser *accountFiee.ChatUserData, client *Client, data ...any) { func (o *ChatRoom) pushEvent(eventType EventType, progress EventProgress, chatUser *accountFiee.ChatUserData, client *Client, data ...any) {
o.EventRwLocker.Lock() //o.EventRwLocker.Lock()
defer o.EventRwLocker.Unlock() //defer o.EventRwLocker.Unlock()
for _, listener := range o.eventBus { for _, listener := range o.eventBus {
hit := false hit := false
for _, need := range listener.ListenEvents { for _, need := range listener.ListenEvents {
@ -358,13 +356,20 @@ func (o *ChatRoom) pushEvent(eventType EventType, progress EventProgress, chatUs
if hit == false { if hit == false {
continue continue
} }
msg := ""
if data != nil {
msg = fmt.Sprintf("%v", data[0])
}
listener.Chan <- ListenEventData{ listener.Chan <- ListenEventData{
ListenEvent: ListenEvent{ ListenEvent: ListenEvent{
EventType: eventType, EventType: eventType,
ProgressType: progress, ProgressType: progress,
}, },
ChatUser: chatUser,
Client: client, Client: client,
Msg: msg,
Data: data, Data: data,
} }
fmt.Printf("chatRooom 推送事件给%s eventType:%v progress:%v", listener.Name, eventType, progress)
} }
} }

View File

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

View File

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

View File

@ -55,19 +55,37 @@ type MessageListType struct {
ID int64 `json:"ID"` ID int64 `json:"ID"`
CreatedAt string `json:"createdAt"` CreatedAt string `json:"createdAt"`
UserId int64 `json:"userId"` UserId int64 `json:"userId"`
Role int32 `json:"role,omitempty"`
Name string `json:"name"` Name string `json:"name"`
Message Message `json:"message"` 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.ID = data.ID
m.CreatedAt = data.CreatedAt m.CreatedAt = data.CreatedAt
m.UserId = data.UserId m.UserId = data.UserId
m.Name = data.Name m.Name = data.Name
m.Role = role
switch data.MsgType { 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: case accountFiee.MsgType_TextMsgType:
m.Message = Message{ m.Message = Message{
MsgType: accountFiee.MsgType_TextMsgType, MsgType: data.MsgType,
Text: data.Content, Text: data.Content,
Media: []MessageMedia{}, Media: []MessageMedia{},
LocalStamp: data.LocalStamp, LocalStamp: data.LocalStamp,

View File

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

View File

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

View File

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

View File

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

View File

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