feat: 新增模型扩展映射与查询配置字段

This commit is contained in:
2026-05-23 18:08:09 +08:00
parent 855d5b9abe
commit 2548ffc7ac
11 changed files with 290 additions and 206 deletions

View File

@@ -3,10 +3,14 @@ package util
import (
"encoding/json"
"fmt"
"strconv"
"github.com/gogf/gf/v2/container/gvar"
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/util/gconv"
tGjson "github.com/tidwall/gjson"
"github.com/tidwall/sjson"
)
// ParseOutput 解析模型输出为 JSON 格式
@@ -57,14 +61,15 @@ func UserFormToJSON(form []map[string]any) string {
return string(b)
}
// MustMarshal 将对象序列化为 JSON 字符串,失败时返回空对象
func MustMarshal(v any) string {
// MustMarshalToMap 将对象序列化为 map[string]any,失败时返回空 map
func MustMarshalToMap(v any) map[string]any {
b, err := json.Marshal(v)
if err != nil {
return "{}"
return make(map[string]any)
}
return string(b)
var m map[string]any
json.Unmarshal(b, &m)
return m
}
// JSONPretty 将任意类型转为格式化的 JSON 字符串
@@ -82,42 +87,6 @@ func JSONPretty(v any) string {
return string(b)
}
// GvarToMap 将 *gvar.Var 类型转换为 map[string]any
func GvarToMap(v *gvar.Var) map[string]any {
if v == nil || v.IsNil() {
return nil
}
result := make(map[string]any)
// 方法1尝试获取 map 值
if m := v.Map(); len(m) > 0 {
return m
}
// 方法2尝试解析 JSON 字符串
str := v.String()
if str != "" && str != "<nil>" {
json.Unmarshal([]byte(str), &result)
if len(result) > 0 {
return result
}
}
// 方法3尝试获取 interface 再转换
if val := v.Val(); val != nil {
switch val.(type) {
case map[string]any:
return val.(map[string]any)
default:
data, _ := json.Marshal(val)
json.Unmarshal(data, &result)
}
}
return result
}
// ParseJSONFieldFromGvar 专门处理 *gvar.Var 类型的 JSON 字段解析
func ParseJSONFieldFromGvar(source any, target any) {
if source == nil {
@@ -149,3 +118,112 @@ func ParseJSONFieldFromGvar(source any, target any) {
json.Unmarshal(data, target)
}
}
// MergeConsult 将 consult 附件合并到模型生成的 messages 结构中。
//
// 参数说明:
// - req: 请求参数 map需包含 "consult" 字段,值为 []any每个元素是 {"type":"xxx","url":"..."}
// - messages: 模型生成的返回结构(如 rounds[...].messages[...].content 数组)
// - extendMapping: 附加映射配置,格式:
// {"attachments": {"image": {"template": {...}, "target_path": "...", "field_mapping": {...}}, ...}}
//
// 返回值:合并后的完整 map。
func MergeConsult(req map[string]any, messages map[string]any, extendMapping map[string]any) map[string]any {
if len(req) == 0 || len(messages) == 0 || len(extendMapping) == 0 {
return messages
}
reqJSON, _ := json.Marshal(req)
msgJSON, _ := json.Marshal(messages)
extJSON, _ := json.Marshal(extendMapping)
reqStr := string(reqJSON)
msgStr := string(msgJSON)
extStr := string(extJSON)
// 获取 consult 数组
consultResult := tGjson.Get(reqStr, "consult")
if !consultResult.Exists() || !consultResult.IsArray() {
return messages
}
// 获取 attachments 配置
attachmentsResult := tGjson.Get(extStr, "attachments")
if !attachmentsResult.Exists() || !attachmentsResult.IsObject() {
return messages
}
consultArr := consultResult.Array()
attachmentsMap := attachmentsResult.Map()
for _, consultItem := range consultArr {
if !consultItem.IsObject() {
continue
}
itemType := consultItem.Get("type").String()
if itemType == "" {
continue
}
// 查找对应类型的附件配置
attachResult, ok := attachmentsMap[itemType]
if !ok || !attachResult.IsObject() {
continue
}
// 获取模板
templateResult := attachResult.Get("template")
if !templateResult.Exists() || !templateResult.IsObject() {
continue
}
// 深拷贝模板
filledTemplateStr := templateResult.Raw
// 应用字段映射
fieldMappingResult := attachResult.Get("field_mapping")
if fieldMappingResult.Exists() && fieldMappingResult.IsObject() {
fieldMapping := fieldMappingResult.Map()
for fieldPath, valueSource := range fieldMapping {
sourceKey := valueSource.String()
valueResult := consultItem.Get(sourceKey)
if valueResult.Exists() {
var err error
filledTemplateStr, err = sjson.SetRaw(filledTemplateStr, fieldPath, valueResult.Raw)
if err != nil {
continue
}
}
}
}
// 获取目标路径
targetPath := attachResult.Get("target_path").String()
if targetPath == "" {
continue
}
// 检查目标路径是否存在且为数组
targetResult := tGjson.Get(msgStr, targetPath)
if !targetResult.Exists() || !targetResult.IsArray() {
continue
}
// 追加到数组末尾
arrLen := len(targetResult.Array())
appendPath := targetPath + "." + strconv.Itoa(arrLen)
var err error
msgStr, err = sjson.SetRaw(msgStr, appendPath, filledTemplateStr)
if err != nil {
continue
}
}
// 转回 map[string]any
var result map[string]any
if err := json.Unmarshal([]byte(msgStr), &result); err != nil {
return messages
}
return result
}