152 lines
3.9 KiB
Go
152 lines
3.9 KiB
Go
|
|
package util
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"fmt"
|
|||
|
|
"model-gateway/model/entity"
|
|||
|
|
"net/url"
|
|||
|
|
"strings"
|
|||
|
|
|
|||
|
|
"github.com/gogf/gf/v2/encoding/gjson"
|
|||
|
|
"github.com/gogf/gf/v2/frame/g"
|
|||
|
|
"github.com/gogf/gf/v2/util/gconv"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// ValidatePromptResult 校验模型返回结果的 JSON 结构完整性
|
|||
|
|
// 校验逻辑:只校验 requestMapping 中默认值为空的必填字段
|
|||
|
|
func ValidatePromptResult(raw map[string]any, model *entity.AsynchModel) error {
|
|||
|
|
// 1) 获取校验配置,并取值
|
|||
|
|
requestMapping := model.RequestMapping
|
|||
|
|
contentKey := ""
|
|||
|
|
for k := range model.ResponseBody {
|
|||
|
|
contentKey = k
|
|||
|
|
break
|
|||
|
|
}
|
|||
|
|
contentStr, ok := raw[contentKey].(string)
|
|||
|
|
if !ok || contentStr == "" {
|
|||
|
|
return fmt.Errorf("%s 字段为空或不是字符串", contentKey)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 2) 解析 content 为 JSON 数组
|
|||
|
|
var rounds []map[string]any
|
|||
|
|
if err := gjson.DecodeTo(contentStr, &rounds); err != nil {
|
|||
|
|
return fmt.Errorf("解析 content JSON 数组失败: %w", err)
|
|||
|
|
}
|
|||
|
|
if len(rounds) == 0 {
|
|||
|
|
return fmt.Errorf("content 数组为空")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 3) 逐条校验:只检查默认值为空的必填字段是否存在
|
|||
|
|
for i, round := range rounds {
|
|||
|
|
for path, defaultValue := range requestMapping {
|
|||
|
|
if !g.IsEmpty(defaultValue) {
|
|||
|
|
continue
|
|||
|
|
}
|
|||
|
|
if gjson.New(round).Get(path).IsNil() {
|
|||
|
|
return fmt.Errorf("rounds[%d] 缺少必填字段: %s", i, path)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ReverseMap 映射 payload 到 mapping
|
|||
|
|
func ReverseMap(mapping map[string]any, payload map[string]any) map[string]any {
|
|||
|
|
jsonObj := gjson.New("{}")
|
|||
|
|
for path, defaultValue := range mapping {
|
|||
|
|
// 从 payload 取对应路径的值
|
|||
|
|
val := gjson.New(payload).Get(path)
|
|||
|
|
if !val.IsNil() {
|
|||
|
|
// payload 有值,用它
|
|||
|
|
_ = jsonObj.Set(path, val.Val())
|
|||
|
|
} else if !g.IsEmpty(defaultValue) {
|
|||
|
|
// payload 没值,用默认值
|
|||
|
|
_ = jsonObj.Set(path, defaultValue)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return jsonObj.Map()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// MapResponsePayload 映射模型响应为标准格式
|
|||
|
|
func MapResponsePayload(mapping map[string]any, responseBytes []byte) ([]byte, error) {
|
|||
|
|
if len(mapping) == 0 {
|
|||
|
|
return responseBytes, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
responseJson := gjson.New(responseBytes)
|
|||
|
|
resultJson := gjson.New("{}")
|
|||
|
|
|
|||
|
|
for standardField, modelPath := range mapping {
|
|||
|
|
path := gconv.String(modelPath)
|
|||
|
|
if path == "" {
|
|||
|
|
continue
|
|||
|
|
}
|
|||
|
|
val := responseJson.Get(path)
|
|||
|
|
if val.IsNil() {
|
|||
|
|
continue
|
|||
|
|
}
|
|||
|
|
resultJson.Set(standardField, val.Val())
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return []byte(resultJson.String()), nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ParseHeadMsgHeaders 支持多个 header 绑定,逗号分隔:
|
|||
|
|
// 示例:
|
|||
|
|
// - X-API-Key:qwen3-tts-key,operation:true,count:123
|
|||
|
|
// - X-API-Key:"qwen3-tts-key",operation:"true"
|
|||
|
|
//
|
|||
|
|
// 说明:
|
|||
|
|
// - HTTP Header 最终都是字符串,这里做的是“值的字符串化表达”。
|
|||
|
|
// - 若 value 用双引号包裹,会去掉外层引号再注入,便于在配置中区分字符串/布尔/数字等表达(以及避免值中包含特殊字符时歧义)。
|
|||
|
|
func ParseHeadMsgHeaders(headMsg string) map[string]string {
|
|||
|
|
headMsg = strings.TrimSpace(headMsg)
|
|||
|
|
if headMsg == "" {
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
out := map[string]string{}
|
|||
|
|
parts := strings.Split(headMsg, ",")
|
|||
|
|
for _, p := range parts {
|
|||
|
|
p = strings.TrimSpace(p)
|
|||
|
|
if p == "" {
|
|||
|
|
continue
|
|||
|
|
}
|
|||
|
|
// HeaderName:HeaderValue(推荐) / HeaderName=HeaderValue(兼容)
|
|||
|
|
if strings.Contains(p, ":") {
|
|||
|
|
kv := strings.SplitN(p, ":", 2)
|
|||
|
|
k := strings.TrimSpace(kv[0])
|
|||
|
|
v := strings.TrimSpace(kv[1])
|
|||
|
|
v = strings.Trim(v, "\"")
|
|||
|
|
if k != "" && v != "" {
|
|||
|
|
out[k] = v
|
|||
|
|
}
|
|||
|
|
continue
|
|||
|
|
}
|
|||
|
|
if strings.Contains(p, "=") {
|
|||
|
|
kv := strings.SplitN(p, "=", 2)
|
|||
|
|
k := strings.TrimSpace(kv[0])
|
|||
|
|
v := strings.TrimSpace(kv[1])
|
|||
|
|
v = strings.Trim(v, "\"")
|
|||
|
|
if k != "" && v != "" {
|
|||
|
|
out[k] = v
|
|||
|
|
}
|
|||
|
|
continue
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if len(out) == 0 {
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
return out
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// PayloadToQuery 将 payload 转为 url.Values
|
|||
|
|
func PayloadToQuery(payload map[string]any) (url.Values, error) {
|
|||
|
|
q := url.Values{}
|
|||
|
|
for k, v := range payload {
|
|||
|
|
if v == nil {
|
|||
|
|
continue
|
|||
|
|
}
|
|||
|
|
q.Set(k, gconv.String(v))
|
|||
|
|
}
|
|||
|
|
return q, nil
|
|||
|
|
}
|