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"` +}