fix: invalid schema for function 'func_name': None is not of type 'object' (#429)(#432) (#434)

* fix: invalid schema for function 'func_name': None is not of type 'object' (#429)(#432)

* test: add integration test for function call (#429)(#432)

* style: remove duplicate import (#429)(#432)
This commit is contained in:
渡邉祐一 / Yuichi Watanabe
2023-07-11 20:48:15 +09:00
committed by GitHub
parent f028c289d2
commit c3b2451f7c
3 changed files with 63 additions and 30 deletions

View File

@@ -11,6 +11,7 @@ import (
. "github.com/sashabaranov/go-openai" . "github.com/sashabaranov/go-openai"
"github.com/sashabaranov/go-openai/internal/test/checks" "github.com/sashabaranov/go-openai/internal/test/checks"
"github.com/sashabaranov/go-openai/jsonschema"
) )
func TestAPI(t *testing.T) { func TestAPI(t *testing.T) {
@@ -100,6 +101,37 @@ func TestAPI(t *testing.T) {
if counter == 0 { if counter == 0 {
t.Error("Stream did not return any responses") t.Error("Stream did not return any responses")
} }
_, err = c.CreateChatCompletion(
context.Background(),
ChatCompletionRequest{
Model: GPT3Dot5Turbo,
Messages: []ChatCompletionMessage{
{
Role: ChatMessageRoleUser,
Content: "What is the weather like in Boston?",
},
},
Functions: []FunctionDefinition{{
Name: "get_current_weather",
Parameters: jsonschema.Definition{
Type: jsonschema.Object,
Properties: map[string]jsonschema.Definition{
"location": {
Type: jsonschema.String,
Description: "The city and state, e.g. San Francisco, CA",
},
"unit": {
Type: jsonschema.String,
Enum: []string{"celsius", "fahrenheit"},
},
},
Required: []string{"location"},
},
}},
},
)
checks.NoError(t, err, "CreateChatCompletion (with functions) returned error")
} }
func TestAPIError(t *testing.T) { func TestAPIError(t *testing.T) {

View File

@@ -36,23 +36,14 @@ type Definition struct {
Items *Definition `json:"items,omitempty"` Items *Definition `json:"items,omitempty"`
} }
func (d *Definition) MarshalJSON() ([]byte, error) { func (d Definition) MarshalJSON() ([]byte, error) {
d.initializeProperties()
return json.Marshal(*d)
}
func (d *Definition) initializeProperties() {
if d.Properties == nil { if d.Properties == nil {
d.Properties = make(map[string]Definition) d.Properties = make(map[string]Definition)
return
}
for k, v := range d.Properties {
if v.Properties == nil {
v.Properties = make(map[string]Definition)
} else {
v.initializeProperties()
}
d.Properties[k] = v
} }
type Alias Definition
return json.Marshal(struct {
Alias
}{
Alias: (Alias)(d),
})
} }

View File

@@ -172,30 +172,40 @@ func TestDefinition_MarshalJSON(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
gotBytes, err := json.Marshal(&tt.def)
if err != nil {
t.Errorf("Failed to Marshal JSON: error = %v", err)
return
}
var got map[string]interface{}
err = json.Unmarshal(gotBytes, &got)
if err != nil {
t.Errorf("Failed to Unmarshal JSON: error = %v", err)
return
}
wantBytes := []byte(tt.want) wantBytes := []byte(tt.want)
var want map[string]interface{} var want map[string]interface{}
err = json.Unmarshal(wantBytes, &want) err := json.Unmarshal(wantBytes, &want)
if err != nil { if err != nil {
t.Errorf("Failed to Unmarshal JSON: error = %v", err) t.Errorf("Failed to Unmarshal JSON: error = %v", err)
return return
} }
got := structToMap(t, tt.def)
gotPtr := structToMap(t, &tt.def)
if !reflect.DeepEqual(got, want) { if !reflect.DeepEqual(got, want) {
t.Errorf("MarshalJSON() got = %v, want %v", got, want) t.Errorf("MarshalJSON() got = %v, want %v", got, want)
} }
if !reflect.DeepEqual(gotPtr, want) {
t.Errorf("MarshalJSON() gotPtr = %v, want %v", gotPtr, want)
}
}) })
} }
} }
func structToMap(t *testing.T, v any) map[string]any {
t.Helper()
gotBytes, err := json.Marshal(v)
if err != nil {
t.Errorf("Failed to Marshal JSON: error = %v", err)
return nil
}
var got map[string]interface{}
err = json.Unmarshal(gotBytes, &got)
if err != nil {
t.Errorf("Failed to Unmarshal JSON: error = %v", err)
return nil
}
return got
}