355 lines
12 KiB
Go
355 lines
12 KiB
Go
package controller
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/tidwall/gjson"
|
|
"kefu/lib"
|
|
"kefu/models"
|
|
"kefu/tools"
|
|
"kefu/types"
|
|
"kefu/ws"
|
|
"log"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
func PostDouyinWebhooks(c *gin.Context) {
|
|
|
|
var jsonData map[string]interface{}
|
|
|
|
// 使用 ShouldBindJSON 将请求中的 JSON 数据绑定到 jsonData 变量
|
|
if err := c.ShouldBindJSON(&jsonData); err != nil {
|
|
// 发生错误,返回错误响应
|
|
c.JSON(400, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
jsonStrByte, _ := json.Marshal(jsonData)
|
|
jsonStr := string(jsonStrByte)
|
|
log.Println("douyin:", jsonStr)
|
|
|
|
jsonEnvent := gjson.Get(jsonStr, "event").String()
|
|
toUserId := gjson.Get(jsonStr, "to_user_id").String()
|
|
fromUserId := gjson.Get(jsonStr, "from_user_id").String()
|
|
clientKey := gjson.Get(jsonStr, "client_key").String()
|
|
content := gjson.Get(jsonStr, "content").String()
|
|
//验证
|
|
if jsonEnvent == "verify_webhook" {
|
|
insertDouyinWebhook(jsonEnvent, fromUserId, toUserId, clientKey, content, "", "")
|
|
challenge := jsonData["content"].(map[string]interface{})["challenge"]
|
|
c.JSON(200, gin.H{"challenge": challenge})
|
|
return
|
|
}
|
|
|
|
userDouyin := models.FindUserDouyinRow("open_id = ?", toUserId)
|
|
if userDouyin.EntId == "" || userDouyin.KefuName == "" {
|
|
return
|
|
}
|
|
insertDouyinWebhook(jsonEnvent, fromUserId, toUserId, clientKey, content, userDouyin.EntId, userDouyin.KefuName)
|
|
//视频评论事件item_comment_reply
|
|
if jsonEnvent == "item_comment_reply" && fromUserId != toUserId {
|
|
go douyinReplyHandle(toUserId, content, userDouyin)
|
|
}
|
|
//接受私信事件im_receive_msg
|
|
if jsonEnvent == "im_receive_msg" {
|
|
go douyinMessageReplyHandle(toUserId, fromUserId, content, userDouyin, jsonEnvent)
|
|
}
|
|
//发出私信事件 im_send_msg
|
|
if jsonEnvent == "im_send_msg" {
|
|
|
|
}
|
|
//进入私信事件 im_enter_direct_msg
|
|
if jsonEnvent == "im_enter_direct_msg" {
|
|
go douyinMessageReplyHandle(toUserId, fromUserId, content, userDouyin, jsonEnvent)
|
|
}
|
|
}
|
|
func insertDouyinWebhook(event, formUserId, toUserId, clientKey, content, entId, kefuName string) {
|
|
newWebhook := models.DouyinWebhook{
|
|
KefuName: kefuName,
|
|
Event: event,
|
|
FromUserID: formUserId,
|
|
ToUserID: toUserId,
|
|
ClientKey: clientKey,
|
|
Content: content,
|
|
EntID: entId,
|
|
}
|
|
go newWebhook.AddDouyinWebhook()
|
|
}
|
|
func douyinReplyHandle(toUserId, responseJson string, userDouyin *models.User_douyin) {
|
|
|
|
content := gjson.Get(responseJson, "content").String()
|
|
avatar := gjson.Get(responseJson, "avatar").String()
|
|
comment_user_id := gjson.Get(responseJson, "comment_user_id").String()
|
|
comment_id := gjson.Get(responseJson, "comment_id").String()
|
|
nickName := gjson.Get(responseJson, "nick_name").String()
|
|
//视频ID
|
|
reply_to_item_id := gjson.Get(responseJson, "reply_to_item_id").String()
|
|
|
|
kefuInfo := models.FindUserByUid(userDouyin.EntId)
|
|
content = strings.TrimSpace(content)
|
|
//查找访客插入访客表
|
|
visitorId := fmt.Sprintf("douyin_comment|%s|%s", userDouyin.EntId, comment_user_id)
|
|
vistorInfo := models.FindVisitorByVistorId(visitorId)
|
|
if vistorInfo.ID == 0 {
|
|
visitorName := nickName
|
|
vistorInfo = models.Visitor{
|
|
Model: models.Model{
|
|
CreatedAt: time.Now(),
|
|
UpdatedAt: time.Now(),
|
|
},
|
|
Name: visitorName,
|
|
Avator: avatar,
|
|
ToId: kefuInfo.Name,
|
|
VisitorId: visitorId,
|
|
Status: 1,
|
|
Refer: "来自抖音评论",
|
|
EntId: userDouyin.EntId,
|
|
VisitNum: 0,
|
|
City: "抖音用户",
|
|
}
|
|
vistorInfo.AddVisitor()
|
|
} else {
|
|
go models.UpdateVisitorStatus(visitorId, 3)
|
|
}
|
|
go ws.VisitorOnline(kefuInfo.Name, vistorInfo)
|
|
go ws.VisitorSendToKefu(kefuInfo.Name, vistorInfo, content)
|
|
|
|
result := ""
|
|
dingConfig := models.GetEntConfigsMap(userDouyin.EntId, "QdrantAIStatus")
|
|
|
|
//调用自动回复
|
|
result = GetLearnReplyContent(userDouyin.EntId, content)
|
|
if result == "" && dingConfig["QdrantAIStatus"] == "true" {
|
|
//调用GPT3.5
|
|
result = ws.Gpt3Knowledge(userDouyin.EntId, visitorId, kefuInfo, content)
|
|
}
|
|
result = tools.TrimHtml(result)
|
|
if result == "" {
|
|
return
|
|
}
|
|
//回复评论
|
|
clientId := models.FindConfig("DouyinClientKey")
|
|
clientKey := models.FindConfig("DouyinClientSecret")
|
|
douyin, _ := lib.NewDouyin(clientId, clientKey)
|
|
accessToken, _ := douyin.RefeshAccessToken(userDouyin.AccessToken)
|
|
res, err := douyin.ReplyVideoComment(accessToken, toUserId, result, reply_to_item_id, comment_id)
|
|
log.Println("调用抖音回复评论接口:", res, err)
|
|
models.CreateMessage(kefuInfo.Name, visitorId, result, "kefu", userDouyin.EntId, "read")
|
|
go ws.KefuMessage(visitorId, result, kefuInfo)
|
|
}
|
|
|
|
// 处理抖音私信
|
|
func douyinMessageReplyHandle(fromUserId, toUserId, responseJson string, userDouyin *models.User_douyin, eventType string) {
|
|
message_type := gjson.Get(responseJson, "message_type").String()
|
|
content := "其他类型消息"
|
|
if message_type == "text" {
|
|
content = gjson.Get(responseJson, "text").String()
|
|
}
|
|
if eventType == "im_enter_direct_msg" {
|
|
content = "用户进入私信会话页"
|
|
}
|
|
avatar := gjson.Get(responseJson, "user_infos.0.avatar").String()
|
|
nickName := gjson.Get(responseJson, "user_infos.0.nick_name").String()
|
|
openId := gjson.Get(responseJson, "user_infos.0.open_id").String()
|
|
kefuInfo := models.FindUserByUid(userDouyin.EntId)
|
|
content = strings.TrimSpace(content)
|
|
//查找访客插入访客表
|
|
visitorId := fmt.Sprintf("douyin_message|%s|%s", userDouyin.EntId, openId)
|
|
vistorInfo := models.FindVisitorByVistorId(visitorId)
|
|
if vistorInfo.ID == 0 {
|
|
visitorName := nickName
|
|
vistorInfo = models.Visitor{
|
|
Model: models.Model{
|
|
CreatedAt: time.Now(),
|
|
UpdatedAt: time.Now(),
|
|
},
|
|
Name: visitorName,
|
|
Avator: avatar,
|
|
ToId: kefuInfo.Name,
|
|
VisitorId: visitorId,
|
|
Status: 1,
|
|
Refer: "来自抖音私信",
|
|
EntId: userDouyin.EntId,
|
|
VisitNum: 0,
|
|
City: "抖音用户",
|
|
}
|
|
vistorInfo.AddVisitor()
|
|
} else {
|
|
go models.UpdateVisitorStatus(visitorId, 3)
|
|
}
|
|
go ws.VisitorOnline(kefuInfo.Name, vistorInfo)
|
|
go ws.VisitorSendToKefu(kefuInfo.Name, vistorInfo, content)
|
|
|
|
result := ""
|
|
dingConfig := models.GetEntConfigsMap(userDouyin.EntId, "QdrantAIStatus")
|
|
|
|
//调用自动回复
|
|
result = GetLearnReplyContent(userDouyin.EntId, content)
|
|
if result == "" && dingConfig["QdrantAIStatus"] == "true" {
|
|
//调用GPT3.5
|
|
result = ws.Gpt3Knowledge(userDouyin.EntId, visitorId, kefuInfo, content)
|
|
}
|
|
result = tools.TrimHtml(result)
|
|
//调用访客消息回调
|
|
visitorMessageCallUrlResult := SendVisitorMessageCallUrl(vistorInfo.EntId, vistorInfo.VisitorId, vistorInfo.ToId, vistorInfo.Name, vistorInfo.Avator, content)
|
|
result = gjson.Get(visitorMessageCallUrlResult, "result").String()
|
|
if result == "" {
|
|
return
|
|
}
|
|
//回复
|
|
clientId := models.FindConfig("DouyinClientKey")
|
|
clientKey := models.FindConfig("DouyinClientSecret")
|
|
douyin, _ := lib.NewDouyin(clientId, clientKey)
|
|
accessToken, _ := douyin.RefeshAccessToken(userDouyin.AccessToken)
|
|
conversation_short_id := gjson.Get(responseJson, "conversation_short_id").String()
|
|
server_message_id := gjson.Get(responseJson, "server_message_id").String()
|
|
res, err := douyin.ReplyMessage(accessToken, eventType, fromUserId, toUserId, conversation_short_id, server_message_id, result)
|
|
log.Println("调用抖音私信接口:", res, err)
|
|
models.CreateMessage(kefuInfo.Name, visitorId, result, "kefu", userDouyin.EntId, "read")
|
|
go ws.KefuMessage(visitorId, result, kefuInfo)
|
|
}
|
|
|
|
// 客服发送抖音视频评论
|
|
func SendDouyinCommentMessage(visitor models.Visitor, content string) bool {
|
|
visitorIdArr := strings.Split(visitor.VisitorId, "|")
|
|
if len(visitorIdArr) < 3 || visitorIdArr[0] != "douyin_comment" {
|
|
return false
|
|
}
|
|
toUserId := visitorIdArr[2]
|
|
userDouyin := models.FindUserDouyinRow("kefu_name = ?", visitor.ToId)
|
|
douyinWebhook := models.FindDouyinWebhook("kefu_name = ? and from_user_id = ?", visitor.ToId, toUserId)
|
|
if userDouyin.EntId == "" || userDouyin.KefuName == "" || douyinWebhook.Content == "" {
|
|
return false
|
|
}
|
|
|
|
//回复评论
|
|
clientId := models.FindConfig("DouyinClientKey")
|
|
clientKey := models.FindConfig("DouyinClientSecret")
|
|
douyin, _ := lib.NewDouyin(clientId, clientKey)
|
|
accessToken, _ := douyin.RefeshAccessToken(userDouyin.AccessToken)
|
|
|
|
//评论ID
|
|
comment_id := gjson.Get(douyinWebhook.Content, "comment_id").String()
|
|
//视频ID
|
|
reply_to_item_id := gjson.Get(douyinWebhook.Content, "reply_to_item_id").String()
|
|
|
|
res, err := douyin.ReplyVideoComment(accessToken, userDouyin.OpenId, content, reply_to_item_id, comment_id)
|
|
log.Println("调用抖音回复评论接口:", res, err)
|
|
return true
|
|
}
|
|
|
|
// 客服发送抖音私信
|
|
func SendDouyinPrivateMessage(visitor models.Visitor, content string) bool {
|
|
visitorIdArr := strings.Split(visitor.VisitorId, "|")
|
|
if len(visitorIdArr) < 3 || visitorIdArr[0] != "douyin_message" {
|
|
return false
|
|
}
|
|
toUserId := visitorIdArr[2]
|
|
userDouyin := models.FindUserDouyinRow("kefu_name = ?", visitor.ToId)
|
|
douyinWebhook := models.FindDouyinWebhook("kefu_name = ? and from_user_id = ?", visitor.ToId, toUserId)
|
|
if userDouyin.EntId == "" || userDouyin.KefuName == "" || douyinWebhook.Content == "" {
|
|
return false
|
|
}
|
|
|
|
clientId := models.FindConfig("DouyinClientKey")
|
|
clientKey := models.FindConfig("DouyinClientSecret")
|
|
douyin, _ := lib.NewDouyin(clientId, clientKey)
|
|
accessToken, _ := douyin.RefeshAccessToken(userDouyin.AccessToken)
|
|
conversation_short_id := gjson.Get(douyinWebhook.Content, "conversation_short_id").String()
|
|
server_message_id := gjson.Get(douyinWebhook.Content, "server_message_id").String()
|
|
res, err := douyin.ReplyMessage(accessToken, "im_receive_msg", userDouyin.OpenId, toUserId, conversation_short_id, server_message_id, content)
|
|
log.Println("调用抖音私信接口:", res, err)
|
|
return true
|
|
}
|
|
|
|
// 抖音绑定
|
|
func GetDouyinList(c *gin.Context) {
|
|
entId, _ := c.Get("ent_id")
|
|
kefuName, _ := c.Get("kefu_name")
|
|
list := models.FindUserDouyinRows("ent_id = ? and kefu_name = ?", entId, kefuName)
|
|
c.JSON(200, gin.H{
|
|
"code": types.ApiCode.SUCCESS,
|
|
"msg": "ok",
|
|
"result": list,
|
|
})
|
|
}
|
|
|
|
// 删除抖音绑定
|
|
func GetDeleteDouyinList(c *gin.Context) {
|
|
entId, _ := c.Get("ent_id")
|
|
kefuName, _ := c.Get("kefu_name")
|
|
id := c.Query("id")
|
|
models.DeleteUserDouyinRows("ent_id = ? and kefu_name = ? and id = ?", entId, kefuName, id)
|
|
c.JSON(200, gin.H{
|
|
"code": types.ApiCode.SUCCESS,
|
|
"msg": "ok",
|
|
})
|
|
}
|
|
|
|
// 抖音绑定
|
|
func PostDouyinBind(c *gin.Context) {
|
|
entId, _ := c.Get("ent_id")
|
|
kefuName, _ := c.Get("kefu_name")
|
|
code := c.PostForm("code")
|
|
clientId := models.FindConfig("DouyinClientKey")
|
|
clientKey := models.FindConfig("DouyinClientSecret")
|
|
douyin, _ := lib.NewDouyin(clientId, clientKey)
|
|
tokenResult, err := douyin.GetAccessToken(code)
|
|
if err != nil {
|
|
log.Println("douyin:", err)
|
|
c.JSON(200, gin.H{
|
|
"code": types.ApiCode.FAILED,
|
|
"msg": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
//获取access_token失败
|
|
status := gjson.Get(tokenResult, "message").String()
|
|
if status != "success" {
|
|
log.Println("douyin:", tokenResult)
|
|
c.JSON(200, gin.H{
|
|
"code": types.ApiCode.FAILED,
|
|
"msg": tokenResult,
|
|
})
|
|
return
|
|
}
|
|
accessToken := gjson.Get(tokenResult, "data.access_token").String()
|
|
refreshToken := gjson.Get(tokenResult, "data.refresh_token").String()
|
|
expiresIn := gjson.Get(tokenResult, "data.expires_in").Int()
|
|
refreshExpiresIn := gjson.Get(tokenResult, "data.refresh_expires_in").Int()
|
|
expiresInInt := tools.Now() + expiresIn
|
|
refreshExpiresInInt := tools.Now() + refreshExpiresIn
|
|
|
|
openId := gjson.Get(tokenResult, "data.open_id").String()
|
|
//获取昵称头像
|
|
douyinInfo, _ := douyin.GetUserInfo(accessToken, openId)
|
|
nickname := gjson.Get(douyinInfo, "data.nickname").String()
|
|
avatar := gjson.Get(douyinInfo, "data.avatar").String()
|
|
unionId := gjson.Get(douyinInfo, "data.union_id").String()
|
|
douyinModel := &models.User_douyin{
|
|
Nickname: nickname,
|
|
Avatar: avatar,
|
|
EntId: entId.(string),
|
|
KefuName: kefuName.(string),
|
|
OpenId: openId,
|
|
AccessToken: accessToken,
|
|
RefreshToken: refreshToken,
|
|
ExpiresIn: types.Time{tools.IntToTime(expiresInInt - 3600)},
|
|
RefreshExpiresIn: types.Time{tools.IntToTime(refreshExpiresInInt - 3600)},
|
|
ClientTokenExpires: tools.IntToTimeStr(expiresInInt, "2006-01-02 15:04:05"),
|
|
UnionId: unionId,
|
|
CreatedAt: types.Time{},
|
|
}
|
|
douyinModel.UpdateOrInsert()
|
|
c.JSON(200, gin.H{
|
|
"code": types.ApiCode.SUCCESS,
|
|
"msg": "ok",
|
|
"result": gin.H{
|
|
"token_result": tokenResult,
|
|
"info_result": douyinInfo,
|
|
},
|
|
})
|
|
return
|
|
}
|