Files
model-gateway/common/util/mapping.go
T
WangLiZhao cc23697201 Merge branch 'dev未优化' into dev优化中
# Conflicts:
#	common/util/mapping.go
#	config.yml
#	model/entity/model_gateway_model.go
#	model/entity/model_gateway_task.go
#	service/gateway/gateway_http_service.go
#	service/task/task_service.go
#	service/task/worker.go
2026-07-03 09:52:41 +08:00

165 lines
3.8 KiB
Go

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
}