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

F projects #2

Merged
merged 2 commits into from
Aug 24, 2024
Merged
Show file tree
Hide file tree
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
4 changes: 2 additions & 2 deletions openai/assistant.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,8 @@ type AssistantToolResources struct {

type AssistantResponseFormat struct {
StringValue string `json:"-"`
Type string `json:"type"`
JsonSchema *struct {
Type string `json:"type"`
JsonSchema *struct {
Description *string `json:"description,omitempty"`
Name string `json:"name"`
Schema map[string]interface{} `json:"schema"`
Expand Down
6 changes: 4 additions & 2 deletions openai/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ const (

// Client - OpenAI client.
type Client struct {
authToken string
authToken string
adminToken string

BaseURL *url.URL
OrganizationID string
Expand All @@ -25,10 +26,11 @@ type Client struct {
}

// NewClient creates new OpenAI client.
func NewClient(authToken string) *Client {
func NewClient(authToken string, adminToken string) *Client {
c := &Client{
HTTPClient: &http.Client{Timeout: 30 * time.Second},
authToken: authToken,
adminToken: adminToken,
UserAgent: "skyscrapr/openai-sdk-go",
}
c.BaseURL, _ = url.Parse(apiURL)
Expand Down
18 changes: 18 additions & 0 deletions openai/endpoint.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package openai

import (
"fmt"
"net/http"
"net/url"
"path"
Expand All @@ -25,6 +26,10 @@ type betaEndpoint struct {
endpoint
}

type organizationEndpoint struct {
endpoint
}

func newEndpoint(c *Client, endpointPath string) *endpoint {
e := &endpoint{
Client: c,
Expand All @@ -40,6 +45,13 @@ func newBetaEndpoint(c *Client, endpointPath string) *betaEndpoint {
return e
}

func newOrganizationEndpoint(c *Client, endpointPath string) *organizationEndpoint {
e := &organizationEndpoint{
endpoint: *newEndpoint(c, endpointPath),
}
return e
}

func (e *endpoint) buildURL(endpointPath string) (*url.URL, error) {
u, err := url.Parse(endpointPath)
if err != nil {
Expand All @@ -64,3 +76,9 @@ func (e *betaEndpoint) newRequest(method string, u *url.URL, body interface{}) (
req.Header.Set("OpenAI-Beta", "assistants=v2")
return req, err
}

func (e *organizationEndpoint) newRequest(method string, u *url.URL, body interface{}) (*http.Request, error) {
req, err := e.Client.newRequest(method, u, body)
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", e.adminToken))
return req, err
}
2 changes: 1 addition & 1 deletion openai/endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (

func TestNewEndpoint(t *testing.T) {
testEndpointPath := "testEndpointPath"
testClient := NewClient("testapikey")
testClient := NewClient("testapikey", "testadminkey")
e := newEndpoint(testClient, testEndpointPath)
if e.BaseURL.String() != testClient.BaseURL.String() {
t.Errorf("VendorsEndpoint BaseURL mismatch. Got %s. Want %s", e.BaseURL.String(), testClient.BaseURL.String())
Expand Down
90 changes: 90 additions & 0 deletions openai/projects.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package openai

import (
"fmt"
"net/url"
)

const ProjectsEndpointPath = "/organization/projects"

// ProjectsEndpoint - OpenAI Projects Endpoint
//
// List and describe the projects available.
// You can refer to the [Projects]: https://platform.openai.com/docs/api-reference/projects documentation.
type ProjectsEndpoint struct {
*organizationEndpoint
}

// Projects - Projects Endpoint
func (c *Client) Projects() *ProjectsEndpoint {
return &ProjectsEndpoint{newOrganizationEndpoint(c, ProjectsEndpointPath)}
}

// Project - OpenAPI Project.
type Project struct {
ID string `json:"id"`
Object string `json:"object"`
Name string `json:"name"`
CreatedAt int64 `json:"created_at"`
ArchivedAt int64 `json:"archived_at"`
Status string `json:"status"`
}

type Projects struct {
Object string `json:"object"`
Data []Project `json:"data"`
}

type ProjectRequest struct {
// The name of the assistant. The maximum length is 256 characters.
Name *string `json:"name"`
}

// Lists the currently available projects,
// and provides basic information about each one.
//
// [OpenAI Documentation]: https://platform.openai.com/docs/api-reference/projects/list
func (e *ProjectsEndpoint) ListProjects() ([]Project, error) {
var projects Projects
err := e.do(e, "GET", "", nil, nil, &projects)
// TODO: This needs to move somewhere central
if err == nil && projects.Object != "list" {
err = fmt.Errorf("expected 'list' object type, got %s", projects.Object)
}
return projects.Data, err
}

// Create a project.
// [OpenAI Documentation]: https://platform.openai.com/docs/api-reference/projects/create
func (e *ProjectsEndpoint) CreateProject(req *ProjectRequest) (*Project, error) {
var project Project
err := e.do(e, "POST", "", req, nil, &project)
return &project, err
}

// Retrieves a project instance,
// providing basic information about the project.
//
// [OpenAI Documentation]: https://platform.openai.com/docs/api-reference/projects/retrieve
func (e *ProjectsEndpoint) RetrieveProject(id string) (*Project, error) {
var project Project
err := e.do(e, "GET", id, nil, nil, &project)
return &project, err
}

// Modifies a project instance,
//
// [OpenAI Documentation]: https://platform.openai.com/docs/api-reference/projects/modify
func (e *ProjectsEndpoint) ModifyProject(id string, req ProjectRequest) (*Project, error) {
var project Project
err := e.do(e, "POST", id, req, nil, &project)
return &project, err
}

// Archive a project.
// [OpenAI Documentation]: https://platform.openai.com/docs/api-reference/projects/archive
func (e *ProjectsEndpoint) ArchiveProject(id string) (*Project, error) {
var project Project
err := e.do(e, "POST", url.QueryEscape(id)+"/archive", nil, nil, &project)
return &project, err
}
70 changes: 70 additions & 0 deletions openai/projects_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package openai_test

import (
"encoding/json"
"fmt"
"net/http"
"testing"

"github.com/skyscrapr/openai-sdk-go/openai"
"github.com/skyscrapr/openai-sdk-go/openai/test"
)

// TestListProjects Tests the Projects endpoint of the API using the mocked server.
func TestListProjects(t *testing.T) {
ts := openai_test.NewTestServer()
ts.RegisterHandler("/v1/organizations/projects", func(w http.ResponseWriter, _ *http.Request) {
resBytes, _ := json.Marshal(openai.Projects{Object: "list", Data: nil})
fmt.Fprintln(w, string(resBytes))
})
ts.HTTPServer.Start()
defer ts.HTTPServer.Close()

client := openai_test.NewTestClient(ts)
_, err := client.Projects().ListProjects()
t.Helper()
if err != nil {
t.Error(err, "TestListProjects error")
}
}

func TestListProjectsInvalidObject(t *testing.T) {
expectedError := "expected 'list' object type, got project"

ts := openai_test.NewTestServer()
ts.RegisterHandler("/v1/organizations/projects", func(w http.ResponseWriter, _ *http.Request) {
resBytes, _ := json.Marshal(openai.Projects{Object: "project", Data: nil})
fmt.Fprintln(w, string(resBytes))
})
ts.HTTPServer.Start()
defer ts.HTTPServer.Close()

client := openai_test.NewTestClient(ts)
_, err := client.Projects().ListProjects()
t.Helper()
if err != nil && err.Error() != expectedError {
t.Errorf("Unexpected error: %v , expected: %s", err, expectedError)
t.Fail()
}
}

func TestRetrieveProject(t *testing.T) {
testProjectID := "testProjectID"
ts := openai_test.NewTestServer()
ts.RegisterHandler("/v1/organizations/projects/testProjectID", func(w http.ResponseWriter, _ *http.Request) {
resBytes, _ := json.Marshal(openai.Project{Object: "project", ID: testProjectID})
fmt.Fprintln(w, string(resBytes))
})
ts.HTTPServer.Start()
defer ts.HTTPServer.Close()

client := openai_test.NewTestClient(ts)
project, err := client.Projects().RetrieveProject(testProjectID)
t.Helper()
if err != nil {
t.Error(err, "GetProject error")
}
if project.ID != testProjectID {
t.Errorf("ProjectsEndpoint GetProject Project ID mismatch. Got %s. Expected %s", testProjectID, project.ID)
}
}
3 changes: 2 additions & 1 deletion openai/test/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ import (
)

const test_api_key = "this-is-my-secure-apikey-do-not-steal!!"
const test_admin_key = "this-is-my-secure-adminkey-do-not-steal!!"

func GetTestAuthToken() string {
return test_api_key
}

func NewTestClient(ts *TestServer) *openai.Client {
client := openai.NewClient(test_api_key)
client := openai.NewClient(test_api_key, test_admin_key)
if ts != nil {
client.BaseURL, _ = url.Parse(ts.HTTPServer.URL)
}
Expand Down
Loading