Commit 53068b6a by Ford

修改了WorldChat支持高并发,加了协程。

parent 889709d3
...@@ -60,7 +60,7 @@ type WorldClient struct { ...@@ -60,7 +60,7 @@ type WorldClient struct {
//DpConversations *models.DpConversations //DpConversations *models.DpConversations
WorldConversations *models.WorldConversation WorldConversations *models.WorldConversation
Socket *websocket.Conn Socket *websocket.Conn
Send chan *WorldEchoRespones Send chan *WorldEchoResponse
WorldName string WorldName string
AuthId string AuthId string
UserSource string UserSource string
...@@ -989,7 +989,7 @@ func (c *WorldClient) WorldRead() { ...@@ -989,7 +989,7 @@ func (c *WorldClient) WorldRead() {
// ExtractRating 从响应中提取整体评分 // ExtractRating 从响应中提取整体评分
func ExtractRating(response WorldEchoRespones) (int, error) { func ExtractRating(response WorldEchoResponse) (int, error) {
endStr, ok := response.WObj["EndStr"].(string) endStr, ok := response.WObj["EndStr"].(string)
if !ok || endStr == "" { if !ok || endStr == "" {
return 0, nil return 0, nil
...@@ -1009,7 +1009,7 @@ func ExtractRating(response WorldEchoRespones) (int, error) { ...@@ -1009,7 +1009,7 @@ func ExtractRating(response WorldEchoRespones) (int, error) {
return 0, fmt.Errorf("未找到评分信息") return 0, fmt.Errorf("未找到评分信息")
} }
func ExtractRating1(response WorldEchoRespones) string { func ExtractRating1(response WorldEchoResponse) string {
endStr, ok := response.WObj["EndStr"].(string) endStr, ok := response.WObj["EndStr"].(string)
if !ok { if !ok {
...@@ -1165,3 +1165,160 @@ func (c *WorldClient) WorldWrite() { ...@@ -1165,3 +1165,160 @@ func (c *WorldClient) WorldWrite() {
} }
/* ============================================================================================= */ /* ============================================================================================= */
// ParseEndStrAndReformat 重新结构化 WorldEchoRespones,以包含结论消息的详细拆分
func ParseEndStrAndReformat1(response *WorldEchoResponse) {
if response == nil || response.WObj == nil {
return
}
endStr, ok := response.WObj["EndStr"].(string)
if !ok || endStr == "" {
return
}
// 解析 "EndStr" 中的详细字段
title := strings.Split(endStr, "@")[0] // 提取 '@' 前的标题
overallScore := extractBetween(endStr, "【整体评分】:", "\n") // 提取整体评分
objectiveEvaluation := extractBetween(endStr, "【客观评价】:", "**言行举止**") // 提取客观评价
// 将 "EndStr" 结构化为 JSON 对象
endStrObj := map[string]interface{}{
"title": title,
"OverallScore": strings.TrimSpace(overallScore),
"ObjectiveEvaluation": strings.TrimSpace(objectiveEvaluation),
}
response.WObj["EndStr"] = endStrObj // 将格式化后的结论字符串对象重新赋值给响应
// 可选处理其他字段如 '地点' 和 '表情'
if address, exists := response.WObj["地点"]; exists {
response.WObj["address"] = address
delete(response.WObj, "地点")
}
if emotion, exists := response.WObj["表情"]; exists {
response.WObj["emotion"] = emotion
delete(response.WObj, "表情")
}
}
// ParseEndStrAndReformat 将 WorldSoulReplyMsg 中的 WObj 修改后返回一个新的 WorldSoulReplyMsg 结构体
func ParseEndStrAndReformat2(response *WorldSoulReplyMsg) *WorldSoulReplyMsg {
if response == nil || response.WObj == nil {
return nil // 如果输入是nil,直接返回nil
}
newResponse := *response // 创建一个新的响应副本以避免修改原始数据
endStr, ok := newResponse.WObj["EndStr"].(string)
if !ok || endStr == "" {
return &newResponse // 如果没有 EndStr 或者为空,返回原始数据的副本
}
// 解析 "EndStr" 中的详细字段
title := strings.Split(endStr, "@")[0] // 提取 '@' 前的标题
overallScore := extractBetween(endStr, "【整体评分】:", "\n") // 提取整体评分
objectiveEvaluation := extractToEnd(endStr, "【客观评价】:") // 提取客观评价
// 将 "EndStr" 结构化为 JSON 对象
endStrObj := map[string]interface{}{
"title": title,
"OverallScore": strings.TrimSpace(overallScore),
"ObjectiveEvaluation": strings.TrimSpace(objectiveEvaluation),
}
newResponse.WObj["EndStr"] = endStrObj // 将格式化后的结论字符串对象重新赋值给响应
// 可选处理其他字段如 '地点' 和 '表情'
if address, exists := newResponse.WObj["地点"]; exists {
newResponse.WObj["address"] = address
delete(newResponse.WObj, "地点")
}
if emotion, exists := newResponse.WObj["表情"]; exists {
newResponse.WObj["emotion"] = emotion
delete(newResponse.WObj, "表情")
}
return &newResponse // 返回修改后的新响应体
}
func ParseEndStrAndReformat3(response *WorldSoulReplyMsg) *WorldSoulReplyMsg {
if response == nil || response.WObj == nil {
return nil // If the input is nil, return nil
}
newResponse := *response // Create a copy of the response to modify
// Determine the message type based on the presence of specific keywords or structures
if len(newResponse.WObj) == 0 && strings.Contains(newResponse.ISLIU, "【任务提示】") {
newResponse.MessageStatusType = "开场白"
} else if endStr, ok := newResponse.WObj["EndStr"].(string); ok && endStr != "" {
newResponse.MessageStatusType = "结局"
} else {
newResponse.MessageStatusType = "会话中消息"
}
// Further reformatting based on the presence of "EndStr"
if endStr, ok := newResponse.WObj["EndStr"].(string); ok {
if endStr != "" {
// Parse details from "EndStr"
title := strings.Split(endStr, "@")[0]
overallScore := extractBetween(endStr, "【整体评分】:", "\n")
objectiveEvaluation := extractToEnd(endStr, "【客观评价】:")
// Structurize "EndStr" into a JSON object
endStrObj := map[string]interface{}{
"title": title,
"overallScore": strings.TrimSpace(overallScore),
"objectiveEvaluation": strings.TrimSpace(objectiveEvaluation),
}
newResponse.WObj["EndStr"] = endStrObj // Assign the reformatted conclusion string object back to the response
}
}
// Handle additional fields such as '地点' and '表情'
if address, exists := newResponse.WObj["地点"]; exists {
newResponse.WObj["address"] = address
delete(newResponse.WObj, "地点")
}
if emotion, exists := newResponse.WObj["表情"]; exists {
newResponse.WObj["emotion"] = emotion
delete(newResponse.WObj, "表情")
}
return &newResponse // Return the modified response
}
// 使用例
func ExampleSend() {
IsLiu_Id := "d018fd63c598f4a13e31f7f8faf0ac15"
originalMsg := WorldSoulReplyMsg{
Code: 1,
WObj: map[string]interface{}{"EndStr": "确定下单@\n## 【整体评分】: 90\n\n## 【客观评价】:\n\n这位业务经理在与客户沟通的过程中展现出了良好的专业素养和沟通技巧。他能清晰地介绍产品,并针对客户提出的问题和疑虑进行耐心解答,并根据客户的需求进行灵活调整,最终促成了交易。\n\n**言行举止**: 业务经理在与客户沟通的过程中保持着礼貌和专业的态度,没有出现任何不当言行。\n\n**优势**: 业务经理对产品知识掌握熟练,能够根据客户的需求进行灵活的方案调整,并展现出一定的谈判技巧,最终促成了交易。\n\n**不足与建议**: 在价格方面,业务经理可以尝试更早地了解客户的心理价位,以便制定更有针对性的报价策略。此外,在介绍产品时,可以更加突出云电脑相比传统电脑的优势,例如节省维护成本、方便升级等。 \n",
"地点": "老板办公室",
"表情": "满意"},
ISLIU: "Some text",
WorldName: "Example World",
IsLIUId: &IsLiu_Id,
}
// 转换消息
transformedMsg := ParseEndStrAndReformat(&originalMsg)
// 序列化消息为JSON
jsonMsg, err := json.Marshal(transformedMsg)
if err != nil {
log.Printf("JSON编码失败: %v", err)
return
}
// 发送消息
//err = c.Socket.WriteMessage(websocket.TextMessage, jsonMsg)
//if err != nil {
// log.Println("发送WebSocket消息失败: ", err)
// WorldDestroyWs(c) // 关闭WebSocket连接
//}
fmt.Println("jsonMsg ==> ", string(jsonMsg))
}
...@@ -51,6 +51,7 @@ type WorldSoulReplyMsg struct { ...@@ -51,6 +51,7 @@ type WorldSoulReplyMsg struct {
WorldName string `json:"WorldName"` WorldName string `json:"WorldName"`
IsLIUId *string `json:"IsLIUId,omitempty"` // 使用指针类型,并添加 omitempty 标签,可选字段 IsLIUId *string `json:"IsLIUId,omitempty"` // 使用指针类型,并添加 omitempty 标签,可选字段
MessageStatusType string `json:"messageStatusType,omitempty"` // Optional field to indicate message type MessageStatusType string `json:"messageStatusType,omitempty"` // Optional field to indicate message type
ErrorMessage string `json:"ErrorMessage,omitempty"` //可选字段
} }
/* /*
...@@ -60,10 +61,11 @@ type WorldClient struct { ...@@ -60,10 +61,11 @@ type WorldClient struct {
//DpConversations *models.DpConversations //DpConversations *models.DpConversations
WorldConversations *models.WorldConversation WorldConversations *models.WorldConversation
Socket *websocket.Conn Socket *websocket.Conn
Send chan *WorldEchoRespones //Send chan *WorldEchoResponse
WorldName string Send chan *WorldSoulReplyMsg
AuthId string WorldName string
UserSource string AuthId string
UserSource string
} }
// 用户类 // 用户类
...@@ -115,11 +117,17 @@ type WorldErrorMessage struct { ...@@ -115,11 +117,17 @@ type WorldErrorMessage struct {
Message string `json:"message"` Message string `json:"message"`
} }
type WorldEchoResponseAndErrorMsg struct {
SoulReplyMsg WorldSoulReplyMsg //WorldSoulReplyMsg
ErrorMessage WorldErrorMessage `json:"ErrorMessage,omitempty"`
}
// Wrapper 结构体仅包含一个字符串字段,用于存储 JSON 字符串 // Wrapper 结构体仅包含一个字符串字段,用于存储 JSON 字符串
type Wrapper struct { type Wrapper struct {
ConfigData map[string]interface{} `json:"ConfigData"` ConfigData map[string]interface{} `json:"ConfigData"`
} }
//世界websocket控制器
func WorldWsHandler(ctx *gin.Context) { func WorldWsHandler(ctx *gin.Context) {
/* /*
http协议升级为webSocket协议 http协议升级为webSocket协议
...@@ -382,16 +390,21 @@ func WorldWsHandler(ctx *gin.Context) { ...@@ -382,16 +390,21 @@ func WorldWsHandler(ctx *gin.Context) {
WorldConversations: worldConversation, WorldConversations: worldConversation,
WorldName: world.Name, WorldName: world.Name,
Socket: conn, Socket: conn,
Send: nil, //Send: nil,
AuthId: ServiceProviderId,
Send: make(chan *WorldSoulReplyMsg, 1024), // 创建一个有缓冲的管道
AuthId: ServiceProviderId,
} }
if user != nil && user.RegisteredSource != "" { if user != nil && user.RegisteredSource != "" {
newClient.UserSource = user.RegisteredSource newClient.UserSource = user.RegisteredSource
} }
go newClient.WorldWrite() // 为每个客户端启动写消息协程
// 用户会话注册到用户管理上 // 用户会话注册到用户管理上
WorldManager.Register <- newClient //WorldManager.Register <- newClient
WorldManager.Register <- newClient // 注册客户端
if isNewHuaSoul { if isNewHuaSoul {
// 注册成功后,把世界信息开场白写入Socket // 注册成功后,把世界信息开场白写入Socket
...@@ -408,7 +421,7 @@ func WorldWsHandler(ctx *gin.Context) { ...@@ -408,7 +421,7 @@ func WorldWsHandler(ctx *gin.Context) {
return return
} }
/* 创建响应体 */ /* 创建响应体 WorldEchoRespones */
HSReplyMsg := WorldSoulReplyMsg{ HSReplyMsg := WorldSoulReplyMsg{
Code: world_response.Code, Code: world_response.Code,
WObj: world_response.WObj, WObj: world_response.WObj,
...@@ -419,13 +432,18 @@ func WorldWsHandler(ctx *gin.Context) { ...@@ -419,13 +432,18 @@ func WorldWsHandler(ctx *gin.Context) {
MessageStatusType: world_response.MessageStatusType, MessageStatusType: world_response.MessageStatusType,
} }
msg, _ := json.Marshal(HSReplyMsg) //向管道写入开场白消息
write_err := newClient.Socket.WriteMessage(websocket.TextMessage, msg) newClient.Send <- &HSReplyMsg
if write_err != nil {
log.Println("返回意识流给客户端时出错! ") /*
WorldDestroyWs(newClient) msg, _ := json.Marshal(HSReplyMsg)
return write_err := newClient.Socket.WriteMessage(websocket.TextMessage, msg)
} if write_err != nil {
log.Println("返回意识流给客户端时出错! ")
WorldDestroyWs(newClient)
return
}*/
/* 保存世界的独白到数据库 */ /* 保存世界的独白到数据库 */
senderType := "world" senderType := "world"
// 拼接会话Id // 拼接会话Id
...@@ -434,14 +452,17 @@ func WorldWsHandler(ctx *gin.Context) { ...@@ -434,14 +452,17 @@ func WorldWsHandler(ctx *gin.Context) {
// 错误处理 // 错误处理
if chatDB_err != nil { if chatDB_err != nil {
log.Println(config.ColorRed, "保存数字人聊天记录至数据库出错!", config.ColorReset) log.Println(config.ColorRed, "保存数字人聊天记录至数据库出错!", config.ColorReset)
errorMsg := WorldSoulReplyMsg{
errorMsg := ErrorMessage{ Code: -1,
Code: -1, ErrorMessage: "保存数字人聊天记录至数据库出错!",
Message: "保存数字人聊天记录至数据库出错!",
} }
errmsg, _ := json.Marshal(errorMsg) /* errorMsg := WorldErrorMessage{
_ = newClient.Socket.WriteMessage(websocket.TextMessage, errmsg) Code: -1,
Message: "保存数字人聊天记录至数据库出错!",
}
errmsg, _ := json.Marshal(errorMsg)
_ = newClient.Socket.WriteMessage(websocket.TextMessage, errmsg)*/
newClient.Send <- &errorMsg
return return
} }
...@@ -529,25 +550,34 @@ func (c *WorldClient) WorldRead() { ...@@ -529,25 +550,34 @@ func (c *WorldClient) WorldRead() {
err := c.Socket.ReadJSON(&sendMsg) err := c.Socket.ReadJSON(&sendMsg)
if err != nil { if err != nil {
log.Println("数据格式不正确", err) log.Println("数据格式不正确", err)
// 向前端返回数据格式不正确的状态码和消息
errorMsg := WorldErrorMessage{
Code: -1,
Message: "数据格式不正确",
}
errmsg, errMarshal := json.Marshal(errorMsg)
if errMarshal != nil {
// 如果JSON编码失败,则打印错误消息
log.Printf("JSON编码错误: %s\n", errMarshal)
} else {
// 发送错误消息
errWrite := c.Socket.WriteMessage(websocket.TextMessage, errmsg)
if errWrite != nil {
// 如果WebSocket发送失败,则打印错误消息
log.Printf("WebSocket发送错误: %s\n", errWrite)
/* // 向前端返回数据格式不正确的状态码和消息
errorMsg := WorldErrorMessage{
Code: -1,
Message: "数据格式不正确",
} }
errmsg, errMarshal := json.Marshal(errorMsg)
if errMarshal != nil {
// 如果JSON编码失败,则打印错误消息
log.Printf("JSON编码错误: %s\n", errMarshal)
} else {
// 发送错误消息
errWrite := c.Socket.WriteMessage(websocket.TextMessage, errmsg)
if errWrite != nil {
// 如果WebSocket发送失败,则打印错误消息
log.Printf("WebSocket发送错误: %s\n", errWrite)
}
}
*/
errorMsg := WorldSoulReplyMsg{
Code: -1,
ErrorMessage: "客户端发送的数据格式不正确!",
} }
c.Send <- &errorMsg
//fmt.Println("errmsg: ", errmsg) //fmt.Println("errmsg: ", errmsg)
//剔除注册的客户端用户 //剔除注册的客户端用户
...@@ -591,7 +621,7 @@ func (c *WorldClient) WorldRead() { ...@@ -591,7 +621,7 @@ func (c *WorldClient) WorldRead() {
if chat_err != nil { if chat_err != nil {
log.Println("会话失败") log.Println("会话失败")
// 向前端返回数据格式不正确的状态码和消息 // 向前端返回数据格式不正确的状态码和消息
errorMsg := WorldErrorMessage{ /*errorMsg := WorldErrorMessage{
Code: -1, Code: -1,
Message: "会话失败", Message: "会话失败",
} }
...@@ -608,7 +638,14 @@ func (c *WorldClient) WorldRead() { ...@@ -608,7 +638,14 @@ func (c *WorldClient) WorldRead() {
//如果发送 WebSocket消息失败,则打印错误 //如果发送 WebSocket消息失败,则打印错误
log.Printf("Error writing websocket message: %v", errWrite) log.Printf("Error writing websocket message: %v", errWrite)
} }
}*/
errorMsg := WorldSoulReplyMsg{
Code: -1,
ErrorMessage: "请求AI模型会话失败!",
} }
c.Send <- &errorMsg
// 删除会话记录 // 删除会话记录
/* if chat_err.Error() == "调用会话接口失败无法获取意识流" { /* if chat_err.Error() == "调用会话接口失败无法获取意识流" {
dropConversationErr := models.DeleteConversation() dropConversationErr := models.DeleteConversation()
...@@ -620,7 +657,9 @@ func (c *WorldClient) WorldRead() { ...@@ -620,7 +657,9 @@ func (c *WorldClient) WorldRead() {
} }
*/ */
return return
} } /*else {
c.Send <- echoResponse // 将回应消息放入 `Send` 频道
}*/
resCode := echoResponse.Code resCode := echoResponse.Code
Wobj := echoResponse.WObj Wobj := echoResponse.WObj
...@@ -629,14 +668,22 @@ func (c *WorldClient) WorldRead() { ...@@ -629,14 +668,22 @@ func (c *WorldClient) WorldRead() {
if ISLIU == "" || Wobj == nil { if ISLIU == "" || Wobj == nil {
log.Println("会话意识流为空...") log.Println("会话意识流为空...")
// 向前端返回数据格式不正确的状态码和消息 // 向前端返回数据格式不正确的状态码和消息
errorMsg := WorldErrorMessage{ /*errorMsg := WorldErrorMessage{
Code: -1, Code: -1,
Message: "会话意识流为空...", Message: "会话意识流为空...",
} }
errmsg, _ := json.Marshal(errorMsg) errmsg, _ := json.Marshal(errorMsg)
_ = c.Socket.WriteMessage(websocket.TextMessage, errmsg) _ = c.Socket.WriteMessage(websocket.TextMessage, errmsg)*/
fmt.Println("AI echo error: 会话意识流为空... ")
errorMsg := WorldSoulReplyMsg{
Code: -1,
ErrorMessage: "AI模型会话意识流为空.",
}
c.Send <- &errorMsg
fmt.Println("AI echo error: ", errmsg)
return return
} }
...@@ -654,13 +701,20 @@ func (c *WorldClient) WorldRead() { ...@@ -654,13 +701,20 @@ func (c *WorldClient) WorldRead() {
if chatDB_err != nil { if chatDB_err != nil {
log.Println("保存用户聊天记录至数据库出错!") log.Println("保存用户聊天记录至数据库出错!")
errorMsg := ErrorMessage{ /*
Code: -1, errorMsg := ErrorMessage{
Message: "保存用户聊天记录至数据库出错!", Code: -1,
Message: "保存用户聊天记录至数据库出错!",
}
errmsg, _ := json.Marshal(errorMsg)
_ = c.Socket.WriteMessage(websocket.TextMessage, errmsg)
*/
errorMsg := WorldSoulReplyMsg{
Code: -1,
ErrorMessage: "保存用户聊天记录至数据库出错!",
} }
errmsg, _ := json.Marshal(errorMsg)
_ = c.Socket.WriteMessage(websocket.TextMessage, errmsg)
c.Send <- &errorMsg
return return
} }
/* /*
...@@ -677,23 +731,28 @@ func (c *WorldClient) WorldRead() { ...@@ -677,23 +731,28 @@ func (c *WorldClient) WorldRead() {
//判断是不是咪咕服务商 //判断是不是咪咕服务商
if c.AuthId == miGuAuthId { if c.AuthId == miGuAuthId {
reformatHSReplyMsg := ParseEndStrAndReformat(&HSReplyMsg) reformatHSReplyMsg := ParseEndStrAndReformat(&HSReplyMsg)
msg, _ := json.Marshal(reformatHSReplyMsg) /* msg, _ := json.Marshal(reformatHSReplyMsg)
write_err := c.Socket.WriteMessage(websocket.TextMessage, msg) write_err := c.Socket.WriteMessage(websocket.TextMessage, msg)
if write_err != nil { if write_err != nil {
log.Println("返回意识流给客户端时出错! ") log.Println("返回意识流给客户端时出错! ")
WorldDestroyWs(c) WorldDestroyWs(c)
return return
} }*/
// 将处理后的消息发送到Write协程
c.Send <- reformatHSReplyMsg
} else { } else {
msg, _ := json.Marshal(HSReplyMsg) /*
write_err := c.Socket.WriteMessage(websocket.TextMessage, msg) msg, _ := json.Marshal(HSReplyMsg)
if write_err != nil { write_err := c.Socket.WriteMessage(websocket.TextMessage, msg)
log.Println("返回意识流给客户端时出错! ") if write_err != nil {
WorldDestroyWs(c) log.Println("返回意识流给客户端时出错! ")
return WorldDestroyWs(c)
} return
}
*/
c.Send <- &HSReplyMsg
} }
/* /*
...@@ -708,13 +767,20 @@ func (c *WorldClient) WorldRead() { ...@@ -708,13 +767,20 @@ func (c *WorldClient) WorldRead() {
if chatDB_err2 != nil { if chatDB_err2 != nil {
log.Println(config.ColorRed, "保存数字人聊天记录至数据库出错!", config.ColorReset) log.Println(config.ColorRed, "保存数字人聊天记录至数据库出错!", config.ColorReset)
errorMsg := ErrorMessage{ /*
Code: -1, errorMsg := ErrorMessage{
Message: "保存数字人聊天记录至数据库出错!", Code: -1,
Message: "保存数字人聊天记录至数据库出错!",
}
errmsg, _ := json.Marshal(errorMsg)
_ = c.Socket.WriteMessage(websocket.TextMessage, errmsg)
*/
errorMsg := WorldSoulReplyMsg{
Code: -1,
ErrorMessage: "保存数字人聊天记录至数据库出错!",
} }
errmsg, _ := json.Marshal(errorMsg)
_ = c.Socket.WriteMessage(websocket.TextMessage, errmsg)
c.Send <- &errorMsg
return return
} }
...@@ -846,14 +912,16 @@ func (c *WorldClient) WorldRead() { ...@@ -846,14 +912,16 @@ func (c *WorldClient) WorldRead() {
IsLIUId: &c.WorldConversations.IsLiuId, IsLIUId: &c.WorldConversations.IsLiuId,
} }
var msg []byte //var msg []byte
//判断是不是咪咕服务商 //判断是不是咪咕服务商
if c.AuthId == miGuAuthId { if c.AuthId == miGuAuthId {
reformatHSReplyMsg := ParseEndStrAndReformat(&HSReplyMsg) reformatHSReplyMsg := ParseEndStrAndReformat(&HSReplyMsg)
msg, _ = json.Marshal(reformatHSReplyMsg) //msg, _ = json.Marshal(reformatHSReplyMsg)
// 将处理后的消息发送到Write协程
c.Send <- reformatHSReplyMsg
} else { } else {
msg, _ = json.Marshal(HSReplyMsg) //msg, _ = json.Marshal(HSReplyMsg)
c.Send <- &HSReplyMsg
} }
//解析AI接口返回的数据 //解析AI接口返回的数据
//msg, _ := json.Marshal(HSReplyMsg) //msg, _ := json.Marshal(HSReplyMsg)
...@@ -868,23 +936,30 @@ func (c *WorldClient) WorldRead() { ...@@ -868,23 +936,30 @@ func (c *WorldClient) WorldRead() {
// 错误处理 // 错误处理
if chatDB_err != nil { if chatDB_err != nil {
log.Println(config.ColorRed, "保存数字人聊天记录至数据库出错!", config.ColorReset) log.Println(config.ColorRed, "保存数字人聊天记录至数据库出错!", config.ColorReset)
errorMsg := ErrorMessage{ /* errorMsg := ErrorMessage{
Code: -1, Code: -1,
Message: "保存数字人聊天记录至数据库出错!", Message: "保存数字人聊天记录至数据库出错!",
}
errmsg, _ := json.Marshal(errorMsg)
_ = c.Socket.WriteMessage(websocket.TextMessage, errmsg)*/
errorMsg := WorldSoulReplyMsg{
Code: -1,
ErrorMessage: "保存数字人聊天记录至数据库出错!",
} }
errmsg, _ := json.Marshal(errorMsg)
_ = c.Socket.WriteMessage(websocket.TextMessage, errmsg)
return
}
// 回复数据至前端用户 c.Send <- &errorMsg
write_err := c.Socket.WriteMessage(websocket.TextMessage, msg)
if write_err != nil {
log.Println(config.ColorRed, "数字人主动关怀,返回意识流给客户端时出错!", config.ColorReset)
WorldDestroyWs(c)
return return
} }
// 回复数据至前端用户
/* write_err := c.Socket.WriteMessage(websocket.TextMessage, msg)
if write_err != nil {
log.Println(config.ColorRed, "数字人主动关怀,返回意识流给客户端时出错!", config.ColorReset)
WorldDestroyWs(c)
return
}
*/
c.Send <- &HSReplyMsg
if endStr, ok := echoResponse.WObj["EndStr"]; ok { if endStr, ok := echoResponse.WObj["EndStr"]; ok {
if endStr != "" { if endStr != "" {
...@@ -989,7 +1064,7 @@ func (c *WorldClient) WorldRead() { ...@@ -989,7 +1064,7 @@ func (c *WorldClient) WorldRead() {
// ExtractRating 从响应中提取整体评分 // ExtractRating 从响应中提取整体评分
func ExtractRating(response WorldEchoRespones) (int, error) { func ExtractRating(response WorldEchoResponse) (int, error) {
endStr, ok := response.WObj["EndStr"].(string) endStr, ok := response.WObj["EndStr"].(string)
if !ok || endStr == "" { if !ok || endStr == "" {
return 0, nil return 0, nil
...@@ -1009,7 +1084,7 @@ func ExtractRating(response WorldEchoRespones) (int, error) { ...@@ -1009,7 +1084,7 @@ func ExtractRating(response WorldEchoRespones) (int, error) {
return 0, fmt.Errorf("未找到评分信息") return 0, fmt.Errorf("未找到评分信息")
} }
func ExtractRating1(response WorldEchoRespones) string { func ExtractRating1(response WorldEchoResponse) string {
endStr, ok := response.WObj["EndStr"].(string) endStr, ok := response.WObj["EndStr"].(string)
if !ok { if !ok {
...@@ -1135,12 +1210,46 @@ func DeepCopy(msg *WorldSoulReplyMsg) *WorldSoulReplyMsg { ...@@ -1135,12 +1210,46 @@ func DeepCopy(msg *WorldSoulReplyMsg) *WorldSoulReplyMsg {
return newMsg return newMsg
} }
/*
实现WorldWrite方法
WorldWrite方法需要修改以适应从通道中读取*WorldEchoRespones类型的数据并将其发送到WebSocket
*/
func (c *WorldClient) WorldWrite() { func (c *WorldClient) WorldWrite() {
defer func() { defer func() {
_ = c.Socket.Close() _ = c.Socket.Close()
}() }()
for { for {
select { select {
case message, ok := <-c.Send:
if !ok {
// 如果通道被关闭,发送WebSocket关闭消息并退出goroutine
_ = c.Socket.WriteMessage(websocket.CloseMessage, []byte{})
return
}
// 序列化消息为JSON
msg, err := json.Marshal(message)
if err != nil {
log.Printf("Error marshaling message: %s\n", err)
continue
}
// 发送序列化后的消息到WebSocket连接
if err := c.Socket.WriteMessage(websocket.TextMessage, msg); err != nil {
// 处理写入错误,例如可以记录日志或关闭连接
log.Printf("WebSocket write error: %s\n", err)
return
}
}
}
}
/* ============================================================================================= */
func (c *WorldClient) WorldWrite1() {
defer func() {
_ = c.Socket.Close()
}()
for {
select {
case message, ok := <-c.Send: case message, ok := <-c.Send:
if !ok { if !ok {
...@@ -1163,162 +1272,3 @@ func (c *WorldClient) WorldWrite() { ...@@ -1163,162 +1272,3 @@ func (c *WorldClient) WorldWrite() {
} }
} }
} }
/* ============================================================================================= */
// ParseEndStrAndReformat 重新结构化 WorldEchoRespones,以包含结论消息的详细拆分
func ParseEndStrAndReformat1(response *WorldEchoRespones) {
if response == nil || response.WObj == nil {
return
}
endStr, ok := response.WObj["EndStr"].(string)
if !ok || endStr == "" {
return
}
// 解析 "EndStr" 中的详细字段
title := strings.Split(endStr, "@")[0] // 提取 '@' 前的标题
overallScore := extractBetween(endStr, "【整体评分】:", "\n") // 提取整体评分
objectiveEvaluation := extractBetween(endStr, "【客观评价】:", "**言行举止**") // 提取客观评价
// "EndStr" 结构化为 JSON 对象
endStrObj := map[string]interface{}{
"title": title,
"OverallScore": strings.TrimSpace(overallScore),
"ObjectiveEvaluation": strings.TrimSpace(objectiveEvaluation),
}
response.WObj["EndStr"] = endStrObj // 将格式化后的结论字符串对象重新赋值给响应
// 可选处理其他字段如 '地点' '表情'
if address, exists := response.WObj["地点"]; exists {
response.WObj["address"] = address
delete(response.WObj, "地点")
}
if emotion, exists := response.WObj["表情"]; exists {
response.WObj["emotion"] = emotion
delete(response.WObj, "表情")
}
}
// ParseEndStrAndReformat WorldSoulReplyMsg 中的 WObj 修改后返回一个新的 WorldSoulReplyMsg 结构体
func ParseEndStrAndReformat2(response *WorldSoulReplyMsg) *WorldSoulReplyMsg {
if response == nil || response.WObj == nil {
return nil // 如果输入是nil,直接返回nil
}
newResponse := *response // 创建一个新的响应副本以避免修改原始数据
endStr, ok := newResponse.WObj["EndStr"].(string)
if !ok || endStr == "" {
return &newResponse // 如果没有 EndStr 或者为空,返回原始数据的副本
}
// 解析 "EndStr" 中的详细字段
title := strings.Split(endStr, "@")[0] // 提取 '@' 前的标题
overallScore := extractBetween(endStr, "【整体评分】:", "\n") // 提取整体评分
objectiveEvaluation := extractToEnd(endStr, "【客观评价】:") // 提取客观评价
// "EndStr" 结构化为 JSON 对象
endStrObj := map[string]interface{}{
"title": title,
"OverallScore": strings.TrimSpace(overallScore),
"ObjectiveEvaluation": strings.TrimSpace(objectiveEvaluation),
}
newResponse.WObj["EndStr"] = endStrObj // 将格式化后的结论字符串对象重新赋值给响应
// 可选处理其他字段如 '地点' '表情'
if address, exists := newResponse.WObj["地点"]; exists {
newResponse.WObj["address"] = address
delete(newResponse.WObj, "地点")
}
if emotion, exists := newResponse.WObj["表情"]; exists {
newResponse.WObj["emotion"] = emotion
delete(newResponse.WObj, "表情")
}
return &newResponse // 返回修改后的新响应体
}
func ParseEndStrAndReformat3(response *WorldSoulReplyMsg) *WorldSoulReplyMsg {
if response == nil || response.WObj == nil {
return nil // If the input is nil, return nil
}
newResponse := *response // Create a copy of the response to modify
// Determine the message type based on the presence of specific keywords or structures
if len(newResponse.WObj) == 0 && strings.Contains(newResponse.ISLIU, "【任务提示】") {
newResponse.MessageStatusType = "开场白"
} else if endStr, ok := newResponse.WObj["EndStr"].(string); ok && endStr != "" {
newResponse.MessageStatusType = "结局"
} else {
newResponse.MessageStatusType = "会话中消息"
}
// Further reformatting based on the presence of "EndStr"
if endStr, ok := newResponse.WObj["EndStr"].(string); ok {
if endStr != "" {
// Parse details from "EndStr"
title := strings.Split(endStr, "@")[0]
overallScore := extractBetween(endStr, "【整体评分】:", "\n")
objectiveEvaluation := extractToEnd(endStr, "【客观评价】:")
// Structurize "EndStr" into a JSON object
endStrObj := map[string]interface{}{
"title": title,
"overallScore": strings.TrimSpace(overallScore),
"objectiveEvaluation": strings.TrimSpace(objectiveEvaluation),
}
newResponse.WObj["EndStr"] = endStrObj // Assign the reformatted conclusion string object back to the response
}
}
// Handle additional fields such as '地点' and '表情'
if address, exists := newResponse.WObj["地点"]; exists {
newResponse.WObj["address"] = address
delete(newResponse.WObj, "地点")
}
if emotion, exists := newResponse.WObj["表情"]; exists {
newResponse.WObj["emotion"] = emotion
delete(newResponse.WObj, "表情")
}
return &newResponse // Return the modified response
}
// 使用例
func ExampleSend() {
IsLiu_Id := "d018fd63c598f4a13e31f7f8faf0ac15"
originalMsg := WorldSoulReplyMsg{
Code: 1,
WObj: map[string]interface{}{"EndStr": "确定下单@\n## 【整体评分】: 90\n\n## 【客观评价】:\n\n这位业务经理在与客户沟通的过程中展现出了良好的专业素养和沟通技巧。他能清晰地介绍产品,并针对客户提出的问题和疑虑进行耐心解答,并根据客户的需求进行灵活调整,最终促成了交易。\n\n**言行举止**: 业务经理在与客户沟通的过程中保持着礼貌和专业的态度,没有出现任何不当言行。\n\n**优势**: 业务经理对产品知识掌握熟练,能够根据客户的需求进行灵活的方案调整,并展现出一定的谈判技巧,最终促成了交易。\n\n**不足与建议**: 在价格方面,业务经理可以尝试更早地了解客户的心理价位,以便制定更有针对性的报价策略。此外,在介绍产品时,可以更加突出云电脑相比传统电脑的优势,例如节省维护成本、方便升级等。 \n",
"地点": "老板办公室",
"表情": "满意"},
ISLIU: "Some text",
WorldName: "Example World",
IsLIUId: &IsLiu_Id,
}
// 转换消息
transformedMsg := ParseEndStrAndReformat(&originalMsg)
// 序列化消息为JSON
jsonMsg, err := json.Marshal(transformedMsg)
if err != nil {
log.Printf("JSON编码失败: %v", err)
return
}
// 发送消息
//err = c.Socket.WriteMessage(websocket.TextMessage, jsonMsg)
//if err != nil {
// log.Println("发送WebSocket消息失败: ", err)
// WorldDestroyWs(c) // 关闭WebSocket连接
//}
fmt.Println("jsonMsg ==> ", string(jsonMsg))
}
...@@ -14,12 +14,14 @@ import ( ...@@ -14,12 +14,14 @@ import (
) )
//创建世界API接口时候返回的响应体 //创建世界API接口时候返回的响应体
type WorldEchoRespones struct { type WorldEchoResponse struct {
Code int `from:"code" json:"code"` Code int `from:"code" json:"code"`
WObj map[string]interface{} `json:"WObj"` WObj map[string]interface{} `json:"WObj"`
ISLIU string `from:"ISLIU" json:"ISLIU"` ISLIU string `from:"ISLIU" json:"ISLIU"`
MuseValue int `json:"muse"` MuseValue int `json:"muse"`
WorldName string `json:"worldName" ` WorldName string `json:"worldName" `
IsLIUId *string `json:"IsLIUId,omitempty"` // 使用指针类型,并添加 omitempty 标签,可选字段
MessageStatusType string `json:"messageStatusType,omitempty"` // Optional field to indicate message type
} }
//世界推演结局 //世界推演结局
...@@ -29,7 +31,7 @@ type OutcomeContent struct { ...@@ -29,7 +31,7 @@ type OutcomeContent struct {
} }
// WorldClient // WorldClient
func (client *WorldClient) WorldEchoAPI(msg *WorldSendMsg) (*WorldEchoRespones, error) { func (client *WorldClient) WorldEchoAPI(msg *WorldSendMsg) (*WorldEchoResponse, error) {
/* /*
创建一个请求参数对象 创建一个请求参数对象
*/ */
...@@ -70,7 +72,7 @@ func (client *WorldClient) WorldEchoAPI(msg *WorldSendMsg) (*WorldEchoRespones, ...@@ -70,7 +72,7 @@ func (client *WorldClient) WorldEchoAPI(msg *WorldSendMsg) (*WorldEchoRespones,
return nil, err return nil, err
} }
// 解析JSON // 解析JSON
var response WorldEchoRespones var response WorldEchoResponse
err = json.Unmarshal(body, &response) err = json.Unmarshal(body, &response)
// 将JSON打印为字符串 // 将JSON打印为字符串
...@@ -135,7 +137,7 @@ func (client *WorldClient) WorldEchoAPI(msg *WorldSendMsg) (*WorldEchoRespones, ...@@ -135,7 +137,7 @@ func (client *WorldClient) WorldEchoAPI(msg *WorldSendMsg) (*WorldEchoRespones,
} }
func AddWorldEchoEndStrRecord(worldId, userId int64, response *WorldEchoRespones) { func AddWorldEchoEndStrRecord(worldId, userId int64, response *WorldEchoResponse) {
// 检查是否存在结束标记 "EndStr" // 检查是否存在结束标记 "EndStr"
if endStr, ok := response.WObj["EndStr"]; ok { if endStr, ok := response.WObj["EndStr"]; ok {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment