Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
WorldEpcho
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Ford
WorldEpcho
Commits
d3c206b4
Commit
d3c206b4
authored
Oct 29, 2024
by
Ford
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
添加了用户画像的创建和查询相关世界的用户画像
parent
fb5e23a9
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
1365 additions
and
34 deletions
+1365
-34
config.json
+1
-1
src/controllers/NpcController.go
+30
-25
src/main.go
+4
-5
src/models/NPCRole.go
+22
-1
src/service/WorldChat_HighConcurrency.go
+30
-2
src/service/WorldChat_HighConcurrency.go_bak
+1278
-0
No files found.
config.json
View file @
d3c206b4
...
@@ -211,7 +211,7 @@
...
@@ -211,7 +211,7 @@
},
},
"npc_role_detail_translations"
:
{
"npc_role_detail_translations"
:
{
"roleName"
:
"角色名
称
"
,
"roleName"
:
"角色名"
,
"introduction"
:
"简介"
,
"introduction"
:
"简介"
,
"consumptionExpectations"
:
"消费心理预期"
,
"consumptionExpectations"
:
"消费心理预期"
,
"psychologicalTraits"
:
"心理特征"
,
"psychologicalTraits"
:
"心理特征"
,
...
...
src/controllers/NpcController.go
View file @
d3c206b4
package
controllers
package
controllers
import
(
import
(
"WorldEpcho/src/config"
"WorldEpcho/src/config/e"
"WorldEpcho/src/config/e"
database
"WorldEpcho/src/datasource"
database
"WorldEpcho/src/datasource"
"WorldEpcho/src/models"
"WorldEpcho/src/models"
"WorldEpcho/src/service"
"WorldEpcho/src/service"
"WorldEpcho/src/utils"
"encoding/json"
"encoding/json"
"fmt"
"fmt"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin"
...
@@ -34,7 +36,7 @@ import (
...
@@ -34,7 +36,7 @@ import (
//创建角色画像的请求体
//创建角色画像的请求体
type
NpcRoleRequest
struct
{
type
NpcRoleRequest
struct
{
Name
string
`json:"name"`
// 名称
Name
string
`json:"name"`
// 名称
Details
Details
`json:"details"`
//详情
Details
models
.
Details
`json:"details"`
//详情
Gender
string
`json:"gender"`
//性别
Gender
string
`json:"gender"`
//性别
Tags
string
`json:"tags"`
//世界标签集
Tags
string
`json:"tags"`
//世界标签集
RelatedWorlds
string
`json:"relatedWorlds"`
//相关世界
RelatedWorlds
string
`json:"relatedWorlds"`
//相关世界
...
@@ -44,27 +46,6 @@ type NpcRoleRequest struct {
...
@@ -44,27 +46,6 @@ type NpcRoleRequest struct {
}
}
// 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用户画像的接口
//创建Npc用户画像的接口
func
CreateNpcUserPortrait
(
ctx
*
gin
.
Context
)
{
func
CreateNpcUserPortrait
(
ctx
*
gin
.
Context
)
{
...
@@ -138,7 +119,6 @@ func CreateNpcUserPortrait(ctx *gin.Context) {
...
@@ -138,7 +119,6 @@ func CreateNpcUserPortrait(ctx *gin.Context) {
/* configData 英文键转换为中文 */
/* configData 英文键转换为中文 */
/*
var
data
map
[
string
]
interface
{}
var
data
map
[
string
]
interface
{}
if
err
:=
json
.
Unmarshal
([]
byte
(
string
(
detailsJSON
)),
&
data
);
err
!=
nil
{
if
err
:=
json
.
Unmarshal
([]
byte
(
string
(
detailsJSON
)),
&
data
);
err
!=
nil
{
ctx
.
JSON
(
http
.
StatusOK
,
gin
.
H
{
"code"
:
e
.
ParamParseError
,
"data"
:
nil
,
"message"
:
"解析用户画像详细信息数据出错"
})
ctx
.
JSON
(
http
.
StatusOK
,
gin
.
H
{
"code"
:
e
.
ParamParseError
,
"data"
:
nil
,
"message"
:
"解析用户画像详细信息数据出错"
})
...
@@ -155,7 +135,6 @@ func CreateNpcUserPortrait(ctx *gin.Context) {
...
@@ -155,7 +135,6 @@ func CreateNpcUserPortrait(ctx *gin.Context) {
return
return
}
}
fmt
.
Println
(
" Details translatedJSON ==> "
,
string
(
translatedJSON
))
fmt
.
Println
(
" Details translatedJSON ==> "
,
string
(
translatedJSON
))
*/
// 创建一个空切片存储相关世界
// 创建一个空切片存储相关世界
relatedWorldIds
:=
[]
int64
{}
relatedWorldIds
:=
[]
int64
{}
...
@@ -178,16 +157,18 @@ func CreateNpcUserPortrait(ctx *gin.Context) {
...
@@ -178,16 +157,18 @@ func CreateNpcUserPortrait(ctx *gin.Context) {
}
}
//用户画像详情信息
//用户画像详情信息
/*
// 将Details结构体转换为 JSON
// 将Details结构体转换为 JSON
jsonData, err := json.Marshal(NpcRequest.Details)
jsonData, err := json.Marshal(NpcRequest.Details)
if err != nil {
if err != nil {
fmt.Println("Error:", err)
fmt.Println("Error:", err)
return
return
}
}
*/
npcUserRole
:=
&
models
.
NpcRole
{
npcUserRole
:=
&
models
.
NpcRole
{
Name
:
NpcRequest
.
Name
,
Name
:
NpcRequest
.
Name
,
Details
:
string
(
jsonData
),
Details
:
string
(
translatedJSON
),
Gender
:
NpcRequest
.
Gender
,
Gender
:
NpcRequest
.
Gender
,
Tags
:
matchingTags
,
Tags
:
matchingTags
,
RelatedWorlds
:
relatedWorldIds
,
RelatedWorlds
:
relatedWorldIds
,
...
@@ -296,6 +277,30 @@ func QueryNpcRoleInfo(ctx *gin.Context) {
...
@@ -296,6 +277,30 @@ func QueryNpcRoleInfo(ctx *gin.Context) {
fmt
.
Println
(
"根据相关世界ID查询用户画像信息出错"
)
fmt
.
Println
(
"根据相关世界ID查询用户画像信息出错"
)
return
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
()
err
=
session
.
Commit
()
if
err
!=
nil
{
if
err
!=
nil
{
...
...
src/main.go
View file @
d3c206b4
...
@@ -4,7 +4,6 @@ import (
...
@@ -4,7 +4,6 @@ import (
"WorldEpcho/src/config"
"WorldEpcho/src/config"
"WorldEpcho/src/datasource"
"WorldEpcho/src/datasource"
"WorldEpcho/src/https_auth"
"WorldEpcho/src/https_auth"
"WorldEpcho/src/models"
"WorldEpcho/src/routers"
"WorldEpcho/src/routers"
"WorldEpcho/src/service"
"WorldEpcho/src/service"
"WorldEpcho/src/utils"
"WorldEpcho/src/utils"
...
@@ -25,10 +24,10 @@ func main() {
...
@@ -25,10 +24,10 @@ func main() {
config
.
RandInit
()
config
.
RandInit
()
datasource
.
InitMysql
()
datasource
.
InitMysql
()
// 同步结构体与数据库表
// 同步结构体与数据库表
err
:=
datasource
.
Engine
.
Sync2
(
new
(
models
.
NpcRole
))
//
err := datasource.Engine.Sync2(new(models.NpcRole))
if
err
!=
nil
{
//
if err != nil {
fmt
.
Printf
(
"创建表失败:"
,
err
)
//
fmt.Printf("创建表失败:", err)
}
//
}
//生成一个9位的邀请码
//生成一个9位的邀请码
//println("生成一个9位的邀请码: ", utils.GenerateInviteCode(1))
//println("生成一个9位的邀请码: ", utils.GenerateInviteCode(1))
...
...
src/models/NPCRole.go
View file @
d3c206b4
...
@@ -20,6 +20,27 @@ type NpcRole struct {
...
@@ -20,6 +20,27 @@ type NpcRole struct {
ServiceProviderId
string
`xorm:"-" json:"authId,omitempty"`
// ServiceProviderId 在数据库中忽略
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 角色
// 增加一个新的 NPC 角色
func
CreateNpcRole
(
session
*
xorm
.
Session
,
npcRole
*
NpcRole
)
(
*
NpcRole
,
error
)
{
func
CreateNpcRole
(
session
*
xorm
.
Session
,
npcRole
*
NpcRole
)
(
*
NpcRole
,
error
)
{
_
,
err
:=
session
.
Insert
(
npcRole
)
_
,
err
:=
session
.
Insert
(
npcRole
)
...
@@ -62,7 +83,7 @@ func UpdateNpcRole(npcRole *NpcRole) error {
...
@@ -62,7 +83,7 @@ func UpdateNpcRole(npcRole *NpcRole) error {
}
}
// 根据 ID 查询单个 NPC 角色
// 根据 ID 查询单个 NPC 角色
func
GetNpcRoleByID
(
id
int
)
(
*
NpcRole
,
error
)
{
func
GetNpcRoleByID
(
id
int
64
)
(
*
NpcRole
,
error
)
{
npcRole
:=
new
(
NpcRole
)
npcRole
:=
new
(
NpcRole
)
has
,
err
:=
datasource
.
Engine
.
ID
(
id
)
.
Get
(
npcRole
)
has
,
err
:=
datasource
.
Engine
.
ID
(
id
)
.
Get
(
npcRole
)
if
err
!=
nil
{
if
err
!=
nil
{
...
...
src/service/WorldChat_HighConcurrency.go
View file @
d3c206b4
...
@@ -127,6 +127,7 @@ type WorldErrorMessage struct {
...
@@ -127,6 +127,7 @@ type WorldErrorMessage struct {
// Wrapper 结构体仅包含一个字符串字段,用于存储 JSON 字符串
// Wrapper 结构体仅包含一个字符串字段,用于存储 JSON 字符串
type
Wrapper
struct
{
type
Wrapper
struct
{
ConfigData
map
[
string
]
interface
{}
`json:"ConfigData"`
ConfigData
map
[
string
]
interface
{}
`json:"ConfigData"`
EmbeddingNpcs
[]
map
[
string
]
interface
{}
`json:"EmbeddingNpcs" `
}
}
//世界websocket控制器
//世界websocket控制器
...
@@ -245,6 +246,7 @@ func WorldWsHandler(ctx *gin.Context) {
...
@@ -245,6 +246,7 @@ func WorldWsHandler(ctx *gin.Context) {
world_Id
:=
ctx
.
Query
(
"worldId"
)
world_Id
:=
ctx
.
Query
(
"worldId"
)
var
world
*
models
.
WorldInfo
var
world
*
models
.
WorldInfo
var
userInfo
string
var
userInfo
string
var
roleInfo
*
models
.
NpcRole
if
worldName
!=
""
{
if
worldName
!=
""
{
world
,
err
=
models
.
GetWorldInfoByName
(
worldName
)
world
,
err
=
models
.
GetWorldInfoByName
(
worldName
)
...
@@ -279,6 +281,20 @@ func WorldWsHandler(ctx *gin.Context) {
...
@@ -279,6 +281,20 @@ func WorldWsHandler(ctx *gin.Context) {
ctx
.
JSON
(
http
.
StatusOK
,
gin
.
H
{
"code"
:
e
.
NotFound
,
"data"
:
nil
,
"message"
:
"世界名称不存在"
})
ctx
.
JSON
(
http
.
StatusOK
,
gin
.
H
{
"code"
:
e
.
NotFound
,
"data"
:
nil
,
"message"
:
"世界名称不存在"
})
return
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
{
if
b
||
SP
!=
nil
{
fmt
.
Println
(
"ServiceProvider ===> "
,
SP
)
fmt
.
Println
(
"ServiceProvider ===> "
,
SP
)
...
@@ -287,6 +303,7 @@ func WorldWsHandler(ctx *gin.Context) {
...
@@ -287,6 +303,7 @@ func WorldWsHandler(ctx *gin.Context) {
if
user_info
!=
""
{
if
user_info
!=
""
{
userInfo
=
user_info
userInfo
=
user_info
}
}
//拼接会话主题
//拼接会话主题
//ConversationTitle = "用户Id为" + user_Id + "的用户和数字人" + strings.Join(DpNames, "和") + "开始会话"
//ConversationTitle = "用户Id为" + user_Id + "的用户和数字人" + strings.Join(DpNames, "和") + "开始会话"
//fmt.Println("ConversationTitle: ", ConversationTitle)
//fmt.Println("ConversationTitle: ", ConversationTitle)
...
@@ -295,10 +312,22 @@ func WorldWsHandler(ctx *gin.Context) {
...
@@ -295,10 +312,22 @@ func WorldWsHandler(ctx *gin.Context) {
BgInfo
=
world
.
Background
BgInfo
=
world
.
Background
}
}
if
user_info
==
""
{
if
user_info
==
""
{
// 创建 Wrapper 实例并将 JSON 字符串封装
//var details models.Details
//若用户画像存在
// 创建 Wrapper 实例并将 JSON 字符串封装
wrapper
:=
Wrapper
{
ConfigData
:
make
(
map
[
string
]
interface
{})}
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{}
// 将 JSON 字符串解析为 map[string]interface{}
//err := json.Unmarshal([]byte(world.ConfigData), &wrapper.ConfigData)
err
:=
json
.
Unmarshal
([]
byte
(
world
.
ConfigData
),
&
wrapper
.
ConfigData
)
err
:=
json
.
Unmarshal
([]
byte
(
world
.
ConfigData
),
&
wrapper
.
ConfigData
)
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Printf
(
"Error parsing JSON: %v"
,
err
)
log
.
Printf
(
"Error parsing JSON: %v"
,
err
)
...
@@ -307,7 +336,6 @@ func WorldWsHandler(ctx *gin.Context) {
...
@@ -307,7 +336,6 @@ func WorldWsHandler(ctx *gin.Context) {
// 打印解析后的数据
// 打印解析后的数据
//fmt.Printf("Wrapper ConfigData: %+v\n", wrapper.ConfigData)
//fmt.Printf("Wrapper ConfigData: %+v\n", wrapper.ConfigData)
// 序列化 Wrapper 实例以生成所需的最终 JSON 输出
// 序列化 Wrapper 实例以生成所需的最终 JSON 输出
finalJSON
,
err
:=
json
.
Marshal
(
wrapper
)
finalJSON
,
err
:=
json
.
Marshal
(
wrapper
)
if
err
!=
nil
{
if
err
!=
nil
{
...
...
src/service/WorldChat_HighConcurrency.go_bak
0 → 100644
View file @
d3c206b4
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
)
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment