Initialize module and dependencies
This commit is contained in:
140
vendor/github.com/sashabaranov/go-openai/jsonschema/validate.go
generated
vendored
Normal file
140
vendor/github.com/sashabaranov/go-openai/jsonschema/validate.go
generated
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
package jsonschema
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
)
|
||||
|
||||
func CollectDefs(def Definition) map[string]Definition {
|
||||
result := make(map[string]Definition)
|
||||
collectDefsRecursive(def, result, "#")
|
||||
return result
|
||||
}
|
||||
|
||||
func collectDefsRecursive(def Definition, result map[string]Definition, prefix string) {
|
||||
for k, v := range def.Defs {
|
||||
path := prefix + "/$defs/" + k
|
||||
result[path] = v
|
||||
collectDefsRecursive(v, result, path)
|
||||
}
|
||||
for k, sub := range def.Properties {
|
||||
collectDefsRecursive(sub, result, prefix+"/properties/"+k)
|
||||
}
|
||||
if def.Items != nil {
|
||||
collectDefsRecursive(*def.Items, result, prefix)
|
||||
}
|
||||
}
|
||||
|
||||
func VerifySchemaAndUnmarshal(schema Definition, content []byte, v any) error {
|
||||
var data any
|
||||
err := json.Unmarshal(content, &data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !Validate(schema, data, WithDefs(CollectDefs(schema))) {
|
||||
return errors.New("data validation failed against the provided schema")
|
||||
}
|
||||
return json.Unmarshal(content, &v)
|
||||
}
|
||||
|
||||
type validateArgs struct {
|
||||
Defs map[string]Definition
|
||||
}
|
||||
|
||||
type ValidateOption func(*validateArgs)
|
||||
|
||||
func WithDefs(defs map[string]Definition) ValidateOption {
|
||||
return func(option *validateArgs) {
|
||||
option.Defs = defs
|
||||
}
|
||||
}
|
||||
|
||||
func Validate(schema Definition, data any, opts ...ValidateOption) bool {
|
||||
args := validateArgs{}
|
||||
for _, opt := range opts {
|
||||
opt(&args)
|
||||
}
|
||||
if len(opts) == 0 {
|
||||
args.Defs = CollectDefs(schema)
|
||||
}
|
||||
switch schema.Type {
|
||||
case Object:
|
||||
return validateObject(schema, data, args.Defs)
|
||||
case Array:
|
||||
return validateArray(schema, data, args.Defs)
|
||||
case String:
|
||||
v, ok := data.(string)
|
||||
if ok && len(schema.Enum) > 0 {
|
||||
return contains(schema.Enum, v)
|
||||
}
|
||||
return ok
|
||||
case Number: // float64 and int
|
||||
_, ok := data.(float64)
|
||||
if !ok {
|
||||
_, ok = data.(int)
|
||||
}
|
||||
return ok
|
||||
case Boolean:
|
||||
_, ok := data.(bool)
|
||||
return ok
|
||||
case Integer:
|
||||
// Golang unmarshals all numbers as float64, so we need to check if the float64 is an integer
|
||||
if num, ok := data.(float64); ok {
|
||||
return num == float64(int64(num))
|
||||
}
|
||||
_, ok := data.(int)
|
||||
return ok
|
||||
case Null:
|
||||
return data == nil
|
||||
default:
|
||||
if schema.Ref != "" && args.Defs != nil {
|
||||
if v, ok := args.Defs[schema.Ref]; ok {
|
||||
return Validate(v, data, WithDefs(args.Defs))
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func validateObject(schema Definition, data any, defs map[string]Definition) bool {
|
||||
dataMap, ok := data.(map[string]any)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
for _, field := range schema.Required {
|
||||
if _, exists := dataMap[field]; !exists {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for key, valueSchema := range schema.Properties {
|
||||
value, exists := dataMap[key]
|
||||
if exists && !Validate(valueSchema, value, WithDefs(defs)) {
|
||||
return false
|
||||
} else if !exists && contains(schema.Required, key) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func validateArray(schema Definition, data any, defs map[string]Definition) bool {
|
||||
dataArray, ok := data.([]any)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
for _, item := range dataArray {
|
||||
if !Validate(*schema.Items, item, WithDefs(defs)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func contains[S ~[]E, E comparable](s S, v E) bool {
|
||||
for i := range s {
|
||||
if v == s[i] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user