From 536a0c33d2be5a6fb31affcf1d2dc84cff2daafc Mon Sep 17 00:00:00 2001 From: the-gigi Date: Sun, 11 Feb 2024 03:13:45 -0800 Subject: [PATCH 1/5] simple-openai support for Azure OpenAI via url intercetor and api-key header + bump cleverclient to 1.0.0 --- pom.xml | 2 +- .../openai/demo/AbstractDemo.java | 12 +++++ .../demo/AzureOpenAIChatServiceDemo.java | 53 +++++++++++++++++++ .../io/github/sashirestela/openai/OpenAI.java | 2 +- .../sashirestela/openai/SimpleOpenAI.java | 16 +++++- .../sashirestela/openai/SimpleOpenAITest.java | 18 +++---- 6 files changed, 91 insertions(+), 12 deletions(-) create mode 100644 src/demo/java/io/github/sashirestela/openai/demo/AzureOpenAIChatServiceDemo.java diff --git a/pom.xml b/pom.xml index de8699e6..47ab6a11 100644 --- a/pom.xml +++ b/pom.xml @@ -52,7 +52,7 @@ 11 [2.0.9,3.0.0) - 0.13.0 + 1.0.0 [1.18.30,2.0.0) [2.15.2,3.0.0) [4.31.1,5.0.0) diff --git a/src/demo/java/io/github/sashirestela/openai/demo/AbstractDemo.java b/src/demo/java/io/github/sashirestela/openai/demo/AbstractDemo.java index 97d3825a..e2091a31 100644 --- a/src/demo/java/io/github/sashirestela/openai/demo/AbstractDemo.java +++ b/src/demo/java/io/github/sashirestela/openai/demo/AbstractDemo.java @@ -4,6 +4,8 @@ import java.util.List; import io.github.sashirestela.openai.SimpleOpenAI; +import java.util.function.Function; +import lombok.NonNull; public abstract class AbstractDemo { @@ -23,6 +25,16 @@ protected AbstractDemo() { .build(); } + protected AbstractDemo(@NonNull String baseUrl, + @NonNull String apiKey, + @NonNull Function urlInterceptor) { + openAI = SimpleOpenAI.builder() + .apiKey(apiKey) + .baseUrl(baseUrl) + .urlInterceptor(urlInterceptor) + .build(); + } + public void addTitleAction(String title, Action action) { titleActions.add(new TitleAction(title, action)); } diff --git a/src/demo/java/io/github/sashirestela/openai/demo/AzureOpenAIChatServiceDemo.java b/src/demo/java/io/github/sashirestela/openai/demo/AzureOpenAIChatServiceDemo.java new file mode 100644 index 00000000..874d3454 --- /dev/null +++ b/src/demo/java/io/github/sashirestela/openai/demo/AzureOpenAIChatServiceDemo.java @@ -0,0 +1,53 @@ +package io.github.sashirestela.openai.demo; + + +import io.github.sashirestela.openai.domain.chat.ChatRequest; +import io.github.sashirestela.openai.domain.chat.message.ChatMsgSystem; +import io.github.sashirestela.openai.domain.chat.message.ChatMsgUser; +import java.util.Arrays; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class AzureOpenAIChatServiceDemo extends AbstractDemo { + + private final ChatRequest chatRequest; + + public AzureOpenAIChatServiceDemo(String baseUrl, String apiKey, String model) { + super(baseUrl, apiKey, url -> { + // add a query parameter to url (current api version for AzureOpenAI) + url += (url.contains("?") ? "&" : "?") + "api-version=2023-05-15"; + // remove '/vN' or '/vN.M' from url + url = url.replaceFirst("/v\\d+(\\.\\d+)?", ""); + return url; + }); + + chatRequest = ChatRequest.builder() + .model(model) + .message(new ChatMsgSystem("You are an expert in AI.")) + .message( + new ChatMsgUser("Write a technical article about ChatGPT, no more than 100 words.")) + .temperature(0.0) + .maxTokens(300) + .build(); + } + + public void demoCallChatBlocking() { + var futureChat = openAI.chatCompletions().create(chatRequest); + var chatResponse = futureChat.join(); + System.out.println(chatResponse.firstContent()); + } + + public static void main(String[] args) { + var baseUrl = System.getenv("CUSTOM_OPENAI_BASE_URL"); + var apiKey = System.getenv("CUSTOM_OPENAI_API_KEY"); + // Services like Azure OpenAI don't require a model (endpoints have built-in model) + var model = Optional.ofNullable(System.getenv("CUSTOM_OPENAI_MODEL")) + .orElse("N/A"); + var demo = new AzureOpenAIChatServiceDemo(baseUrl, apiKey, model); + + demo.addTitleAction("Call Completion (Blocking Approach)", demo::demoCallChatBlocking); + + demo.run(); + } +} \ No newline at end of file diff --git a/src/main/java/io/github/sashirestela/openai/OpenAI.java b/src/main/java/io/github/sashirestela/openai/OpenAI.java index 3408c75c..7c27b3d6 100644 --- a/src/main/java/io/github/sashirestela/openai/OpenAI.java +++ b/src/main/java/io/github/sashirestela/openai/OpenAI.java @@ -218,7 +218,7 @@ default CompletableFuture> createStream(@Body ChatRequest c /** * Given a prompt, the model will return one or more predicted completions. It - * is recommend most users to use the Chat Completion. + * is recommended for most users to use the Chat Completion. * * @see OpenAI diff --git a/src/main/java/io/github/sashirestela/openai/SimpleOpenAI.java b/src/main/java/io/github/sashirestela/openai/SimpleOpenAI.java index 928f1f74..afc1ae58 100644 --- a/src/main/java/io/github/sashirestela/openai/SimpleOpenAI.java +++ b/src/main/java/io/github/sashirestela/openai/SimpleOpenAI.java @@ -5,6 +5,7 @@ import java.util.Optional; import io.github.sashirestela.cleverclient.CleverClient; +import java.util.function.Function; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @@ -19,6 +20,7 @@ public class SimpleOpenAI { public static final String OPENAI_BASE_URL = "https://api.openai.com"; private static final String AUTHORIZATION_HEADER = "Authorization"; + private static final String AZURE_OPENAI_API_KEY_HEADER = "api-key"; private static final String ORGANIZATION_HEADER = "OpenAI-Organization"; private static final String BEARER_AUTHORIZATION = "Bearer "; private static final String END_OF_STREAM = "[DONE]"; @@ -30,6 +32,9 @@ public class SimpleOpenAI { private final String baseUrl; @Deprecated private final String urlBase = null; + + private String queryParams; + private HttpClient httpClient; private CleverClient cleverClient; @@ -77,6 +82,7 @@ public class SimpleOpenAI { * .... Optional. * @param urlBase [[ Deprecated ]] Host's url. See baseUrl. urlBase will * be removed in a future version. Optional. + * @queryParams Query params to be used in the requests. Optional. * @param httpClient A {@link java.net.http.HttpClient HttpClient} object. * One is created by default if not provided. Optional. */ @@ -86,17 +92,24 @@ public SimpleOpenAI( String organizationId, String baseUrl, String urlBase, - HttpClient httpClient) { + String queryParams, + HttpClient httpClient, + Function urlInterceptor) { this.apiKey = apiKey; this.organizationId = organizationId; this.baseUrl = Optional.ofNullable(baseUrl) .orElse(Optional.ofNullable(urlBase).orElse(OPENAI_BASE_URL)); + this.queryParams = queryParams; this.httpClient = Optional.ofNullable(httpClient).orElse(HttpClient.newHttpClient()); var headers = new ArrayList(); headers.add(AUTHORIZATION_HEADER); headers.add(BEARER_AUTHORIZATION + apiKey); + // Azure OpenAI API requires the API Key to be passed as api-key: + headers.add(AZURE_OPENAI_API_KEY_HEADER); + headers.add(apiKey); + if (organizationId != null) { headers.add(ORGANIZATION_HEADER); headers.add(organizationId); @@ -106,6 +119,7 @@ public SimpleOpenAI( .baseUrl(this.baseUrl) .headers(headers) .endOfStream(END_OF_STREAM) + .urlInterceptor(urlInterceptor) .build(); } diff --git a/src/test/java/io/github/sashirestela/openai/SimpleOpenAITest.java b/src/test/java/io/github/sashirestela/openai/SimpleOpenAITest.java index 12ef68db..8c460254 100644 --- a/src/test/java/io/github/sashirestela/openai/SimpleOpenAITest.java +++ b/src/test/java/io/github/sashirestela/openai/SimpleOpenAITest.java @@ -165,7 +165,7 @@ void shouldInstanceAudioServiceOnlyOnceWhenItIsCalledSeveralTimes() { when(cleverClient.create(any())) .thenReturn(ReflectUtil.createProxy( OpenAI.Audios.class, - new HttpProcessor(null, null, null))); + HttpProcessor.builder().build())); repeat(NUMBER_CALLINGS, () -> openAI.audios()); verify(cleverClient, times(NUMBER_INVOCATIONS)).create(any()); } @@ -175,7 +175,7 @@ void shouldInstanceChatCompletionServiceOnlyOnceWhenItIsCalledSeveralTimes() { when(cleverClient.create(any())) .thenReturn(ReflectUtil.createProxy( OpenAI.ChatCompletions.class, - new HttpProcessor(null, null, null))); + HttpProcessor.builder().build())); repeat(NUMBER_CALLINGS, () -> openAI.chatCompletions()); verify(cleverClient, times(NUMBER_INVOCATIONS)).create(any()); } @@ -185,7 +185,7 @@ void shouldInstanceCompletionServiceOnlyOnceWhenItIsCalledSeveralTimes() { when(cleverClient.create(any())) .thenReturn(ReflectUtil.createProxy( OpenAI.Completions.class, - new HttpProcessor(null, null, null))); + HttpProcessor.builder().build())); repeat(NUMBER_CALLINGS, () -> openAI.completions()); verify(cleverClient, times(NUMBER_INVOCATIONS)).create(any()); } @@ -195,7 +195,7 @@ void shouldInstanceEmbeddingServiceOnlyOnceWhenItIsCalledSeveralTimes() { when(cleverClient.create(any())) .thenReturn(ReflectUtil.createProxy( OpenAI.Embeddings.class, - new HttpProcessor(null, null, null))); + HttpProcessor.builder().build())); repeat(NUMBER_CALLINGS, () -> openAI.embeddings()); verify(cleverClient, times(NUMBER_INVOCATIONS)).create(any()); } @@ -205,7 +205,7 @@ void shouldInstanceFilesServiceOnlyOnceWhenItIsCalledSeveralTimes() { when(cleverClient.create(any())) .thenReturn(ReflectUtil.createProxy( OpenAI.Files.class, - new HttpProcessor(null, null, null))); + HttpProcessor.builder().build())); repeat(NUMBER_CALLINGS, () -> openAI.files()); verify(cleverClient, times(NUMBER_INVOCATIONS)).create(any()); } @@ -215,7 +215,7 @@ void shouldInstanceFineTunningServiceOnlyOnceWhenItIsCalledSeveralTimes() { when(cleverClient.create(any())) .thenReturn(ReflectUtil.createProxy( OpenAI.FineTunings.class, - new HttpProcessor(null, null, null))); + HttpProcessor.builder().build())); repeat(NUMBER_CALLINGS, () -> openAI.fineTunings()); verify(cleverClient, times(NUMBER_INVOCATIONS)).create(any()); } @@ -225,7 +225,7 @@ void shouldInstanceImageServiceOnlyOnceWhenItIsCalledSeveralTimes() { when(cleverClient.create(any())) .thenReturn(ReflectUtil.createProxy( OpenAI.Images.class, - new HttpProcessor(null, null, null))); + HttpProcessor.builder().build())); repeat(NUMBER_CALLINGS, () -> openAI.images()); verify(cleverClient, times(NUMBER_INVOCATIONS)).create(any()); } @@ -235,7 +235,7 @@ void shouldInstanceModelsServiceOnlyOnceWhenItIsCalledSeveralTimes() { when(cleverClient.create(any())) .thenReturn(ReflectUtil.createProxy( OpenAI.Models.class, - new HttpProcessor(null, null, null))); + HttpProcessor.builder().build())); repeat(NUMBER_CALLINGS, () -> openAI.models()); verify(cleverClient, times(NUMBER_INVOCATIONS)).create(any()); } @@ -245,7 +245,7 @@ void shouldInstanceModerationServiceOnlyOnceWhenItIsCalledSeveralTimes() { when(cleverClient.create(any())) .thenReturn(ReflectUtil.createProxy( OpenAI.Moderations.class, - new HttpProcessor(null, null, null))); + HttpProcessor.builder().build())); repeat(NUMBER_CALLINGS, () -> openAI.moderations()); verify(cleverClient, times(NUMBER_INVOCATIONS)).create(any()); } From d954db59a10d12b8f2d81ca4dd7ba90f314f00ae Mon Sep 17 00:00:00 2001 From: the-gigi Date: Mon, 12 Feb 2024 00:50:17 -0800 Subject: [PATCH 2/5] formatting --- .../openai/demo/AzureOpenAIChatServiceDemo.java | 2 +- .../java/io/github/sashirestela/openai/SimpleOpenAI.java | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/demo/java/io/github/sashirestela/openai/demo/AzureOpenAIChatServiceDemo.java b/src/demo/java/io/github/sashirestela/openai/demo/AzureOpenAIChatServiceDemo.java index 874d3454..10236b9e 100644 --- a/src/demo/java/io/github/sashirestela/openai/demo/AzureOpenAIChatServiceDemo.java +++ b/src/demo/java/io/github/sashirestela/openai/demo/AzureOpenAIChatServiceDemo.java @@ -50,4 +50,4 @@ public static void main(String[] args) { demo.run(); } -} \ No newline at end of file +} diff --git a/src/main/java/io/github/sashirestela/openai/SimpleOpenAI.java b/src/main/java/io/github/sashirestela/openai/SimpleOpenAI.java index afc1ae58..25195c01 100644 --- a/src/main/java/io/github/sashirestela/openai/SimpleOpenAI.java +++ b/src/main/java/io/github/sashirestela/openai/SimpleOpenAI.java @@ -33,8 +33,6 @@ public class SimpleOpenAI { @Deprecated private final String urlBase = null; - private String queryParams; - private HttpClient httpClient; private CleverClient cleverClient; @@ -82,7 +80,6 @@ public class SimpleOpenAI { * .... Optional. * @param urlBase [[ Deprecated ]] Host's url. See baseUrl. urlBase will * be removed in a future version. Optional. - * @queryParams Query params to be used in the requests. Optional. * @param httpClient A {@link java.net.http.HttpClient HttpClient} object. * One is created by default if not provided. Optional. */ @@ -92,7 +89,6 @@ public SimpleOpenAI( String organizationId, String baseUrl, String urlBase, - String queryParams, HttpClient httpClient, Function urlInterceptor) { this.apiKey = apiKey; @@ -100,7 +96,6 @@ public SimpleOpenAI( this.baseUrl = Optional.ofNullable(baseUrl) .orElse(Optional.ofNullable(urlBase).orElse(OPENAI_BASE_URL)); - this.queryParams = queryParams; this.httpClient = Optional.ofNullable(httpClient).orElse(HttpClient.newHttpClient()); var headers = new ArrayList(); @@ -109,7 +104,6 @@ public SimpleOpenAI( // Azure OpenAI API requires the API Key to be passed as api-key: headers.add(AZURE_OPENAI_API_KEY_HEADER); headers.add(apiKey); - if (organizationId != null) { headers.add(ORGANIZATION_HEADER); headers.add(organizationId); From d87fb33d82d532d1f085046a32ab1ee3ac4e596c Mon Sep 17 00:00:00 2001 From: the-gigi Date: Mon, 12 Feb 2024 17:49:49 -0800 Subject: [PATCH 3/5] bump cleverclient to 1.1.0 + use request interceptor to support Azure OpenAI --- pom.xml | 2 +- .../openai/demo/AbstractDemo.java | 6 ++- .../demo/AzureOpenAIChatServiceDemo.java | 43 +++++++++++++++---- .../sashirestela/openai/SimpleOpenAI.java | 23 +++++----- .../openai/support/JsonSchemaUtil.java | 4 +- .../sashirestela/openai/SimpleOpenAITest.java | 4 +- .../openai/support/JsonSchemaUtilTest.java | 3 +- 7 files changed, 57 insertions(+), 28 deletions(-) diff --git a/pom.xml b/pom.xml index 47ab6a11..f401c0c9 100644 --- a/pom.xml +++ b/pom.xml @@ -52,7 +52,7 @@ 11 [2.0.9,3.0.0) - 1.0.0 + 1.1.0 [1.18.30,2.0.0) [2.15.2,3.0.0) [4.31.1,5.0.0) diff --git a/src/demo/java/io/github/sashirestela/openai/demo/AbstractDemo.java b/src/demo/java/io/github/sashirestela/openai/demo/AbstractDemo.java index e2091a31..fe47412d 100644 --- a/src/demo/java/io/github/sashirestela/openai/demo/AbstractDemo.java +++ b/src/demo/java/io/github/sashirestela/openai/demo/AbstractDemo.java @@ -1,10 +1,12 @@ package io.github.sashirestela.openai.demo; +import io.github.sashirestela.cleverclient.http.HttpRequestData; import java.util.ArrayList; import java.util.List; import io.github.sashirestela.openai.SimpleOpenAI; import java.util.function.Function; +import java.util.function.UnaryOperator; import lombok.NonNull; public abstract class AbstractDemo { @@ -27,11 +29,11 @@ protected AbstractDemo() { protected AbstractDemo(@NonNull String baseUrl, @NonNull String apiKey, - @NonNull Function urlInterceptor) { + @NonNull UnaryOperator requestInterceptor) { openAI = SimpleOpenAI.builder() .apiKey(apiKey) .baseUrl(baseUrl) - .urlInterceptor(urlInterceptor) + .requestInterceptor(requestInterceptor) .build(); } diff --git a/src/demo/java/io/github/sashirestela/openai/demo/AzureOpenAIChatServiceDemo.java b/src/demo/java/io/github/sashirestela/openai/demo/AzureOpenAIChatServiceDemo.java index 10236b9e..d60b69c3 100644 --- a/src/demo/java/io/github/sashirestela/openai/demo/AzureOpenAIChatServiceDemo.java +++ b/src/demo/java/io/github/sashirestela/openai/demo/AzureOpenAIChatServiceDemo.java @@ -1,25 +1,52 @@ package io.github.sashirestela.openai.demo; +import io.github.sashirestela.cleverclient.support.ContentType; import io.github.sashirestela.openai.domain.chat.ChatRequest; import io.github.sashirestela.openai.domain.chat.message.ChatMsgSystem; import io.github.sashirestela.openai.domain.chat.message.ChatMsgUser; -import java.util.Arrays; +import java.util.Map; import java.util.Optional; -import java.util.function.Function; -import java.util.stream.Collectors; public class AzureOpenAIChatServiceDemo extends AbstractDemo { - + private static final String AZURE_OPENAI_API_KEY_HEADER = "api-key"; private final ChatRequest chatRequest; public AzureOpenAIChatServiceDemo(String baseUrl, String apiKey, String model) { - super(baseUrl, apiKey, url -> { - // add a query parameter to url (current api version for AzureOpenAI) + super(baseUrl, apiKey, request -> { + var url = request.getUrl(); + var contentType = request.getContentType(); + var body = request.getBody(); + + // add a header to the request + var headers = request.getHeaders(); + headers.put(AZURE_OPENAI_API_KEY_HEADER, apiKey); + request.setHeaders(headers); + + // add a query parameter to url url += (url.contains("?") ? "&" : "?") + "api-version=2023-05-15"; // remove '/vN' or '/vN.M' from url - url = url.replaceFirst("/v\\d+(\\.\\d+)?", ""); - return url; + url = url.replaceFirst("(\\/v\\d+\\.*\\d*)", ""); + request.setUrl(url); + + if (contentType != null) { + if (contentType.equals(ContentType.APPLICATION_JSON)) { + var bodyJson = (String) request.getBody(); + // remove a field from body (as Json) + bodyJson = bodyJson.replaceFirst(",?\"model\":\"[^\"]*\",?", ""); + bodyJson = bodyJson.replaceFirst("\"\"", "\",\""); + body = bodyJson; + } + if (contentType.equals(ContentType.MULTIPART_FORMDATA)) { + Map bodyMap = (Map) request.getBody(); + // remove a field from body (as Map) + bodyMap.remove("model"); + body = bodyMap; + } + request.setBody(body); + } + + return request; }); chatRequest = ChatRequest.builder() diff --git a/src/main/java/io/github/sashirestela/openai/SimpleOpenAI.java b/src/main/java/io/github/sashirestela/openai/SimpleOpenAI.java index 25195c01..fcdc75c5 100644 --- a/src/main/java/io/github/sashirestela/openai/SimpleOpenAI.java +++ b/src/main/java/io/github/sashirestela/openai/SimpleOpenAI.java @@ -1,11 +1,17 @@ package io.github.sashirestela.openai; +import io.github.sashirestela.cleverclient.http.HttpRequestData; import java.net.http.HttpClient; import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; import java.util.Optional; import io.github.sashirestela.cleverclient.CleverClient; +import java.util.Set; import java.util.function.Function; +import java.util.function.UnaryOperator; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @@ -20,7 +26,6 @@ public class SimpleOpenAI { public static final String OPENAI_BASE_URL = "https://api.openai.com"; private static final String AUTHORIZATION_HEADER = "Authorization"; - private static final String AZURE_OPENAI_API_KEY_HEADER = "api-key"; private static final String ORGANIZATION_HEADER = "OpenAI-Organization"; private static final String BEARER_AUTHORIZATION = "Bearer "; private static final String END_OF_STREAM = "[DONE]"; @@ -90,7 +95,7 @@ public SimpleOpenAI( String baseUrl, String urlBase, HttpClient httpClient, - Function urlInterceptor) { + UnaryOperator requestInterceptor) { this.apiKey = apiKey; this.organizationId = organizationId; this.baseUrl = Optional.ofNullable(baseUrl) @@ -98,22 +103,14 @@ public SimpleOpenAI( this.httpClient = Optional.ofNullable(httpClient).orElse(HttpClient.newHttpClient()); - var headers = new ArrayList(); - headers.add(AUTHORIZATION_HEADER); - headers.add(BEARER_AUTHORIZATION + apiKey); - // Azure OpenAI API requires the API Key to be passed as api-key: - headers.add(AZURE_OPENAI_API_KEY_HEADER); - headers.add(apiKey); - if (organizationId != null) { - headers.add(ORGANIZATION_HEADER); - headers.add(organizationId); - } + var headers = new HashMap(); + headers.put(AUTHORIZATION_HEADER, BEARER_AUTHORIZATION + apiKey); this.cleverClient = CleverClient.builder() .httpClient(this.httpClient) .baseUrl(this.baseUrl) .headers(headers) .endOfStream(END_OF_STREAM) - .urlInterceptor(urlInterceptor) + .requestInterceptor(requestInterceptor) .build(); } diff --git a/src/main/java/io/github/sashirestela/openai/support/JsonSchemaUtil.java b/src/main/java/io/github/sashirestela/openai/support/JsonSchemaUtil.java index da53db69..3b2269dd 100644 --- a/src/main/java/io/github/sashirestela/openai/support/JsonSchemaUtil.java +++ b/src/main/java/io/github/sashirestela/openai/support/JsonSchemaUtil.java @@ -15,6 +15,8 @@ import io.github.sashirestela.openai.SimpleUncheckedException; public class JsonSchemaUtil { + + public static final String JSON_EMPTY_CLASS = "{\"type\":\"object\",\"properties\":{}}"; private static ObjectMapper objectMapper = new ObjectMapper(); private JsonSchemaUtil() { @@ -39,7 +41,7 @@ public static JsonNode classToJsonSchema(Class clazz) { } } else { try { - jsonSchema = objectMapper.readTree(Constant.JSON_EMPTY_CLASS); + jsonSchema = objectMapper.readTree(JSON_EMPTY_CLASS); } catch (JsonProcessingException e) { throw new SimpleUncheckedException("Cannot generate the Json Schema for the class {0}.", clazz.getName(), e); diff --git a/src/test/java/io/github/sashirestela/openai/SimpleOpenAITest.java b/src/test/java/io/github/sashirestela/openai/SimpleOpenAITest.java index 8c460254..65b4c9f5 100644 --- a/src/test/java/io/github/sashirestela/openai/SimpleOpenAITest.java +++ b/src/test/java/io/github/sashirestela/openai/SimpleOpenAITest.java @@ -99,7 +99,7 @@ void shouldNotAddOrganizationToHeadersWhenBuilderIsCalledWithoutOrganizationId() var openAI = SimpleOpenAI.builder() .apiKey("apiKey") .build(); - assertFalse(openAI.getCleverClient().getHeaders().contains(openAI.getOrganizationId())); + assertFalse(openAI.getCleverClient().getHeaders().containsValue(openAI.getOrganizationId())); } @Test @@ -108,7 +108,7 @@ void shouldAddOrganizationToHeadersWhenBuilderIsCalledWithOrganizationId() { .apiKey("apiKey") .organizationId("orgId") .build(); - assertTrue(openAI.getCleverClient().getHeaders().contains(openAI.getOrganizationId())); + assertTrue(openAI.getCleverClient().getHeaders().containsValue(openAI.getOrganizationId())); } @Test diff --git a/src/test/java/io/github/sashirestela/openai/support/JsonSchemaUtilTest.java b/src/test/java/io/github/sashirestela/openai/support/JsonSchemaUtilTest.java index 529df928..d64794d4 100644 --- a/src/test/java/io/github/sashirestela/openai/support/JsonSchemaUtilTest.java +++ b/src/test/java/io/github/sashirestela/openai/support/JsonSchemaUtilTest.java @@ -1,5 +1,6 @@ package io.github.sashirestela.openai.support; +import static io.github.sashirestela.openai.support.JsonSchemaUtil.JSON_EMPTY_CLASS; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; @@ -24,7 +25,7 @@ void shouldGenerateFullJsonSchemaWhenClassHasSomeFields() { @Test void shouldGenerateEmptyJsonSchemaWhenClassHasNoFields() { var actualJsonSchema = JsonSchemaUtil.classToJsonSchema(EmptyClass.class).toString(); - var expectedJsonSchema = Constant.JSON_EMPTY_CLASS; + var expectedJsonSchema = JSON_EMPTY_CLASS; assertEquals(expectedJsonSchema, actualJsonSchema); } From 19844ce716f4ec5ed68b3e3ffe6851a437c6ff5f Mon Sep 17 00:00:00 2001 From: the-gigi Date: Mon, 12 Feb 2024 17:56:56 -0800 Subject: [PATCH 4/5] fix a test mixup --- src/main/java/io/github/sashirestela/openai/SimpleOpenAI.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/io/github/sashirestela/openai/SimpleOpenAI.java b/src/main/java/io/github/sashirestela/openai/SimpleOpenAI.java index fcdc75c5..a824d393 100644 --- a/src/main/java/io/github/sashirestela/openai/SimpleOpenAI.java +++ b/src/main/java/io/github/sashirestela/openai/SimpleOpenAI.java @@ -105,6 +105,9 @@ public SimpleOpenAI( var headers = new HashMap(); headers.put(AUTHORIZATION_HEADER, BEARER_AUTHORIZATION + apiKey); + if (organizationId != null) { + headers.put(ORGANIZATION_HEADER, organizationId); + } this.cleverClient = CleverClient.builder() .httpClient(this.httpClient) .baseUrl(this.baseUrl) From 7eaadacd9788f31fdf2a954899a93f5d7a4944e7 Mon Sep 17 00:00:00 2001 From: the-gigi Date: Tue, 13 Feb 2024 09:01:39 -0800 Subject: [PATCH 5/5] fix review comments --- .../io/github/sashirestela/openai/demo/AbstractDemo.java | 4 +--- .../openai/demo/AzureOpenAIChatServiceDemo.java | 1 + .../java/io/github/sashirestela/openai/SimpleOpenAI.java | 8 +------- .../sashirestela/openai/support/JsonSchemaUtil.java | 2 -- .../sashirestela/openai/support/JsonSchemaUtilTest.java | 5 +---- 5 files changed, 4 insertions(+), 16 deletions(-) diff --git a/src/demo/java/io/github/sashirestela/openai/demo/AbstractDemo.java b/src/demo/java/io/github/sashirestela/openai/demo/AbstractDemo.java index fe47412d..55a01d35 100644 --- a/src/demo/java/io/github/sashirestela/openai/demo/AbstractDemo.java +++ b/src/demo/java/io/github/sashirestela/openai/demo/AbstractDemo.java @@ -1,11 +1,9 @@ package io.github.sashirestela.openai.demo; import io.github.sashirestela.cleverclient.http.HttpRequestData; +import io.github.sashirestela.openai.SimpleOpenAI; import java.util.ArrayList; import java.util.List; - -import io.github.sashirestela.openai.SimpleOpenAI; -import java.util.function.Function; import java.util.function.UnaryOperator; import lombok.NonNull; diff --git a/src/demo/java/io/github/sashirestela/openai/demo/AzureOpenAIChatServiceDemo.java b/src/demo/java/io/github/sashirestela/openai/demo/AzureOpenAIChatServiceDemo.java index d60b69c3..23c384c7 100644 --- a/src/demo/java/io/github/sashirestela/openai/demo/AzureOpenAIChatServiceDemo.java +++ b/src/demo/java/io/github/sashirestela/openai/demo/AzureOpenAIChatServiceDemo.java @@ -12,6 +12,7 @@ public class AzureOpenAIChatServiceDemo extends AbstractDemo { private static final String AZURE_OPENAI_API_KEY_HEADER = "api-key"; private final ChatRequest chatRequest; + @SuppressWarnings("unchecked") public AzureOpenAIChatServiceDemo(String baseUrl, String apiKey, String model) { super(baseUrl, apiKey, request -> { var url = request.getUrl(); diff --git a/src/main/java/io/github/sashirestela/openai/SimpleOpenAI.java b/src/main/java/io/github/sashirestela/openai/SimpleOpenAI.java index a824d393..e7f74c77 100644 --- a/src/main/java/io/github/sashirestela/openai/SimpleOpenAI.java +++ b/src/main/java/io/github/sashirestela/openai/SimpleOpenAI.java @@ -1,16 +1,10 @@ package io.github.sashirestela.openai; +import io.github.sashirestela.cleverclient.CleverClient; import io.github.sashirestela.cleverclient.http.HttpRequestData; import java.net.http.HttpClient; -import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; -import java.util.Map; import java.util.Optional; - -import io.github.sashirestela.cleverclient.CleverClient; -import java.util.Set; -import java.util.function.Function; import java.util.function.UnaryOperator; import lombok.AccessLevel; import lombok.Builder; diff --git a/src/main/java/io/github/sashirestela/openai/support/JsonSchemaUtil.java b/src/main/java/io/github/sashirestela/openai/support/JsonSchemaUtil.java index 3b2269dd..e47999f1 100644 --- a/src/main/java/io/github/sashirestela/openai/support/JsonSchemaUtil.java +++ b/src/main/java/io/github/sashirestela/openai/support/JsonSchemaUtil.java @@ -10,8 +10,6 @@ import com.github.victools.jsonschema.generator.SchemaVersion; import com.github.victools.jsonschema.module.jackson.JacksonModule; import com.github.victools.jsonschema.module.jackson.JacksonOption; - -import io.github.sashirestela.cleverclient.util.Constant; import io.github.sashirestela.openai.SimpleUncheckedException; public class JsonSchemaUtil { diff --git a/src/test/java/io/github/sashirestela/openai/support/JsonSchemaUtilTest.java b/src/test/java/io/github/sashirestela/openai/support/JsonSchemaUtilTest.java index d64794d4..543bb507 100644 --- a/src/test/java/io/github/sashirestela/openai/support/JsonSchemaUtilTest.java +++ b/src/test/java/io/github/sashirestela/openai/support/JsonSchemaUtilTest.java @@ -3,14 +3,11 @@ import static io.github.sashirestela.openai.support.JsonSchemaUtil.JSON_EMPTY_CLASS; import static org.junit.jupiter.api.Assertions.assertEquals; -import org.junit.jupiter.api.Test; - import com.fasterxml.jackson.annotation.JsonProperty; - -import io.github.sashirestela.cleverclient.util.Constant; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; +import org.junit.jupiter.api.Test; class JsonSchemaUtilTest {