Skip to content

Commit

Permalink
Add support for Project Users and Service Accounts
Browse files Browse the repository at this point in the history
  • Loading branch information
StefanBratanov committed Aug 26, 2024
1 parent 3c246fc commit b477db1
Show file tree
Hide file tree
Showing 12 changed files with 539 additions and 4 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,10 @@ ChatCompletion chatCompletion = chatClient.createChatCompletion(createChatComple
| API | Status |
|----------------------------------------------------------------------------------|:------:|
| [Invites](https://platform.openai.com/docs/api-reference/invite) | ✔️ |
| [Users](https://platform.openai.com/docs/api-reference/users) | ✔️ |
| [Projects](https://platform.openai.com/docs/api-reference/projects) | ✔️ |
| [Project Users](https://platform.openai.com/docs/api-reference/project-users) | |
| [Project Service Accounts](https://platform.openai.com/docs/api-reference/project-service-accounts) | |
| [Users](https://platform.openai.com/docs/api-reference/users) | ✔️ |
| [Projects](https://platform.openai.com/docs/api-reference/projects) | ✔️ |
| [Project Users](https://platform.openai.com/docs/api-reference/project-users) | ✔️ |
| [Project Service Accounts](https://platform.openai.com/docs/api-reference/project-service-accounts) | ✔️ |
| [Project API Keys](https://platform.openai.com/docs/api-reference/project-api-keys) | |
| [Audit Logs](https://platform.openai.com/docs/api-reference/audit-logs) | |

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package io.github.stefanbratanov.jvm.openai;

public record CreateProjectServiceAccountRequest(String name) {

public static Builder newBuilder() {
return new Builder();
}

public static class Builder {

private String name;

/**
* @param name The name of the service account being created.
*/
public Builder name(String name) {
this.name = name;
return this;
}

public CreateProjectServiceAccountRequest build() {
return new CreateProjectServiceAccountRequest(name);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package io.github.stefanbratanov.jvm.openai;

public record CreateProjectUserRequest(String userId, String role) {

public static Builder newBuilder() {
return new Builder();
}

public static class Builder {

private String userId;
private String role;

/**
* @param userId The ID of the user.
*/
public Builder userId(String userId) {
this.userId = userId;
return this;
}

/**
* @param role `owner` or `member`.
*/
public Builder role(String role) {
this.role = role;
return this;
}

public CreateProjectUserRequest build() {
return new CreateProjectUserRequest(userId, role);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package io.github.stefanbratanov.jvm.openai;

public record ModifyProjectUserRequest(String role) {

public static Builder newBuilder() {
return new Builder();
}

public static class Builder {

private String role;

/**
* @param role `owner` or `member`
*/
public Builder role(String role) {
this.role = role;
return this;
}

public ModifyProjectUserRequest build() {
return new ModifyProjectUserRequest(role);
}
}
}
24 changes: 24 additions & 0 deletions src/main/java/io/github/stefanbratanov/jvm/openai/OpenAI.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public final class OpenAI {
private final InvitesClient invitesClient;
private final UsersClient usersClient;
private final ProjectsClient projectsClient;
private final ProjectUsersClient projectUsersClient;
private final ProjectServiceAccountsClient projectServiceAccountsClient;

private OpenAI(
URI baseUrl,
Expand Down Expand Up @@ -79,6 +81,11 @@ private OpenAI(
usersClient = new UsersClient(baseUrl, adminAuthenticationHeaders, httpClient, requestTimeout);
projectsClient =
new ProjectsClient(baseUrl, adminAuthenticationHeaders, httpClient, requestTimeout);
projectUsersClient =
new ProjectUsersClient(baseUrl, adminAuthenticationHeaders, httpClient, requestTimeout);
projectServiceAccountsClient =
new ProjectServiceAccountsClient(
baseUrl, adminAuthenticationHeaders, httpClient, requestTimeout);
}

/**
Expand Down Expand Up @@ -252,6 +259,23 @@ public ProjectsClient projectsClient() {
return projectsClient;
}

/**
* @return a client based on <a
* href="https://platform.openai.com/docs/api-reference/project-users">Project Users</a>
*/
public ProjectUsersClient projectUsersClient() {
return projectUsersClient;
}

/**
* @return a client based on <a
* href="https://platform.openai.com/docs/api-reference/project-service-accounts">Project
* Service Accounts</a>
*/
public ProjectServiceAccountsClient projectServiceAccountsClient() {
return projectServiceAccountsClient;
}

private String[] createAuthenticationHeaders(
Optional<String> apiKey, Optional<String> organization, Optional<String> project) {
List<String> authHeaders = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package io.github.stefanbratanov.jvm.openai;

/** Represents an individual service account in a project. */
public record ProjectServiceAccount(String id, String name, String role, long createdAt) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package io.github.stefanbratanov.jvm.openai;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
* Manage service accounts within a project. A service account is a bot user that is not associated
* with a user. If a user leaves an organization, their keys and membership in projects will no
* longer work. Service accounts do not have this limitation. However, service accounts can also be
* deleted from a project.
*
* <p>Based on <a
* href="https://platform.openai.com/docs/api-reference/project-service-accounts/list">Project
* Service Accounts</a>
*/
public final class ProjectServiceAccountsClient extends OpenAIClient {

private static final String SERVICE_ACCOUNTS_SEGMENT = "/service_accounts";

private final URI baseUrl;

ProjectServiceAccountsClient(
URI baseUrl,
String[] authenticationHeaders,
HttpClient httpClient,
Optional<Duration> requestTimeout) {
super(authenticationHeaders, httpClient, requestTimeout);
this.baseUrl = baseUrl;
}

/**
* Returns a list of service accounts in the project.
*
* @param after A cursor for use in pagination. after is an object ID that defines your place in
* the list.
* @param limit A limit on the number of objects to be returned.
* @throws OpenAIException in case of API errors
*/
public PaginatedProjectServiceAccounts listProjectServiceAccounts(
String projectId, Optional<String> after, Optional<Integer> limit) {
String queryParameters =
createQueryParameters(
Map.of(Constants.LIMIT_QUERY_PARAMETER, limit, Constants.AFTER_QUERY_PARAMETER, after));
HttpRequest httpRequest =
newHttpRequestBuilder()
.uri(
baseUrl.resolve(
Endpoint.PROJECTS.getPath()
+ "/"
+ projectId
+ SERVICE_ACCOUNTS_SEGMENT
+ queryParameters))
.GET()
.build();
HttpResponse<byte[]> httpResponse = sendHttpRequest(httpRequest);
return deserializeResponse(httpResponse.body(), PaginatedProjectServiceAccounts.class);
}

public record PaginatedProjectServiceAccounts(
List<ProjectServiceAccount> data, String firstId, String lastId, boolean hasMore) {}

/**
* Creates a new service account in the project. This also returns an unredacted API key for the
* service account.
*
* @param projectId The ID of the project.
* @throws OpenAIException in case of API errors
*/
public ProjectServiceAccountCreateResponse createProjectServiceAccount(
String projectId, CreateProjectServiceAccountRequest request) {
HttpRequest httpRequest =
newHttpRequestBuilder(Constants.CONTENT_TYPE_HEADER, Constants.JSON_MEDIA_TYPE)
.uri(
baseUrl.resolve(
Endpoint.PROJECTS.getPath() + "/" + projectId + SERVICE_ACCOUNTS_SEGMENT))
.POST(createBodyPublisher(request))
.build();
HttpResponse<byte[]> httpResponse = sendHttpRequest(httpRequest);
return deserializeResponse(httpResponse.body(), ProjectServiceAccountCreateResponse.class);
}

public record ProjectServiceAccountCreateResponse(
String id, String name, String role, long createdAt, ApiKey apiKey) {}

public record ApiKey(String id, String name, String value, long createdAt) {}

/**
* Retrieves a service account in the project.
*
* @param projectId The ID of the project.
* @param serviceAccountId The ID of the service account.
* @throws OpenAIException in case of API errors
*/
public ProjectServiceAccount retrieveProjectServiceAccount(
String projectId, String serviceAccountId) {
HttpRequest httpRequest =
newHttpRequestBuilder()
.uri(
baseUrl.resolve(
Endpoint.PROJECTS.getPath()
+ "/"
+ projectId
+ SERVICE_ACCOUNTS_SEGMENT
+ "/"
+ serviceAccountId))
.GET()
.build();
HttpResponse<byte[]> httpResponse = sendHttpRequest(httpRequest);
return deserializeResponse(httpResponse.body(), ProjectServiceAccount.class);
}

/**
* Deletes a service account from the project.
*
* @param projectId The ID of the project.
* @param serviceAccountId The ID of the service account.
* @throws OpenAIException in case of API errors
*/
public DeletionStatus deleteProjectServiceAccount(String projectId, String serviceAccountId) {
HttpRequest httpRequest =
newHttpRequestBuilder()
.uri(
baseUrl.resolve(
Endpoint.PROJECTS.getPath()
+ "/"
+ projectId
+ SERVICE_ACCOUNTS_SEGMENT
+ "/"
+ serviceAccountId))
.DELETE()
.build();
HttpResponse<byte[]> httpResponse = sendHttpRequest(httpRequest);
return deserializeResponse(httpResponse.body(), DeletionStatus.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package io.github.stefanbratanov.jvm.openai;

/** Represents an individual user in a project. */
public record ProjectUser(String id, String name, String email, String role, long addedAt) {}
Loading

0 comments on commit b477db1

Please sign in to comment.