From d3c206b4074ee86f39e1055a3c1e3489b3dc2d0d Mon Sep 17 00:00:00 2001
From: Ford <3014117377@qq.com>
Date: Tue, 29 Oct 2024 20:09:38 +0800
Subject: [PATCH] 添加了用户画像的创建和查询相关世界的用户画像

---
 config.json                                  |    2 +-
 src/controllers/NpcController.go             |  113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------------
 src/main.go                                  |    9 ++++-----
 src/models/NPCRole.go                        |   23 ++++++++++++++++++++++-
 src/service/WorldChat_HighConcurrency.go     |   34 +++++++++++++++++++++++++++++++---
 src/service/WorldChat_HighConcurrency.go_bak | 1278 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 1395 insertions(+), 64 deletions(-)
 create mode 100644 src/service/WorldChat_HighConcurrency.go_bak

diff --git a/config.json b/config.json
index 559d4b0..d98362e 100644
--- a/config.json
+++ b/config.json
@@ -211,7 +211,7 @@
   },
 
   "npc_role_detail_translations": {
-  "roleName":                "角色名称",
+  "roleName":                "角色名",
   "introduction":            "简介",
   "consumptionExpectations": "消费心理预期",
   "psychologicalTraits":     "心理特征",
diff --git a/src/controllers/NpcController.go b/src/controllers/NpcController.go
index b134e29..7dc52a4 100644
--- a/src/controllers/NpcController.go
+++ b/src/controllers/NpcController.go
@@ -1,10 +1,12 @@
 package controllers
 
 import (
+	"WorldEpcho/src/config"
 	"WorldEpcho/src/config/e"
 	database "WorldEpcho/src/datasource"
 	"WorldEpcho/src/models"
 	"WorldEpcho/src/service"
+	"WorldEpcho/src/utils"
 	"encoding/json"
 	"fmt"
 	"github.com/gin-gonic/gin"
@@ -33,38 +35,17 @@ import (
 */
 //创建角色画像的请求体
 type NpcRoleRequest struct {
-	Name              string  `json:"name"`             // 名称
-	Details           Details `json:"details"`          //详情
-	Gender            string  `json:"gender"`           //性别
-	Tags              string  `json:"tags"`             //世界标签集
-	RelatedWorlds     string  `json:"relatedWorlds"`    //相关世界
-	UpdateTime        int64   `json:"updateTime"`       //更新时间
-	CreateTime        int64   `json:"createTime"`       //构造时间
-	ServiceProviderId string  `json:"authId,omitempty"` // ServiceProviderId
+	Name              string         `json:"name"`             // 名称
+	Details           models.Details `json:"details"`          //详情
+	Gender            string         `json:"gender"`           //性别
+	Tags              string         `json:"tags"`             //世界标签集
+	RelatedWorlds     string         `json:"relatedWorlds"`    //相关世界
+	UpdateTime        int64          `json:"updateTime"`       //更新时间
+	CreateTime        int64          `json:"createTime"`       //构造时间
+	ServiceProviderId string         `json:"authId,omitempty"` // ServiceProviderId
 
 }
 
-// Detail 用于解析详细信息中的 JSON 字符串
-type Details struct {
-	RoleName                string       `json:"roleName"`                //角色名称
-	Introduction            Introduction `json:"introduction"`            //简介
-	ConsumptionExpectations []string     `json:"consumptionExpectations"` //消费心理预期
-	PsychologicalTraits     []string     `json:"psychologicalTraits"`     //心理特征
-	Appearance              string       `json:"appearance"`              //外观
-	Personality             string       `json:"personality"`             //性格
-	DecisionMakingStyle     string       `json:"decisionMakingStyle"`     //决策风格
-	RiskPreference          string       `json:"riskPreference"`          //风险偏好
-	AttitudeTowardsUsers    string       `json:"attitudeTowardsUsers"`    //对用户的态度
-}
-
-//个人传记 Personal profile
-type Introduction struct {
-	EducationLevel         string `json:"educationLevel"`         //教育水平
-	ProfessionalBackground string `json:"professionalBackground"` //职业背景
-	Purpose                string `json:"purpose"`                //目的性
-	KnownInformation       string `json:"knownInformation"`       //已知信息
-}
-
 //创建Npc用户画像的接口
 func CreateNpcUserPortrait(ctx *gin.Context) {
 
@@ -138,24 +119,22 @@ func CreateNpcUserPortrait(ctx *gin.Context) {
 
 	/* configData 英文键转换为中文 */
 
-	/*
-	   var data map[string]interface{}
-	   	if err := json.Unmarshal([]byte(string(detailsJSON)), &data); err != nil {
-	   		ctx.JSON(http.StatusOK, gin.H{"code": e.ParamParseError, "data": nil, "message": "解析用户画像详细信息数据出错"})
-	   		return
-	   	}
-	   	// 转换键名 => 英文转中文
-	   	NpcRoleDetailTranslations := config.Conf.NpcRoleDetailTranslations
-	   	translatedData := utils.TranslateKeysEnglishToChinese(NpcRoleDetailTranslations, data)
-
-	   	translatedJSON, err := json.MarshalIndent(translatedData, "", "    ")
-	   	if err != nil {
-	   		fmt.Println("Error marshalling JSON:", err)
-	   		ctx.JSON(http.StatusOK, gin.H{"code": e.ParamParseError, "data": nil, "message": "解析用户画像详细信息数据出错"})
-	   		return
-	   	}
-	   	fmt.Println(" Details  translatedJSON ==> ", string(translatedJSON))
-	*/
+	var data map[string]interface{}
+	if err := json.Unmarshal([]byte(string(detailsJSON)), &data); err != nil {
+		ctx.JSON(http.StatusOK, gin.H{"code": e.ParamParseError, "data": nil, "message": "解析用户画像详细信息数据出错"})
+		return
+	}
+	// 转换键名 => 英文转中文
+	NpcRoleDetailTranslations := config.Conf.NpcRoleDetailTranslations
+	translatedData := utils.TranslateKeysEnglishToChinese(NpcRoleDetailTranslations, data)
+
+	translatedJSON, err := json.MarshalIndent(translatedData, "", "    ")
+	if err != nil {
+		fmt.Println("Error marshalling JSON:", err)
+		ctx.JSON(http.StatusOK, gin.H{"code": e.ParamParseError, "data": nil, "message": "解析用户画像详细信息数据出错"})
+		return
+	}
+	fmt.Println(" Details  translatedJSON ==> ", string(translatedJSON))
 
 	// 创建一个空切片存储相关世界
 	relatedWorldIds := []int64{}
@@ -178,16 +157,18 @@ func CreateNpcUserPortrait(ctx *gin.Context) {
 	}
 
 	//用户画像详情信息
-	// 将Details结构体转换为 JSON
-	jsonData, err := json.Marshal(NpcRequest.Details)
-	if err != nil {
-		fmt.Println("Error:", err)
-		return
-	}
+	/*
+		// 将Details结构体转换为 JSON
+			jsonData, err := json.Marshal(NpcRequest.Details)
+			if err != nil {
+				fmt.Println("Error:", err)
+				return
+			}
+	*/
 
 	npcUserRole := &models.NpcRole{
 		Name:          NpcRequest.Name,
-		Details:       string(jsonData),
+		Details:       string(translatedJSON),
 		Gender:        NpcRequest.Gender,
 		Tags:          matchingTags,
 		RelatedWorlds: relatedWorldIds,
@@ -296,6 +277,30 @@ func QueryNpcRoleInfo(ctx *gin.Context) {
 		fmt.Println("根据相关世界ID查询用户画像信息出错")
 		return
 	}
+	/*
+	  转换世界配置信息中的英文字段
+	*/
+	var data map[string]interface{}
+
+	for i, npcRole := range npcRoles {
+		if err := json.Unmarshal([]byte(npcRole.Details), &data); err != nil {
+			ctx.JSON(http.StatusOK, gin.H{"code": e.ParamParseError, "data": nil, "message": "解析用户画像详情信息数据出错"})
+			return
+		}
+		// 转换键名
+		// 中文转英文
+		ReverseTranslations := config.Conf.NpcRoleDetailReverseTranslations
+		translatedData := utils.TranslateKeysChineseToEnglish(ReverseTranslations, data)
+		translatedJSON, err := json.MarshalIndent(translatedData, "", "    ")
+		if err != nil {
+			fmt.Println("Error marshalling JSON:", err)
+			ctx.JSON(http.StatusOK, gin.H{"code": e.ParamParseError, "data": nil, "message": "解析用户画像详情信息数据出错"})
+			return
+		}
+		npcRoles[i].Details = string(translatedJSON)
+		fmt.Println(" configData translatedJSON ==> ", string(translatedJSON))
+	}
+
 	//提交事务
 	err = session.Commit()
 	if err != nil {
diff --git a/src/main.go b/src/main.go
index 7a149b0..6d315ab 100644
--- a/src/main.go
+++ b/src/main.go
@@ -4,7 +4,6 @@ import (
 	"WorldEpcho/src/config"
 	"WorldEpcho/src/datasource"
 	"WorldEpcho/src/https_auth"
-	"WorldEpcho/src/models"
 	"WorldEpcho/src/routers"
 	"WorldEpcho/src/service"
 	"WorldEpcho/src/utils"
@@ -25,10 +24,10 @@ func main() {
 	config.RandInit()
 	datasource.InitMysql()
 	// 同步结构体与数据库表
-	err := datasource.Engine.Sync2(new(models.NpcRole))
-	if err != nil {
-		fmt.Printf("创建表失败:", err)
-	}
+	//err := datasource.Engine.Sync2(new(models.NpcRole))
+	//if err != nil {
+	//	fmt.Printf("创建表失败:", err)
+	//}
 
 	//生成一个9位的邀请码
 	//println("生成一个9位的邀请码: ", utils.GenerateInviteCode(1))
diff --git a/src/models/NPCRole.go b/src/models/NPCRole.go
index 459e34b..79eb455 100644
--- a/src/models/NPCRole.go
+++ b/src/models/NPCRole.go
@@ -20,6 +20,27 @@ type NpcRole struct {
 	ServiceProviderId string   `xorm:"-" json:"authId,omitempty"`                   // ServiceProviderId 在数据库中忽略
 }
 
+// Detail 用于解析详细信息中的 JSON 字符串
+type Details struct {
+	RoleName                string       `json:"roleName"`                //角色名称
+	Introduction            Introduction `json:"introduction"`            //简介
+	ConsumptionExpectations []string     `json:"consumptionExpectations"` //消费心理预期
+	PsychologicalTraits     []string     `json:"psychologicalTraits"`     //心理特征
+	Appearance              string       `json:"appearance"`              //外观
+	Personality             string       `json:"personality"`             //性格
+	DecisionMakingStyle     string       `json:"decisionMakingStyle"`     //决策风格
+	RiskPreference          string       `json:"riskPreference"`          //风险偏好
+	AttitudeTowardsUsers    string       `json:"attitudeTowardsUsers"`    //对用户的态度
+}
+
+//个人传记 Personal profile
+type Introduction struct {
+	EducationLevel         string `json:"educationLevel"`         //教育水平
+	ProfessionalBackground string `json:"professionalBackground"` //职业背景
+	Purpose                string `json:"purpose"`                //目的性
+	KnownInformation       string `json:"knownInformation"`       //已知信息
+}
+
 // 增加一个新的 NPC 角色
 func CreateNpcRole(session *xorm.Session, npcRole *NpcRole) (*NpcRole, error) {
 	_, err := session.Insert(npcRole)
@@ -62,7 +83,7 @@ func UpdateNpcRole(npcRole *NpcRole) error {
 }
 
 // 根据 ID 查询单个 NPC 角色
-func GetNpcRoleByID(id int) (*NpcRole, error) {
+func GetNpcRoleByID(id int64) (*NpcRole, error) {
 	npcRole := new(NpcRole)
 	has, err := datasource.Engine.ID(id).Get(npcRole)
 	if err != nil {
diff --git a/src/service/WorldChat_HighConcurrency.go b/src/service/WorldChat_HighConcurrency.go
index b9ef183..2f27b02 100644
--- a/src/service/WorldChat_HighConcurrency.go
+++ b/src/service/WorldChat_HighConcurrency.go
@@ -126,7 +126,8 @@ type WorldErrorMessage struct {
 
 // Wrapper 结构体仅包含一个字符串字段,用于存储 JSON 字符串
 type Wrapper struct {
-	ConfigData map[string]interface{} `json:"ConfigData"`
+	ConfigData    map[string]interface{}   `json:"ConfigData"`
+	EmbeddingNpcs []map[string]interface{} `json:"EmbeddingNpcs" `
 }
 
 //世界websocket控制器
@@ -245,6 +246,7 @@ func WorldWsHandler(ctx *gin.Context) {
 	world_Id := ctx.Query("worldId")
 	var world *models.WorldInfo
 	var userInfo string
+	var roleInfo *models.NpcRole
 
 	if worldName != "" {
 		world, err = models.GetWorldInfoByName(worldName)
@@ -279,6 +281,20 @@ func WorldWsHandler(ctx *gin.Context) {
 		ctx.JSON(http.StatusOK, gin.H{"code": e.NotFound, "data": nil, "message": "世界名称不存在"})
 		return
 	}
+	NpcRoleId := ctx.Query("NpcRoleId")
+	if NpcRoleId != "" {
+		NpcRole_Id, err := strconv.ParseInt(NpcRoleId, 10, 64)
+		if err != nil {
+			ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "用户画像ID类型转换出错"})
+			return
+		}
+		roleInfo, err = models.GetNpcRoleByID(NpcRole_Id)
+		if err != nil {
+			ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "根据用户画像ID查询画像信息出错"})
+			return
+		}
+
+	}
 
 	if b || SP != nil {
 		fmt.Println("ServiceProvider ===> ", SP)
@@ -287,6 +303,7 @@ func WorldWsHandler(ctx *gin.Context) {
 		if user_info != "" {
 			userInfo = user_info
 		}
+
 		//拼接会话主题
 		//ConversationTitle = "用户Id为" + user_Id + "的用户和数字人" + strings.Join(DpNames, "和") + "开始会话"
 		//fmt.Println("ConversationTitle: ", ConversationTitle)
@@ -295,10 +312,22 @@ func WorldWsHandler(ctx *gin.Context) {
 				BgInfo = world.Background
 			}
 			if user_info == "" {
-				// 创建 Wrapper 实例并将 JSON 字符串封装
+				//var details models.Details
+				//若用户画像存在
 
+				// 创建 Wrapper 实例并将 JSON 字符串封装
 				wrapper := Wrapper{ConfigData: make(map[string]interface{})}
+				fmt.Println("world.ConfigData ==> ", world.ConfigData)
+				if roleInfo != nil {
+					var npcMap map[string]interface{}
+					err = json.Unmarshal([]byte(roleInfo.Details), &npcMap)
+					if err != nil {
+						log.Fatalf("Error unmarshalling JSON: %v", err)
+					}
+					wrapper.EmbeddingNpcs = append(wrapper.EmbeddingNpcs, npcMap)
+				}
 				// 将 JSON 字符串解析为 map[string]interface{}
+				//err := json.Unmarshal([]byte(world.ConfigData), &wrapper.ConfigData)
 				err := json.Unmarshal([]byte(world.ConfigData), &wrapper.ConfigData)
 				if err != nil {
 					log.Printf("Error parsing JSON: %v", err)
@@ -307,7 +336,6 @@ func WorldWsHandler(ctx *gin.Context) {
 
 				// 打印解析后的数据
 				//fmt.Printf("Wrapper ConfigData: %+v\n", wrapper.ConfigData)
-
 				// 序列化 Wrapper 实例以生成所需的最终 JSON 输出
 				finalJSON, err := json.Marshal(wrapper)
 				if err != nil {
diff --git a/src/service/WorldChat_HighConcurrency.go_bak b/src/service/WorldChat_HighConcurrency.go_bak
new file mode 100644
index 0000000..05cf8eb
--- /dev/null
+++ b/src/service/WorldChat_HighConcurrency.go_bak
@@ -0,0 +1,1278 @@
+package service
+
+import (
+	"WorldEpcho/src/config"
+	"WorldEpcho/src/config/e"
+	"WorldEpcho/src/datasource"
+	"WorldEpcho/src/models"
+	"WorldEpcho/src/utils"
+	"github.com/gin-contrib/sessions"
+	"os"
+	"strconv"
+	"strings"
+	"time"
+
+	//"time"
+
+	//"chat/cache"
+	//"chat/conf"
+	"encoding/json"
+	"fmt"
+	"github.com/gin-gonic/gin"
+	"github.com/gorilla/websocket"
+	"log"
+	"net/http"
+	//"strconv"
+	//"time"
+)
+
+//const month = 60 * 60 * 24 * 30 // 按照30天算一个月
+
+// 发送消息的类型
+type WorldSendMsg struct {
+	Type    int    `json:"type"`
+	Content string `json:"content"`
+}
+
+// 回复的消息
+/* 这个要注释掉 */
+type WorldReplyMsg struct {
+	From       string `json:"from"`
+	Code       int    `json:"code"`
+	Content    string `json:"content"`
+	StatusCode int    `json:"statusCode,omitempty"`
+}
+
+// 转发AI接口意识流响应给前端
+type WorldSoulReplyMsg struct {
+	Code              int                    `json:"code"`
+	WObj              map[string]interface{} `json:"WObj"`
+	ISLIU             string                 `json:"ISLIU"`
+	WorldName         string                 `json:"WorldName"`
+	IsLIUId           *string                `json:"IsLIUId,omitempty"`           // 使用指针类型,并添加 omitempty 标签,可选字段
+	MessageStatusType string                 `json:"messageStatusType,omitempty"` // Optional field to indicate message type
+	ErrorMessage      string                 `json:"ErrorMessage,omitempty"`      //可选字段
+}
+
+/*
+构建Client表
+*/
+type WorldClient struct {
+	//DpConversations *models.DpConversations
+	WorldConversations *models.WorldConversation
+	Socket             *websocket.Conn
+	//Send               chan *WorldEchoResponse
+	Send       chan *WorldSoulReplyMsg
+	WorldName  string
+	AuthId     string
+	UserSource string
+}
+
+// 用户类
+/*
+type Client struct {
+	Id     string
+	SendID string
+	Socket *websocket.Conn
+	Send   chan []byte
+}
+*/
+
+// 广播类,包括广播内容和源用户
+/*
+type Broadcast struct {
+	Client  *Client
+	Message []byte
+	Type    int
+}
+*/
+
+// 用户管理
+type WorldClientManager struct {
+	Client map[string]*WorldClient
+	//Broadcast  chan *Broadcast
+	Reply      chan *WorldClient
+	Register   chan *WorldClient
+	Unregister chan *WorldClient
+}
+
+// Message 信息转JSON (包括:发送者、接收者、内容)
+type WorldMessage struct {
+	Sender    string `json:"sender,omitempty"`
+	Recipient string `json:"recipient,omitempty"`
+	Content   string `json:"content,omitempty"`
+}
+
+var WorldManager = WorldClientManager{
+	Client: make(map[string]*WorldClient), // 参与连接的用户,出于性能的考虑,需要设置最大连接数
+	//Broadcast:  make(chan *Broadcast),
+	Register:   make(chan *WorldClient),
+	Reply:      make(chan *WorldClient),
+	Unregister: make(chan *WorldClient),
+}
+
+//错误消息响应结构体
+type WorldErrorMessage struct {
+	Code    int    `json:"code"`
+	Message string `json:"message"`
+}
+
+/*
+ type WorldEchoResponseAndErrorMsg struct {
+	SoulReplyMsg WorldSoulReplyMsg //WorldSoulReplyMsg
+	ErrorMessage WorldErrorMessage `json:"ErrorMessage,omitempty"`
+ }
+*/
+
+// Wrapper 结构体仅包含一个字符串字段,用于存储 JSON 字符串
+type Wrapper struct {
+	ConfigData map[string]interface{} `json:"ConfigData"`
+}
+
+//世界websocket控制器
+func WorldWsHandler(ctx *gin.Context) {
+	/*
+	 http协议升级为webSocket协议
+	*/
+	conn, err := (&websocket.Upgrader{
+		CheckOrigin: func(r *http.Request) bool { // CheckOrigin解决跨域问题
+			return true
+		}}).Upgrade(ctx.Writer, ctx.Request, nil) // 升级成ws协议
+
+	if err != nil {
+		http.NotFound(ctx.Writer, ctx.Request)
+		return
+	}
+	/*
+	   从session里获取用户id
+	*/
+	session := sessions.Default(ctx)
+	userId := session.Get("WorldUserID")
+	if userId == nil {
+		// 处理session中未找到值的情况,返回错误信息
+		/*这里是双保险为了测试用*/
+		userId = ctx.Query("uid")
+		if userId == nil {
+			ctx.JSON(http.StatusOK, gin.H{"code": e.NotLoginUser, "data": nil, "message": "Session中未找到用户ID,用户未登录"})
+			fmt.Println(config.ColorYellow, "Session中未找到用户ID,用户未登录", config.ColorReset)
+			return
+		}
+	}
+	fmt.Println("world chat session UserID:", userId)
+	var SP *models.ServiceProvider
+	// 服务商id获取
+	//从配置文件读取咪咕服务商ID
+	miGuAuthId := config.Conf.MiGuAuthId
+
+	ServiceProviderId := ctx.Query("AuthId")
+	if ServiceProviderId != "" || ServiceProviderId == miGuAuthId {
+		// 从请求头中获取 JWT token
+		tokenString := ctx.GetHeader("Token")
+		if tokenString == "" {
+			fmt.Printf("no Authorization token provided")
+			ctx.JSON(http.StatusOK, gin.H{"code": e.EmptyParamsError, "data": nil, "message": "请求头中无token信息!"})
+			return
+		}
+		isValid, err := IsValidMiGuToken(tokenString)
+		if err != nil {
+			ctx.JSON(http.StatusOK, gin.H{"code": e.TokenAuthError, "data": nil, "message": "解析token出错!"})
+			return
+		}
+		if !isValid {
+			ctx.JSON(http.StatusOK, gin.H{"code": e.InvalidToken, "data": nil, "message": "无效的token"})
+			return
+		}
+
+		SP, err = models.GetServiceProviderById(ServiceProviderId)
+		if err != nil {
+			fmt.Println("根据服务商id查询出错:", err)
+			ctx.JSON(http.StatusOK, gin.H{"code": 0, "data": nil, "message": "根据服务商id查询服务商出错"})
+			return
+		}
+		if SP == nil {
+			ctx.JSON(http.StatusOK, gin.H{"code": 0, "data": nil, "message": "非法的服务商"})
+			return
+		}
+	}
+	user_Id, ok := userId.(string)
+	if !ok {
+		// 类型断言失败,处理类型不匹配的情况
+		ctx.JSON(http.StatusOK, gin.H{"code": 0, "data": nil, "message": "用户ID类型错误"})
+		return
+	}
+	//userId作为string类型的值进行后续操作
+	_, b := config.WorldLoginCacheCode.Get(user_Id)
+
+	uid, err := strconv.ParseInt(user_Id, 10, 64)
+	if err != nil {
+		ctx.JSON(http.StatusOK, gin.H{"code": 0, "data": nil, "message": "数字人id类型转换出错"})
+		//continue
+		return
+	}
+	if user_Id == "" && ServiceProviderId == "" {
+		fmt.Println(config.ColorPurple, "用户id或者服务商id为空", config.ColorReset)
+		ctx.JSON(http.StatusOK, gin.H{"code": 0, "data": nil, "message": "用户id或者服务商id为空"})
+		return
+	}
+	if SP != nil {
+		if SP.InspirationValue == 0 {
+			ctx.JSON(http.StatusOK, gin.H{"code": 0, "data": nil, "message": "服务商的灵感值余额不足,无法进行数字人聊天"})
+			return
+		}
+	}
+
+	//校验用户是不是服务商那边的用户
+	if user_Id != "" && SP != nil {
+		user, err := models.GetUserByID(uid)
+		if err != nil {
+			fmt.Println(config.ColorPurple, "根据用户ID查询用户信息出错", config.ColorReset)
+			ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "根据用户ID查询用户信息出错"})
+			return
+		}
+		if user.RegisteredSource != SP.Name {
+			ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": " 该用户不是服务商的用户不能连接! "})
+			fmt.Println("该用户不是服务商的用户不能连接!")
+			return
+		}
+
+	}
+	/*
+	   判断用户是否登录
+	*/
+	//定义会话主题
+	//var ConversationTitle string
+	worldName := ctx.Query("world_name")
+	world_Id := ctx.Query("worldId")
+	var world *models.WorldInfo
+	var userInfo string
+
+	if worldName != "" {
+		world, err = models.GetWorldInfoByName(worldName)
+		if err != nil {
+			log.Println("根据世界名称,查询世界信息失败")
+			ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "根据世界名称,查询世界信息失败"})
+			return
+		}
+	}
+	if world_Id != "" {
+		worldId, err := strconv.ParseInt(world_Id, 10, 64)
+		if err != nil {
+			ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "世界ID类型转换出错"})
+
+			return
+		}
+		world, _, err = models.GetWorldInfoById(worldId)
+		if err != nil {
+			log.Println("根据世界名称,查询世界信息失败")
+			ctx.JSON(http.StatusOK, gin.H{"code": e.ErrorDatabase, "data": nil, "message": "根据世界名称,查询世界信息失败"})
+			return
+		}
+		if world == nil {
+			log.Println("世界信息不存在")
+			ctx.JSON(http.StatusOK, gin.H{"code": e.NotFound, "data": nil, "message": "世界信息不存在"})
+			return
+		}
+	}
+
+	if world == nil {
+		log.Println("世界名称不存在")
+		ctx.JSON(http.StatusOK, gin.H{"code": e.NotFound, "data": nil, "message": "世界名称不存在"})
+		return
+	}
+
+	if b || SP != nil {
+		fmt.Println("ServiceProvider ===> ", SP)
+		BgInfo := ctx.Query("BgInfo")
+		user_info := ctx.Query("userInfo")
+		if user_info != "" {
+			userInfo = user_info
+		}
+		//拼接会话主题
+		//ConversationTitle = "用户Id为" + user_Id + "的用户和数字人" + strings.Join(DpNames, "和") + "开始会话"
+		//fmt.Println("ConversationTitle: ", ConversationTitle)
+		if SP != nil && world != nil {
+			if BgInfo == "" {
+				BgInfo = world.Background
+			}
+			if user_info == "" {
+				// 创建 Wrapper 实例并将 JSON 字符串封装
+
+				wrapper := Wrapper{ConfigData: make(map[string]interface{})}
+				// 将 JSON 字符串解析为 map[string]interface{}
+				err := json.Unmarshal([]byte(world.ConfigData), &wrapper.ConfigData)
+				if err != nil {
+					log.Printf("Error parsing JSON: %v", err)
+					return
+				}
+				// 打印解析后的数据
+				//fmt.Printf("Wrapper ConfigData: %+v\n", wrapper.ConfigData)
+				// 序列化 Wrapper 实例以生成所需的最终 JSON 输出
+				finalJSON, err := json.Marshal(wrapper)
+				if err != nil {
+					fmt.Println("Error marshaling final JSON: ", err)
+					ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "业务经理考核系统配置信息解析失败"})
+					return
+				}
+
+				fmt.Println("ConfigData ===>", string(finalJSON))
+				//userInfo = string(finalJSON)
+				userInfo = string(finalJSON)
+			}
+
+		}
+
+		worldConversation, _, err := models.GetWorldConversationByUidAndWorldName(uid, world.Name)
+		if err != nil {
+			log.Println("查询世界信息失败")
+			ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "查询世界信息失败"})
+			return
+		}
+
+		ISULU_ID := ""
+		var world_response WorldCreateResponse
+		var isNewHuaSoul bool
+		if worldConversation == nil {
+			//世界意识流不存在调用new接口创建
+			world, new_conversation, err := CreateVirtualWorldHandler(uid, world.Name, BgInfo, userInfo)
+			if err != nil {
+				ctx.JSON(http.StatusOK, gin.H{"code": 0, "content": "创建世界失败!"})
+				return
+			}
+			// 把新创建的世界会话赋值给会话对象
+			worldConversation = new_conversation
+			isNewHuaSoul = true
+			ISULU_ID = world.ISLIUid
+			world_response.Code = world.Code
+			world_response.ISLIUid = world.ISLIUid
+			world_response.WObj = world.WObj
+			world_response.ISLIU = world.ISLIU
+			//这里加了一个消息状态类型
+			world_response.MessageStatusType = world.MessageStatusType
+		} else {
+			ISULU_ID = worldConversation.IsLiuId
+			isNewHuaSoul = false
+			// 如果查询到记录,调用查询意识流Id接口判断意识流id是否有效,若无效则修改意识流ID为新的意识流ID
+			flag, err := FindWorldISLIU(uid, world.Name)
+			if err != nil {
+				ctx.JSON(http.StatusOK, gin.H{"code": 0, "content": "查询世界意识流id失败!"})
+				return
+			}
+			fmt.Println("查询世界意识流Id, flag: ", flag)
+			//没找到
+			if !flag {
+				//调用new接口创建世界
+				world, new_conversation, err := CreateVirtualWorldHandler(uid, world.Name, BgInfo, userInfo)
+				if err != nil {
+					ctx.JSON(http.StatusOK, gin.H{"code": 0, "content": "创建世界失败!"})
+					return
+				}
+				// 把新创建的世界会话赋值给会话对象
+				worldConversation = new_conversation
+				isNewHuaSoul = true
+				ISULU_ID = world.ISLIUid
+				world_response.Code = world.Code
+				world_response.ISLIUid = world.ISLIUid
+				world_response.WObj = world.WObj
+				world_response.ISLIU = world.ISLIU
+				//这里加了一个消息状态类型
+				world_response.MessageStatusType = world.MessageStatusType
+			}
+
+		}
+		//根据uid查询用户来源是否为咪咕
+		user, err := models.GetUserByID(worldConversation.Uid)
+		if err != nil {
+			ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "根据用户id查询用户出错!"})
+			return
+		}
+		// 创建一个用户客户端会话实例
+		newClient := &WorldClient{
+			WorldConversations: worldConversation,
+			WorldName:          world.Name,
+			Socket:             conn,
+			//Send:               nil,
+
+			Send:   make(chan *WorldSoulReplyMsg, 1024), // 创建一个有缓冲的管道
+			AuthId: ServiceProviderId,
+		}
+
+		if user != nil && user.RegisteredSource != "" {
+			newClient.UserSource = user.RegisteredSource
+		}
+
+		go newClient.WorldWrite() // 为每个客户端启动写消息协程
+
+		// 用户会话注册到用户管理上
+		//WorldManager.Register <- newClient
+		WorldManager.Register <- newClient // 注册客户端
+
+		if isNewHuaSoul {
+			//  注册成功后,把世界信息开场白写入Socket
+			if world_response.ISLIU == "" || world_response.WObj == nil {
+				log.Println("世界开场白,意识流为空...")
+				// 向前端返回数据格式不正确的状态码和消息
+				errorMsg := WorldErrorMessage{
+					Code:    -1,
+					Message: "世界开场白,意识流为空...",
+				}
+				errmsg, _ := json.Marshal(errorMsg)
+				_ = newClient.Socket.WriteMessage(websocket.TextMessage, errmsg)
+				fmt.Println("返回世界开场白信息失败: ", errmsg)
+				return
+
+			}
+			/* 创建响应体 WorldEchoRespones */
+			HSReplyMsg := WorldSoulReplyMsg{
+				Code:      world_response.Code,
+				WObj:      world_response.WObj,
+				ISLIU:     world_response.ISLIU,
+				WorldName: world.Name,
+				//加了一个消息状态类型
+				IsLIUId:           &world_response.ISLIUid,
+				MessageStatusType: world_response.MessageStatusType,
+			}
+
+			//向管道写入开场白消息
+			newClient.Send <- &HSReplyMsg
+
+			/*
+				msg, _ := json.Marshal(HSReplyMsg)
+				write_err := newClient.Socket.WriteMessage(websocket.TextMessage, msg)
+				if write_err != nil {
+					log.Println("返回意识流给客户端时出错! ")
+					WorldDestroyWs(newClient)
+					return
+				}*/
+
+			/* 保存世界的独白到数据库 */
+			senderType := "world"
+			// 拼接会话Id
+			conversation_Id := utils.Strval(newClient.WorldConversations.Uid) + "_" + utils.Strval(newClient.WorldConversations.WorldId)
+			_, chatDB_err := datasource.SaveWorldChatRecordMongoDB(conversation_Id, newClient.WorldConversations.WorldId, newClient.WorldConversations.WorldName, world_response.ISLIU, world_response.WObj, senderType)
+			// 错误处理
+			if chatDB_err != nil {
+				log.Println(config.ColorRed, "保存数字人聊天记录至数据库出错!", config.ColorReset)
+				errorMsg := WorldSoulReplyMsg{
+					Code:         -1,
+					ErrorMessage: "保存数字人聊天记录至数据库出错!",
+				}
+				/*		errorMsg := WorldErrorMessage{
+							Code:    -1,
+							Message: "保存数字人聊天记录至数据库出错!",
+						}
+						errmsg, _ := json.Marshal(errorMsg)
+						_ = newClient.Socket.WriteMessage(websocket.TextMessage, errmsg)*/
+				newClient.Send <- &errorMsg
+				return
+			}
+
+		}
+
+		// ------------------上传意识流---------------------- //
+
+		url := config.Conf.SoulUrl + "/world/neural"
+
+		fileName := "./neural/" + ISULU_ID + ".CFN"
+		// 获取文件信息
+		_, err = os.Stat(fileName)
+		if err == nil {
+			fmt.Println("文件存在")
+			// 构造请求参数
+			request := SoulNeuralRequest{
+				Auth:    config.Conf.SoulAuth,
+				Type:    1, // 1表示上载
+				ISLIUid: ISULU_ID,
+			}
+			// 调用函数
+			_, err := SoulNeuralFileUpload(url, request, fileName)
+			if err != nil {
+				log.Printf("Error during soul neural transfer: %v", err)
+			}
+			// 处理响应
+			//fmt.Println("Response received: ", response)
+
+		} else if os.IsNotExist(err) {
+			fmt.Println("文件不存在")
+		} else {
+			fmt.Println("获取文件信息出错:", err)
+		}
+
+		// ---------------------------------------- //
+		//fmt.Println("调用socket的Read方法前:", ISULU_ID)
+		go newClient.WorldRead()
+		//go newClient.WorldWrite()
+
+	} else {
+		ctx.JSON(http.StatusOK, gin.H{"code": e.NotLoginUser, "data": nil, "message": "用户未登录"})
+		return
+	}
+
+}
+
+func WorldDestroyWs(c *WorldClient) { // 避免忘记关闭,所以要加上close
+
+	//关闭websocket之前,下载关于数字人的神经网络记忆文件
+	url := config.Conf.SoulUrl + "/world/neural"
+	fileName := "./neural/" + c.WorldConversations.IsLiuId + ".CFN"
+
+	// 构造请求参数
+	request := SoulNeuralRequest{
+		Auth:    config.Conf.SoulAuth,
+		Type:    0, // 0表示下载
+		ISLIUid: c.WorldConversations.IsLiuId,
+	}
+	// 调用函数
+	err1 := SoulNeuralFileDownload(url, request, fileName)
+	if err1 != nil {
+		log.Printf("Error during soul neural transfer: %v", err1)
+	}
+	//注销websocket的客户端
+	WorldManager.Unregister <- c
+	_ = c.Socket.Close()
+	c.Socket = nil
+
+}
+
+/*
+ 从websocket读取客户端用户的消息,然后服务器回应前端一个消息
+*/
+func (c *WorldClient) WorldRead() {
+	//从配置文件读取咪咕服务商ID
+	miGuAuthId := config.Conf.MiGuAuthId
+	//延迟关闭websocket
+	defer WorldDestroyWs(c)
+	/*
+	  死循环执行websocket消息接收和发送
+	*/
+	for {
+		c.Socket.PongHandler()
+		sendMsg := new(WorldSendMsg)
+		err := c.Socket.ReadJSON(&sendMsg)
+		if err != nil {
+			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 := WorldSoulReplyMsg{
+				Code:         -1,
+				ErrorMessage: "客户端发送的数据格式不正确!",
+			}
+
+			c.Send <- &errorMsg
+
+			//fmt.Println("errmsg: ", errmsg)
+
+			//剔除注册的客户端用户
+			WorldManager.Unregister <- c
+			fmt.Println(" Socket.Close() ... ")
+			//关闭webSocket
+			_ = c.Socket.Close()
+
+			break
+		}
+		//打印前端发送过来的消息
+		sendMsgMarshal, err := json.Marshal(sendMsg)
+		if err != nil {
+			// 打印错误信息的字符串表示
+			log.Printf("Error marshaling sendMsg to JSON: %s", err.Error())
+			// 在这里还可以做其它错误处理,例如返回一个错误响应等
+		} else {
+			// 打印 sendMsg JSON 字符串
+			fmt.Printf("【==== sendMsg ===】 : %s\n", string(sendMsgMarshal))
+
+			// 在这里可以继续处理 sendMsg JSON 字符串,比如发送它
+		}
+
+		/*
+
+		 */
+		go func() {
+			/*
+			   响应类型0 交互
+			*/
+			// 拼接会话Id
+			conversation_Id := utils.Strval(c.WorldConversations.Uid) + "_" + utils.Strval(c.WorldConversations.WorldId)
+			/*		dpIdsStr := utils.Int64SliceToStringSlice(c.DpConversations.DpIds)
+					conversation_Id := utils.Strval(c.DpConversations.Uid) + "_" + strings.Join(dpIdsStr, ",") + "_" + utils.Strval(c.DpConversations.AppId)*/
+
+			// 调用AI的会话接口
+			echoResponse, chat_err := c.WorldEchoAPI(sendMsg)
+			if c.Socket == nil {
+				return
+			}
+			if chat_err != nil {
+				log.Println("会话失败")
+				// 向前端返回数据格式不正确的状态码和消息
+				/*errorMsg := WorldErrorMessage{
+					Code:    -1,
+					Message: "会话失败",
+				}
+
+				// 将错误消息对象转换为 JSON 字符串
+				errmsg, errMarshal := json.Marshal(errorMsg)
+				if errMarshal != nil {
+					// 如果 JSON 编码失败,则打印错误
+					log.Printf("WorldEchoAPI error: %v", errMarshal)
+				} else {
+					// 发送错误消息
+					errWrite := c.Socket.WriteMessage(websocket.TextMessage, errmsg)
+					if errWrite != nil {
+						//如果发送 WebSocket消息失败,则打印错误
+						log.Printf("Error writing websocket message: %v", errWrite)
+					}
+				}*/
+				errorMsg := WorldSoulReplyMsg{
+					Code:         -1,
+					ErrorMessage: "请求AI模型会话失败!",
+				}
+
+				c.Send <- &errorMsg
+
+				// 删除会话记录
+				/*		if chat_err.Error() == "调用会话接口失败无法获取意识流" {
+							dropConversationErr := models.DeleteConversation()
+							if dropConversationErr != nil {
+								log.Println("删除会话失败")
+
+							}
+
+						}
+				*/
+				return
+			} /*else {
+				c.Send <- echoResponse // 将回应消息放入 `Send` 频道
+			}*/
+
+			resCode := echoResponse.Code
+			Wobj := echoResponse.WObj
+			ISLIU := echoResponse.ISLIU
+
+			if ISLIU == "" || Wobj == nil {
+				log.Println("会话意识流为空...")
+				// 向前端返回数据格式不正确的状态码和消息
+				/*errorMsg := WorldErrorMessage{
+					Code:    -1,
+					Message: "会话意识流为空...",
+				}
+				errmsg, _ := json.Marshal(errorMsg)
+				_ = c.Socket.WriteMessage(websocket.TextMessage, errmsg)*/
+
+				fmt.Println("AI echo error: 会话意识流为空... ")
+
+				errorMsg := WorldSoulReplyMsg{
+					Code:         -1,
+					ErrorMessage: "AI模型会话意识流为空.",
+				}
+
+				c.Send <- &errorMsg
+
+				return
+
+			}
+			// 读取前端发送过来的消息并打印
+			fmt.Println("客户端消息: ", sendMsg)
+
+			if sendMsg.Type == 0 {
+				/*
+				   收到前端发送过来的消息,保存至数据库
+				*/
+				senderType := "user"
+				user_status := make(map[string]interface{})
+				_, chatDB_err := datasource.SaveWorldChatRecordMongoDB(conversation_Id, c.WorldConversations.Uid, c.WorldConversations.WorldName, sendMsg.Content, user_status, senderType)
+				// 错误处理
+				if chatDB_err != nil {
+					log.Println("保存用户聊天记录至数据库出错!")
+
+					/*
+						errorMsg := ErrorMessage{
+							Code:    -1,
+							Message: "保存用户聊天记录至数据库出错!",
+						}
+						errmsg, _ := json.Marshal(errorMsg)
+						_ = c.Socket.WriteMessage(websocket.TextMessage, errmsg)
+					*/
+					errorMsg := WorldSoulReplyMsg{
+						Code:         -1,
+						ErrorMessage: "保存用户聊天记录至数据库出错!",
+					}
+
+					c.Send <- &errorMsg
+					return
+				}
+				/*
+				   调用AI模型接口回复前端用户的消息
+				*/
+				HSReplyMsg := WorldSoulReplyMsg{
+					Code:      resCode,
+					WObj:      Wobj,
+					ISLIU:     ISLIU,
+					WorldName: c.WorldName,
+					IsLIUId:   &c.WorldConversations.IsLiuId,
+				}
+
+				//判断是不是咪咕服务商
+				if c.AuthId == miGuAuthId {
+					reformatHSReplyMsg := ParseEndStrAndReformat(&HSReplyMsg)
+					/*	msg, _ := json.Marshal(reformatHSReplyMsg)
+						write_err := c.Socket.WriteMessage(websocket.TextMessage, msg)
+						if write_err != nil {
+							log.Println("返回意识流给客户端时出错! ")
+							WorldDestroyWs(c)
+							return
+						}*/
+					// 将处理后的消息发送到Write协程
+					c.Send <- reformatHSReplyMsg
+
+				} else {
+					/*
+						msg, _ := json.Marshal(HSReplyMsg)
+						write_err := c.Socket.WriteMessage(websocket.TextMessage, msg)
+						if write_err != nil {
+							log.Println("返回意识流给客户端时出错! ")
+							WorldDestroyWs(c)
+							return
+						}
+					*/
+
+					c.Send <- &HSReplyMsg
+				}
+
+				/*
+				   mongoDB保存数字人发送给前端用户的聊天记录
+				*/
+				//最后一次聊天的数字人
+				//c.LastMsg = ISLIU
+				//LastDpId := c.DpConversations.DpIds[c.LastIndex]
+				senderType2 := "world"
+				maxTimeStamp, chatDB_err2 := datasource.SaveWorldChatRecordMongoDB(conversation_Id, c.WorldConversations.WorldId, c.WorldConversations.WorldName, ISLIU, Wobj, senderType2)
+				// 错误处理
+				if chatDB_err2 != nil {
+					log.Println(config.ColorRed, "保存数字人聊天记录至数据库出错!", config.ColorReset)
+
+					/*
+						errorMsg := ErrorMessage{
+								Code:    -1,
+								Message: "保存数字人聊天记录至数据库出错!",
+							}
+							errmsg, _ := json.Marshal(errorMsg)
+							_ = c.Socket.WriteMessage(websocket.TextMessage, errmsg)
+					*/
+					errorMsg := WorldSoulReplyMsg{
+						Code:         -1,
+						ErrorMessage: "保存数字人聊天记录至数据库出错!",
+					}
+
+					c.Send <- &errorMsg
+					return
+				}
+
+				if c.AuthId == miGuAuthId {
+
+					if endStr, ok := echoResponse.WObj["EndStr"]; ok {
+						if endStr != "" {
+							fmt.Println(" endStr ====> :", endStr)
+
+							score, err := ExtractRating(*echoResponse)
+							if err != nil {
+								fmt.Println("错误提取评分: ", err)
+								return
+							}
+							fmt.Println("推演到结局,保存结局内容...")
+							// 创建 OutcomeContent 对象
+							outcome := OutcomeContent{
+								WObj:  echoResponse.WObj,
+								ISLIU: echoResponse.ISLIU,
+							}
+
+							// 将 OutcomeContent 对象转换成 JSON 字符串
+							outcomeContentBytes, err := json.Marshal(outcome)
+							if err != nil {
+								fmt.Println("无法将推演结局内容序列化:", err)
+								return
+							}
+
+							outcomeContentStr := string(outcomeContentBytes)
+
+							// 创建 WorldDeductionResult 对象
+							deductionResult := models.WorldDeductionResult{
+								WorldId:        c.WorldConversations.WorldId,
+								UserId:         c.WorldConversations.Uid,
+								WorldName:      c.WorldName,
+								OutcomeTitle:   "推演结局", // 使用 EndStr 作为结局标题
+								OutcomeContent: outcomeContentStr,
+								ChatStartTime:  maxTimeStamp,
+								ChatEndTime:    time.Now().Unix(),
+								Score:          score,
+							}
+
+							// 保存到数据库
+							_, err = models.AddWorldDeductionResult(&deductionResult)
+							if err != nil {
+								fmt.Println("保存推演结局内容到数据库失败:", err)
+								return
+							}
+
+							fmt.Println("推演结局内容已成功保存到mysql数据库,推演结果表中。")
+
+							chatRecordArray := datasource.WorldChatRecordArray{
+								ConversationId: utils.Strval(c.WorldConversations.Uid) + "_" + utils.Strval(c.WorldConversations.WorldId),
+								Timestamp:      time.Now().Unix(),
+								//存个空的聊天记录数组
+								Records: []datasource.WorldChatRecord{},
+							}
+							err = datasource.SaveWorldChatRecord(chatRecordArray)
+							if err != nil {
+								log.Println("MongoDB数据库,新插入一条数据出错,err: ", err)
+								//ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "重置世界记忆文件,插入数据失败!"})
+								return
+							}
+							fmt.Println(config.ColorBlue, "用户聊天到结局,MongoDB创建新的聊天数组", config.ColorReset)
+
+						}
+					}
+
+				}
+
+				/*
+				  发送消息成功,resCode为1
+				*/
+
+				if resCode == 1 {
+					/*		//增加数字人的交互量
+
+							err := models.IncrementDigitalPersonInteractionCount(c.DpConversations.DpIds[c.LastIndex])
+							if err != nil {
+								log.Println(config.ColorRed, "更新交互量失败:", err, config.ColorReset)
+								return
+							}
+							fmt.Println(config.ColorGreen, "交互量更新成功!", config.ColorReset)
+					*/
+					if c.AuthId != "" {
+						sp, err := models.GetServiceProviderById(c.AuthId)
+						if err != nil {
+							fmt.Println("根据服务商id查询出错:", err)
+							return
+						}
+						if sp != nil && c.UserSource == sp.Name {
+							/* 添加服务商调用AI会话,灵感消耗日志信息 */
+							museNum := int64(echoResponse.MuseValue)
+							// 构建一个InspirationUsageLog实例
+
+							/* 更新服务商的灵感值 */
+							if museNum > sp.InspirationValue {
+								// 处理错误或返回
+								fmt.Println("服务商灵感值不足本次扣除")
+								return
+							}
+							sp.InspirationValue = sp.InspirationValue - museNum
+							sp.TotalInspiration = sp.TotalInspiration + museNum
+							err := models.UpdateServiceProvider(sp)
+							if err != nil {
+								log.Println(config.ColorRed, "更新服务商灵感消耗值失败:", err, config.ColorReset)
+								return
+							} else {
+								log.Println(config.ColorBlue, "更新服务商灵感消耗值成功,剩余灵感值:", sp.InspirationValue, config.ColorReset)
+							}
+						}
+
+					}
+
+				}
+			}
+
+			/*
+			   type为1,表示用户无回应,数字人进行主动发送信息,进行主动关怀!!
+			*/
+
+			if sendMsg.Type == 1 {
+				//响应给客户端
+				HSReplyMsg := WorldSoulReplyMsg{
+					Code:      resCode,
+					WObj:      Wobj,
+					ISLIU:     ISLIU,
+					WorldName: c.WorldName,
+					IsLIUId:   &c.WorldConversations.IsLiuId,
+				}
+
+				//var msg []byte
+				//判断是不是咪咕服务商
+				if c.AuthId == miGuAuthId {
+					reformatHSReplyMsg := ParseEndStrAndReformat(&HSReplyMsg)
+					//msg, _ = json.Marshal(reformatHSReplyMsg)
+					// 将处理后的消息发送到Write协程
+					c.Send <- reformatHSReplyMsg
+				} else {
+					//msg, _ = json.Marshal(HSReplyMsg)
+					c.Send <- &HSReplyMsg
+				}
+				//解析AI接口返回的数据
+				//msg, _ := json.Marshal(HSReplyMsg)
+				//c.LastMsg = ISLIU
+
+				/*
+				   mongoDB保存数字人发送给前端用户的聊天记录
+				*/
+
+				senderType := "world"
+				maxTimeStamp, chatDB_err := datasource.SaveWorldChatRecordMongoDB(conversation_Id, c.WorldConversations.WorldId, c.WorldConversations.WorldName, ISLIU, Wobj, senderType)
+				// 错误处理
+				if chatDB_err != nil {
+					log.Println(config.ColorRed, "保存数字人聊天记录至数据库出错!", config.ColorReset)
+					/*	errorMsg := ErrorMessage{
+							Code:    -1,
+							Message: "保存数字人聊天记录至数据库出错!",
+						}
+						errmsg, _ := json.Marshal(errorMsg)
+						_ = c.Socket.WriteMessage(websocket.TextMessage, errmsg)*/
+					errorMsg := WorldSoulReplyMsg{
+						Code:         -1,
+						ErrorMessage: "保存数字人聊天记录至数据库出错!",
+					}
+
+					c.Send <- &errorMsg
+					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 != "" {
+
+						fmt.Println("推演到结局,保存结局内容...")
+						// 创建 OutcomeContent 对象
+						outcome := OutcomeContent{
+							WObj:  echoResponse.WObj,
+							ISLIU: echoResponse.ISLIU,
+						}
+
+						// 将 OutcomeContent 对象转换成 JSON 字符串
+						outcomeContentBytes, err := json.Marshal(outcome)
+						if err != nil {
+							fmt.Println("无法将推演结局内容序列化:", err)
+							return
+						}
+
+						outcomeContentStr := string(outcomeContentBytes)
+
+						// 创建 WorldDeductionResult 对象
+						deductionResult := models.WorldDeductionResult{
+							WorldId:        c.WorldConversations.WorldId,
+							UserId:         c.WorldConversations.Uid,
+							WorldName:      c.WorldName,
+							OutcomeTitle:   "推演结局", // 使用 EndStr 作为结局标题
+							OutcomeContent: outcomeContentStr,
+							ChatStartTime:  maxTimeStamp,
+							ChatEndTime:    time.Now().Unix(),
+						}
+
+						// 保存到数据库
+						_, err = models.AddWorldDeductionResult(&deductionResult)
+						if err != nil {
+							fmt.Println("保存推演结局内容到数据库失败:", err)
+							return
+						}
+
+						fmt.Println("推演结局内容已成功保存到mysql数据库,推演结果表中。")
+
+						chatRecordArray := datasource.WorldChatRecordArray{
+							ConversationId: utils.Strval(c.WorldConversations.Uid) + "_" + utils.Strval(c.WorldConversations.WorldId),
+							Timestamp:      time.Now().Unix(),
+							//存个空的聊天记录数组
+							Records: []datasource.WorldChatRecord{},
+						}
+						err = datasource.SaveWorldChatRecord(chatRecordArray)
+						if err != nil {
+							log.Println("MongoDB数据库,新插入一条数据出错,err: ", err)
+							//ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "重置世界记忆文件,插入数据失败!"})
+							return
+						}
+						fmt.Println(config.ColorBlue, "用户聊天到结局,MongoDB创建新的聊天数组", config.ColorReset)
+
+					}
+				}
+
+				/*
+				  发送消息成功,resCode为1
+				*/
+				if resCode == 1 {
+					/*//增加数字人的交互量
+					err := models.IncrementDigitalPersonInteractionCount(c.DpConversations.DpIds[c.LastIndex])
+					if err != nil {
+						log.Println(config.ColorRed, "更新交互量失败:", err, config.ColorReset)
+					}
+					fmt.Println(config.ColorGreen, "交互量更新成功!", config.ColorReset)*/
+					if c.AuthId != "" {
+						sp, err := models.GetServiceProviderById(c.AuthId)
+						if err != nil {
+							fmt.Println("根据服务商id查询出错:", err)
+							return
+						}
+						if sp != nil && c.UserSource == sp.Name {
+							/* 添加服务商调用AI会话,灵感消耗日志信息 */
+							museNum := int64(echoResponse.MuseValue)
+
+							/* 更新服务商的灵感值 */
+							if museNum > sp.InspirationValue {
+								// 处理错误或返回
+								fmt.Println("服务商灵感值不足本次扣除")
+								return
+							}
+							sp.InspirationValue = sp.InspirationValue - museNum
+							sp.TotalInspiration = sp.TotalInspiration + museNum
+							err := models.UpdateServiceProvider(sp)
+							if err != nil {
+								log.Println(config.ColorRed, "更新服务商灵感消耗值失败:", err, config.ColorReset)
+								return
+							} else {
+								log.Println(config.ColorBlue, "更新服务商灵感消耗值成功,剩余灵感值:", sp.InspirationValue, config.ColorReset)
+							}
+						}
+
+					}
+				}
+			}
+		}()
+
+	}
+
+}
+
+// ExtractRating 从响应中提取整体评分
+
+func ExtractRating(response WorldEchoResponse) (int, error) {
+	endStr, ok := response.WObj["EndStr"].(string)
+	if !ok || endStr == "" {
+		return 0, nil
+	}
+
+	lines := strings.Split(endStr, "\n")
+	for _, line := range lines {
+		if strings.Contains(line, "【整体评分】") {
+			scoreStr := strings.TrimSpace(strings.Split(line, ":")[1])
+			score, err := strconv.Atoi(scoreStr)
+			if err != nil {
+				return 0, fmt.Errorf("评分转换错误: %v", err)
+			}
+			return score, nil
+		}
+	}
+
+	return 0, fmt.Errorf("未找到评分信息")
+}
+
+func ExtractRating1(response WorldEchoResponse) string {
+
+	endStr, ok := response.WObj["EndStr"].(string)
+	if !ok {
+		return "评分信息不可用"
+	}
+
+	lines := strings.Split(endStr, "\n")
+	for _, line := range lines {
+		if strings.Contains(line, "【整体评分】") {
+			// 假设评分总是单个数字跟在冒号和换行符后面
+			return strings.TrimSpace(strings.Split(line, ":")[1])
+		}
+	}
+
+	return "评分信息不可用"
+}
+
+/* ============================================================================================= */
+
+// ParseEndStrAndReformat 重新解析 WorldSoulReplyMsg 中的 WObj 并返回一个新的结构体
+func ParseEndStrAndReformat(response *WorldSoulReplyMsg) *WorldSoulReplyMsg {
+	if response == nil || response.WObj == nil {
+		return nil // 如果输入是nil,直接返回nil
+	}
+
+	//newResponse := *response // 创建一个新的响应体对象副本
+
+	newResponse := *DeepCopy(response)
+	if len(newResponse.WObj) == 0 && strings.Contains(newResponse.ISLIU, "【任务提示】") {
+		newResponse.MessageStatusType = "prologue"
+	} else if endStr, ok := newResponse.WObj["EndStr"].(string); ok && endStr != "" {
+		newResponse.MessageStatusType = "end"
+	} else {
+		newResponse.MessageStatusType = "chatting"
+	}
+
+	endStr, ok := newResponse.WObj["EndStr"].(string)
+	if ok {
+		if endStr != "" {
+			// 解析 "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),
+			}
+
+			newResponse.WObj["EndStr"] = endStrObj // 将格式化后的结论字符串对象重新赋值给响应
+		} else {
+			newResponse.WObj["EndStr"] = nil
+		}
+
+	}
+
+	// 无论 "EndStr" 是否存在,均检查和处理 '地点' 和 '表情'
+	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, "表情")
+	}
+	if chatTime, exists := newResponse.WObj["时间"]; exists {
+		newResponse.WObj["time"] = chatTime
+		delete(newResponse.WObj, "时间")
+	}
+	return &newResponse // 返回修改后的新响应体
+}
+
+// extractBetween 查找并提取开始和结束分隔符之间的子字符串
+func extractBetween(s, start, end string) string {
+	startIdx := strings.Index(s, start)
+	if startIdx == -1 {
+		return ""
+	}
+	startPos := startIdx + len(start)
+	endIdx := strings.Index(s[startPos:], end)
+	if endIdx == -1 {
+		return s[startPos:]
+	}
+	return s[startPos : startPos+endIdx]
+}
+
+// extractToEnd 查找并提取从指定开始分隔符到字符串末尾的内容
+func extractToEnd(s, start string) string {
+	startIdx := strings.Index(s, start)
+	if startIdx == -1 {
+		return ""
+	}
+	return s[startIdx+len(start):]
+}
+
+//深拷贝对象
+func DeepCopy(msg *WorldSoulReplyMsg) *WorldSoulReplyMsg {
+	// 创建一个新的 WorldSoulReplyMsg 实例
+	newMsg := &WorldSoulReplyMsg{
+		Code:      msg.Code,
+		ISLIU:     msg.ISLIU,
+		WorldName: msg.WorldName,
+	}
+
+	// 深拷贝 WObj map
+	if msg.WObj != nil {
+		newMsg.WObj = make(map[string]interface{})
+		for k, v := range msg.WObj {
+			newMsg.WObj[k] = v // 注意这里只是简单拷贝,对于更复杂的对象可能需要更深层次的拷贝
+		}
+	}
+
+	// 复制可选指针类型字段 IsLIUId
+	if msg.IsLIUId != nil {
+		newIsLIUId := *msg.IsLIUId // 创建 IsLIUId 的副本
+		newMsg.IsLIUId = &newIsLIUId
+	}
+
+	// 复制其他可选字段
+	if msg.MessageStatusType != "" {
+		newMsg.MessageStatusType = msg.MessageStatusType
+	}
+
+	return newMsg
+}
+
+/*
+ 实现WorldWrite方法
+  WorldWrite方法需要修改以适应从通道中读取*WorldEchoRespones类型的数据并将其发送到WebSocket
+*/
+func (c *WorldClient) WorldWrite() {
+	defer func() {
+		_ = c.Socket.Close()
+	}()
+	for {
+		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:
+			if !ok {
+				_ = c.Socket.WriteMessage(websocket.CloseMessage, []byte{})
+				return
+			}
+			/*
+				resCode := message.Code
+				status := message.Status
+				ISLIU := message.ISLIU
+			*/
+
+			log.Println(c.WorldConversations.Uid, "接受消息:", message)
+			replyMsg := WorldReplyMsg{
+				Code:    e.WebsocketSuccess,
+				Content: fmt.Sprintf("%s", message),
+			}
+			msg, _ := json.Marshal(replyMsg)
+			_ = c.Socket.WriteMessage(websocket.TextMessage, msg)
+		}
+	}
+}
--
libgit2 0.26.0