kefu/controller/douyin.go

355 lines
12 KiB
Go
Raw Normal View History

2024-12-10 02:50:12 +00:00
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
}