package util import ( "bytes" "context" "encoding/json" "fmt" "io" "model-gateway/model/entity" "net/http" "net/url" "regexp" "strings" "time" "github.com/gogf/gf/v2/encoding/gjson" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/util/gconv" tgjson "github.com/tidwall/gjson" ) // ======================== 响应解析 ======================== // ParseAndValidate 解析模型响应,校验必填字段,返回标准 rounds 格式 func ParseAndValidate(raw map[string]any, requiredFields []string) (map[string]any, error) { contentStr := gconv.String(raw[entity.ResponseBody]) if strings.TrimSpace(contentStr) == "" { return raw, fmt.Errorf("字段 %s 为空", entity.ResponseBody) } contentStr = cleanControlChars(contentStr) var arr []any if err := json.Unmarshal([]byte(contentStr), &arr); err != nil { return raw, fmt.Errorf("JSON解析失败: %w", err) } if len(arr) == 0 { return raw, fmt.Errorf("解析后数组为空") } for _, field := range requiredFields { for i, r := range arr { round, _ := r.(map[string]any) if round != nil && gjson.New(round).Get(field).IsNil() { return raw, fmt.Errorf("rounds[%d] 缺少必填字段: %s", i, field) } } } return map[string]any{"total_rounds": len(arr), "rounds": arr}, nil } // ParseStructResult 解析结构结果 func ParseStructResult(raw map[string]any, responseBody string) map[string]any { contentStr := gconv.String(raw[responseBody]) if contentStr == "" || contentStr == "0" { return map[string]any{ "total_rounds": 1, "rounds": []map[string]any{{responseBody: raw}}, } } if arr := tryParseArray(contentStr); arr != nil { return map[string]any{ "total_rounds": 1, "rounds": []map[string]any{{responseBody: arr}}, } } if parsed := tryParseAny(contentStr); parsed != nil { return map[string]any{ "total_rounds": 1, "rounds": []map[string]any{{responseBody: parsed}}, } } return map[string]any{ "total_rounds": 1, "rounds": []map[string]any{{responseBody: contentStr}}, } } // ParseHeadMsgHeaders 从 head_msg JSON 中提取请求头 // head_msg 格式示例: // // { // "Authorization": "Bearer xxx", // "Content-Type": "application/json", // "X-Api-App-Id": "5147401364", // "X-Api-Access-Key": "VCqRX7..." // } func ParseHeadMsgHeaders(headMsg map[string]any) map[string]string { if len(headMsg) == 0 { return nil } out := make(map[string]string, len(headMsg)) for k, v := range headMsg { out[k] = gconv.String(v) } return out } // MapResponsePayload 映射模型响应为标准格式 func MapResponsePayload(mapping map[string]any, result map[string]any) (map[string]any, error) { if len(mapping) == 0 { return result, nil } // 把 result 转成 JSON 字符串,tidwall/gjson 需要字符串输入 resultBytes, _ := json.Marshal(result) resultStr := string(resultBytes) mapped := make(map[string]any) for standardField, modelPath := range mapping { path := gconv.String(modelPath) if path == "" { continue } value := tgjson.Get(resultStr, path) if !value.Exists() { continue } if strings.Contains(path, "#") { var arr []any for _, v := range value.Array() { arr = append(arr, v.Value()) } mapped[standardField] = arr } else { mapped[standardField] = value.Value() } } return mapped, nil } // ======================== 内部辅助 ======================== func cleanControlChars(s string) string { return strings.Map(func(r rune) rune { if r < 32 && r != ' ' { return -1 } return r }, s) } func tryParseArray(s string) []any { var arr []any if err := json.Unmarshal([]byte(s), &arr); err == nil && len(arr) > 0 { return arr } return nil } func tryParseAny(s string) any { var parsed any if err := json.Unmarshal([]byte(s), &parsed); err == nil { return parsed } return nil }