forked from sashabaranov/go-openai
-
Notifications
You must be signed in to change notification settings - Fork 0
/
files.go
156 lines (129 loc) · 3.32 KB
/
files.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package gogpt
import (
"bytes"
"context"
"fmt"
"io"
"mime/multipart"
"net/http"
"net/url"
"os"
"strings"
)
type FileRequest struct {
FileName string `json:"file"`
FilePath string `json:"-"`
Purpose string `json:"purpose"`
}
// File struct represents an OpenAPI file.
type File struct {
Bytes int `json:"bytes"`
CreatedAt int64 `json:"created_at"`
ID string `json:"id"`
FileName string `json:"filename"`
Object string `json:"object"`
Owner string `json:"owner"`
Purpose string `json:"purpose"`
}
// FilesList is a list of files that belong to the user or organization.
type FilesList struct {
Files []File `json:"data"`
}
// isUrl is a helper function that determines whether the given FilePath
// is a remote URL or a local file path.
func isURL(path string) bool {
_, err := url.ParseRequestURI(path)
if err != nil {
return false
}
u, err := url.Parse(path)
if err != nil || u.Scheme == "" || u.Host == "" {
return false
}
return true
}
// CreateFile uploads a jsonl file to GPT3
// FilePath can be either a local file path or a URL.
func (c *Client) CreateFile(ctx context.Context, request FileRequest) (file File, err error) {
var b bytes.Buffer
w := multipart.NewWriter(&b)
var fw, pw io.Writer
pw, err = w.CreateFormField("purpose")
if err != nil {
return
}
_, err = io.Copy(pw, strings.NewReader(request.Purpose))
if err != nil {
return
}
fw, err = w.CreateFormFile("file", request.FileName)
if err != nil {
return
}
var fileData io.ReadCloser
if isURL(request.FilePath) {
var remoteFile *http.Response
remoteFile, err = http.Get(request.FilePath)
if err != nil {
return
}
defer remoteFile.Body.Close()
// Check server response
if remoteFile.StatusCode != http.StatusOK {
err = fmt.Errorf("error, status code: %d, message: failed to fetch file", remoteFile.StatusCode)
return
}
fileData = remoteFile.Body
} else {
fileData, err = os.Open(request.FilePath)
if err != nil {
return
}
}
_, err = io.Copy(fw, fileData)
if err != nil {
return
}
w.Close()
req, err := http.NewRequest("POST", c.fullURL("/files"), &b)
if err != nil {
return
}
req = req.WithContext(ctx)
req.Header.Set("Content-Type", w.FormDataContentType())
err = c.sendRequest(req, &file)
return
}
// DeleteFile deletes an existing file.
func (c *Client) DeleteFile(ctx context.Context, fileID string) (err error) {
req, err := http.NewRequest("DELETE", c.fullURL("/files/"+fileID), nil)
if err != nil {
return
}
req = req.WithContext(ctx)
err = c.sendRequest(req, nil)
return
}
// ListFiles Lists the currently available files,
// and provides basic information about each file such as the file name and purpose.
func (c *Client) ListFiles(ctx context.Context) (files FilesList, err error) {
req, err := http.NewRequest("GET", c.fullURL("/files"), nil)
if err != nil {
return
}
req = req.WithContext(ctx)
err = c.sendRequest(req, &files)
return
}
// GetFile Retrieves a file instance, providing basic information about the file
// such as the file name and purpose.
func (c *Client) GetFile(ctx context.Context, fileID string) (file File, err error) {
urlSuffix := fmt.Sprintf("/files/%s", fileID)
req, err := http.NewRequest("GET", c.fullURL(urlSuffix), nil)
if err != nil {
return
}
req = req.WithContext(ctx)
err = c.sendRequest(req, &file)
return
}