70 lines
1.8 KiB
Go
70 lines
1.8 KiB
Go
package util
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
)
|
|
|
|
// ValidatePromptResult 完整的校验逻辑
|
|
func ValidatePromptResult(raw map[string]any, requestMapping map[string]any) error {
|
|
contentStr, ok := raw["content"].(string)
|
|
if !ok || contentStr == "" {
|
|
return fmt.Errorf("content 字段为空或不是字符串")
|
|
}
|
|
|
|
var rounds []map[string]any
|
|
if err := json.Unmarshal([]byte(contentStr), &rounds); err != nil {
|
|
return fmt.Errorf("解析 content JSON 数组失败: %w", err)
|
|
}
|
|
if len(rounds) == 0 {
|
|
return fmt.Errorf("content 数组为空")
|
|
}
|
|
|
|
// 对 rounds 中的每一个元素进行结构校验
|
|
for i, round := range rounds {
|
|
if err := validateStructure(requestMapping, round); err != nil {
|
|
return fmt.Errorf("rounds[%d] 结构校验失败: %w", i, err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// validateStructure 递归校验 actual 是否包含 expected 定义的所有字段路径
|
|
func validateStructure(expected any, actual any) error {
|
|
switch exp := expected.(type) {
|
|
case map[string]any:
|
|
act, ok := actual.(map[string]any)
|
|
if !ok {
|
|
return fmt.Errorf("期望对象,实际类型 %T", actual)
|
|
}
|
|
for key, expVal := range exp {
|
|
actVal, exists := act[key]
|
|
if !exists {
|
|
return fmt.Errorf("缺少字段: %s", key)
|
|
}
|
|
if err := validateStructure(expVal, actVal); err != nil {
|
|
return fmt.Errorf("%s: %w", key, err)
|
|
}
|
|
}
|
|
return nil
|
|
case []any:
|
|
act, ok := actual.([]any)
|
|
if !ok {
|
|
return fmt.Errorf("期望数组,实际类型 %T", actual)
|
|
}
|
|
if len(exp) == 0 {
|
|
return nil // 空数组模板,只校验类型
|
|
}
|
|
// 用第一个元素的结构去校验每个实际元素
|
|
for i, actItem := range act {
|
|
if err := validateStructure(exp[0], actItem); err != nil {
|
|
return fmt.Errorf("[%d]: %w", i, err)
|
|
}
|
|
}
|
|
return nil
|
|
default:
|
|
// 基本类型,不校验具体值,只检查存在
|
|
return nil
|
|
}
|
|
}
|