diff --git a/README.md b/README.md index ef1db98cc..da1a2804d 100644 --- a/README.md +++ b/README.md @@ -516,6 +516,66 @@ func main() { ``` +
+JSON Schema for function calling + +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). +
+
Error handling diff --git a/chat.go b/chat.go index b74720d38..e4f23df07 100644 --- a/chat.go +++ b/chat.go @@ -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 ( diff --git a/chat_test.go b/chat_test.go index 3c759b310..d5879e60f 100644 --- a/chat_test.go +++ b/chat_test.go @@ -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" @@ -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) { @@ -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"}, }, }, @@ -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"}, }, }, diff --git a/jsonschema/json.go b/jsonschema/json.go new file mode 100644 index 000000000..24af8584e --- /dev/null +++ b/jsonschema/json.go @@ -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"` +}