kefu/controller/wechatKefu.go

380 lines
12 KiB
Go
Raw Normal View History

2024-12-10 02:50:12 +00:00
package controller
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/patrickmn/go-cache"
"github.com/tidwall/gjson"
"io/ioutil"
"kefu/common"
"kefu/lib"
"kefu/lib/wechat_kf_sdk"
"kefu/models"
"kefu/service"
"kefu/tools"
"kefu/types"
"kefu/ws"
"log"
"os"
"time"
)
// 企业微信相关
var retryCache = cache.New(60*time.Minute, 10*time.Minute)
func isRetry(signature string) bool {
var base = "retry:signature:%s"
key := fmt.Sprintf(base, signature)
_, found := retryCache.Get(key)
if found {
return true
}
retryCache.Set(key, "1", 1*time.Minute)
return false
}
// 企业微信客服消息回调
func PostEntWechatCallback(c *gin.Context) {
entId := c.Param("entId")
kefuName := c.Param("kefuName")
verifyMsgSign := c.Query("msg_signature")
verifyTimestamp := c.Query("timestamp")
verifyNonce := c.Query("nonce")
bodyBytes, _ := ioutil.ReadAll(c.Request.Body)
body := string(bodyBytes)
log.Println("企业微信客服回调:", body, verifyMsgSign)
if isRetry(verifyMsgSign) {
log.Println("企业微信客服重试机制:", verifyMsgSign)
return
}
//获取配置
configs := models.GetEntConfigsMap(entId, "QdrantAIStatus", "chatGPTUrl", "chatGPTSecret", "kefuWeworkCorpid", "kefuWeworkSecret", "kefuWeworkToken", "kefuWeworkEncodingAESKey", "kefuWeworkNextCursor", "QiyeWechatKefuPreRobot")
kefuWework := wechat_kf_sdk.NewKefuWework(configs["kefuWeworkCorpid"], configs["kefuWeworkSecret"], configs["kefuWeworkToken"], configs["kefuWeworkEncodingAESKey"])
receiveMessage, err := kefuWework.DecryptMsg(verifyMsgSign, verifyTimestamp, verifyNonce, body)
if err != nil {
log.Println("企业微信客服解析数据失败:", err)
return
}
syncMsgs, err := kefuWework.SyncMsg(map[string]interface{}{
"token": receiveMessage.Token,
"cursor": configs["kefuWeworkNextCursor"],
})
if err != nil {
log.Println("企业微信客服获取数据失败:", err)
return
}
models.UpdateInsertEntConfig(entId, "企业微信客服NextCursor", "kefuWeworkNextCursor", syncMsgs.NextCursor)
size := len(syncMsgs.MsgList)
if size < 1 {
log.Println("企业微信客服获取数据为空", syncMsgs)
return
}
current := syncMsgs.MsgList[size-1]
log.Println("企业微信客服最新数据", current)
userId := current.ExternalUserid
kfId := current.OpenKfid
content := ""
//文本消息
fildDir := fmt.Sprintf("%s%d%s/", common.Upload, time.Now().Year(), time.Now().Month().String())
if current.Msgtype == "text" {
content = current.Text.Content
} else if current.Msgtype == "image" {
//图片消息
mediaId := current.Image.MediaId
fileName := mediaId + ".jpg"
isExist, _ := tools.IsFileExist(fildDir)
if !isExist {
os.Mkdir(fildDir, os.ModePerm)
}
filepath := fmt.Sprintf("%s%s", fildDir, fileName)
_, err := kefuWework.DownloadTempFileByMediaID(mediaId, filepath)
if err != nil {
log.Println("企业微信客服下载临时素材失败:", err)
return
}
content = "img[/" + filepath + "]"
} else if current.Msgtype == "voice" {
//语音消息
mediaId := current.Voice.MediaId
fileName := mediaId + ".wav"
isExist, _ := tools.IsFileExist(fildDir)
if !isExist {
os.Mkdir(fildDir, os.ModePerm)
}
filepath := fmt.Sprintf("%s%s", fildDir, fileName)
_, err := kefuWework.DownloadTempFileByMediaID(mediaId, filepath)
if err != nil {
log.Println("企业微信客服下载临时素材失败:", err)
return
}
if configs["chatGPTUrl"] != "" && configs["chatGPTSecret"] != "" {
gpt := lib.NewChatGptTool(configs["chatGPTUrl"], configs["chatGPTSecret"])
response, err := gpt.GetWhisper(filepath)
if err == nil {
log.Println(response)
content = gjson.Get(response, "text").String()
} else {
log.Println(err)
content = "audio[/" + filepath + "]"
}
} else {
content = "audio[/" + filepath + "]"
}
} else if current.Msgtype == "event" {
//事件消息
//进入会话
if current.Event.EventType == "enter_session" {
welcomeCode := current.Event.WelcomeCode
//发送欢迎语
welcomes := models.FindWelcomesByKeyword(kefuName, "wechat")
if len(welcomes) > 0 {
welcomeContent := ""
for _, welcome := range welcomes {
welcome.Content, _ = tools.ReplaceStringByRegex(welcome.Content, `<[^a>]+>|target="[^"]+"`, "")
welcomeContent += welcome.Content + "\r\n"
}
go kefuWework.SendWelcomeMsg(welcomeContent, welcomeCode)
}
}
}
if content == "" {
return
}
//查找访客插入访客表
visitorId := fmt.Sprintf("wxkf|%s|%s", entId, userId)
vistorInfo := models.FindVisitorByVistorId(visitorId)
if vistorInfo.ID == 0 {
//获取客户昵称头像
reqData := map[string]interface{}{
"external_userid_list": []string{
userId,
},
}
ret, _ := kefuWework.BatchGet(reqData)
visitorName := gjson.Get(ret, "customer_list.0.nickname").String()
avator := gjson.Get(ret, "customer_list.0.avatar").String()
extra := gjson.Get(ret, "customer_list.0.enter_session_context.scene_param").String()
refer := gjson.Get(ret, "customer_list.0.enter_session_context.scene").String()
if visitorName == "" {
visitorName = "微信客服用户"
}
if avator == "" {
avator = "/static/images/we-chat-wx.png"
}
vistorInfo = models.Visitor{
Model: models.Model{
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
},
Name: visitorName,
Avator: avator,
ToId: kfId,
VisitorId: visitorId,
Status: 1,
Refer: refer,
EntId: entId,
VisitNum: 0,
City: "微信客服",
Extra: extra,
ClientIp: c.ClientIP(),
}
vistorInfo.AddVisitor()
} else {
go models.UpdateVisitorKefuName(visitorId, kfId)
}
kefuInfo := models.FindUser(kfId)
if kefuInfo.ID == 0 {
kefuInfo = models.FindUserByUid(entId)
}
go ws.VisitorOnline(kefuInfo.Name, vistorInfo)
go ws.VisitorSendToKefu(kefuInfo.Name, vistorInfo, content)
go SendWechatVisitorMessageTemplate(kefuInfo.Name, vistorInfo.Name, vistorInfo.VisitorId, content, vistorInfo.EntId)
go service.SendWorkWechatMesage(vistorInfo.EntId, vistorInfo, kefuInfo, content, c)
//判断当前访客是否机器人回复
if !models.CheckVisitorRobotReply(vistorInfo.State) {
return
}
result := ""
//调用自动回复
result = GetLearnReplyContent(entId, content)
if result == "" && configs["QdrantAIStatus"] == "true" {
if configs["QiyeWechatKefuPreRobot"] != "" {
go kefuWework.SendTextMsg(kfId, userId, configs["QiyeWechatKefuPreRobot"])
}
//调用GPT3.5
result = ws.Gpt3Knowledge(entId, visitorId, kefuInfo, content)
}
if result != "" {
result, _ = tools.ReplaceStringByRegex(result, `<[^a>]+>|target="[^"]+"`, "")
var err error
if imgUrl := ParseImgMessage2(result); imgUrl != "" {
err = kefuWework.SendImagesMsg(kfId, userId, common.StaticDirPath+imgUrl)
} else if voiceUrl := ParseVoiceMessage(result); voiceUrl != "" {
err = kefuWework.SendVoiceMsg(kfId, userId, common.UploadDirPath+voiceUrl)
} else {
log.Println("企业微信客服发送消息:", kfId, userId, result)
err = kefuWework.SendTextMsg(kfId, userId, result)
}
if err != nil {
log.Println("企业微信客服发送消息失败:", err)
} else {
models.CreateMessage(kefuInfo.Name, visitorId, result, "kefu", entId, "read")
go ws.KefuMessage(visitorId, result, kefuInfo)
}
}
}
// 微信客服验签
func GetWechatKefuCheckSign(c *gin.Context) {
entId := c.Param("entId")
signature := c.Query("msg_signature")
timestamp := c.Query("timestamp")
nonce := c.Query("nonce")
echostr := c.Query("echostr")
//获取配置
configs := models.GetEntConfigsMap(entId, "kefuWeworkCorpid", "kefuWeworkSecret", "kefuWeworkToken", "kefuWeworkEncodingAESKey")
kefuWework := wechat_kf_sdk.NewKefuWework(configs["kefuWeworkCorpid"], configs["kefuWeworkSecret"], configs["kefuWeworkToken"], configs["kefuWeworkEncodingAESKey"])
res, err := kefuWework.CheckSign(signature, timestamp, nonce, echostr)
log.Println("企业微信客服验签:", res, err)
c.Writer.Write([]byte(res))
}
// 微信客服列表
func GetKefuWeworkList(c *gin.Context) {
entId, _ := c.Get("ent_id")
wechat := service.GetKefuWework(entId.(string))
str, _ := wechat.GetAccountList(0, 1000)
c.JSON(200, gin.H{
"code": types.ApiCode.SUCCESS,
"msg": types.ApiCode.GetMessage(types.ApiCode.SUCCESS),
"result": str,
})
}
// 微信客服链接
func GetKefuWeworkLink(c *gin.Context) {
entId, _ := c.Get("ent_id")
openKfId := c.Query("open_kfid")
//获取配置
configs := models.GetEntConfigsMap(entId.(string), "kefuWeworkCorpid", "kefuWeworkSecret", "kefuWeworkToken", "kefuWeworkEncodingAESKey")
kefuWework := wechat_kf_sdk.NewKefuWework(configs["kefuWeworkCorpid"], configs["kefuWeworkSecret"], configs["kefuWeworkToken"], configs["kefuWeworkEncodingAESKey"])
str, _ := kefuWework.GetAccountLink(openKfId)
c.JSON(200, gin.H{
"code": types.ApiCode.SUCCESS,
"msg": types.ApiCode.GetMessage(types.ApiCode.SUCCESS),
"result": str,
})
}
// 企业微信机器人
func PostEntWechatRobot(c *gin.Context) {
entId := c.Param("entId")
robotCode := c.Param("robotCode")
kefuName := c.Param("kefuName")
var jsonData map[string]interface{}
if err := c.ShouldBindJSON(&jsonData); err != nil {
// 发生错误,返回错误响应
c.JSON(200, gin.H{"error": err.Error()})
return
}
log.Println("entwechat robot", jsonData)
spoken := jsonData["spoken"].(string)
receivedName := jsonData["receivedName"].(string)
groupName := jsonData["groupName"].(string)
groupRemark := jsonData["groupRemark"].(string)
if groupRemark != "" {
groupName = groupRemark
}
roomType := jsonData["roomType"]
if spoken == "" {
c.JSON(200, gin.H{
"code": 0,
"message": "success",
"data": gin.H{
"type": 5000,
"info": gin.H{
"text": "",
},
},
})
return
}
kefuInfo := models.FindUserByUid(entId)
if kefuInfo.ID == 0 || kefuInfo.Name != kefuName {
c.JSON(200, gin.H{
"code": types.ApiCode.ACCOUNT_NO_EXIST,
"msg": types.ApiCode.GetMessage(types.ApiCode.ACCOUNT_NO_EXIST),
})
return
}
//查找访客插入访客表
visitorId := fmt.Sprintf("entwechat|%s|%s", entId, tools.Md5(fmt.Sprintf("%s|%s|%v", groupName, receivedName, roomType)))
vistorInfo := models.FindVisitorByVistorId(visitorId)
if vistorInfo.ID == 0 {
visitorName := receivedName
avator := "/static/images/we-chat-wx.png"
if visitorName == "" {
visitorName = "企业微信用户"
}
vistorInfo = models.Visitor{
Model: models.Model{
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
},
Name: visitorName,
Avator: avator,
ToId: kefuInfo.Name,
VisitorId: visitorId,
Status: 1,
Refer: "来自企业微信",
EntId: entId,
VisitNum: 0,
City: "企业微信",
ClientIp: c.ClientIP(),
}
vistorInfo.AddVisitor()
} else {
go models.UpdateVisitorStatus(visitorId, 3)
}
go ws.VisitorOnline(kefuInfo.Name, vistorInfo)
go ws.VisitorSendToKefu(kefuInfo.Name, vistorInfo, spoken)
//调用GPT3.5
result := ws.Gpt3Knowledge(entId, visitorId, kefuInfo, spoken)
models.CreateMessage(kefuInfo.Name, visitorId, result, "kefu", entId, "read")
go ws.KefuMessage(visitorId, result, kefuInfo)
payload := fmt.Sprintf(`{
"socketType":2,
"list":[
{
"type":203,
"titleList":[
"%s"
],
"atList":[
"%s"
],
"receivedContent":"%s"
}
]
}`, groupName, receivedName, result)
url := "https://worktool.asrtts.cn/wework/sendRawMessage?robotId=" + robotCode
tools.PostJson(url, []byte(payload))
c.JSON(200, gin.H{
"code": 0,
"message": "success",
"data": gin.H{
"type": 5000,
"info": gin.H{
"text": "",
},
},
})
}