Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

move json schema to directory/package #407

Merged
merged 2 commits into from
Jun 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,66 @@ func main() {
```
</details>

<details>
<summary>JSON Schema for function calling</summary>

It is now possible for chat completion to choose to call a function for more information ([see developer docs here](https://platform.openai.com/docs/guides/gpt/function-calling)).

In order to describe the type of functions that can be called, a JSON schema must be provided. Many JSON schema libraries exist and are more advanced than what we can offer in this library, however we have included a simple `jsonschema` package for those who want to use this feature without formatting their own JSON schema payload.

The developer documents give this JSON schema definition as an example:

```json
{
"name":"get_current_weather",
"description":"Get the current weather in a given location",
"parameters":{
"type":"object",
"properties":{
"location":{
"type":"string",
"description":"The city and state, e.g. San Francisco, CA"
},
"unit":{
"type":"string",
"enum":[
"celsius",
"fahrenheit"
]
}
},
"required":[
"location"
]
}
}
```

Using the `jsonschema` package, this schema could be created using structs as such:

```go
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{"celcius", "fahrenheit"},
},
},
Required: []string{"location"},
},
}
```

The `Parameters` field of a `FunctionDefinition` can accept either of the above styles, or even a nested struct from another library (as long as it can be marshalled into JSON).
</details>

<details>
<summary>Error handling</summary>

Expand Down
39 changes: 4 additions & 35 deletions chat.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,47 +62,16 @@ type FunctionDefinition struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
// Parameters is an object describing the function.
// You can pass a raw byte array describing the schema,
// or you can pass in a struct which serializes to the proper JSONSchema.
// The JSONSchemaDefinition struct is provided for convenience, but you should
// consider another specialized library for more complex schemas.
// You can pass a []byte describing the schema,
// or you can pass in a struct which serializes to the proper JSON schema.
// The jsonschema package is provided for convenience, but you should
// consider another specialized library if you require more complex schemas.
Parameters any `json:"parameters"`
}

// Deprecated: use FunctionDefinition instead.
type FunctionDefine = FunctionDefinition

type JSONSchemaType string

const (
JSONSchemaTypeObject JSONSchemaType = "object"
JSONSchemaTypeNumber JSONSchemaType = "number"
JSONSchemaTypeString JSONSchemaType = "string"
JSONSchemaTypeArray JSONSchemaType = "array"
JSONSchemaTypeNull JSONSchemaType = "null"
JSONSchemaTypeBoolean JSONSchemaType = "boolean"
)

// JSONSchemaDefinition is a struct for JSON Schema.
// It is fairly limited and you may have better luck using a third-party library.
type JSONSchemaDefinition struct {
// Type is a type of JSON Schema.
Type JSONSchemaType `json:"type,omitempty"`
// Description is a description of JSON Schema.
Description string `json:"description,omitempty"`
// Enum is a enum of JSON Schema. It used if Type is JSONSchemaTypeString.
Enum []string `json:"enum,omitempty"`
// Properties is a properties of JSON Schema. It used if Type is JSONSchemaTypeObject.
Properties map[string]JSONSchemaDefinition `json:"properties,omitempty"`
// Required is a required of JSON Schema. It used if Type is JSONSchemaTypeObject.
Required []string `json:"required,omitempty"`
// Items is a property of JSON Schema. It used if Type is JSONSchemaTypeArray.
Items *JSONSchemaDefinition `json:"items,omitempty"`
}

// Deprecated: use JSONSchemaDefinition instead.
type JSONSchemaDefine = JSONSchemaDefinition

type FinishReason string

const (
Expand Down
39 changes: 20 additions & 19 deletions chat_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package openai_test

import (
. "github.com/sashabaranov/go-openai"
"github.com/sashabaranov/go-openai/internal/test/checks"

"context"
"encoding/json"
"fmt"
Expand All @@ -13,6 +10,10 @@ import (
"strings"
"testing"
"time"

. "github.com/sashabaranov/go-openai"
"github.com/sashabaranov/go-openai/internal/test/checks"
"github.com/sashabaranov/go-openai/jsonschema"
)

func TestChatCompletionsWrongModel(t *testing.T) {
Expand Down Expand Up @@ -128,22 +129,22 @@ func TestChatCompletionsFunctions(t *testing.T) {
},
Functions: []FunctionDefinition{{
Name: "test",
Parameters: &JSONSchemaDefinition{
Type: JSONSchemaTypeObject,
Properties: map[string]JSONSchemaDefinition{
Parameters: &jsonschema.Definition{
Type: jsonschema.Object,
Properties: map[string]jsonschema.Definition{
"count": {
Type: JSONSchemaTypeNumber,
Type: jsonschema.Number,
Description: "total number of words in sentence",
},
"words": {
Type: JSONSchemaTypeArray,
Type: jsonschema.Array,
Description: "list of words in sentence",
Items: &JSONSchemaDefinition{
Type: JSONSchemaTypeString,
Items: &jsonschema.Definition{
Type: jsonschema.String,
},
},
"enumTest": {
Type: JSONSchemaTypeString,
Type: jsonschema.String,
Enum: []string{"hello", "world"},
},
},
Expand All @@ -165,22 +166,22 @@ func TestChatCompletionsFunctions(t *testing.T) {
},
Functions: []FunctionDefine{{
Name: "test",
Parameters: &JSONSchemaDefine{
Type: JSONSchemaTypeObject,
Properties: map[string]JSONSchemaDefine{
Parameters: &jsonschema.Definition{
Type: jsonschema.Object,
Properties: map[string]jsonschema.Definition{
"count": {
Type: JSONSchemaTypeNumber,
Type: jsonschema.Number,
Description: "total number of words in sentence",
},
"words": {
Type: JSONSchemaTypeArray,
Type: jsonschema.Array,
Description: "list of words in sentence",
Items: &JSONSchemaDefine{
Type: JSONSchemaTypeString,
Items: &jsonschema.Definition{
Type: jsonschema.String,
},
},
"enumTest": {
Type: JSONSchemaTypeString,
Type: jsonschema.String,
Enum: []string{"hello", "world"},
},
},
Expand Down
35 changes: 35 additions & 0 deletions jsonschema/json.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Package jsonschema provides very simple functionality for representing a JSON schema as a
// (nested) struct. This struct can be used with the chat completion "function call" feature.
// For more complicated schemas, it is recommended to use a dedicated JSON schema library
// and/or pass in the schema in []byte format.
package jsonschema

type DataType string

const (
Object DataType = "object"
Number DataType = "number"
Integer DataType = "integer"
String DataType = "string"
Array DataType = "array"
Null DataType = "null"
Boolean DataType = "boolean"
)

// Definition is a struct for describing a JSON Schema.
// It is fairly limited and you may have better luck using a third-party library.
type Definition struct {
// Type specifies the data type of the schema.
Type DataType `json:"type,omitempty"`
// Description is the description of the schema.
Description string `json:"description,omitempty"`
// Enum is used to restrict a value to a fixed set of values. It must be an array with at least
// one element, where each element is unique. You will probably only use this with strings.
Enum []string `json:"enum,omitempty"`
// Properties describes the properties of an object, if the schema type is Object.
Properties map[string]Definition `json:"properties,omitempty"`
// Required specifies which properties are required, if the schema type is Object.
Required []string `json:"required,omitempty"`
// Items specifies which data type an array contains, if the schema type is Array.
Items *Definition `json:"items,omitempty"`
}