⚠️ Project Status Update: Unfortunately, I’m no longer able to actively maintain this project due to time constraints. Thank you to everyone who has contributed and supported this project. If you'd like to continue using or adapting the code, feel free to fork the repository and make any modifications that suit your needs. For those seeking a maintained alternative, openai-java is a solid option worth exploring.
A minimalistic unofficial OpenAI API client for the JVM, written in Java. The only dependency used is Jackson for JSON parsing.
jvm-openai works on Java 17+. Android support is not yet available.
implementation("io.github.stefanbratanov:jvm-openai:${version}")<dependency> <groupId>io.github.stefanbratanov</groupId> <artifactId>jvm-openai</artifactId> <version>${version}</version> </dependency>OpenAI openAI = OpenAI.newBuilder(System.getenv("OPENAI_API_KEY")).build(); ChatClient chatClient = openAI.chatClient(); CreateChatCompletionRequest createChatCompletionRequest = CreateChatCompletionRequest.newBuilder() .model(OpenAIModel.GPT_3_5_TURBO) .message(ChatMessage.userMessage("Who won the world series in 2020?")) .build(); ChatCompletion chatCompletion = chatClient.createChatCompletion(createChatCompletionRequest);| API | Status |
|---|---|
| Audio | ✔️ |
| Chat | ✔️ |
| Embeddings | ✔️ |
| Fine-tuning | ✔️ |
| Batch | ✔️ |
| Files | ✔️ |
| Uploads | ✔️ |
| Images | ✔️ |
| Models | ✔️ |
| Moderations | ✔️ |
| API | Status |
|---|---|
| Assistants | ✔️ |
| Threads | ✔️ |
| Messages | ✔️ |
| Runs | ✔️ |
| Run Steps | ✔️ |
| Vector Stores | ✔️ |
| Vector Store Files | ✔️ |
| Vector Store File Batches | ✔️ |
| API | Status |
|---|---|
| Admin API Keys | |
| Invites | ✔️ |
| Users | ✔️ |
| Projects | ✔️ |
| Project Users | ✔️ |
| Project Service Accounts | ✔️ |
| Project API Keys | ✔️ |
| Project rate limits | |
| Audit Logs | ✔️ |
| Usage |
NOTE: Realtime and Legacy APIs are not supported
- Configure an organization and project
OpenAI openAI = OpenAI.newBuilder(System.getenv("OPENAI_API_KEY")) .organization("org-zweLLamVlP6c5n66zY334ivs") .project(System.getenv("PROJECT_ID")) .build();- Configure a custom base url
OpenAI openAI = OpenAI.newBuilder(System.getenv("OPENAI_API_KEY")) .baseUrl("https://api.foobar.com/v1/") .build();- Configure a custom Java's
HttpClient
HttpClient httpClient = HttpClient.newBuilder() .connectTimeout(Duration.ofSeconds(20)) .executor(Executors.newFixedThreadPool(3)) .proxy(ProxySelector.of(new InetSocketAddress("proxy.example.com", 80))) .build(); OpenAI openAI = OpenAI.newBuilder(System.getenv("OPENAI_API_KEY")) .httpClient(httpClient) .build();- Configure a timeout for all requests
OpenAI openAI = OpenAI.newBuilder(System.getenv("OPENAI_API_KEY")) .requestTimeout(Duration.ofSeconds(10)) .build();- Create chat completion async
ChatClient chatClient = openAI.chatClient(); CreateChatCompletionRequest request = CreateChatCompletionRequest.newBuilder() .model(OpenAIModel.GPT_3_5_TURBO) .message(ChatMessage.userMessage("Who won the world series in 2020?")) .build(); CompletableFuture<ChatCompletion> chatCompletion = chatClient.createChatCompletionAsync(request); chatCompletion.thenAccept(System.out::println);- Streaming
ChatClient chatClient = openAI.chatClient(); CreateChatCompletionRequest request = CreateChatCompletionRequest.newBuilder() .message(ChatMessage.userMessage("Who won the world series in 2020?")) .stream(true) .build(); // with java.util.stream.Stream chatClient.streamChatCompletion(request).forEach(System.out::println); // with subscriber chatClient.streamChatCompletion(request, new ChatCompletionStreamSubscriber() { @Override public void onChunk(ChatCompletionChunk chunk) { System.out.println(chunk); } @Override public void onException(Throwable ex) { // ... } @Override public void onComplete() { // ... } });- Create image
ImagesClient imagesClient = openAI.imagesClient(); CreateImageRequest createImageRequest = CreateImageRequest.newBuilder() .model(OpenAIModel.DALL_E_3) .prompt("A cute baby sea otter") .build(); Images images = imagesClient.createImage(createImageRequest);- Create speech
AudioClient audioClient = openAI.audioClient(); SpeechRequest request = SpeechRequest.newBuilder() .model(OpenAIModel.TTS_1) .input("The quick brown fox jumped over the lazy dog.") .voice(Voice.ALLOY) .build(); Path output = Paths.get("/tmp/speech.mp3"); audioClient.createSpeech(request, output);- Create translation
AudioClient audioClient = openAI.audioClient(); TranslationRequest request = TranslationRequest.newBuilder() .model(OpenAIModel.WHISPER_1) .file(Paths.get("/tmp/german.m4a")) .build(); String translatedText = audioClient.createTranslation(request);- List models
ModelsClient modelsClient = openAI.modelsClient(); List<Model> models = modelsClient.listModels();- Classify if text violates OpenAI's Content Policy
ModerationsClient moderationsClient = openAI.moderationsClient(); ModerationRequest request = ModerationRequest.newBuilder() .input("I want to bake a cake.") .build(); Moderation moderation = moderationsClient.createModeration(request); boolean violence = moderation.results().get(0).categories().violence();- Create and execute a batch
// Upload JSONL file containing requests for the batch FilesClient filesClient = openAI.filesClient(); UploadFileRequest uploadInputFileRequest = UploadFileRequest.newBuilder() .file(Paths.get("/tmp/batch-requests.jsonl")) .purpose(Purpose.BATCH) .build(); File inputFile = filesClient.uploadFile(uploadInputFileRequest); BatchClient batchClient = openAI.batchClient(); CreateBatchRequest request = CreateBatchRequest.newBuilder() .inputFileId(inputFile.id()) .endpoint("/v1/chat/completions") .completionWindow("24h") .build(); Batch batch = batchClient.createBatch(request); // check status of the batch Batch retrievedBatch = batchClient.retrieveBatch(batch.id()); System.out.println(retrievedBatch.status()); - Upload large file in multiple parts
UploadsClient uploadsClient = openAI.uploadsClient(); CreateUploadRequest createUploadRequest = CreateUploadRequest.newBuilder() .filename("training_examples.jsonl") .purpose(Purpose.FINE_TUNE) .bytes(2147483648) .mimeType("text/jsonl") .build(); Upload upload = uploadsClient.createUpload(createUploadRequest); UploadPart part1 = uploadsClient.addUploadPart(upload.id(), Paths.get("/tmp/part1.jsonl")); UploadPart part2 = uploadsClient.addUploadPart(upload.id(), Paths.get("/tmp/part2.jsonl")); CompleteUploadRequest completeUploadRequest = CompleteUploadRequest.newBuilder() .partIds(List.of(part1.id(), part2.id())) .build(); Upload completedUpload = uploadsClient.completeUpload(upload.id(), completeUploadRequest); // the created usable File object File file = completedUpload.file();- Build AI Assistant
AssistantsClient assistantsClient = openAI.assistantsClient(); ThreadsClient threadsClient = openAI.threadsClient(); MessagesClient messagesClient = openAI.messagesClient(); RunsClient runsClient = openAI.runsClient(); // Step 1: Create an Assistant CreateAssistantRequest createAssistantRequest = CreateAssistantRequest.newBuilder() .name("Math Tutor") .model(OpenAIModel.GPT_3_5_TURBO_1106) .instructions("You are a personal math tutor. Write and run code to answer math questions.") .tool(Tool.codeInterpreterTool()) .build(); Assistant assistant = assistantsClient.createAssistant(createAssistantRequest); // Step 2: Create a Thread CreateThreadRequest createThreadRequest = CreateThreadRequest.newBuilder().build(); Thread thread = threadsClient.createThread(createThreadRequest); // Step 3: Add a Message to a Thread CreateMessageRequest createMessageRequest = CreateMessageRequest.newBuilder() .role(Role.USER) .content("I need to solve the equation `3x + 11 = 14`. Can you help me?") .build(); ThreadMessage message = messagesClient.createMessage(thread.id(), createMessageRequest); // Step 4: Run the Assistant CreateRunRequest createRunRequest = CreateRunRequest.newBuilder() .assistantId(assistant.id()) .instructions("Please address the user as Jane Doe. The user has a premium account.") .build(); ThreadRun run = runsClient.createRun(thread.id(), createRunRequest); // Step 5: Check the Run status ThreadRun retrievedRun = runsClient.retrieveRun(thread.id(), run.id()); String status = retrievedRun.status(); // Step 6: Display the Assistant's Response MessagesClient.PaginatedThreadMessages paginatedMessages = messagesClient.listMessages(thread.id(), PaginationQueryParameters.none(), Optional.empty()); List<ThreadMessage> messages = paginatedMessages.data();- Build AI Assistant with File Search Enabled
AssistantsClient assistantsClient = openAI.assistantsClient(); ThreadsClient threadsClient = openAI.threadsClient(); MessagesClient messagesClient = openAI.messagesClient(); RunsClient runsClient = openAI.runsClient(); VectorStoresClient vectorStoresClient = openAI.vectorStoresClient(); FilesClient filesClient = openAI.filesClient(); VectorStoreFileBatchesClient vectorStoreFileBatchesClient = openAI.vectorStoreFileBatchesClient(); // Step 1: Create a new Assistant with File Search Enabled CreateAssistantRequest createAssistantRequest = CreateAssistantRequest.newBuilder() .name("Financial Analyst Assistant") .model(OpenAIModel.GPT_4_TURBO) .instructions("You are an expert financial analyst. Use you knowledge base to answer questions about audited financial statements.") .tool(Tool.fileSearchTool()) .build(); Assistant assistant = assistantsClient.createAssistant(createAssistantRequest); // Step 2: Upload files and add them to a Vector Store CreateVectorStoreRequest createVectorStoreRequest = CreateVectorStoreRequest.newBuilder() .name("Financial Statements") .build(); VectorStore vectorStore = vectorStoresClient.createVectorStore(createVectorStoreRequest); UploadFileRequest uploadFileRequest1 = UploadFileRequest.newBuilder() .file(Paths.get("edgar/goog-10k.pdf")) .purpose(Purpose.ASSISTANTS) .build(); File file1 = filesClient.uploadFile(uploadFileRequest1); UploadFileRequest uploadFileRequest2 = UploadFileRequest.newBuilder() .file(Paths.get("edgar/brka-10k.txt")) .purpose(Purpose.ASSISTANTS) .build(); File file2 = filesClient.uploadFile(uploadFileRequest2); CreateVectorStoreFileBatchRequest createVectorStoreFileBatchRequest = CreateVectorStoreFileBatchRequest.newBuilder() .fileIds(List.of(file1.id(), file2.id())) .build(); VectorStoreFileBatch batch = vectorStoreFileBatchesClient.createVectorStoreFileBatch(vectorStore.id(), createVectorStoreFileBatchRequest); // need to query the status of the file batch for completion vectorStoreFileBatchesClient.retrieveVectorStoreFileBatch(vectorStore.id(), batch.id()); // Step 3: Update the assistant to use the new Vector Store ModifyAssistantRequest modifyAssistantRequest = ModifyAssistantRequest.newBuilder() .toolResources(ToolResources.fileSearchToolResources(vectorStore.id())) .build(); assistantsClient.modifyAssistant(assistant.id(), modifyAssistantRequest); // Step 4: Create a thread CreateThreadRequest.Message message = CreateThreadRequest.Message.newBuilder() .role(Role.USER) .content("How many shares of AAPL were outstanding at the end of of October 2023?") .build(); CreateThreadRequest createThreadRequest = CreateThreadRequest.newBuilder() .message(message) .build(); Thread thread = threadsClient.createThread(createThreadRequest); // Step 5: Create a run and check the output CreateRunRequest createRunRequest = CreateRunRequest.newBuilder() .assistantId(assistant.id()) .instructions("Please address the user as Jane Doe. The user has a premium account.") .build(); ThreadRun run = runsClient.createRun(thread.id(), createRunRequest); // check the run status ThreadRun retrievedRun = runsClient.retrieveRun(thread.id(), run.id()); String status = retrievedRun.status(); // display the Assistant's Response MessagesClient.PaginatedThreadMessages paginatedMessages = messagesClient.listMessages(thread.id(), PaginationQueryParameters.none(), Optional.empty()); List<ThreadMessage> messages = paginatedMessages.data();- Create a run and stream the result of executing the run (Assistants Streaming)
RunsClient runsClient = openAI.runsClient(); CreateRunRequest createRunRequest = CreateRunRequest.newBuilder() .assistantId(assistant.id()) .instructions("Please address the user as Jane Doe. The user has a premium account.") .stream(true) .build(); // with java.util.stream.Stream runsClient.createRunAndStream(thread.id(), createRunRequest).forEach(assistantStreamEvent -> { System.out.println(assistantStreamEvent.event()); System.out.println(assistantStreamEvent.data()); }); // with subscriber runsClient.createRunAndStream(thread.id(), createRunRequest, new AssistantStreamEventSubscriber() { @Override public void onThread(String event, Thread thread) { // ... } @Override public void onThreadRun(String event, ThreadRun threadRun) { // ... } @Override public void onThreadRunStep(String event, ThreadRunStep threadRunStep) { // ... } @Override public void onThreadRunStepDelta(String event, ThreadRunStepDelta threadRunStepDelta) { // ... } @Override public void onThreadMessage(String event, ThreadMessage threadMessage) { // ... } @Override public void onThreadMessageDelta(String event, ThreadMessageDelta threadMessageDelta) { // ... } @Override public void onUnknownEvent(String event, String data) { // ... } @Override public void onException(Throwable ex) { // ... } @Override public void onComplete() { // ... } }); // "createThreadAndRunAndStream" and "submitToolOutputsAndStream" methods are also available- List all the users in an organization.
OpenAI openAI = OpenAI.newBuilder() .adminKey(System.getenv("OPENAI_ADMIN_KEY")) .build(); UsersClient usersClient = openAI.usersClient(); List<User> users = usersClient.listUsers(Optional.empty(), Optional.empty()).data();- List user actions and configuration changes within an organization
OpenAI openAI = OpenAI.newBuilder() .adminKey(System.getenv("OPENAI_ADMIN_KEY")) .build(); AuditLogsClient auditLogsClient = openAI.auditLogsClient(); ListAuditLogsQueryParameters queryParameters = ListAuditLogsQueryParameters.newBuilder() .eventTypes(List.of("invite.sent", "invite.deleted")) .build(); List<AuditLog> auditLogs = auditLogsClient.listAuditLogs(queryParameters).data();