-
Notifications
You must be signed in to change notification settings - Fork 65
Models, Files and Fine-Tuning APIs #20
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
Open
thehappydinoa
wants to merge
8
commits into
PullRequestInc:main
Choose a base branch
from
thehappydinoa:adh/files-and-fine-tune
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 7 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
17cca76
feat: add the files and fine tune apis
c39eee1
chore: various cleanup and linting
06fa40c
chore: add gitignore
019b4b4
fix: null pointer exception
6755689
chore: refactor
136b50e
chore: boilerplate tests
087deb9
chore: update tests
1ffa0b6
fix: apply feedback
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,32 @@ | ||
| # If you prefer the allow list template instead of the deny list, see community template: | ||
| # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore | ||
| # | ||
| # Binaries for programs and plugins | ||
| *.exe | ||
| *.exe~ | ||
| *.dll | ||
| *.so | ||
| *.dylib | ||
|
|
||
| # Test binary, built with `go test -c` | ||
| *.test | ||
|
|
||
| # Output of the go coverage tool, specifically when used with LiteIDE | ||
| *.out | ||
|
|
||
| # Dependency directories (remove the comment below to include it) | ||
| # vendor/ | ||
|
|
||
| # Go workspace file | ||
| go.work | ||
|
|
||
| # Env | ||
| .env | ||
| .env.* | ||
|
|
||
| # IDEs | ||
| .idea/ | ||
| .vscode/ | ||
|
|
||
| # macOS | ||
| .DS_Store |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,139 @@ | ||
| package gpt3 | ||
|
|
||
| import ( | ||
| "bytes" | ||
| "context" | ||
| "encoding/json" | ||
| "fmt" | ||
| "io" | ||
| "io/ioutil" | ||
| "net/http" | ||
| "time" | ||
| ) | ||
|
|
||
| const ( | ||
| DEFAULT_BASE_URL = "https://api.openai.com/v1" | ||
| DEFAULT_USER_AGENT = "gpt3-go" | ||
| DEFAULT_TIMEOUT = 30 | ||
| ) | ||
|
|
||
| var dataPrefix = []byte("data: ") | ||
| var streamTerminationPrefix = []byte("[DONE]") | ||
|
|
||
| type Client interface { | ||
| Models(ctx context.Context) (*ModelsResponse, error) | ||
| Model(ctx context.Context, model string) (*ModelObject, error) | ||
| Completion(ctx context.Context, request CompletionRequest) (*CompletionResponse, error) | ||
| CompletionStream(ctx context.Context, request CompletionRequest, onData func(*CompletionResponse)) error | ||
| Edits(ctx context.Context, request EditsRequest) (*EditsResponse, error) | ||
| Embeddings(ctx context.Context, request EmbeddingsRequest) (*EmbeddingsResponse, error) | ||
| Files(ctx context.Context) (*FilesResponse, error) | ||
| UploadFile(ctx context.Context, request UploadFileRequest) (*FileObject, error) | ||
| DeleteFile(ctx context.Context, fileID string) (*DeleteFileResponse, error) | ||
| File(ctx context.Context, fileID string) (*FileObject, error) | ||
| FileContent(ctx context.Context, fileID string) ([]byte, error) | ||
| CreateFineTune(ctx context.Context, request CreateFineTuneRequest) (*FineTuneObject, error) | ||
| FineTunes(ctx context.Context) (*FineTunesResponse, error) | ||
| FineTune(ctx context.Context, fineTuneID string) (*FineTuneObject, error) | ||
| CancelFineTune(ctx context.Context, fineTuneID string) (*FineTuneObject, error) | ||
| FineTuneEvents(ctx context.Context, request FineTuneEventsRequest) (*FineTuneEventsResponse, error) | ||
| FineTuneStreamEvents(ctx context.Context, request FineTuneEventsRequest, onData func(*FineTuneEvent)) error | ||
| DeleteFineTuneModel(ctx context.Context, modelID string) (*DeleteFineTuneModelResponse, error) | ||
| } | ||
|
|
||
| type client struct { | ||
| baseURL string | ||
| apiKey string | ||
| orgID string | ||
| userAgent string | ||
| httpClient *http.Client | ||
| defaultModel string | ||
| } | ||
|
|
||
| func NewClient(apiKey string, options ...ClientOption) (Client, error) { | ||
| c := &client{ | ||
| baseURL: DEFAULT_BASE_URL, | ||
| apiKey: apiKey, | ||
| orgID: "", | ||
| userAgent: DEFAULT_USER_AGENT, | ||
| httpClient: &http.Client{Timeout: time.Duration(DEFAULT_TIMEOUT) * time.Second}, | ||
| defaultModel: DavinciModel, | ||
| } | ||
|
|
||
| for _, option := range options { | ||
| if err := option(c); err != nil { | ||
thehappydinoa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return nil, err | ||
| } | ||
| } | ||
|
|
||
| return c, nil | ||
| } | ||
|
|
||
| func (c *client) newRequest(ctx context.Context, method, path string, payload interface{}) (*http.Request, error) { | ||
thehappydinoa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| bodyReader, err := jsonBodyReader(payload) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| url := c.baseURL + path | ||
| req, err := http.NewRequestWithContext(ctx, method, url, bodyReader) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| req.Header.Set("Content-type", "application/json") | ||
| req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.apiKey)) | ||
| req.Header.Set("User-Agent", c.userAgent) | ||
| if len(c.orgID) > 0 { | ||
| req.Header.Set("OpenAI-Organization", c.orgID) | ||
| } | ||
| return req, nil | ||
| } | ||
|
|
||
| func (c *client) performRequest(req *http.Request) (*http.Response, error) { | ||
| resp, err := c.httpClient.Do(req) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| return resp, checkForSuccess(resp) | ||
| } | ||
|
|
||
| func checkForSuccess(resp *http.Response) error { | ||
thehappydinoa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if resp.StatusCode >= 200 && resp.StatusCode < 300 { | ||
| return nil | ||
| } | ||
| defer resp.Body.Close() | ||
thehappydinoa marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| data, err := ioutil.ReadAll(resp.Body) | ||
thehappydinoa marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if err != nil { | ||
| return fmt.Errorf("failed to read from body: %w", err) | ||
| } | ||
| var result APIErrorResponse | ||
| if err := json.Unmarshal(data, &result); err != nil { | ||
| // if we can't decode the json error then create an unexpected error | ||
| apiError := APIError{ | ||
| StatusCode: resp.StatusCode, | ||
| Type: "Unexpected", | ||
| Message: string(data), | ||
| } | ||
| return apiError | ||
| } | ||
| result.Error.StatusCode = resp.StatusCode | ||
| return result.Error | ||
| } | ||
|
|
||
| func getResponseObject(rsp *http.Response, v interface{}) error { | ||
| defer rsp.Body.Close() | ||
| if err := json.NewDecoder(rsp.Body).Decode(v); err != nil { | ||
| return fmt.Errorf("invalid json response: %w", err) | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| func jsonBodyReader(body interface{}) (io.Reader, error) { | ||
| if body == nil { | ||
thehappydinoa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return bytes.NewBuffer(nil), nil | ||
| } | ||
| raw, err := json.Marshal(body) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("failed encoding json: %w", err) | ||
| } | ||
| return bytes.NewBuffer(raw), nil | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| package gpt3_test | ||
|
|
||
| import ( | ||
| "net/http" | ||
| "testing" | ||
|
|
||
| "github.com/PullRequestInc/go-gpt3" | ||
| "github.com/stretchr/testify/assert" | ||
| ) | ||
|
|
||
| func TestClientWithOrg(t *testing.T) { | ||
| client, err := gpt3.NewClient("test-key", gpt3.WithOrg("test-org")) | ||
| assert.Nil(t, err) | ||
thehappydinoa marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| assert.NotNil(t, client) | ||
| } | ||
|
|
||
| func TestClientWithDefaultModel(t *testing.T) { | ||
| client, err := gpt3.NewClient("test-key", gpt3.WithDefaultModel("test-model")) | ||
| assert.Nil(t, err) | ||
| assert.NotNil(t, client) | ||
| } | ||
|
|
||
| func TestClientWithUserAgent(t *testing.T) { | ||
| client, err := gpt3.NewClient("test-key", gpt3.WithUserAgent("test-agent")) | ||
| assert.Nil(t, err) | ||
| assert.NotNil(t, client) | ||
| } | ||
|
|
||
| func TestClientWithBaseURL(t *testing.T) { | ||
| client, err := gpt3.NewClient("test-key", gpt3.WithBaseURL("test-url")) | ||
| assert.Nil(t, err) | ||
| assert.NotNil(t, client) | ||
| } | ||
|
|
||
| func TestClientWithHTTPClient(t *testing.T) { | ||
| httpClient := &http.Client{} | ||
| client, err := gpt3.NewClient("test-key", gpt3.WithHTTPClient(httpClient)) | ||
| assert.Nil(t, err) | ||
| assert.NotNil(t, client) | ||
| } | ||
|
|
||
| func TestClientWithTimeout(t *testing.T) { | ||
| client, err := gpt3.NewClient("test-key", gpt3.WithTimeout(10)) | ||
| assert.Nil(t, err) | ||
| assert.NotNil(t, client) | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| package gpt3_test | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| "github.com/PullRequestInc/go-gpt3" | ||
| "github.com/stretchr/testify/assert" | ||
| ) | ||
|
|
||
| func TestInitNewClient(t *testing.T) { | ||
| client, err := gpt3.NewClient("test-key") | ||
| assert.Nil(t, err) | ||
| assert.NotNil(t, client) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.