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

Added Fine Tuning #10

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
184 changes: 184 additions & 0 deletions file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
package chatgpt

import (
"bytes"
"context"
"encoding/json"
"io"
"mime/multipart"
"net/http"
)

type FileStatus string

const (
FILESTATUS_UPLOADED FileStatus = "uploaded"
FILESTATUS_PROCESSED FileStatus = "processed"
FILESTATUS_PENDING FileStatus = "pending"
FILESTATUS_ERROR FileStatus = "error"
FILESTATUS_DELETING FileStatus = "deleting"
FILESTATUS_DELETED FileStatus = "deleted"
)

type FilePurpose string

const (
FILEPURPOSE_FINETUNE FilePurpose = "fine-tune"
)

type File struct {
Id string `json:"id"`
Object string `json:"object"`
Bytes int `json:"bytes"`
CreatedAt int `json:"created_at"`
Filename string `json:"filename"`
Purpose FilePurpose `json:"purpose"`
Status FileStatus `json:"status"`
StatusDetails *string `json:"status_details"`
}

type FileList struct {
Data []File `json:"data"`
Object string `json:"object"`
}

type DeleteFileResponse struct {
Id string `json:"id"`
Object string `json:"object"`
Deleted bool `json:"deleted"`
}

func (c *Client) ListFiles(ctx context.Context) (*FileList, error) {
endpoint := "/files"
httpReq, err := http.NewRequest("GET", c.config.BaseURL+endpoint, nil)
if err != nil {
return nil, err
}
httpReq = httpReq.WithContext(ctx)

res, err := c.sendRequest(ctx, httpReq)
if err != nil {
return nil, err
}
defer res.Body.Close()

var fileList FileList
if err := json.NewDecoder(res.Body).Decode(&fileList); err != nil {
return nil, err
}

return &fileList, nil
}

func (c *Client) UploadFile(ctx context.Context, file io.Reader) (*File, error) {
endpoint := "/files"
httpReq, err := http.NewRequest("POST", c.config.BaseURL+endpoint, nil)
if err != nil {
return nil, err
}
httpReq = httpReq.WithContext(ctx)

var requestBody bytes.Buffer
writer := multipart.NewWriter(&requestBody)
err = writer.WriteField("purpose", string(FILEPURPOSE_FINETUNE))
if err != nil {
return nil, err
}

part, err := writer.CreateFormFile("file", "mydata.jsonl")
if err != nil {
return nil, err
}

_, err = io.Copy(part, file)
if err != nil {
return nil, err
}

err = writer.Close()
if err != nil {
return nil, err
}

httpReq.Body = io.NopCloser(&requestBody)

res, err := c.sendRequest(ctx, httpReq)
if err != nil {
return nil, err
}
defer res.Body.Close()

var responseFile File
if err := json.NewDecoder(res.Body).Decode(&responseFile); err != nil {
return nil, err
}

return &responseFile, nil
}

func (c *Client) DeleteFile(ctx context.Context, fileId string) (*DeleteFileResponse, error) {
endpoint := "/files/" + fileId
httpReq, err := http.NewRequest("DELETE", c.config.BaseURL+endpoint, nil)
if err != nil {
return nil, err
}
httpReq = httpReq.WithContext(ctx)

res, err := c.sendRequest(ctx, httpReq)
if err != nil {
return nil, err
}
defer res.Body.Close()

var deletedFile DeleteFileResponse
if err := json.NewDecoder(res.Body).Decode(&deletedFile); err != nil {
return nil, err
}

return &deletedFile, nil
}

func (c *Client) RetrieveFile(ctx context.Context, fileId string) (*File, error) {
endpoint := "/files/" + fileId
httpReq, err := http.NewRequest("GET", c.config.BaseURL+endpoint, nil)
if err != nil {
return nil, err
}
httpReq = httpReq.WithContext(ctx)

res, err := c.sendRequest(ctx, httpReq)
if err != nil {
return nil, err
}
defer res.Body.Close()

var file File
if err := json.NewDecoder(res.Body).Decode(&file); err != nil {
return nil, err
}

return &file, nil
}

func (c *Client) RetrieveFileContent(ctx context.Context, fileId string) (*string, error) {
endpoint := "/files/" + fileId + "/content"

httpReq, err := http.NewRequest("GET", c.config.BaseURL+endpoint, nil)
if err != nil {
return nil, err
}
httpReq = httpReq.WithContext(ctx)

res, err := c.sendRequest(ctx, httpReq)
if err != nil {
return nil, err
}
defer res.Body.Close()

var fileContent string
if err := json.NewDecoder(res.Body).Decode(&fileContent); err != nil {
return nil, err
}

return &fileContent, nil
}
226 changes: 226 additions & 0 deletions finetune.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
package chatgpt

import (
"bytes"
"context"
"encoding/json"
"net/http"
"net/url"
"strconv"
)

type FineTuningJobStatus string

const (
FINETUNINGJOBSTATUS_CREATED FineTuningJobStatus = "created"
FINETUNINGJOBSTATUS_PENDING FineTuningJobStatus = "pending"
FINETUNINGJOBSTATUS_RUNNING FineTuningJobStatus = "running"
FINETUNINGJOBSTATUS_SUCCEEDED FineTuningJobStatus = "succeeded"
FINETUNINGJOBSTATUS_FAILED FineTuningJobStatus = "failed"
FINETUNINGJOBSTATUS_CANCELLED FineTuningJobStatus = "cancelled"
)

type FineTuningJob struct {
Object string `json:"object"`
Id string `json:"id"`
Model string `json:"model,omitempty"`
CreatedAt int `json:"created_at"`
FinishedAt int `json:"finished_at,omitempty"`
FineTunedModel string `json:"fine_tuned_model,omitempty"`
OrganizationId string `json:"organization_id,omitempty"`
ResultFiles []string `json:"result_files,omitempty"`
Status FineTuningJobStatus `json:"status,omitempty"`
ValidationFile interface{} `json:"validation_file,omitempty"`
TrainingFile string `json:"training_file,omitempty"`
Hyperparameters struct {
NEpochs int `json:"n_epochs"`
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can either be a string or an integer. Doc link - https://platform.openai.com/docs/api-reference/fine-tuning/object

} `json:"hyperparameters,omitempty"`
TrainedTokens int `json:"trained_tokens,omitempty"`
Level string `json:"level,omitempty"`
Message string `json:"message,omitempty"`
Data string `json:"data,omitempty"`
Type string `json:"type,omitempty"`
Comment on lines +41 to +42
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are not valid anymore :(

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ayush6624 this PR is kinda a year old. I don't have any need for this anymore, therefore you can close it.

}

type FineTuningRequest struct {
TrainingFile string `json:"training_file"`
ValidationFile *string `json:"validation_file"`
Model ChatGPTModel `json:"model"`
}

type FineTuningResponse struct {
Object string `json:"object"`
Id string `json:"id"`
Model string `json:"model"`
CreatedAt int `json:"created_at"`
FineTunedModel interface{} `json:"fine_tuned_model"`
OrganizationId string `json:"organization_id"`
ResultFiles []interface{} `json:"result_files"`
Status string `json:"status"`
ValidationFile interface{} `json:"validation_file"`
TrainingFile string `json:"training_file"`
}

type FineTuningList struct {
Object string `json:"object"`
Data []FineTuningJob `json:"data"`
HasMore bool `json:"has_more"`
}

func (c *Client) CreateFineTuningRequest(ctx context.Context, req FineTuningRequest) (*FineTuningResponse, error) {
endpoint := "/fine_tuning/jobs"

reqBytes, err := json.Marshal(req)
if err != nil {
return nil, err
}

httpReq, err := http.NewRequest("POST", c.config.BaseURL+endpoint, bytes.NewBuffer(reqBytes))
if err != nil {
return nil, err
}
httpReq = httpReq.WithContext(ctx)

res, err := c.sendRequest(ctx, httpReq)
if err != nil {
return nil, err
}
defer res.Body.Close()

var response FineTuningResponse
if err := json.NewDecoder(res.Body).Decode(&response); err != nil {
return nil, err
}

return &response, nil
}

func (c *Client) ListFineTuningJobs(ctx context.Context, after *string, limit *int) (*FineTuningList, error) {
endpoint := "/fine_tuning/jobs"

queryParams := map[string]string{}

if nil != after {
queryParams["after"] = *after
}

if nil != limit {
queryParams["limit"] = strconv.Itoa(*limit)
}

if len(queryParams) > 0 {
values := url.Values{}
for key, value := range queryParams {
values.Add(key, value)
}

endpoint = endpoint + "?" + values.Encode()
}

httpReq, err := http.NewRequest("GET", c.config.BaseURL+endpoint, nil)
if err != nil {
return nil, err
}
httpReq = httpReq.WithContext(ctx)

res, err := c.sendRequest(ctx, httpReq)
if err != nil {
return nil, err
}
defer res.Body.Close()

var fineTuningList FineTuningList
if err := json.NewDecoder(res.Body).Decode(&fineTuningList); err != nil {
return nil, err
}

return &fineTuningList, nil
}

func (c *Client) RetrieveFineTuningJob(ctx context.Context, fineTuningJobId string) (*FineTuningJob, error) {
endpoint := "/fine_tuning/jobs/" + fineTuningJobId

httpReq, err := http.NewRequest("GET", c.config.BaseURL+endpoint, nil)
if err != nil {
return nil, err
}
httpReq = httpReq.WithContext(ctx)

res, err := c.sendRequest(ctx, httpReq)
if err != nil {
return nil, err
}
defer res.Body.Close()

var job FineTuningJob
if err := json.NewDecoder(res.Body).Decode(&job); err != nil {
return nil, err
}

return &job, nil
}

func (c *Client) CancelFineTuningJob(ctx context.Context, fineTuningJobId string) (*FineTuningJob, error) {
endpoint := "/fine_tuning/jobs/" + fineTuningJobId + "/cancel"

httpReq, err := http.NewRequest("POST", c.config.BaseURL+endpoint, nil)
if err != nil {
return nil, err
}
httpReq = httpReq.WithContext(ctx)

res, err := c.sendRequest(ctx, httpReq)
if err != nil {
return nil, err
}
defer res.Body.Close()

var job FineTuningJob
if err := json.NewDecoder(res.Body).Decode(&job); err != nil {
return nil, err
}

return &job, nil
}

func (c *Client) ListFineTuningEvents(ctx context.Context, fineTuningJobId string, after *string, limit *int) (*FineTuningList, error) {
endpoint := "/fine_tuning/jobs/" + fineTuningJobId + "/events"

queryParams := map[string]string{}

if nil != after {
queryParams["after"] = *after
}

if nil != limit {
queryParams["limit"] = strconv.Itoa(*limit)
}

if len(queryParams) > 0 {
values := url.Values{}
for key, value := range queryParams {
values.Add(key, value)
}

endpoint = endpoint + "?" + values.Encode()
}

httpReq, err := http.NewRequest("GET", c.config.BaseURL+endpoint, nil)
if err != nil {
return nil, err
}
httpReq = httpReq.WithContext(ctx)

res, err := c.sendRequest(ctx, httpReq)
if err != nil {
return nil, err
}
defer res.Body.Close()

var fineTuningList FineTuningList
if err := json.NewDecoder(res.Body).Decode(&fineTuningList); err != nil {
return nil, err
}

return &fineTuningList, nil
}