Skip to content

Commit

Permalink
Merge pull request #2 from skyscrapr/f-projects
Browse files Browse the repository at this point in the history
F projects
  • Loading branch information
skyscrapr authored Aug 24, 2024
2 parents 49a5f03 + 4e8018c commit 0104509
Show file tree
Hide file tree
Showing 7 changed files with 187 additions and 6 deletions.
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

0 comments on commit 0104509

Please sign in to comment.