diff --git a/pkg/service/asChat/robot/replyAndRuler.go b/pkg/service/asChat/robot/replyAndRuler.go index 0483d9d..13b2b6d 100644 --- a/pkg/service/asChat/robot/replyAndRuler.go +++ b/pkg/service/asChat/robot/replyAndRuler.go @@ -27,220 +27,3 @@ func (r *Reply) Hit(event ws.ListenEventData, robotInfo *accountFiee.ChatUserDat } return } - -// -//// 规则接口 -//type IRule interface { -// Hit(event ws.ListenEventData, robotInfo *accountFiee.ChatUserData) (hit bool, task RobotTask) -//} -// -//// KeywordsRuleChecker 关键字回复 -//type ReplyWhenHitKeywords struct { -// Keywords []string `json:"keywords"` -//} -// -//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 -// } -// if event.ChatUser.Role != 1 { -// return -// } -// for _, v := range k.Keywords { -// if strings.Contains(event.Msg, v) { -// hit = true -// break -// } -// } -// atUserId := event.Client.UserId -// 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, -// Robot: true, -// AtUserId: atUserId, -// SessionId: event.Client.SessionId, -// Message: dto.Message{ -// MsgType: 1, -// Text: msg, -// LocalStamp: time.Now().Unix(), -// }, -// }) -// }, -// } -// return -//} -// -//// 用户打开聊天会话直接发送 -//type ReplyWhenUserJoinSession struct { -//} -// -//func NewReplyWhenUserJoinSession() IRule { -// return &ReplyWhenUserJoinSession{} -//} -// -//func (k ReplyWhenUserJoinSession) Hit(event ws.ListenEventData, robotInfo *accountFiee.ChatUserData) (hit bool, task RobotTask) { -// if event.EventType != ws.EventUserJoin { -// return -// } -// if event.Client == nil { -// return -// } -// clientSessionId := event.Client.SessionId -// atUserId := event.Client.UserId -// ctx := context.Background() -// queryRes, err := service.AccountFieeProvider.GetChatRecordList(ctx, &accountFiee.GetChatRecordListRequest{ -// Query: &accountFiee.ChatRecordData{ -// SessionId: event.Client.SessionId, -// }, -// Page: 1, -// PageSize: 1, -// Order: "created_at desc", -// }) -// if err != nil { -// return -// } -// //如果最近一次的消息也是机器人发送的,就不再发送了 -// for i, v := range queryRes.List { -// if i == 0 { -// if v.UserId == robotInfo.ID { -// return -// } else { -// break -// } -// } -// } -// hit = true -// if event.ChatUser == nil { -// event.ChatUser, err = service.AccountFieeProvider.GetChatUserDetail(context.Background(), &accountFiee.GetChatUserByIdRequest{Id: event.Client.UserId}) -// if err != nil { -// return -// } -// } -// 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, -// Robot: true, -// AtUserId: atUserId, -// SessionId: clientSessionId, -// 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, -//// } -////} -// -//func (k *ReplyWhenWaiterNoAction) Hit(event ws.ListenEventData, sender *accountFiee.ChatUserData) (hit bool, task RobotTask) { -// if event.Client == nil || event.EventType != ws.EventChatMessage { -// return -// } -// //客服和机器人的的消息不需要处理 -// if event.ChatUser.Role != 1 { -// return -// } -// hit = true // 立即保存SessionId的值 -// -// clientSessionId := event.Client.SessionId -// atUserId := event.Client.UserId -// fmt.Printf("闭包前: clientSessionId=%s\n", clientSessionId) -// task = RobotTask{ -// RunTime: time.Now().Add(k.DelaySecond * time.Second), -// Run: func(content string, cache *chatCache.ChatCache, Sender *accountFiee.ChatUserData) error { -// // 记录闭包执行时的Client状态 -// fmt.Printf("闭包执行: clientSessionId=%s\n", clientSessionId) -// -// //如果客服已经回复则不发送消息 -// 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 -// } -// -// //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 -// fmt.Println("延时回复 sessionID:", clientSessionId) -// err = logic.NewMessage(context.Background(), cache, sender, dto.NewMessageRequest{ -// Waiter: true, -// Robot: true, -// AtUserId: atUserId, -// SessionId: clientSessionId, -// Message: dto.Message{ -// MsgType: 1, -// Text: content, -// LocalStamp: time.Now().Unix(), -// }, -// }) -// return err -// }, -// Response: "", -// ChatUser: event.ChatUser, -// } -// return -// -//} diff --git a/pkg/service/asChat/robot/robot.go b/pkg/service/asChat/robot/robot.go index 4317ea5..eb08f77 100644 --- a/pkg/service/asChat/robot/robot.go +++ b/pkg/service/asChat/robot/robot.go @@ -64,13 +64,13 @@ func NewRobot(cache *chatCache.ChatCache) *Robot { } type Robot struct { - Info *accountFiee.ChatUserData //机器人信息 - Rules []Reply //回复规则 - DelayTask []IRobotTask //演示任务 - ticker *time.Ticker //定时器 - stopChan chan struct{} //停止管道 - isRunning bool //运行状态 - mu sync.Mutex + Info *accountFiee.ChatUserData //机器人信息 + joinSessionRules, keywordsRules, noReplyAfterRules []IRobotTask //自动回复规则 + DelayTask []IRobotTask //延时任务 + ticker *time.Ticker //定时器 + stopChan chan struct{} //停止管道 + isRunning bool //运行状态 + mu sync.Mutex *ws.EventListener cache *chatCache.ChatCache } @@ -164,22 +164,52 @@ func (r *Robot) Run() { case event := <-r.EventListener.Chan: fmt.Printf("robot listen event:%#v\n", event) r.mu.Lock() - for _, ruleResponse := range r.Rules { - hit, task := ruleResponse.Hit(event, r.Info) + //加入聊天室规则 + hit := false + for _, rule := range r.joinSessionRules { + hit = rule.Hit(event, r.Info) if hit { - fmt.Println("命中规则:", ruleResponse.Title) - if task.RunTime().IsZero() { - task.SetResponse(ruleResponse.Response) - err := task.Run(r.cache) + fmt.Println("命中规则:", rule.GetTitle()) + if rule.RunTime().IsZero() { + err := rule.Run(r.cache) if err != nil { log.Printf("robot 执行任务失败:%v\n", err) } } else { - ruleResponse := ruleResponse - task.SetResponse(ruleResponse.Response) - r.RegisterDelayTask(task) + r.RegisterDelayTask(rule) + } + } + } + if !hit { + for _, rule := range r.keywordsRules { + hit = rule.Hit(event, r.Info) + if hit { + fmt.Println("命中规则:", rule.GetTitle()) + if rule.RunTime().IsZero() { + err := rule.Run(r.cache) + if err != nil { + log.Printf("robot 执行任务失败:%v\n", err) + } + } else { + r.RegisterDelayTask(rule) + } + } + } + } + if !hit { + for _, rule := range r.noReplyAfterRules { + hit := rule.Hit(event, r.Info) + if hit { + fmt.Println("命中规则:", rule.GetTitle()) + if rule.RunTime().IsZero() { + err := rule.Run(r.cache) + if err != nil { + log.Printf("robot 执行任务失败:%v\n", err) + } + } else { + r.RegisterDelayTask(rule) + } } - break } } r.mu.Unlock() @@ -206,7 +236,9 @@ func (r *Robot) RegisterDelayTask(task IRobotTask) { func (r *Robot) ReloadRules(ctx context.Context) error { r.mu.Lock() defer r.mu.Unlock() - r.Rules = []Reply{} + r.joinSessionRules = []IRobotTask{} + r.keywordsRules = []IRobotTask{} + r.noReplyAfterRules = []IRobotTask{} ruleListRes, err := service.AccountFieeProvider.GetChatAutoReplyRulerList(ctx, &accountFiee.GetChatAutoReplyRulerListRequest{ Query: &accountFiee.ChatAutoReplyRulerData{Status: 1}, Page: 1, @@ -222,10 +254,7 @@ func (r *Robot) ReloadRules(ctx context.Context) error { tmp.Parse(v) data = append(data, &tmp) } - for _, v := range data { - reply := ParseReplyRule(v) - r.Rules = append(r.Rules, reply) - } + ParseReplyRule(data) } return nil } diff --git a/pkg/service/asChat/robot/rulerList.go b/pkg/service/asChat/robot/rulerList.go index 1e23495..2417b28 100644 --- a/pkg/service/asChat/robot/rulerList.go +++ b/pkg/service/asChat/robot/rulerList.go @@ -13,30 +13,37 @@ import ( ) // 自动回复规则结构转换 -func ParseReplyRule(data *dto.ChatAutoReplyData) (r Reply) { - r.Response = data.Response - r.Title = data.Title - for ruleName, v := range data.Rules { - if !v.Enable { - continue - } - switch ruleName { - case "keywords": //关键字回复 - var keywords []string - if v.Content == "" { - continue - } else { - keywords = strings.Split(v.Content, ",") - } - fmt.Println("ParseReplyRule 解析keywords:", keywords) - r.Rules = append(r.Rules, NewReplyWhenHitKeywords(keywords)) - case "joinSession": //加入聊天后回复 - r.Rules = append(r.Rules, NewReplyWhenUserJoinSession()) - case "noReplyAfter": //指定时间没有回复则自动回复 - if v.SecondDuration == 0 { +func ParseReplyRule(data []*dto.ChatAutoReplyData) (joinSessionRules, keywordsRules, noReplyAfterRules []IRobotTask) { + for _, responseRules := range data { + responseRules := responseRules + for ruleName, v := range responseRules.Rules { + if !v.Enable { continue } - r.Rules = append(r.Rules, NewReplyWhenWaiterNoAction(v.SecondDuration)) + switch ruleName { + case "keywords": //关键字回复 + var keywords []string + if v.Content == "" { + continue + } else { + keywords = strings.Split(v.Content, ",") + } + fmt.Println("ParseReplyRule 解析keywords:", keywords) + r := NewReplyWhenHitKeywords(responseRules.Title+"-keywords", keywords) + r.SetResponse(responseRules.Response) + keywordsRules = append(keywordsRules, r) + case "joinSession": //加入聊天后回复 + r := NewReplyWhenUserJoinSession(responseRules.Title + "-joinSession") + r.SetResponse(responseRules.Response) + joinSessionRules = append(joinSessionRules, r) + case "noReplyAfter": //指定时间没有回复则自动回复 + if v.SecondDuration == 0 { + continue + } + r := NewReplyWhenWaiterNoAction(responseRules.Title+"-noReplyAfter", v.SecondDuration) + r.SetResponse(responseRules.Response) + noReplyAfterRules = append(noReplyAfterRules, r) + } } } return diff --git a/pkg/service/asChat/robot/ruler_ReplyWhenWaiterNoAction.go b/pkg/service/asChat/robot/ruler_ReplyWhenWaiterNoAction.go index 8d27646..cbae6f5 100644 --- a/pkg/service/asChat/robot/ruler_ReplyWhenWaiterNoAction.go +++ b/pkg/service/asChat/robot/ruler_ReplyWhenWaiterNoAction.go @@ -23,16 +23,21 @@ type IRobotTask interface { Run(cache *chatCache.ChatCache) error RunTime() time.Time SetResponse(response string) + GetResponse() string + SetTitle(title string) + GetTitle() string } // 客服指定时间不回复则自动回复 -func NewReplyWhenWaiterNoAction(delaySecond time.Duration) IRobotTask { +func NewReplyWhenWaiterNoAction(title string, delaySecond time.Duration) IRobotTask { return &RobotTaskReplyWhenWaiterNoAction{ delaySecond: delaySecond, + title: title, } } type RobotTaskReplyWhenWaiterNoAction struct { + title string runTime time.Time Response string Receiver *accountFiee.ChatUserData @@ -96,3 +101,12 @@ func (r *RobotTaskReplyWhenWaiterNoAction) RunTime() time.Time { func (r *RobotTaskReplyWhenWaiterNoAction) SetResponse(response string) { r.Resp = response } +func (r *RobotTaskReplyWhenWaiterNoAction) GetResponse() string { + return r.Response +} +func (r *RobotTaskReplyWhenWaiterNoAction) SetTitle(title string) { + r.title = title +} +func (r *RobotTaskReplyWhenWaiterNoAction) GetTitle() string { + return r.title +} diff --git a/pkg/service/asChat/robot/ruler_keywords.go b/pkg/service/asChat/robot/ruler_keywords.go index 08a8d1d..cccc3d8 100644 --- a/pkg/service/asChat/robot/ruler_keywords.go +++ b/pkg/service/asChat/robot/ruler_keywords.go @@ -13,6 +13,7 @@ import ( ) type RobotTaskWithKeyworkds struct { + title string runTime time.Time Response string Receiver *accountFiee.ChatUserData @@ -22,8 +23,8 @@ type RobotTaskWithKeyworkds struct { keywords []string } -func NewReplyWhenHitKeywords(keywords []string) IRobotTask { - return &RobotTaskWithKeyworkds{keywords: keywords} +func NewReplyWhenHitKeywords(title string, keywords []string) IRobotTask { + return &RobotTaskWithKeyworkds{title: title, keywords: keywords} } func (r *RobotTaskWithKeyworkds) Hit(event ws.ListenEventData, sender *accountFiee.ChatUserData) (hit bool) { if event.EventType != ws.EventChatMessage || event.Msg == "" || event.Client == nil || event.ChatUser == nil { @@ -67,3 +68,13 @@ func (r *RobotTaskWithKeyworkds) RunTime() time.Time { func (r *RobotTaskWithKeyworkds) SetResponse(response string) { r.Resp = response } + +func (r *RobotTaskWithKeyworkds) GetResponse() string { + return r.Response +} +func (r *RobotTaskWithKeyworkds) SetTitle(title string) { + r.title = title +} +func (r *RobotTaskWithKeyworkds) GetTitle() string { + return r.title +} diff --git a/pkg/service/asChat/robot/ruler_replyWhenUserJoinSession.go b/pkg/service/asChat/robot/ruler_replyWhenUserJoinSession.go index 4175915..5a2f68a 100644 --- a/pkg/service/asChat/robot/ruler_replyWhenUserJoinSession.go +++ b/pkg/service/asChat/robot/ruler_replyWhenUserJoinSession.go @@ -12,8 +12,8 @@ import ( "time" ) -func NewReplyWhenUserJoinSession() IRobotTask { - return &ReplyWhenUserJoinSession{} +func NewReplyWhenUserJoinSession(title string) IRobotTask { + return &ReplyWhenUserJoinSession{title: title} } type ReplyWhenUserJoinSession struct { @@ -23,6 +23,7 @@ type ReplyWhenUserJoinSession struct { Resp string sessionId string atUserId int + title string } func (r *ReplyWhenUserJoinSession) Hit(event ws.ListenEventData, sender *accountFiee.ChatUserData) (hit bool) { @@ -83,3 +84,12 @@ func (r *ReplyWhenUserJoinSession) RunTime() time.Time { func (r *ReplyWhenUserJoinSession) SetResponse(response string) { r.Resp = response } +func (r *ReplyWhenUserJoinSession) GetResponse() string { + return r.Response +} +func (r *ReplyWhenUserJoinSession) SetTitle(title string) { + r.title = title +} +func (r *ReplyWhenUserJoinSession) GetTitle() string { + return r.title +}