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 格式 func ParseOutput(text string) (map[string]any, error) { j, err := gjson.LoadJson([]byte(text)) if err != nil { return nil, fmt.Errorf("解析模型输出失败: %w", err) } return j.Map(), nil } // ConvertToMessages 将原始数据转换为消息列表 func ConvertToMessages(raw any) []map[string]any { if raw == nil { return nil } j, err := gjson.LoadJson(gconv.Bytes(raw)) if err != nil { return nil } if j.Contains("messages") { return gconv.Maps(j.Get("messages").Array()) } return []map[string]any{j.Map()} } // FormToJSON 将表单数据转换为 JSON 字符串 func FormToJSON(form map[string]any) string { if form == nil { return "{}" } b, _ := json.Marshal(form) return string(b) } // UserFormToJSON 将用户表单数据转换为 JSON 字符串 func UserFormToJSON(form []map[string]any) string { if form == nil { return "{}" } b, _ := json.Marshal(form) return string(b) } // MustMarshalToMap 将对象序列化为 map[string]any,失败时返回空 map func MustMarshalToMap(v any) map[string]any { b, err := json.Marshal(v) if err != nil { return make(map[string]any) } var m map[string]any json.Unmarshal(b, &m) return m } // JSONPretty 将任意类型转为格式化的 JSON 字符串 func JSONPretty(v any) string { if gv, ok := v.(*gvar.Var); ok { v = gconv.Map(gv.String()) } var tmp map[string]any if err := gconv.Struct(v, &tmp); err != nil { return gconv.String(v) } b, _ := json.MarshalIndent(tmp, "", " ") return string(b) } // ParseJSONFieldFromGvar 专门处理 *gvar.Var 类型的 JSON 字段解析 func ParseJSONFieldFromGvar(source any, target any) { if source == nil { return } switch v := source.(type) { case *gvar.Var: if v.IsNil() { return } // 尝试获取 map if m := v.Map(); len(m) > 0 { data, _ := json.Marshal(m) json.Unmarshal(data, target) return } // 尝试解析 JSON 字符串 str := v.String() if str != "" && str != "" { json.Unmarshal([]byte(str), target) } default: // 其他类型走原来的逻辑 data, _ := json.Marshal(source) 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 }