{"id":29888586,"url":"https://github.com/sashirestela/simple-openai","last_synced_at":"2026-02-22T09:49:38.744Z","repository":{"id":184369086,"uuid":"671751674","full_name":"sashirestela/simple-openai","owner":"sashirestela","description":"A Java library to use the OpenAI Api in the simplest possible way.","archived":false,"fork":false,"pushed_at":"2025-09-17T21:45:15.000Z","size":8596,"stargazers_count":342,"open_issues_count":9,"forks_count":48,"subscribers_count":11,"default_branch":"main","last_synced_at":"2025-09-17T23:32:13.737Z","etag":null,"topics":["ai","api","awesome","azure-openai","chatgpt","client","deepseek","gemini","gen-ai","generative-ai","gpt","httpclient","java","llm","mistral","okhttp","openai","realtime","simple","websocket"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sashirestela.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-07-28T03:55:25.000Z","updated_at":"2025-09-17T21:37:14.000Z","dependencies_parsed_at":"2023-08-18T01:37:40.483Z","dependency_job_id":"80a9849b-c03e-46bb-8999-9132b8581d45","html_url":"https://github.com/sashirestela/simple-openai","commit_stats":null,"previous_names":["sashirestela/simple-openai"],"tags_count":67,"template":false,"template_full_name":null,"purl":"pkg:github/sashirestela/simple-openai","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sashirestela%2Fsimple-openai","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sashirestela%2Fsimple-openai/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sashirestela%2Fsimple-openai/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sashirestela%2Fsimple-openai/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sashirestela","download_url":"https://codeload.github.com/sashirestela/simple-openai/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sashirestela%2Fsimple-openai/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29708374,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-22T05:59:28.568Z","status":"ssl_error","status_checked_at":"2026-02-22T05:58:46.208Z","response_time":110,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","api","awesome","azure-openai","chatgpt","client","deepseek","gemini","gen-ai","generative-ai","gpt","httpclient","java","llm","mistral","okhttp","openai","realtime","simple","websocket"],"created_at":"2025-07-31T21:00:43.632Z","updated_at":"2026-02-22T09:49:38.736Z","avatar_url":"https://github.com/sashirestela.png","language":"Java","funding_links":[],"categories":["Awesome-lists","Recently Updated","Projects","人工智能"],"sub_categories":["[Jul 27, 2025](/content/2025/07/27/README.md)","Artificial Intelligence"],"readme":"# Simple-OpenAI\nA Java library to use the OpenAI Api in the simplest possible way.\n\n\u003cimg src=\"media/simple-openai.png\" width=\"250\"\u003e\n\n[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=sashirestela_simple-openai\u0026metric=alert_status)](https://sonarcloud.io/summary/new_code?id=sashirestela_simple-openai)\n[![codecov](https://codecov.io/gh/sashirestela/simple-openai/graph/badge.svg?token=TYLE5788R3)](https://codecov.io/gh/sashirestela/simple-openai)\n![Maven Central](https://img.shields.io/maven-central/v/io.github.sashirestela/simple-openai)\n![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/sashirestela/simple-openai/build_java_maven.yml)\n[![javadoc](https://javadoc.io/badge2/io.github.sashirestela/simple-openai/javadoc.svg)](https://javadoc.io/doc/io.github.sashirestela/simple-openai/latest/index.html)\n[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/sashirestela/simple-openai)\n\n\n### Table of Contents\n- [Description](#-description)\n- [Supported Services](#-supported-services)\n- [Installation](#-installation)\n- [How to Use](#-how-to-use)\n  - [Creating a SimpleOpenAI Object](#creating-a-simpleopenai-object)\n  - [Using HttpClient or OkHttp](#using-httpclient-or-okhttp)\n  - [Using Realtime Feature](#using-realtime-feature)\n  - [Audio Example](#audio-example)\n  - [Image Example](#image-example)\n  - [Chat Completion Example](#chat-completion-example)\n  - [Chat Completion with Streaming Example](#chat-completion-with-streaming-example)\n  - [Chat Completion with Functions Example](#chat-completion-with-functions-example)\n  - [Chat Completion with Vision Example](#chat-completion-with-vision-example)\n  - [Chat Completion with Audio Example](#chat-completion-with-audio-example)\n  - [Chat Completion with Structured Outputs](#chat-completion-with-structured-outputs)\n  - [Chat Completion Conversation Example](#chat-completion-conversation-example)\n  - [Assistant v2 Conversation Example](#assistant-v2-conversation-example)\n  - [Response Conversation Example](#response-conversation-example)\n  - [Realtime Conversation Example](#realtime-conversation-example)\n- [Exception Handling](#-exception-handling)\n- [Retrying Requests](#-retrying-requests)\n- [Instructions for Android](#-instructions-for-android)\n- [Support for OpenAI-compatible API Providers](#-support-for-openai-compatible-api-providers)\n  - [Gemini Vertex API](#gemini-vertex-api)\n  - [Gemini Google API](#gemini-google-api)\n  - [Deepseek API](#deepseek-api)\n  - [Mistral API](#mistral-api)\n  - [Azure OpenAI](#azure-openai)\n  - [Anyscale](#anyscale)\n- [Run Examples](#-run-examples)\n- [Contributing](#-contributing)\n- [License](#-license)\n- [Who is Using Simple-OpenAI?](#-who-is-using-simple-openai)\n- [Show Us Your Love](#-show-us-your-love)\n\n\n## 💡 Description\nSimple-OpenAI is a Java http client library for sending requests to and receiving responses from the [OpenAI API](https://platform.openai.com/docs/api-reference). It exposes a consistent interface across all the services, yet as simple as you can find in other languages like Python or NodeJs. It's an unofficial library.\n\nSimple-OpenAI uses the [CleverClient](https://github.com/sashirestela/cleverclient) library for http communication, [Jackson](https://github.com/FasterXML/jackson) for Json parsing, and [Lombok](https://projectlombok.org/) to minimize boilerplate code, among others libraries.\n\n\n## ✅ Supported Services\nSimple-OpenAI seeks to stay up to date with the most recent changes in OpenAI. Currently, it supports most of the existing features and will continue to update with future changes.\n\nFull support for most of the OpenAI services:\n\n* Audio (Speech, Transcription, Translation)\n* Batch (Batches of Chat Completion)\n* [📌 _**UPDATED**_] Chat Completion (Text Generation, Streaming, Function Calling, Vision, Structured Outputs, Audio, Web Search)\n* Completion (Legacy Text Generation)\n* Embedding  (Vectoring Text)\n* Files (Upload Files)\n* Fine Tuning (Customize Models)\n* Image (Generate, Edit, Variation)\n* Models (List)\n* Moderation (Check Harmful Text)\n* [📌 _**UPDATED**_] Realtime (Speech-to-Speech Conversation, Multimodality, Function Calling)\n* [📌 _**UPDATED**_] Response (Text Generation, Streaming, Function Calling, Vision, Structured Outputs, Reasoning, Computer Use, File Search, Web Search, Remote MCP, Image Generation, Code Interpreter, Reusable Prompts). See examples of this service in [ResponseDemo.java](src/demo/java/io/github/sashirestela/openai/demo/ResponseDemo.java)\n* [📌 _**UPDATED**_] Session Token (Create Ephemeral Tokens, Create Transcription Ephemeral Tokens)\n* Upload (Upload Large Files in Parts)\n* Assistants Beta v2 (Assistants, Threads, Messages, Runs, Steps, Vector Stores, Streaming, Function Calling, Vision, Structured Outputs)\n\n\n## 📝 Installation\nYou can install Simple-OpenAI by adding the following dependencies to your Maven project:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.sashirestela\u003c/groupId\u003e\n    \u003cartifactId\u003esimple-openai\u003c/artifactId\u003e\n    \u003cversion\u003e[simple-openai_latest_version]\u003c/version\u003e\n\u003c/dependency\u003e\n\u003c!-- OkHttp dependency is optional if you decide to use it with simple-openai --\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.squareup.okhttp3\u003c/groupId\u003e\n    \u003cartifactId\u003eokhttp\u003c/artifactId\u003e\n    \u003cversion\u003e[okhttp_latest_version]\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nOr alternatively using Gradle:\n\n```groovy\ndependencies {\n    implementation 'io.github.sashirestela:simple-openai:[simple-openai_latest_version]'\n    /* OkHttp dependency is optional if you decide to use it with simple-openai */\n    implementation 'com.squareup.okhttp3:okhttp:[okhttp_latest_version]'\n}\n```\nTake in account that you need to use Java 11 or greater.\n\n\n## 📘 How to Use\n\n### Creating a SimpleOpenAI Object\nThis is the first step you need to do before to use the services. You must provide at least your _OpenAI Api Key_ ([See here](https://platform.openai.com/docs/api-reference/authentication) for more details). In the following example we are getting the Api Key from an environment variable called ```OPENAI_API_KEY``` which we have created to keep it:\n```java\nvar openAI = SimpleOpenAI.builder()\n    .apiKey(System.getenv(\"OPENAI_API_KEY\"))\n    .build();\n```\nOptionally you could pass your _OpenAI Organization Id_ in case you have multiple organizations and you want to identify usage by organization and/or you could pass your _OpenAI Project Id_ in case you want to provides access to a single project. In the following example we are using environment variable for those Ids:\n```java\nvar openAI = SimpleOpenAI.builder()\n    .apiKey(System.getenv(\"OPENAI_API_KEY\"))\n    .organizationId(System.getenv(\"OPENAI_ORGANIZATION_ID\"))\n    .projectId(System.getenv(\"OPENAI_PROJECT_ID\"))\n    .build();\n```\nAfter you have created a SimpleOpenAI object, you are ready to call its services in order to communicate to OpenAI API.\n\n### Using HttpClient or OkHttp\nSimple-OpenAI uses one of the following available http client components: [Java's HttpClient](https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/HttpClient.html) (by default) or [Square's OkHttp](https://square.github.io/okhttp/) (adding a dependency).You can use the ```clientAdapter``` attribute to indicate which to use. In the following example we are providing a custom Java HttpClient:\n```java\nvar httpClient = HttpClient.newBuilder()\n    .version(Version.HTTP_1_1)\n    .followRedirects(Redirect.NORMAL)\n    .connectTimeout(Duration.ofSeconds(20))\n    .executor(Executors.newFixedThreadPool(3))\n    .proxy(ProxySelector.of(new InetSocketAddress(\"proxy.example.com\", 80)))\n    .build();\n\nvar openAI = SimpleOpenAI.builder()\n    .apiKey(System.getenv(\"OPENAI_API_KEY\"))\n    .clientAdapter(new JavaHttpClientAdpter(httpClient))    // To use a custom Java HttpClient\n    //.clientAdapter(new JavaHttpClientAdpter())            // To use a default Java HttpClient\n    //.clientAdapter(new OkHttpClientAdpter(okHttpClient))  // To use a custom OkHttpClient\n    //.clientAdapter(new OkHttpClientAdpter())              // To use a default OkHttpClient\n    .build();\n```\n\n### Using Realtime Feature\nIf you want to use the Realtime feature, you need to set the ```realtimeConfig``` attribute. For this feature you will set another http client (similar to ```clientAdapter```) for WebSocket communication: Java's HttpClient (by default) or Square's OkHttp\n```java\nvar openAI = SimpleOpenAI.builder()\n    .apiKey(System.getenv(\"OPENAI_API_KEY\"))\n    // -- To use a default Java HttpClient for WebSocket\n    .realtimeConfig(RealtimeConfig.of(\"model\")\n    // -- To use a default Java HttpClient for WebSocket\n    //.realtimeConfig(RealtimeConfig.of(\"model\", new JavaHttpWebSocketAdpter())\n    // -- To use a custom Java HttpClient for WebSocket\n    //.realtimeConfig(RealtimeConfig.of(\"model\", new JavaHttpWebSocketAdpter(httpClient))\n    // -- To use a default OkHttpClient for WebSocket\n    //.realtimeConfig(RealtimeConfig.of(\"model\", new OkHttpWebSocketAdpter())\n    // -- To use a custom OkHttpClient for WebSocket\n    //.realtimeConfig(RealtimeConfig.of(\"model\", new OkHttpWebSocketAdpter(okHttpClient))\n    .build();\n```\n\n### Audio Example\nExample to call the Audio service to transform text to audio. We are requesting to receive the audio in binary format (InputStream):\n```java\nvar speechRequest = SpeechRequest.builder()\n        .model(\"tts-1\")\n        .input(\"Hello world, welcome to the AI universe!\")\n        .voice(Voice.ALLOY)\n        .responseFormat(SpeechResponseFormat.MP3)\n        .speed(1.0)\n        .build();\nvar futureSpeech = openAI.audios().speak(speechRequest);\nvar speechResponse = futureSpeech.join();\ntry {\n    var audioFile = new FileOutputStream(speechFileName);\n    audioFile.write(speechResponse.readAllBytes());\n    System.out.println(audioFile.getChannel().size() + \" bytes\");\n    audioFile.close();\n} catch (Exception e) {\n    e.printStackTrace();\n}\n```\n\nExample to call the Audio service to transcribe an audio to text. We are requesting to receive the transcription in plain text format (see the name of the method):\n```java\nvar audioRequest = TranscriptionRequest.builder()\n        .file(Paths.get(\"hello_audio.mp3\"))\n        .model(\"whisper-1\")\n        .responseFormat(AudioResponseFormat.VERBOSE_JSON)\n        .temperature(0.2)\n        .timestampGranularity(TimestampGranularity.WORD)\n        .timestampGranularity(TimestampGranularity.SEGMENT)\n        .build();\nvar futureAudio = openAI.audios().transcribe(audioRequest);\nvar audioResponse = futureAudio.join();\nSystem.out.println(audioResponse);\n```\n### Image Example\nExample to call the Image service to generate two images in response to our prompt. We are requesting to receive the images' urls and we are printing out them in the console:\n```java\nvar imageRequest = ImageRequest.builder()\n        .prompt(\"An image of orange cat hugging other white cat with a light blue scarf.\")\n        .model(\"gpt-image-1\")\n        .background(Background.TRANSPARENT)\n        .outputFormat(OutputFormat.PNG)\n        .quality(Quality.MEDIUM)\n        .size(Size.X_1024_1024)\n        .moderation(Moderation.LOW)\n        .n(2)\n        .build();\nvar futureImage = openAI.images().create(imageRequest);\nvar imageResponse = futureImage.join();\nIntStream.range(0, imageResponse.getData().size()).forEach(i -\u003e {\n    var filePath = \"src/demo/resources/image\" + (i + 1) + \".png\";\n    Base64Util.decode(imageResponse.getData().get(i).getB64Json(), filePath);\n    System.out.println(filePath);\n});\n```\n### Chat Completion Example\nExample to call the Chat Completion service to ask a question and wait for a full answer. We are printing out it in the console:\n```java\nvar chatRequest = ChatRequest.builder()\n        .model(\"gpt-4o-mini\")\n        .message(SystemMessage.of(\"You are an expert in AI.\"))\n        .message(UserMessage.of(\"Write a technical article about ChatGPT, no more than 100 words.\"))\n        .temperature(0.0)\n        .maxCompletionTokens(300)\n        .build();\nvar futureChat = openAI.chatCompletions().create(chatRequest);\nvar chatResponse = futureChat.join();\nSystem.out.println(chatResponse.firstContent());\n```\n### Chat Completion with Streaming Example\nExample to call the Chat Completion service to ask a question and wait for an answer in partial message deltas. We are printing out it in the console as soon as each delta is arriving:\n```java\nvar chatRequest = ChatRequest.builder()\n        .model(\"gpt-4o-mini\")\n        .message(SystemMessage.of(\"You are an expert in AI.\"))\n        .message(UserMessage.of(\"Write a technical article about ChatGPT, no more than 100 words.\"))\n        .temperature(0.0)\n        .maxCompletionTokens(300)\n        .build();\nvar futureChat = openAI.chatCompletions().createStream(chatRequest);\nvar chatResponse = futureChat.join();\nchatResponse.filter(chatResp -\u003e chatResp.getChoices().size() \u003e 0 \u0026\u0026 chatResp.firstContent() != null)\n        .map(Chat::firstContent)\n        .forEach(System.out::print);\nSystem.out.println();\n```\n### Chat Completion with Functions Example\nThis functionality empowers the Chat Completion service to solve specific problems to our context. In this example we are setting three functions and we are entering a prompt that will require to call one of them (the function ```product```). For setting functions we are using additional classes which implements the interface ```Functional```. Those classes define a field by each function argument, annotating them to describe them and each class must override the ```execute``` method with the function's logic. Note that we are using the ```FunctionExecutor``` utility class to enroll the functions and to execute the function selected by the ```openai.chatCompletions()``` calling:\n```java\npublic void demoCallChatWithFunctions() {\n    var functionExecutor = new FunctionExecutor();\n    functionExecutor.enrollFunction(\n            FunctionDef.builder()\n                    .name(\"get_weather\")\n                    .description(\"Get the current weather of a location\")\n                    .functionalClass(Weather.class)\n                    .strict(Boolean.TRUE)\n                    .build());\n    functionExecutor.enrollFunction(\n            FunctionDef.builder()\n                    .name(\"product\")\n                    .description(\"Get the product of two numbers\")\n                    .functionalClass(Product.class)\n                    .strict(Boolean.TRUE)\n                    .build());\n    functionExecutor.enrollFunction(\n            FunctionDef.builder()\n                    .name(\"run_alarm\")\n                    .description(\"Run an alarm\")\n                    .functionalClass(RunAlarm.class)\n                    .strict(Boolean.TRUE)\n                    .build());\n    var messages = new ArrayList\u003cChatMessage\u003e();\n    messages.add(UserMessage.of(\"What is the product of 123 and 456?\"));\n    chatRequest = ChatRequest.builder()\n            .model(\"gpt-4o-mini\")\n            .messages(messages)\n            .tools(functionExecutor.getToolFunctions())\n            .build();\n    var futureChat = openAI.chatCompletions().create(chatRequest);\n    var chatResponse = futureChat.join();\n    var chatMessage = chatResponse.firstMessage();\n    var chatToolCall = chatMessage.getToolCalls().get(0);\n    var result = functionExecutor.execute(chatToolCall.getFunction());\n    messages.add(chatMessage);\n    messages.add(ToolMessage.of(result.toString(), chatToolCall.getId()));\n    chatRequest = ChatRequest.builder()\n            .model(\"gpt-4o-mini\")\n            .messages(messages)\n            .tools(functionExecutor.getToolFunctions())\n            .build();\n    futureChat = openAI.chatCompletions().create(chatRequest);\n    chatResponse = futureChat.join();\n    System.out.println(chatResponse.firstContent());\n}\n\npublic static class Weather implements Functional {\n\n    @JsonPropertyDescription(\"City and state, for example: León, Guanajuato\")\n    @JsonProperty(required = true)\n    public String location;\n\n    @JsonPropertyDescription(\"The temperature unit, can be 'celsius' or 'fahrenheit'\")\n    @JsonProperty(required = true)\n    public String unit;\n\n    @Override\n    public Object execute() {\n        return Math.random() * 45;\n    }\n\n}\n\npublic static class Product implements Functional {\n\n    @JsonPropertyDescription(\"The multiplicand part of a product\")\n    @JsonProperty(required = true)\n    public double multiplicand;\n\n    @JsonPropertyDescription(\"The multiplier part of a product\")\n    @JsonProperty(required = true)\n    public double multiplier;\n\n    @Override\n    public Object execute() {\n        return multiplicand * multiplier;\n    }\n\n}\n\npublic static class RunAlarm implements Functional {\n\n    @Override\n    public Object execute() {\n        return \"DONE\";\n    }\n\n}\n```\n### Chat Completion with Vision Example\nExample to call the Chat Completion service to allow the model to take in external images and answer questions about them:\n```java\nvar chatRequest = ChatRequest.builder()\n        .model(\"gpt-4o-mini\")\n        .messages(List.of(\n                UserMessage.of(List.of(\n                        ContentPartText.of(\n                                \"What do you see in the image? Give in details in no more than 100 words.\"),\n                        ContentPartImageUrl.of(ImageUrl.of(\n                                \"https://upload.wikimedia.org/wikipedia/commons/e/eb/Machu_Picchu%2C_Peru.jpg\"))))))\n        .temperature(0.0)\n        .maxCompletionTokens(500)\n        .build();\nvar chatResponse = openAI.chatCompletions().createStream(chatRequest).join();\nchatResponse.filter(chatResp -\u003e chatResp.getChoices().size() \u003e 0 \u0026\u0026 chatResp.firstContent() != null)\n        .map(Chat::firstContent)\n        .forEach(System.out::print);\nSystem.out.println();\n```\nExample to call the Chat Completion service to allow the model to take in local images and answer questions about them (_check the Base64Util's code in this repository_):\n```java\nvar chatRequest = ChatRequest.builder()\n        .model(\"gpt-4o-mini\")\n        .messages(List.of(\n                UserMessage.of(List.of(\n                        ContentPartText.of(\n                                \"What do you see in the image? Give in details in no more than 100 words.\"),\n                        ContentPartImageUrl.of(ImageUrl.of(\n                                Base64Util.encode(\"src/demo/resources/machupicchu.jpg\", MediaType.IMAGE)))))))\n        .temperature(0.0)\n        .maxCompletionTokens(500)\n        .build();\nvar chatResponse = openAI.chatCompletions().createStream(chatRequest).join();\nchatResponse.filter(chatResp -\u003e chatResp.getChoices().size() \u003e 0 \u0026\u0026 chatResp.firstContent() != null)\n        .map(Chat::firstContent)\n        .forEach(System.out::print);\nSystem.out.println();\n```\n### Chat Completion with Audio Example\nExample to call the Chat Completion service to generate a spoken audio response to a prompt, and to use audio inputs to prompt the model (_check the Base64Util's code in this repository_):\n```java\nvar messages = new ArrayList\u003cChatMessage\u003e();\nmessages.add(SystemMessage.of(\"Respond in a short and concise way.\"));\nmessages.add(UserMessage.of(List.of(ContentPartInputAudio.of(InputAudio.of(\n        Base64Util.encode(\"src/demo/resources/question1.mp3\", null), InputAudioFormat.MP3)))));\nchatRequest = ChatRequest.builder()\n        .model(\"gpt-4o-audio-preview\")\n        .modality(Modality.TEXT)\n        .modality(Modality.AUDIO)\n        .audio(Audio.of(Voice.ALLOY, AudioFormat.MP3))\n        .messages(messages)\n        .build();\nvar chatResponse = openAI.chatCompletions().create(chatRequest).join();\nvar audio = chatResponse.firstMessage().getAudio();\nBase64Util.decode(audio.getData(), \"src/demo/resources/answer1.mp3\");\nSystem.out.println(\"Answer 1: \" + audio.getTranscript());\n\nmessages.add(AssistantMessage.builder().audioId(audio.getId()).build());\nmessages.add(UserMessage.of(List.of(ContentPartInputAudio.of(InputAudio.of(\n        Base64Util.encode(\"src/demo/resources/question2.mp3\", null), InputAudioFormat.MP3)))));\nchatRequest = ChatRequest.builder()\n        .model(\"gpt-4o-audio-preview\")\n        .modality(Modality.TEXT)\n        .modality(Modality.AUDIO)\n        .audio(Audio.of(Voice.ALLOY, AudioFormat.MP3))\n        .messages(messages)\n        .build();\nchatResponse = openAI.chatCompletions().create(chatRequest).join();\naudio = chatResponse.firstMessage().getAudio();\nBase64Util.decode(audio.getData(), \"src/demo/resources/answer2.mp3\");\nSystem.out.println(\"Answer 2: \" + audio.getTranscript());\n```\n### Chat Completion with Structured Outputs\nExample to call the Chat Completion service to ensure the model will always generate responses that adhere to a Json Schema defined through Java classes:\n```java\npublic void demoCallChatWithStructuredOutputs() {\n    var chatRequest = ChatRequest.builder()\n            .model(\"gpt-4o-mini\")\n            .message(SystemMessage\n                    .of(\"You are a helpful math tutor. Guide the user through the solution step by step.\"))\n            .message(UserMessage.of(\"How can I solve 8x + 7 = -23\"))\n            .responseFormat(ResponseFormat.jsonSchema(JsonSchema.builder()\n                    .name(\"MathReasoning\")\n                    .schemaClass(MathReasoning.class)\n                    .build()))\n            .build();\n    var chatResponse = openAI.chatCompletions().createStream(chatRequest).join();\n    chatResponse.filter(chatResp -\u003e chatResp.getChoices().size() \u003e 0 \u0026\u0026 chatResp.firstContent() != null)\n            .map(Chat::firstContent)\n            .forEach(System.out::print);\n    System.out.println();\n}\n\npublic static class MathReasoning {\n\n    public List\u003cStep\u003e steps;\n    public String finalAnswer;\n\n    public static class Step {\n\n        public String explanation;\n        public String output;\n\n    }\n\n}\n```\n### Chat Completion Conversation Example\nThis example simulates a conversation chat by the command console and demonstrates the usage of ChatCompletion with streaming and call functions.\n\nYou can see the full demo code as well as the results from running the demo code:\n\n[ConversationDemo.java](src/demo/java/io/github/sashirestela/openai/demo/ConversationDemo.java)\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cb\u003eDemo Results\u003c/b\u003e\u003c/summary\u003e\n\n```txt\nWelcome! Write any message: Hi, can you help me with some quetions about Lima, Peru?\nOf course! What would you like to know about Lima, Peru?\n\nWrite any message (or write 'exit' to finish): Tell me something brief about Lima Peru, then tell me how's the weather there right now. Finally give me three tips to travel there.\n### Brief About Lima, Peru\nLima, the capital city of Peru, is a bustling metropolis that blends modernity with rich historical heritage. Founded by Spanish conquistador Francisco Pizarro in 1535, Lima is known for its colonial architecture, vibrant culture, and delicious cuisine, particularly its world-renowned ceviche. The city is also a gateway to exploring Peru's diverse landscapes, from the coastal deserts to the Andean highlands and the Amazon rainforest.\n\n### Current Weather in Lima, Peru\nI'll check the current temperature and the probability of rain in Lima for you.### Current Weather in Lima, Peru\n- **Temperature:** Approximately 11.8°C\n- **Probability of Rain:** Approximately 97.8%\n\n### Three Tips for Traveling to Lima, Peru\n1. **Explore the Historic Center:**\n   - Visit the Plaza Mayor, the Government Palace, and the Cathedral of Lima. These landmarks offer a glimpse into Lima's colonial past and are UNESCO World Heritage Sites.\n\n2. **Savor the Local Cuisine:**\n   - Don't miss out on trying ceviche, a traditional Peruvian dish made from fresh raw fish marinated in citrus juices. Also, explore the local markets and try other Peruvian delicacies.\n\n3. **Visit the Coastal Districts:**\n   - Head to Miraflores and Barranco for stunning ocean views, vibrant nightlife, and cultural experiences. These districts are known for their beautiful parks, cliffs, and bohemian atmosphere.\n\nEnjoy your trip to Lima! If you have any more questions, feel free to ask.\n\nWrite any message (or write 'exit' to finish): exit\n```\n\u003c/details\u003e\n\n### Assistant v2 Conversation Example\nThis example simulates a conversation chat by the command console and demonstrates the usage of the latest Assistants API v2 features:\n- _Vector Stores_ to upload files and incorporate it as new knowledge base.\n- _Function Tools_ to use internal bussiness services to answer questions.\n- _File Search Tools_ to use vectorized files to do semantic search.\n- _Thread Run Streaming_ to answer with chunks of tokens in real time.\n\nYou can see the full demo code as well as the results from running the demo code:\n\n[ConversationV2Demo.java](src/demo/java/io/github/sashirestela/openai/demo/ConversationV2Demo.java)\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cb\u003eDemo Results\u003c/b\u003e\u003c/summary\u003e\n\n```txt\nFile was created with id: file-oDFIF7o4SwuhpwBNnFIILhMK\nVector Store was created with id: vs_lG1oJmF2s5wLhqHUSeJpELMr\nAssistant was created with id: asst_TYS5cZ05697tyn3yuhDrCCIv\nThread was created with id: thread_33n258gFVhZVIp88sQKuqMvg\n\n\nWelcome! Write any message: Hello\n=====\u003e\u003e Thread Run: id=run_nihN6dY0uyudsORg4xyUvQ5l, status=QUEUED\nHello! How can I assist you today?\n=====\u003e\u003e Thread Run: id=run_nihN6dY0uyudsORg4xyUvQ5l, status=COMPLETED\n\nWrite any message (or write 'exit' to finish): Tell me something brief about Lima Peru, then tell me how's the weather there right now. Finally give me three tips to travel there.\n=====\u003e\u003e Thread Run: id=run_QheimPyP5UK6FtmH5obon0fB, status=QUEUED\nLima, the capital city of Peru, is located on the country's arid Pacific coast. It's known for its vibrant culinary scene, rich history, and as a cultural hub with numerous museums, colonial architecture, and remnants of pre-Columbian civilizations. This bustling metropolis serves as a key gateway to visiting Peru’s more famous attractions, such as Machu Picchu and the Amazon rainforest.\n\nLet me find the current weather conditions in Lima for you, and then I'll provide three travel tips.\n=====\u003e\u003e Thread Run: id=run_QheimPyP5UK6FtmH5obon0fB, status=REQUIRES_ACTION\n### Current Weather in Lima, Peru:\n- **Temperature:** 12.8°C\n- **Rain Probability:** 82.7%\n\n### Three Travel Tips for Lima, Peru:\n1. **Best Time to Visit:** Plan your trip during the dry season, from May to September, which offers clearer skies and milder temperatures. This period is particularly suitable for outdoor activities and exploring the city comfortably.\n\n2. **Local Cuisine:** Don't miss out on tasting the local Peruvian dishes, particularly the ceviche, which is renowned worldwide. Lima is also known as the gastronomic capital of South America, so indulge in the wide variety of dishes available.\n\n3. **Cultural Attractions:** Allocate enough time to visit Lima's rich array of museums, such as the Larco Museum, which showcases pre-Columbian art, and the historical center which is a UNESCO World Heritage Site. Moreover, exploring districts like Miraflores and Barranco can provide insights into the modern and bohemian sides of the city.\n\nEnjoy planning your trip to Lima! If you need more information or help, feel free to ask.\n=====\u003e\u003e Thread Run: id=run_QheimPyP5UK6FtmH5obon0fB, status=COMPLETED\n\nWrite any message (or write 'exit' to finish): Tell me something about the Mistral company\n=====\u003e\u003e Thread Run: id=run_5u0t8kDQy87p5ouaTRXsCG8m, status=QUEUED\nMistral AI is a French company that specializes in selling artificial intelligence products. It was established in April 2023 by former employees of Meta Platforms and Google DeepMind. Notably, the company secured a significant amount of funding, raising €385 million in October 2023, and achieved a valuation exceeding $2 billion by December of the same year.\n\nThe prime focus of Mistral AI is on developing and producing open-source large language models. This approach underscores the foundational role of open-source software as a counter to proprietary models. As of March 2024, Mistral AI has published two models, which are available in terms of weights, while three more models—categorized as Small, Medium, and Large—are accessible only through an API[1].\n=====\u003e\u003e Thread Run: id=run_5u0t8kDQy87p5ouaTRXsCG8m, status=COMPLETED\n\nWrite any message (or write 'exit' to finish): exit\n\nFile was deleted: true\nVector Store was deleted: true\nAssistant was deleted: true\nThread was deleted: true\n```\n\u003c/details\u003e\n\n### Response Conversation Example\nThis example simulates a conversation chat by the command console and demonstrates the usage of the  Response API features:\n- Text Generation\n- Streaming\n- Function Calling\n- Vision\n- FileSearch\n- WebSearch\n\nYou can see the full demo code as well as the results from running the demo code:\n\n[ConversationV3Demo.java](src/demo/java/io/github/sashirestela/openai/demo/ConversationV3Demo.java)\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003cb\u003eDemo Results\u003c/b\u003e\u003c/summary\u003e\n\n```txt\nAsk anything ('x' to finish): Where is Lima located?\n====\u003e FileSearch ...\n====\u003e Message ...\nLima is the capital city of Peru, located on the country's central coast along the Pacific Ocean.\n\nAsk anything ('x' to finish): What is the temperature there?\n====\u003e Function: CurrentTemperature. Arguments: {\"location\":\"Lima, Peru\",\"unit\":\"C\"}\n====\u003e Message ...\nThe current temperature in Lima, Peru is approximately 13.4°C.\n\nAsk anything ('x' to finish): What are the main news there right now?\n====\u003e FileSearch ...\n====\u003e WebSearch ...\n====\u003e Message ...\nAs of May 18, 2025, several significant events have been reported in Lima, Peru:\n\n**State of Emergency Declared Amid Rising Crime**\n\nPeru has declared a state of emergency in Lima due to escalating violence and criminal activities. The government has deployed troops to the streets, granting police and military forces the authority to detain individuals with minimal restrictions. This measure follows a series of violent incidents, including the death of a popular singer in a criminal attack. Authorities have reported 459 killings from January 1 to March 16, and 1,909 extortion cases in January alone. ([aljazeera.com](https://www.aljazeera.com/news/2025/3/18/peru-declares-state-of-emergency-as-violent-crimewave-engulfs-lima?utm_source=openai))\n\n**Former President Sentenced for Money Laundering**\n\nFormer President Ollanta Humala and his wife, Nadine Heredia, have been sentenced to 15 years in prison for money laundering. The National Superior Court in Lima found them guilty of receiving over $3 million in illegal campaign financing from Venezuela and the Brazilian construction company Odebrecht. This conviction marks the third former president in two decades to be jailed for corruption, following Alejandro Toledo and Alberto Fujimori. ([ft.com](https://www.ft.com/content/7bb306c4-c6a6-4369-96f8-a43a170f2077?utm_source=openai))\n\n**Death of Nobel Laureate Mario Vargas Llosa**\n\nPeruvian Nobel laureate Mario Vargas Llosa, a prominent figure in Latin America's literary \"Boom generation,\" has died at the age of 89 in Lima. Vargas Llosa gained worldwide recognition with his second novel, \"The Green House,\" and was known for his contributions to literature and his political activism. ([axios.com](https://www.axios.com/2025/04/14/nobel-peruvian-novelist-mario-vargas-llosa-dies?utm_source=openai))\n\n**Pope Leo XIV's Election Celebrated**\n\nPeruvians are celebrating the election of Pope Leo XIV, previously Cardinal Robert Prevost, who has strong ties to Peru. Born in Chicago in 1955, Prevost became a Peruvian citizen in 2015 and led the diocese of Chiclayo until 2023. His deep connection with Chiclayo, a key hub in northern Peru, has made him a beloved figure. President Dina Boluarte praised his commitment to the Peruvian people, calling his election historic. ([apnews.com](https://apnews.com/article/7d26905df2dfd253f3fd87f047c764e6?utm_source=openai))\n\n\n## Recent News in Lima, Peru:\n- [Rejoicing Peruvians see Pope Leo XIV as one of their own after his many years in Peru](https://apnews.com/article/7d26905df2dfd253f3fd87f047c764e6?utm_source=openai)\n- [Death threats by WhatsApp: extortion drains Peruvians' cash](https://www.ft.com/content/a8de251c-3137-4da4-8a00-6d709600e729?utm_source=openai)\n- [13 workers kidnapped from a Peruvian gold mine are found dead](https://apnews.com/article/659b25d54a63be62f95f8769667231d3?utm_source=openai) \n\nAsk anything ('x' to finish): What is the most important point of the Mistral AI architecture?\n====\u003e FileSearch ...\n====\u003e Message ...\nThe most important points of the Mistral AI architecture include:\n\n1. **Function Calling Capabilities**: Mistral models can integrate with other platforms and perform tasks beyond their original capabilities, enhancing accuracy and versatility.\n\n2. **Multilingual Proficiency**: Most Mistral models are natively fluent in multiple languages, allowing for nuanced understanding and complex multilingual reasoning tasks.\n\n3. **Wide Range of Applications**: Mistral's models are designed for various natural language processing tasks, including chatbots, text summarization, content creation, text classification, and code completion.\n\n4. **Open Source and Commercial Models**: Mistral offers both open-source and commercial models, with unique strengths tailored for different applications.\n\n5. **Advanced Context Windows**: Some models, like Mistral Large 2, support extensive context windows (up to 128k tokens), which is beneficial for handling large datasets and complex tasks.\n\nAsk anything ('x' to finish): x\n```\n\u003c/details\u003e\n\n### Realtime Conversation Example\nIn this example you can see the code to establish a speech-to-speech conversation between you and the model using your microphone and your speaker. Here you can see in action the following events:\n- ClientEvent.SessionUpdate\n- ClientEvent.InputAudioBufferAppend\n- ClientEvent.ResponseCreate\n- ServerEvent.ResponseAudioDelta\n- ServerEvent.ResponseAudioDone\n- ServerEvent.ResponseAudioTranscriptDone\n- ServerEvent.ConversationItemAudioTransCompleted\n\nYou can see the full code on:\n\n[RealtimeDemo.java](src/demo/java/io/github/sashirestela/openai/demo/RealtimeDemo.java)\n\n## 🔱 Exception Handling\nSimple-OpenAI provides an exception handling mechanism through the `OpenAIExceptionConverter` class. This converter maps HTTP errors to specific OpenAI exceptions, making it easier to handle different types of API errors:\n\n- `BadRequestException` (400)\n- `AuthenticationException` (401)\n- `PermissionDeniedException` (403)\n- `NotFoundException` (404) \n- `UnprocessableEntityException` (422)\n- `RateLimitException` (429)\n- `InternalServerException` (500+)\n- `UnexpectedStatusCodeException` (other status codes)\n\nHere's a minimalist example of handling OpenAI exceptions:\n\n```java\ntry {\n\n    // Your code to call the OpenAI API using simple-openai goes here;\n\n} catch (Exception e) {\n    try {\n        OpenAIExceptionConverter.rethrow(e);\n    } catch (AuthenticationException ae) {\n        // Handle this exception\n    } catch (NotFoundException ne) {\n        // Handle this exception\n\n    // Catching other exceptions\n\n    } catch (RuntimeException re) {\n        // Handle default exceptions\n    }\n}\n```\nEach exception provides access to `OpenAIResponseInfo`, which contains detailed information about the error including:\n\n- HTTP status code\n- Error message and type\n- Request and response headers\n- API endpoint URL and HTTP method\n\nThis exception handling mechanism allows you to handle API errors and provide feedback in your applications.\n\n## 🔁 Retrying Requests\n\nSimple-OpenAI provides automatic request retries using exponential backoff with optional jitter. You can configure retries using the `RetryConfig` class.\n\n### Retry Configuration Options\n\n| Attribute            | Description                                           | Default Value |\n|----------------------|-------------------------------------------------------|---------------|\n| maxAttempts          | Maximum number of retry attempts                      | 3             |\n| initialDelayMs       | Initial delay before retrying (in milliseconds)       | 1000          |\n| maxDelayMs           | Maximum delay between retries (in milliseconds)       | 10000         |\n| backoffMultiplier    | Multiplier for exponential backoff                    | 2.0           |\n| jitterFactor         | Percentage of jitter to apply to delay values         | 0.2           |\n| retryableExceptions  | List of exception types that should trigger a retry   | IOException, ConnectException, SocketTimeoutException |\n| retryableStatusCodes | List of HTTP status codes that should trigger a retry | 408, 409, 429, 500-599 |\n\n#### Example Usage\n\n```java\nvar retryConfig = RetryConfig.builder()\n    .maxAttempts(4)\n    .initialDelayMs(500)\n    .maxDelayMs(8000)\n    .backoffMultiplier(1.5)\n    .jitterFactor(0.1)\n    .build();\n\nvar openAI = SimpleOpenAI.builder()\n    .apiKey(System.getenv(\"OPENAI_API_KEY\"))\n    .retryConfig(retryConfig)\n    .build();\n```\n\nWith this configuration, failed requests matching the criteria will be retried automatically with increasing delays based on exponential backoff. If you not set the `retryConfig` attribute, the default values will be used for retrying.\n\n\n## 🤖 Instructions for Android\nFollow the next instructions to run Simple-OpenAI in Android devices:\n\n### Configuration (build.gradle)\n```groovy\nandroid {\n    //...\n    defaultConfig {\n        //...\n        minSdk 24\n        //...\n    }\n    //...\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_11\n        targetCompatibility JavaVersion.VERSION_11\n    }\n    kotlinOptions {\n        jvmTarget = '11'\n    }\n}\n\ndependencies {\n    //...\n    implementation 'io.github.sashirestela:simple-openai:[simple-openai_version]'\n    implementation 'com.squareup.okhttp3:okhttp:[okhttp_version]'\n}\n```\n\n### Create a SimpleOpenAI object\nIn Java:\n```java\nSimpleOpenAI openAI = SimpleOpenAI.builder()\n    .apiKey(API_KEY)\n    .clientAdapter(new OkHttpClientAdapter())  // Optionally you could add a custom OkHttpClient\n    .build();\n```\nIn Kotlin:\n```kotlin\nval openAI = SimpleOpenAI.builder()\n    .apiKey(API_KEY)\n    .clientAdapter(OkHttpClientAdapter())  // Optionally you could add a custom OkHttpClient\n    .build()\n```\n\n## 👥 Support for OpenAI-compatible API Providers\nSimple-OpenAI can be used with additional providers that are compatible with the OpenAI API. At this moment, there is support for the following additional providers:\n\n### Gemini Vertex API\n[Gemini Vertex API](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/inference) is supported by Simple-OpenAI. We can use the class `SimpleOpenAIGeminiVertex` to start using this provider.\n\nNote that `SimpleOpenAIGeminiVertex` depends on the following library that you must add your project:\n\n```\n    \u003cdependency\u003e\n      \u003cgroupId\u003ecom.google.auth\u003c/groupId\u003e\n      \u003cartifactId\u003egoogle-auth-library-oauth2-http\u003c/artifactId\u003e\n      \u003cversion\u003e1.15.0\u003c/version\u003e\n    \u003c/dependency\u003e\n```\n\n```java\nvar openai = SimpleOpenAIGeminiVertex.builder()\n    .baseUrl(System.getenv(\"GEMINI_VERTEX_BASE_URL\"))\n    .apiKeyProvider(\u003ca function that returns a valid API key that refreshes every hour\u003e)\n    //.clientAdapter(...)   Optionally you could pass a custom clientAdapter\n    .build();\n```\n\nCurrently we are supporting the following service:\n- `chatCompletionService` (text generation, streaming, function calling, vision, structured outputs)\n\n### Gemini Google API\n[Gemini Google API](https://ai.google.dev/gemini-api/docs/openai) is supported by Simple-OpenAI. We can use the class `SimpleOpenAIGeminiGoogle` to start using this provider.\n```java\nvar openai = SimpleOpenAIGeminiGoogle.builder()\n    .apiKey(System.getenv(\"GEMINIGOOGLE_API_KEY\"))\n    //.baseUrl(customUrl)   Optionally you could pass a custom baseUrl\n    //.clientAdapter(...)   Optionally you could pass a custom clientAdapter\n    .build();\n```\nCurrently we are supporting the following services:\n- `chatCompletionService` (text generation, streaming, function calling, vision, structured outputs)\n- `embeddingService` (float format)\n\n### Deepseek API\n[Deepseek API](https://api-docs.deepseek.com/) is supported by Simple-OpenAI. We can use the class `SimpleOpenAIDeepseek` to start using this provider.\n```java\nvar openai = SimpleOpenAIDeepseek.builder()\n    .apiKey(System.getenv(\"DEEPSEEK_API_KEY\"))\n    //.baseUrl(customUrl)   Optionally you could pass a custom baseUrl\n    //.clientAdapter(...)   Optionally you could pass a custom clientAdapter\n    .build();\n```\nCurrently we are supporting the following services:\n- `chatCompletionService` (text generation, streaming, thinking, function calling)\n- `modelService` (list)\n\n### Mistral API\n[Mistral API](https://docs.mistral.ai/getting-started/quickstart/) is supported by Simple-OpenAI. We can use the class `SimpleOpenAIMistral` to start using this provider.\n```java\nvar openai = SimpleOpenAIMistral.builder()\n    .apiKey(System.getenv(\"MISTRAL_API_KEY\"))\n    //.baseUrl(customUrl)   Optionally you could pass a custom baseUrl\n    //.clientAdapter(...)   Optionally you could pass a custom clientAdapter\n    .build();\n```\nCurrently we are supporting the following services:\n- `chatCompletionService` (text generation, streaming, function calling, vision)\n- `embeddingService` (float format)\n- `modelService` (list, detail, delete)\n\n### Azure OpenAI\n[Azure OpenIA](https://learn.microsoft.com/en-us/azure/ai-services/openai/reference) is supported by Simple-OpenAI. We can use the class `SimpleOpenAIAzure` to start using this provider. \n```java\nvar openai = SimpleOpenAIAzure.builder()\n    .apiKey(System.getenv(\"AZURE_OPENAI_API_KEY\"))\n    .baseUrl(System.getenv(\"AZURE_OPENAI_BASE_URL\"))   // Including resourceName and deploymentId\n    .apiVersion(System.getenv(\"AZURE_OPENAI_API_VERSION\"))\n    //.clientAdapter(...)   Optionally you could pass a custom clientAdapter\n    .build();\n```\nAzure OpenAI is powered by a diverse set of models with different capabilities and it requires a separate deployment for each model.\nModel availability varies by region and cloud. See more details about [Azure OpenAI Models](https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models).\n\nCurrently we are supporting the following services only:\n- `chatCompletionService` (text generation, streaming, function calling, vision, structured outputs)\n- `fileService` (upload files)\n- `assistantService beta V2` (assistants, threads, messages, runs, steps, vector stores, streaming, function calling, vision, structured outputs)\n\n### Anyscale\n[Anyscale](https://www.anyscale.com/endpoints) is suported by Simple-OpenAI. We can use the class `SimpleOpenAIAnyscale` to start using this provider.\n```java\nvar openai = SimpleOpenAIAnyscale.builder()\n    .apiKey(System.getenv(\"ANYSCALE_API_KEY\"))\n    //.baseUrl(customUrl)   Optionally you could pass a custom baseUrl\n    //.clientAdapter(...)   Optionally you could pass a custom clientAdapter\n    .build();\n```\nCurrently we are supporting the `chatCompletionService` service only. It was tested with the _Mistral_ model.\n\n\n## 🎬 Run Examples\nExamples for each OpenAI service have been created in the folder [demo](src/demo/java/io/github/sashirestela/openai/demo) and you can follow the next steps to execute them:\n* Clone this repository:\n  ```\n  git clone https://github.com/sashirestela/simple-openai.git\n  cd simple-openai\n  ```\n* Build the project:\n  ```\n  mvn clean install\n  ```\n* Create an environment variable for your OpenAI Api Key (the variable varies according to the OpenAI provider that we want to run):\n  ```\n  export OPENAI_API_KEY=\u003chere goes your api key\u003e\n  ```\n* Grant execution permission to the script file:\n  ```\n  chmod +x rundemo.sh\n  ```\n* Run examples:\n  ```\n  ./rundemo.sh \u003cdemo\u003e\n  ```\n  Where:\n\n  * ```\u003cdemo\u003e``` Is mandatory and must be one of the Java files in the folder demo without the suffix `Demo`, for example: _Audio, Chat, ChatMistral, Realtime, Response, AssistantV2, Conversation, ConversationV2, etc._\n  \n  * For example, to run the chat demo with a log file: ```./rundemo.sh Chat```\n\n* Instructions for Azure OpenAI demo\n\n    The recommended models to run this demo are:\n\n    1. gpt-4o\n    1. gpt-4o-mini\n    \n    See the Azure OpenAI docs for more details: [Azure OpenAI documentation](https://learn.microsoft.com/en-us/azure/ai-services/openai/).\n    Once you have the deployment URL and the API key, set the following environment variables:\n    ```\n    export AZURE_OPENAI_BASE_URL=\u003chttps://YOUR_RESOURCE_NAME.openai.azure.com/openai/deployments/YOUR_DEPLOYMENT_NAME\u003e\n    export AZURE_OPENAI_API_KEY=\u003chere goes your regional API key\u003e\n    export AZURE_OPENAI_API_VERSION=\u003cfor example: 2025-01-01-preview\u003e\n    ```\n    Note that some models may not be available in all regions. If you have trouble finding a model, \n    try a different region. The API keys are regional (per cognitive account). If you provision \n    multiple models in the same region they will share the same API key (actually there are two keys\n    per region to support alternate key rotation).\n\n* Instructions for Gemini Vertex Demo\n\n    You need a GCP project with the Vertex AI API enabled and a GCP service account with the necessary permissions to access the API.\n  \n    For details see https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/inference \n    Note the target region for the endpoint, the GCP project ID and the service account credentials JSON file.\n    Before you run the demo define the following environment variables:\n  \n    ```\n    export GEMINI_VERTEX_BASE_URL=https://\u003clocation\u003e-aiplatform.googleapis.com/v1beta1/projects/\u003cgcp project\u003e/locations/\u003clocation\u003e\u003e/endpoints/openapi\n    export GEMINI_VERTEX_SA_CREDS_PATH=\u003cpath to GCP service account credentials JSON file\u003e\n    ```\n\n## 💼 Contributing\nKindly read our [Contributing guide](CONTRIBUTING.md) to learn and understand how to contribute to this project.\n\n\n## 📄 License\nSimple-OpenAI is licensed under the MIT License. See the\n[LICENSE](https://github.com/sashirestela/simple-openai/blob/main/LICENSE) file\nfor more information.\n\n\n## 🔗 Who Is Using Simple-OpenAI?\nList of the main users of our library:\n- [ChatMotor](https://www.chatmotor.ai/): A framework for OpenAI services. Thanks for [credits](https://docs.chatmotor.ai/rest/soft/1.0-BETA/user-guide/User-Guide.html#credits-and-acknowledgments)!\n- [OpenOLAT](https://github.com/OpenOLAT/OpenOLAT): A learning managment system.\n- [SuperTurtyBot](https://github.com/DaRealTurtyWurty/SuperTurtyBot): A multi-purpose discord bot.\n- [Woolly](https://github.com/da-z/woolly): A code generation IntelliJ plugin.\n- [ScalerX.ai](https://scalerX.ai): A Telegram chatbot factory.\n- [Katie Backend](https://github.com/wyona/katie-backend): A question-answering platform.\n- [Java for Programmers, 5/e](https://deitel.com/java-for-programmers-5e): A Java book with Generative AI.\n- [Sentinel AI](https://phonepe.github.io/sentinel-ai/): A framework to build and deploy AI Agents.\n- [Furhat Robotics](https://www.furhatrobotics.com/): A social robot platform with conversational skills.\n- [Invisible Platforms](https://getinvisible.com/): A multi-agent platform for industry-agnostic.\n\n\n## 😍 Show Us Your Love\nThanks for using **simple-openai**. If you find this project valuable there are a few ways you can show us your love, preferably all of them 🙂:\n\n* Letting your friends know about this project 🗣📢.\n* Writing a brief review on your social networks ✍🌐.\n* Giving us a star on Github ⭐.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsashirestela%2Fsimple-openai","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsashirestela%2Fsimple-openai","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsashirestela%2Fsimple-openai/lists"}