Skip to content

Commit

Permalink
Merge branch 'master' into embedding_example
Browse files Browse the repository at this point in the history
  • Loading branch information
aceld committed Jul 12, 2023
2 parents 330ec63 + c3b2451 commit 9e2d687
Show file tree
Hide file tree
Showing 38 changed files with 1,468 additions and 487 deletions.
2 changes: 1 addition & 1 deletion .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# These are supported funding model platforms

github: [sashabaranov]
github: [sashabaranov, vvatanabe]
32 changes: 32 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''

---

Your issue may already be reported!
Please search on the [issue tracker](https://github.com/sashabaranov/go-openai/issues) before creating one.

**Describe the bug**
A clear and concise description of what the bug is. If it's an API-related bug, please provide relevant endpoint(s).

**To Reproduce**
Steps to reproduce the behavior, including any relevant code snippets.

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots/Logs**
If applicable, add screenshots to help explain your problem. For non-graphical issues, please provide any relevant logs or stack traces.

**Environment (please complete the following information):**
- go-openai version: [e.g. v1.12.0]
- Go version: [e.g. 1.18]
- OpenAI API version: [e.g. v1]
- OS: [e.g. Ubuntu 20.04]

**Additional context**
Add any other context about the problem here.
23 changes: 23 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''

---

Your issue may already be reported!
Please search on the [issue tracker](https://github.com/sashabaranov/go-openai/issues) before creating one.

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.
20 changes: 20 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
A similar PR may already be submitted!
Please search among the [Pull request](https://github.com/sashabaranov/go-openai/pulls) before creating one.

If your changes introduce breaking changes, please prefix the title of your pull request with "[BREAKING_CHANGES]". This allows for clear identification of such changes in the 'What's Changed' section on the release page, making it developer-friendly.

Thanks for submitting a pull request! Please provide enough information so that others can review your pull request.

**Describe the change**
Please provide a clear and concise description of the changes you're proposing. Explain what problem it solves or what feature it adds.

**Describe your solution**
Describe how your changes address the problem or how they add the feature. This should include a brief description of your approach and any new libraries or dependencies you're using.

**Tests**
Briefly describe how you have tested these changes.

**Additional context**
Add any other context or screenshots or logs about your pull request here. If the pull request relates to an open issue, please link to it.

Issue: #XXXX
94 changes: 93 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ This library provides unofficial Go clients for [OpenAI API](https://platform.op
```
go get github.com/sashabaranov/go-openai
```

Currently, go-openai requires Go version 1.18 or greater.

### ChatGPT example usage:

Expand Down Expand Up @@ -52,6 +52,17 @@ func main() {

```

### Getting an OpenAI API Key:

1. Visit the OpenAI website at [https://platform.openai.com/account/api-keys](https://platform.openai.com/account/api-keys).
2. If you don't have an account, click on "Sign Up" to create one. If you do, click "Log In".
3. Once logged in, navigate to your API key management page.
4. Click on "Create new secret key".
5. Enter a name for your new key, then click "Create secret key".
6. Your new API key will be displayed. Use this key to interact with the OpenAI API.

**Note:** Your API key is sensitive information. Do not share it with anyone.

### Other examples:

<details>
Expand Down Expand Up @@ -712,6 +723,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 All @@ -738,3 +809,24 @@ if errors.As(err, &e) {
</details>

See the `examples/` folder for more.

### Integration tests:

Integration tests are requested against the production version of the OpenAI API. These tests will verify that the library is properly coded against the actual behavior of the API, and will fail upon any incompatible change in the API.

**Notes:**
These tests send real network traffic to the OpenAI API and may reach rate limits. Temporary network problems may also cause the test to fail.

**Run tests using:**
```
OPENAI_TOKEN=XXX go test -v -tags=integration ./api_integration_test.go
```

If the `OPENAI_TOKEN` environment variable is not available, integration tests will be skipped.

## Thank you

We want to take a moment to express our deepest gratitude to the [contributors](https://github.com/sashabaranov/go-openai/graphs/contributors) and sponsors of this project:
- [Carson Kahn](https://carsonkahn.com) of [Spindle AI](https://spindleai.com)

To all of you: thank you. You've helped us achieve more than we ever imagined possible. Can't wait to see where we go next, together!
170 changes: 170 additions & 0 deletions api_integration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
//go:build integration

package openai_test

import (
"context"
"errors"
"io"
"os"
"testing"

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

func TestAPI(t *testing.T) {
apiToken := os.Getenv("OPENAI_TOKEN")
if apiToken == "" {
t.Skip("Skipping testing against production OpenAI API. Set OPENAI_TOKEN environment variable to enable it.")
}

var err error
c := NewClient(apiToken)
ctx := context.Background()
_, err = c.ListEngines(ctx)
checks.NoError(t, err, "ListEngines error")

_, err = c.GetEngine(ctx, "davinci")
checks.NoError(t, err, "GetEngine error")

fileRes, err := c.ListFiles(ctx)
checks.NoError(t, err, "ListFiles error")

if len(fileRes.Files) > 0 {
_, err = c.GetFile(ctx, fileRes.Files[0].ID)
checks.NoError(t, err, "GetFile error")
} // else skip

embeddingReq := EmbeddingRequest{
Input: []string{
"The food was delicious and the waiter",
"Other examples of embedding request",
},
Model: AdaSearchQuery,
}
_, err = c.CreateEmbeddings(ctx, embeddingReq)
checks.NoError(t, err, "Embedding error")

_, err = c.CreateChatCompletion(
ctx,
ChatCompletionRequest{
Model: GPT3Dot5Turbo,
Messages: []ChatCompletionMessage{
{
Role: ChatMessageRoleUser,
Content: "Hello!",
},
},
},
)

checks.NoError(t, err, "CreateChatCompletion (without name) returned error")

_, err = c.CreateChatCompletion(
ctx,
ChatCompletionRequest{
Model: GPT3Dot5Turbo,
Messages: []ChatCompletionMessage{
{
Role: ChatMessageRoleUser,
Name: "John_Doe",
Content: "Hello!",
},
},
},
)
checks.NoError(t, err, "CreateChatCompletion (with name) returned error")

stream, err := c.CreateCompletionStream(ctx, CompletionRequest{
Prompt: "Ex falso quodlibet",
Model: GPT3Ada,
MaxTokens: 5,
Stream: true,
})
checks.NoError(t, err, "CreateCompletionStream returned error")
defer stream.Close()

counter := 0
for {
_, err = stream.Recv()
if err != nil {
if errors.Is(err, io.EOF) {
break
}
t.Errorf("Stream error: %v", err)
} else {
counter++
}
}
if counter == 0 {
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) {
apiToken := os.Getenv("OPENAI_TOKEN")
if apiToken == "" {
t.Skip("Skipping testing against production OpenAI API. Set OPENAI_TOKEN environment variable to enable it.")
}

var err error
c := NewClient(apiToken + "_invalid")
ctx := context.Background()
_, err = c.ListEngines(ctx)
checks.HasError(t, err, "ListEngines should fail with an invalid key")

var apiErr *APIError
if !errors.As(err, &apiErr) {
t.Fatalf("Error is not an APIError: %+v", err)
}

if apiErr.HTTPStatusCode != 401 {
t.Fatalf("Unexpected API error status code: %d", apiErr.HTTPStatusCode)
}

switch v := apiErr.Code.(type) {
case string:
if v != "invalid_api_key" {
t.Fatalf("Unexpected API error code: %s", v)
}
default:
t.Fatalf("Unexpected API error code type: %T", v)
}

if apiErr.Error() == "" {
t.Fatal("Empty error message occurred")
}
}
2 changes: 1 addition & 1 deletion api_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func TestRequestAuthHeader(t *testing.T) {
az.OrgID = c.OrgID

cli := NewClientWithConfig(az)
req, err := cli.newStreamRequest(context.Background(), "POST", "/chat/completions", nil, "")
req, err := cli.newRequest(context.Background(), "POST", "/chat/completions")
if err != nil {
t.Errorf("Failed to create request: %v", err)
}
Expand Down
Loading

0 comments on commit 9e2d687

Please sign in to comment.