From e404ef17ebbba6c0826b1c086c0cbe02e993dede Mon Sep 17 00:00:00 2001 From: Dmitrii Limonov Date: Mon, 10 Jun 2024 00:01:56 +0300 Subject: [PATCH] initial commit --- .gitignore | 17 + LICENSE | 21 + api.go | 334 ++++++++++++++ assistants.go | 19 + chat.go | 33 ++ client.go | 101 +++++ common.go | 71 +++ examples/assistant_run/main.go | 38 ++ examples/chat_completion/main.go | 42 ++ examples/image_gen/main.go | 35 ++ files.go | 1 + go.mod | 3 + images.go | 52 +++ messages.go | 40 ++ model.go | 13 + openapi/spec.yaml | 744 +++++++++++++++++++++++++++++++ run.go | 7 + threads.go | 12 + 18 files changed, 1583 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 api.go create mode 100644 assistants.go create mode 100644 chat.go create mode 100644 client.go create mode 100644 common.go create mode 100644 examples/assistant_run/main.go create mode 100644 examples/chat_completion/main.go create mode 100644 examples/image_gen/main.go create mode 100644 files.go create mode 100644 go.mod create mode 100644 images.go create mode 100644 messages.go create mode 100644 model.go create mode 100644 openapi/spec.yaml create mode 100644 run.go create mode 100644 threads.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..34d983a --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +.idea/ +.vscode/* + +# System Files +.DS_Store +Thumbs.db + +# Test binary, built with `go test -c` +*.test + +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a62e340 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Rovergulf Engineers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/api.go b/api.go new file mode 100644 index 0000000..539b3d0 --- /dev/null +++ b/api.go @@ -0,0 +1,334 @@ +package openai + +import ( + "context" + "fmt" + "net/http" +) + +const ( + modelsUrl = "/v1/models" +) + +// ChatCompletion ... +func (c *client) ChatCompletion(ctx context.Context, req *CompletionRequest) (*CompletionResponse, error) { + var result CompletionResponse + + if err := c.makeRequest( + ctx, + http.MethodPost, + chatCompletionUrl, + nil, + req, + &result, + ); err != nil { + return nil, err + } + + return &result, nil +} + +// Models ... +func (c *client) Models(ctx context.Context) (*ModelResponse, error) { + var result ModelResponse + + if err := c.makeRequest( + ctx, + http.MethodGet, + modelsUrl, + nil, + nil, + &result, + ); err != nil { + return nil, err + } + + return &result, nil +} + +func (c *client) ImageGeneration(ctx context.Context, req *ImageGenRequest) (*ImageGenResponse, error) { + var result ImageGenResponse + + if err := c.makeRequest( + ctx, + http.MethodPost, + imageGenUrl, + nil, + req, + &result, + ); err != nil { + return nil, err + } + + return &result, nil +} + +func (c *client) CreateAssistant(ctx context.Context, req *Assistant) (*Assistant, error) { + var result Assistant + + headers := http.Header{} + headers.Add("OpenAI-Beta", "assistants=v2") + + if err := c.makeRequest( + ctx, + http.MethodPost, + assistantUrl, + headers, + req, + &result, + ); err != nil { + return nil, err + } + + return &result, nil +} + +func (c *client) ListAssistants(ctx context.Context, req *ListRequestParams) (*ListResponse[*Assistant], error) { + var result *ListResponse[*Assistant] + + headers := http.Header{} + headers.Add("OpenAI-Beta", "assistants=v2") + + query := req.ToUrlValues() + + if err := c.makeRequest( + ctx, + http.MethodGet, + assistantUrl+"?"+query.Encode(), + headers, + req, + &result, + ); err != nil { + return nil, err + } + + return result, nil +} + +func (c *client) RetrieveAssistant(ctx context.Context, id string) (*Assistant, error) { + var result Assistant + + headers := http.Header{} + headers.Add("OpenAI-Beta", "assistants=v2") + + requestUrl := fmt.Sprintf(assistantUrlFmt, id) + if err := c.makeRequest( + ctx, + http.MethodGet, + requestUrl, + headers, + nil, + &result, + ); err != nil { + return nil, err + } + + return &result, nil +} + +func (c *client) ModifyAssistant(ctx context.Context, id string, data *Assistant) (*Assistant, error) { + var result Assistant + + headers := http.Header{} + headers.Add("OpenAI-Beta", "assistants=v2") + + requestUrl := fmt.Sprintf(assistantUrlFmt, id) + if err := c.makeRequest( + ctx, + http.MethodPost, + requestUrl, + headers, + data, + &result, + ); err != nil { + return nil, err + } + + return &result, nil +} + +func (c *client) DeleteAssistant(ctx context.Context, id string) (*DeleteResponse, error) { + requestUrl := fmt.Sprintf(assistantUrlFmt, id) + + return c.deleteEntity(ctx, requestUrl) +} + +func (c *client) CreateThread(ctx context.Context) (*Thread, error) { + var result Thread + + headers := http.Header{} + headers.Add("OpenAI-Beta", "assistants=v2") + + if err := c.makeRequest( + ctx, + http.MethodPost, + threadUrl, + headers, + nil, + &result, + ); err != nil { + return nil, err + } + + return &result, nil +} + +func (c *client) RetrieveThread(ctx context.Context, id string) (*Thread, error) { + var result Thread + + headers := http.Header{} + headers.Add("OpenAI-Beta", "assistants=v2") + + requestUrl := fmt.Sprintf(threadUrlFmt, id) + if err := c.makeRequest( + ctx, + http.MethodGet, + requestUrl, + headers, + nil, + &result, + ); err != nil { + return nil, err + } + + return &result, nil +} + +func (c *client) ModifyThread(ctx context.Context, id string, data *Thread) (*Thread, error) { + var result Thread + + headers := http.Header{} + headers.Add("OpenAI-Beta", "assistants=v2") + + requestUrl := fmt.Sprintf(threadUrlFmt, id) + if err := c.makeRequest( + ctx, + http.MethodPost, + requestUrl, + headers, + data, + &result, + ); err != nil { + return nil, err + } + + return &result, nil +} + +func (c *client) DeleteThread(ctx context.Context, id string) (*DeleteResponse, error) { + requestUrl := fmt.Sprintf(threadUrlFmt, id) + + return c.deleteEntity(ctx, requestUrl) +} + +func (c *client) deleteEntity(ctx context.Context, requestUrl string) (*DeleteResponse, error) { + var result DeleteResponse + + headers := http.Header{} + headers.Add("OpenAI-Beta", "assistants=v2") + + if err := c.makeRequest( + ctx, + http.MethodDelete, + requestUrl, + headers, + nil, + &result, + ); err != nil { + return nil, err + } + + return &result, nil +} + +func (c *client) CreateMessage(ctx context.Context, threadId string, req *CompletionMessage) (*Message, error) { + var result Message + + headers := http.Header{} + headers.Add("OpenAI-Beta", "assistants=v2") + + requestUrl := fmt.Sprintf(messagesUrlFmt, threadId) + if err := c.makeRequest( + ctx, + http.MethodPost, + requestUrl, + headers, + req, + &result, + ); err != nil { + return nil, err + } + + return &result, nil +} + +func (c *client) ListMessages(ctx context.Context, threadId string, req *MessagesRequest) (*ListResponse[*Message], error) { + var result ListResponse[*Message] + + headers := http.Header{} + headers.Add("OpenAI-Beta", "assistants=v2") + + query := req.ToUrlValues() + + requestUrl := fmt.Sprintf(messagesUrlFmt, threadId) + if err := c.makeRequest( + ctx, + http.MethodGet, + requestUrl+"?"+query.Encode(), + headers, + nil, + &result, + ); err != nil { + return nil, err + } + + return &result, nil +} + +func (c *client) RetrieveMessage(ctx context.Context, threadId, messageId string) (*Message, error) { + var result Message + + headers := http.Header{} + headers.Add("OpenAI-Beta", "assistants=v2") + + requestUrl := fmt.Sprintf(messageUrlFmt, threadId, messageId) + if err := c.makeRequest( + ctx, + http.MethodGet, + requestUrl, + headers, + nil, + &result, + ); err != nil { + return nil, err + } + + return &result, nil +} + +func (c *client) ModifyMessage(ctx context.Context, threadId, messageId string, data *Message) (*Message, error) { + var result Message + + headers := http.Header{} + headers.Add("OpenAI-Beta", "assistants=v2") + + requestUrl := fmt.Sprintf(messageUrlFmt, threadId, messageId) + if err := c.makeRequest( + ctx, + http.MethodPost, + requestUrl, + headers, + data, + &result, + ); err != nil { + return nil, err + } + + return &result, nil +} + +func (c *client) DeleteMessage(ctx context.Context, threadId, messageId string) (*DeleteResponse, error) { + requestUrl := fmt.Sprintf(messageUrlFmt, threadId, messageId) + + return c.deleteEntity(ctx, requestUrl) +} diff --git a/assistants.go b/assistants.go new file mode 100644 index 0000000..9216433 --- /dev/null +++ b/assistants.go @@ -0,0 +1,19 @@ +package openai + +const ( + assistantsUrl = "/v1/assistants" + assistantUrl = "/v1/assistants/%s" +) + +type Assistant struct { + Id string `json:"id"` + Object string `json:"object"` + Model string `json:"model"` + Name string `json:"name"` + Description string `json:"description"` + Instructions string `json:"instructions"` + Tools []Tool `json:"tools"` + Temperature float32 `json:"temperature"` + TopP float32 `json:"top_p"` + ResponseFormat string `json:"response_format"` +} diff --git a/chat.go b/chat.go new file mode 100644 index 0000000..ba298a4 --- /dev/null +++ b/chat.go @@ -0,0 +1,33 @@ +package openai + +const ( + chatCompletionUrl = "/v1/chat/completions" +) + +type CompletionMessage struct { + Role string `json:"role"` + Content string `json:"content"` +} + +type CompletionRequest struct { + Model string `json:"model"` + Messages []*CompletionMessage `json:"messages"` + Seed int64 `json:"seed,omitempty"` + Temperature float32 `json:"temperature,omitempty"` +} + +type CompletionResponse struct { + Id string `json:"id"` + Object string `json:"object"` + CreatedAt int64 `json:"created"` + Model string `json:"model"` + Choices []*Choice `json:"choices"` + Usage *Usage `json:"usage"` + SystemFingerprint string `json:"system_fingerprint"` +} + +type Choice struct { + Index int `json:"index"` + Message *CompletionMessage `json:"message"` + Finish string `json:"finish_reason"` +} diff --git a/client.go b/client.go new file mode 100644 index 0000000..7521e3b --- /dev/null +++ b/client.go @@ -0,0 +1,101 @@ +package openai + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "net/http" + "reflect" + "time" +) + +const ( + apiUrl = "https://api.openai.com" +) + +type Client interface { + Models(ctx context.Context) (*ModelResponse, error) + + ChatCompletion(ctx context.Context, req *CompletionRequest) (*CompletionResponse, error) + + ImageGeneration(ctx context.Context, req *ImageGenRequest) (*ImageGenResponse, error) + + ListAssistants(ctx context.Context, req *ListRequestParams) (*ListResponse[*Assistant], error) + CreateAssistant(ctx context.Context, req *Assistant) (*Assistant, error) + RetrieveAssistant(ctx context.Context, id string) (*Assistant, error) + ModifyAssistant(ctx context.Context, id string, data *Assistant) (*Assistant, error) + DeleteAssistant(ctx context.Context, id string) (*DeleteResponse, error) + + CreateThread(ctx context.Context) (*Thread, error) + RetrieveThread(ctx context.Context, id string) (*Thread, error) + ModifyThread(ctx context.Context, id string, thread *Thread) (*Thread, error) + DeleteThread(ctx context.Context, id string) (*DeleteResponse, error) + + ListMessages(ctx context.Context, threadId string, req *MessagesRequest) (*ListResponse[*Message], error) + CreateMessage(ctx context.Context, threadId string, req *CompletionMessage) (*Message, error) + RetrieveMessage(ctx context.Context, threadId, messageId string) (*Message, error) + ModifyMessage(ctx context.Context, threadId, messageId string, data *Message) (*Message, error) + DeleteMessage(ctx context.Context, threadId, messageId string) (*DeleteResponse, error) +} + +type client struct { + apiKey string + client *http.Client +} + +func NewClient(apikey string) Client { + return &client{ + apiKey: apikey, + client: &http.Client{Timeout: 25 * time.Second}, + } +} + +func (c *client) makeRequest(ctx context.Context, method, url string, headers http.Header, body any, result any) error { + if result != nil && reflect.ValueOf(result).Kind() != reflect.Ptr { + return fmt.Errorf("result must be a pointer") + } + var payload *bytes.Buffer + if body != nil { + payload = new(bytes.Buffer) + encoder := json.NewEncoder(payload) + if err := encoder.Encode(body); err != nil { + return err + } + } + + requestUrl := fmt.Sprintf("%s%s", apiUrl, url) + req, err := http.NewRequestWithContext(ctx, method, requestUrl, payload) + if err != nil { + return err + } + req.Header.Add("Content-Type", "application/json") + req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", c.apiKey)) + + for k, v := range headers { + req.Header.Add(k, v[0]) + } + + res, err := c.client.Do(req) + if err != nil { + return err + } + defer res.Body.Close() + + if res.StatusCode != http.StatusOK { + var openAIErr ErrorResponse + decoder := json.NewDecoder(res.Body) + if err := decoder.Decode(&openAIErr); err != nil { + return fmt.Errorf("unexpected status code: %d", res.StatusCode) + } + + return &openAIErr + } + + decoder := json.NewDecoder(res.Body) + if err := decoder.Decode(result); err != nil { + return err + } + + return nil +} diff --git a/common.go b/common.go new file mode 100644 index 0000000..158a30e --- /dev/null +++ b/common.go @@ -0,0 +1,71 @@ +package openai + +import "fmt" + +const ( + ChatGPT35Turbo = "gpt-3.5-turbo" + ChatGPT4o = "gpt-4o" + ChatGPT4Turbo = "gpt-4-turbo" +) + +const ( + SystemRole = "system" + UserRole = "user" + AssistantRole = "assistant" + FunctionRole = "function" + ToolRole = "tool" +) + +const ( + defaultTemperature = 1 +) + +const ( + DefaultSystemTask = "You're a helpful assistant." +) + +type ErrorResponse struct { + Data Err `json:"error"` +} + +type Err struct { + Message string `json:"message"` + Type string `json:"type"` + Param any `json:"param"` + Code string `json:"code"` +} + +func (e ErrorResponse) Error() string { + return fmt.Sprintf("[%s] %s", e.Data.Code, e.Data.Message) +} + +type Usage struct { + PromptTokens int64 `json:"prompt_tokens"` + CompletionTokens int64 `json:"completion_tokens"` + TotalTokens int64 `json:"total_tokens"` +} + +type Tool struct { + Type string `json:"type"` +} + +type ListRequestParams struct { + Limit int `json:"limit"` // defaults to 20 + Order string `json:"order"` + After string `json:"after"` + Before string `json:"before"` +} + +type ListResponse[T any] struct { + Object string `json:"object"` + Data []T `json:"data"` + FirstId string `json:"first_id"` + LastId string `json:"last_id"` + HasMore bool `json:"has_more"` +} + +type DeleteResponse struct { + Id string `json:"id"` + Object string `json:"object"` + Deleted bool `json:"deleted"` +} diff --git a/examples/assistant_run/main.go b/examples/assistant_run/main.go new file mode 100644 index 0000000..eb665ef --- /dev/null +++ b/examples/assistant_run/main.go @@ -0,0 +1,38 @@ +package main + +import ( + "context" + "flag" + "github.com/rovergulf/openai" + "log" + "os" +) + +func main() { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + apiKey := os.Getenv("OPENAI_API_KEY") + + var assistantId, threadId string + + flag.StringVar(&assistantId, "assistant-id", "", "") + flag.StringVar(&threadId, "thread-id", "", "") + flag.Parse() + + client := openai.NewClient(apiKey) + + assistant, err := client.RetrieveAssistant(ctx, assistantId) + if err != nil { + log.Fatal(err) + } + + log.Println(assistant) + + thread, err := client.RetrieveThread(ctx, threadId) + if err != nil { + log.Fatal(err) + } + + log.Println(thread) +} diff --git a/examples/chat_completion/main.go b/examples/chat_completion/main.go new file mode 100644 index 0000000..8249f22 --- /dev/null +++ b/examples/chat_completion/main.go @@ -0,0 +1,42 @@ +package main + +import ( + "context" + "fmt" + "github.com/rovergulf/openai" + "log" + "os" +) + +// https://platform.openai.com/docs/api-reference/chat/create +func main() { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + apiKey := os.Getenv("OPENAI_API_KEY") + + client := openai.NewClient(apiKey) + + req := &openai.CompletionRequest{ + Model: openai.ChatGPT4o, + Messages: []*openai.CompletionMessage{ + { + Role: openai.SystemRole, + Content: openai.DefaultSystemTask, + }, + { + Role: openai.UserRole, + Content: "Hello there! Who was the father of Luke Skywalker?", + }, + }, + } + + completionResult, err := client.ChatCompletion(ctx, req) + if err != nil { + log.Fatal(err) + } + + contents := completionResult.Choices[0].Message.Content + + fmt.Println(contents) +} diff --git a/examples/image_gen/main.go b/examples/image_gen/main.go new file mode 100644 index 0000000..de52a3b --- /dev/null +++ b/examples/image_gen/main.go @@ -0,0 +1,35 @@ +package main + +import ( + "context" + "fmt" + "github.com/rovergulf/openai" + "log" + "os" +) + +// https://platform.openai.com/docs/api-reference/images/create +func main() { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + apiKey := os.Getenv("OPENAI_API_KEY") + + client := openai.NewClient(apiKey) + + req := &openai.ImageGenRequest{ + Model: openai.Dalle3, + Prompt: "Draw a monkey with banana and fruits", + Size: openai.Size1024x1024, + Amount: 1, + Style: openai.NaturalStyle, + //ResponseFormat: "base64", // json + } + + imageGenResponse, err := client.ImageGeneration(ctx, req) + if err != nil { + log.Fatal(err) + } + + fmt.Println(imageGenResponse.Data[0].Url) +} diff --git a/files.go b/files.go new file mode 100644 index 0000000..0aac709 --- /dev/null +++ b/files.go @@ -0,0 +1 @@ +package openai diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..027819c --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/rovergulf/openai + +go 1.22.3 diff --git a/images.go b/images.go new file mode 100644 index 0000000..71cba69 --- /dev/null +++ b/images.go @@ -0,0 +1,52 @@ +package openai + +import "os" + +const ( + Dalle2 = "dall-e-2" + Dalle3 = "dall-e-3" + + Size1024x1024 = "1024x1024" + Size1792x1024 = "1792x1024" + Size1024x1792 = "1024x1792" + + VividStyle = "vivid" + NaturalStyle = "natural" +) + +const ( + imageGenUrl = "/v1/images/generations" + imageEditUrl = "/v1/images/edit" + imageVariationsUrl = "/v1/images/variations" + audioSpeechUrl = "/v1/audio/speech" +) + +type ImageGenRequest struct { + Model string `json:"model"` + Prompt string `json:"prompt"` + Size string `json:"size"` + Amount int64 `json:"n,omitempty"` + Style string `json:"style,omitempty"` + //ResponseFormat string `json:"response_format,omitempty"` +} + +type ImageGenResponse struct { + CreatedAt int64 `json:"created"` + Data []*ImageGenDataItem `json:"data"` +} + +type ImageGenDataItem struct { + Url string `json:"url"` + RevisedPrompt string `json:"revised_prompt"` + B64Json string `json:"b64_json"` +} + +type ImageEditRequest struct { + Image os.File `json:"image"` + Mask os.File `json:"mask"` + Model string `json:"model"` + Prompt string `json:"prompt"` + Amount int64 `json:"n"` +} + +type ImageVariationRequest struct{} diff --git a/messages.go b/messages.go new file mode 100644 index 0000000..17055c5 --- /dev/null +++ b/messages.go @@ -0,0 +1,40 @@ +package openai + +const ( + messagesUrlFmt = "/v1/threads/%s/messages" + messageUrlFmt = "/v1/threads/%s/messages/%s" +) + +type MessagesRequest struct { + Limit int `json:"limit"` // defaults to 20 + Order string `json:"order"` + After string `json:"after"` + Before string `json:"before"` + RunId string `json:"run_id"` +} + +type MessageAttachment struct { + FileId string `json:"file_id"` + Tools []Tool `json:"tools,omitempty"` +} + +type MessageContent struct { + Type string `json:"type"` + Text MessageText `json:"text"` +} + +type MessageText struct { + Value string `json:"value"` + Annotations []any `json:"annotations"` +} + +type Message struct { + Id string `json:"id"` + Object string `json:"object"` + CreatedAt int `json:"created_at"` + AssistantId string `json:"assistant_id"` + ThreadId string `json:"thread_id"` + RunId string `json:"run_id"` + Role string `json:"role"` + Content []MessageContent `json:"content"` +} diff --git a/model.go b/model.go new file mode 100644 index 0000000..d347e87 --- /dev/null +++ b/model.go @@ -0,0 +1,13 @@ +package openai + +type ModelResponse struct { + Object string `json:"object"` + Data []*Model `json:"data"` +} + +type Model struct { + Id string `json:"id"` + Object string `json:"object"` + CreatedAt int64 `json:"created"` + OwnedBy string `json:"owned_by"` +} diff --git a/openapi/spec.yaml b/openapi/spec.yaml new file mode 100644 index 0000000..54898e4 --- /dev/null +++ b/openapi/spec.yaml @@ -0,0 +1,744 @@ +openapi: 3.0.0 +info: + description: OpenAI API based on documentation + version: "0.0.1" + title: OpenAI API + termsOfService: 'None' + contact: + email: dev@rovergulf.net + license: + name: Unlicensed +servers: + - description: OpenAI API official server + url: https://api.openai.com +tags: + - name: models + - name: chat-gpt + description: Chat GPT operations + - name: dalle + description: DALL-E operations + - name: assistants + description: Assistants operations + - name: threads + description: Threads operations + - name: messages + description: Messages operations +externalDocs: + description: Example description + url: '' +paths: + /v1/models: + get: + tags: + - models + summary: Get models + operationId: getModels + security: + - BearerAuth: [ ] + responses: + '200': + description: Successful result + content: + application/json: + schema: + $ref: '#/components/schemas/ModelsResponse' + '400': + description: Invalid body parameters specified + /v1/chat/completions: + post: + tags: + - chat-gpt + summary: Create completion + operationId: createCompletion + security: + - BearerAuth: [ ] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CompletionRequest' + responses: + '200': + description: Successful result + content: + application/json: + schema: + $ref: '#/components/schemas/CompletionResponse' + '400': + description: Invalid body parameters specified + /v1/images/generations: + post: + tags: + - dalle + summary: Generate image + operationId: genImage + security: + - BearerAuth: [ ] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ImageGenRequest' + responses: + '200': + description: Successful result + content: + application/json: + schema: + $ref: '#/components/schemas/ImageGenResponse' + '400': + description: Invalid body parameters specified + /v1/assistants: + post: + tags: + - assistants + summary: Create assistant + operationId: createAssistant + security: + - BearerAuth: [ ] + parameters: + - in: header + name: OpenAI-Beta + example: assistants=v2 + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Assistant' + responses: + '200': + description: Successful result + content: + application/json: + schema: + $ref: '#/components/schemas/Assistant' + '400': + description: Invalid body parameters specified + get: + tags: + - assistants + summary: List assistant + operationId: listAssistants + security: + - BearerAuth: [ ] + parameters: + - in: header + name: OpenAI-Beta + example: assistants=v2 + schema: + type: string + - in: query + name: limit + schema: + type: number + default: 20 + - in: query + name: after + schema: + type: string + - in: query + name: before + schema: + type: string + - in: query + name: order + schema: + type: string + default: 'DESC' + responses: + '200': + description: Successful result + content: + application/json: + schema: + $ref: '#/components/schemas/ListAssistantsResponse' + /v1/assistants/{id}: + post: + tags: + - assistants + summary: Modify assistant + operationId: modifyAssistant + security: + - BearerAuth: [ ] + parameters: + - in: header + name: OpenAI-Beta + example: assistants=v2 + schema: + type: string + - in: path + name: id + schema: + type: string + required: true + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Assistant' + responses: + '200': + description: Successful result + content: + application/json: + schema: + $ref: '#/components/schemas/Assistant' + '400': + description: Invalid body parameters specified + get: + tags: + - assistants + summary: Retrieve assistant + operationId: retrieveAssistant + security: + - BearerAuth: [ ] + parameters: + - in: header + name: OpenAI-Beta + example: assistants=v2 + schema: + type: string + - in: path + name: id + schema: + type: string + required: true + responses: + '200': + description: Successful result + content: + application/json: + schema: + $ref: '#/components/schemas/Assistant' + delete: + tags: + - assistants + summary: Delete assistant + operationId: deleteAssistant + security: + - BearerAuth: [ ] + parameters: + - in: header + name: OpenAI-Beta + example: assistants=v2 + schema: + type: string + - in: path + name: id + schema: + type: string + required: true + responses: + '200': + description: Successful result + content: + application/json: + schema: + $ref: '#/components/schemas/DeleteResponse' + /v1/threads: + post: + tags: + - threads + summary: Create thread + operationId: createThread + security: + - BearerAuth: [ ] + parameters: + - in: header + name: OpenAI-Beta + example: assistants=v2 + schema: + type: string + responses: + '200': + description: Successful result + content: + application/json: + schema: + $ref: '#/components/schemas/Thread' + '400': + description: Invalid body parameters specified + /v1/threads/{threadId}: + post: + tags: + - threads + summary: Modify thread + operationId: modifyThread + security: + - BearerAuth: [ ] + parameters: + - in: header + name: OpenAI-Beta + example: assistants=v2 + schema: + type: string + - in: path + name: threadId + schema: + type: string + required: true + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Thread' + responses: + '200': + description: Successful result + content: + application/json: + schema: + $ref: '#/components/schemas/Thread' + '400': + description: Invalid body parameters specified + get: + tags: + - threads + summary: Retrieve thread + operationId: retrieveThread + security: + - BearerAuth: [ ] + parameters: + - in: header + name: OpenAI-Beta + example: assistants=v2 + schema: + type: string + - in: path + name: threadId + schema: + type: string + required: true + responses: + '200': + description: Successful result + content: + application/json: + schema: + $ref: '#/components/schemas/Assistant' + delete: + tags: + - threads + summary: Delete thread + operationId: deleteThread + security: + - BearerAuth: [ ] + parameters: + - in: header + name: OpenAI-Beta + example: assistants=v2 + schema: + type: string + - in: path + name: id + schema: + type: string + required: true + responses: + '200': + description: Successful result + content: + application/json: + schema: + $ref: '#/components/schemas/DeleteResponse' + /v1/threads/{threadId}/messages: + post: + tags: + - messages + summary: Create message + operationId: createMessage + security: + - BearerAuth: [ ] + parameters: + - in: header + name: OpenAI-Beta + example: assistants=v2 + schema: + type: string + - in: path + name: threadId + schema: + type: string + required: true + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CompletionMessage' + responses: + '200': + description: Successful result + content: + application/json: + schema: + $ref: '#/components/schemas/Message' + '400': + description: Invalid body parameters specified + get: + tags: + - messages + summary: List messages + operationId: listMessages + security: + - BearerAuth: [ ] + parameters: + - in: header + name: OpenAI-Beta + example: assistants=v2 + schema: + type: string + - in: path + name: threadId + schema: + type: string + required: true + - in: query + name: limit + schema: + type: number + default: 20 + - in: query + name: after + schema: + type: string + - in: query + name: before + schema: + type: string + - in: query + name: order + schema: + type: string + default: 'DESC' + - in: query + name: run_id + schema: + type: string + responses: + '200': + description: Successful result + content: + application/json: + schema: + $ref: '#/components/schemas/ListMessagesResponse' + /v1/threads/{threadId}/messages/{messageId}: + post: + tags: + - messages + summary: Modify message + operationId: modifyMessage + security: + - BearerAuth: [ ] + parameters: + - in: header + name: OpenAI-Beta + example: assistants=v2 + schema: + type: string + - in: path + name: threadId + schema: + type: string + required: true + - in: path + name: messageId + schema: + type: string + required: true + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Message' + responses: + '200': + description: Successful result + content: + application/json: + schema: + $ref: '#/components/schemas/Message' + '400': + description: Invalid body parameters specified + get: + tags: + - messages + summary: Retrieve message + operationId: retrieveMessage + security: + - BearerAuth: [ ] + parameters: + - in: header + name: OpenAI-Beta + example: assistants=v2 + schema: + type: string + - in: path + name: threadId + schema: + type: string + - in: path + name: messageId + schema: + type: string + required: true + responses: + '200': + description: Successful result + content: + application/json: + schema: + $ref: '#/components/schemas/Message' + delete: + tags: + - messages + summary: Delete message + operationId: deleteMessage + security: + - BearerAuth: [ ] + parameters: + - in: header + name: OpenAI-Beta + example: assistants=v2 + schema: + type: string + - in: path + name: threadId + schema: + type: string + - in: path + name: messageId + schema: + type: string + required: true + responses: + '200': + description: Successful result + content: + application/json: + schema: + $ref: '#/components/schemas/DeleteResponse' +components: + securitySchemes: + BearerAuth: + type: http + scheme: bearer + name: Authorization + in: header + schemas: + CompletionMessage: + type: object + properties: + role: + type: string + content: + type: string + CompletionRequest: + type: object + properties: + model: + type: string + example: "gpt-4o" + messages: + type: array + items: + $ref: '#/components/schemas/CompletionMessage' + CompletionResponse: + type: object + properties: + data: + type: object + ModelsResponse: + type: object + properties: + object: + type: string + data: + type: array + items: + $ref: '#/components/schemas/Model' + Model: + type: object + properties: + id: + type: string + object: + type: string + ownedBy: + type: string + created: + type: number + ImageGenRequest: + type: object + properties: + model: + type: string + example: dall-e-3 + prompt: + type: string + size: + type: string + example: 1024x1024 + n: + type: number + example: 1 + ImageGenItem: + type: object + properties: + revised_prompt: + type: number + url: + type: string + b64_json: + type: string + ImageGenResponse: + type: object + properties: + created: + type: number + format: int64 + data: + type: array + items: + $ref: '#/components/schemas/ImageGenItem' + Tool: + type: object + properties: + type: + type: string + description: 'code_interpreter or file_search' + Assistant: + type: object + properties: + id: + type: string + object: + type: string + model: + type: string + name: + type: string + description: + type: string + instructions: + type: string + tools: + type: array + items: + $ref: '#/components/schemas/Tool' + temperature: + type: number + minimum: 0 + maximum: 2 + format: float32 + top_p: + type: number + minimum: 0 + maximum: 2 + format: float32 + response_format: + type: string + required: + - model + - name + - instructions + ListAssistantsResponse: + type: object + properties: + object: + type: string + data: + type: array + items: + $ref: '#/components/schemas/Assistant' + first_id: + type: string + last_id: + type: string + has_more: + type: boolean + CreateMessageRequest: + type: object + properties: + role: + type: string + content: + type: string + MessageText: + type: object + properties: + value: + type: string + annotations: + type: array + MessageContent: + type: object + properties: + type: + type: string + text: + $ref: '#/components/schemas/MessageText' + image_url: + type: string + image_file: + type: string + Message: + type: object + properties: + role: + type: string + thread_id: + type: string + content: + $ref: '#/components/schemas/MessageContent' + created_at: + type: number + assistant_id: + type: string + run_id: + type: string + ListMessagesResponse: + type: object + properties: + object: + type: string + data: + type: array + items: + $ref: '#/components/schemas/Message' + first_id: + type: string + last_id: + type: string + has_more: + type: boolean + Thread: + type: object + properties: + id: + type: string + object: + type: string + messages: + type: array + items: + $ref: '#/components/schemas/Message' + DeleteResponse: + type: object + properties: + id: + type: string + object: + type: string + deleted: + type: boolean + Run: + type: object + properties: + assistant_id: + type: string + thread_id: + type: string + required: + - assistant_id diff --git a/run.go b/run.go new file mode 100644 index 0000000..4e8840d --- /dev/null +++ b/run.go @@ -0,0 +1,7 @@ +package openai + +type Run struct { + Id string `json:"id"` + AssistantId string `json:"assistant_id"` + ThreadId string `json:"thread_id"` +} diff --git a/threads.go b/threads.go new file mode 100644 index 0000000..5f9136c --- /dev/null +++ b/threads.go @@ -0,0 +1,12 @@ +package openai + +const ( + threadUrl = "/v1/threads" + threadUrlFmt = "/v1/threads/%s" +) + +type Thread struct { + Id string `json:"id"` + Type string `json:"type"` + Messages []*Message `json:"messages"` +}