Skip to content

Commit bbc0146

Browse files
committed
Fixes
1 parent 8554091 commit bbc0146

File tree

3 files changed

+106
-44
lines changed

3 files changed

+106
-44
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.sap.ai.sdk.foundationmodels.openai;
2+
3+
import com.fasterxml.jackson.annotation.JsonSubTypes;
4+
import com.fasterxml.jackson.annotation.JsonTypeInfo;
5+
import com.sap.ai.sdk.foundationmodels.openai.model2.CreateChatCompletionResponse;
6+
import com.sap.ai.sdk.foundationmodels.openai.model2.CreateChatCompletionStreamResponse;
7+
import lombok.AccessLevel;
8+
import lombok.NoArgsConstructor;
9+
10+
@NoArgsConstructor(access = AccessLevel.PRIVATE)
11+
final class JacksonMixins {
12+
13+
@JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
14+
interface CreateChatCompletionStreamResponseMixIn {}
15+
16+
@JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
17+
interface CreateChatCompletionResponseMixIn {}
18+
19+
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "object", defaultImpl = CreateChatCompletionResponse.class, visible = true)
20+
@JsonSubTypes({
21+
@JsonSubTypes.Type(value = CreateChatCompletionResponse.class, name="chat.completion"),
22+
@JsonSubTypes.Type(value = CreateChatCompletionStreamResponse.class, name = "chat.completion.chunk"),
23+
})
24+
public interface ChatCompletionCreate200ResponseMixIn {}
25+
}

foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiClient.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
import com.sap.ai.sdk.foundationmodels.openai.model2.ChatCompletionRequestUserMessage;
1818
import com.sap.ai.sdk.foundationmodels.openai.model2.ChatCompletionRequestUserMessageContent;
1919
import com.sap.ai.sdk.foundationmodels.openai.model2.ChatCompletionStreamOptions;
20+
import com.sap.ai.sdk.foundationmodels.openai.model2.ChatCompletionsCreate200Response;
2021
import com.sap.ai.sdk.foundationmodels.openai.model2.CreateChatCompletionRequest;
2122
import com.sap.ai.sdk.foundationmodels.openai.model2.CreateChatCompletionResponse;
23+
import com.sap.ai.sdk.foundationmodels.openai.model2.CreateChatCompletionStreamResponse;
2224
import com.sap.ai.sdk.foundationmodels.openai.model2.EmbeddingsCreate200Response;
2325
import com.sap.ai.sdk.foundationmodels.openai.model2.EmbeddingsCreateRequest;
2426
import com.sap.cloud.sdk.cloudplatform.connectivity.ApacheHttpClient5Accessor;
@@ -320,6 +322,11 @@ private <D extends StreamedDelta> Stream<D> streamRequest(
320322
try {
321323
final var client = ApacheHttpClient5Accessor.getHttpClient(destination);
322324
return new ClientStreamingHandler<>(deltaType, OpenAiError.class, OpenAiClientException::new)
325+
.objectMapper(JACKSON
326+
.addMixIn(CreateChatCompletionResponse.class, JacksonMixins.CreateChatCompletionResponseMixIn.class)
327+
.addMixIn(CreateChatCompletionStreamResponse.class, JacksonMixins.CreateChatCompletionStreamResponseMixIn.class)
328+
.addMixIn(ChatCompletionsCreate200Response.class, JacksonMixins.ChatCompletionCreate200ResponseMixIn.class)
329+
)
323330
.handleStreamingResponse(client.executeOpen(null, request, null));
324331
} catch (final IOException e) {
325332
throw new OpenAiClientException("Request to OpenAI model failed", e);

foundation-models/openai/src/test/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiClientTest.java

Lines changed: 74 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
package com.sap.ai.sdk.foundationmodels.openai;
22

33
import static com.github.tomakehurst.wiremock.client.WireMock.*;
4-
import static com.sap.ai.sdk.foundationmodels.openai.model.OpenAiContentFilterSeverityResult.Severity.SAFE;
4+
import static com.sap.ai.sdk.foundationmodels.openai.model2.ChatCompletionResponseMessageRole.ASSISTANT;
5+
import static com.sap.ai.sdk.foundationmodels.openai.model2.ContentFilterSeverityResult.SeverityEnum.SAFE;
6+
import static com.sap.ai.sdk.foundationmodels.openai.model2.CreateChatCompletionResponse.ObjectEnum.UNKNOWN_DEFAULT_OPEN_API;
7+
import static com.sap.ai.sdk.foundationmodels.openai.model2.CreateChatCompletionResponseChoicesInner.FinishReasonEnum.STOP;
8+
import static com.sap.ai.sdk.foundationmodels.openai.model2.CreateChatCompletionStreamResponse.ObjectEnum.CHAT_COMPLETION_CHUNK;
9+
import static org.assertj.core.api.Assertions.as;
510
import static org.assertj.core.api.Assertions.assertThat;
611
import static org.assertj.core.api.Assertions.assertThatThrownBy;
12+
import static org.assertj.core.api.InstanceOfAssertFactories.map;
713
import static org.mockito.ArgumentMatchers.any;
814
import static org.mockito.Mockito.doReturn;
915
import static org.mockito.Mockito.mock;
@@ -21,10 +27,12 @@
2127
import com.sap.ai.sdk.foundationmodels.openai.model2.ChatCompletionRequestUserMessageContent;
2228
import com.sap.ai.sdk.foundationmodels.openai.model2.CompletionUsage;
2329
import com.sap.ai.sdk.foundationmodels.openai.model2.ContentFilterChoiceResults;
30+
import com.sap.ai.sdk.foundationmodels.openai.model2.ContentFilterSeverityResult;
2431
import com.sap.ai.sdk.foundationmodels.openai.model2.CreateChatCompletionRequest;
2532
import com.sap.ai.sdk.foundationmodels.openai.model2.CreateChatCompletionResponse;
2633
import com.sap.ai.sdk.foundationmodels.openai.model2.CreateChatCompletionResponseChoicesInner;
2734
import com.sap.ai.sdk.foundationmodels.openai.model2.CreateChatCompletionStreamResponse;
35+
import com.sap.ai.sdk.foundationmodels.openai.model2.CreateChatCompletionStreamResponseChoicesInner;
2836
import com.sap.ai.sdk.foundationmodels.openai.model2.EmbeddingsCreateRequest;
2937
import com.sap.ai.sdk.foundationmodels.openai.model2.EmbeddingsCreateRequestInput;
3038
import com.sap.cloud.sdk.cloudplatform.connectivity.ApacheHttpClient5Accessor;
@@ -35,6 +43,7 @@
3543
import java.io.InputStream;
3644
import java.math.BigDecimal;
3745
import java.util.List;
46+
import java.util.Map;
3847
import java.util.Objects;
3948
import java.util.concurrent.Callable;
4049
import java.util.function.Function;
@@ -226,7 +235,7 @@ void chatCompletion(@Nonnull final Callable<CreateChatCompletionResponse> reques
226235
assertThat(result.getCreated()).isEqualTo(1727436279);
227236
assertThat(result.getId()).isEqualTo("chatcmpl-AC3NPPYlxem8kRBBAX9EBObMMsrnf");
228237
assertThat(result.getModel()).isEqualTo("gpt-35-turbo");
229-
assertThat(result.getObject()).isEqualTo("\"chat.completion\"");
238+
assertThat(result.getObject().getValue()).isEqualTo("chat.completion");
230239
assertThat(result.getSystemFingerprint()).isEqualTo("fp_e49e4201a9");
231240

232241
assertThat(result.getUsage()).isNotNull();
@@ -256,12 +265,12 @@ void chatCompletion(@Nonnull final Callable<CreateChatCompletionResponse> reques
256265

257266
assertThat(result.getChoices()).hasSize(1);
258267
CreateChatCompletionResponseChoicesInner choice = result.getChoices().get(0);
259-
assertThat(choice.getFinishReason()).isEqualTo("stop");
268+
assertThat(choice.getFinishReason()).isEqualTo(STOP);
260269
assertThat(choice.getIndex()).isEqualTo(0);
261270
assertThat(choice.getMessage().getContent())
262271
.isEqualTo(
263272
"I'm an AI and cannot answer that question as beauty is subjective and varies from person to person.");
264-
assertThat(choice.getMessage().getRole()).isEqualTo("assistant");
273+
assertThat(choice.getMessage().getRole()).isEqualTo(ASSISTANT);
265274
assertThat(choice.getMessage().getToolCalls()).isNull();
266275

267276
ContentFilterChoiceResults contentFilterResults = choice.getContentFilterResults();
@@ -289,16 +298,23 @@ void chatCompletion(@Nonnull final Callable<CreateChatCompletionResponse> reques
289298
equalToJson(
290299
"""
291300
{
292-
"messages" : [ {
293-
"role" : "system",
294-
"content" : "You are a helpful AI"
295-
}, {
296-
"role" : "user",
297-
"content" : [ {
298-
"type" : "text",
299-
"text" : "Hello World! Why is this phrase so famous?"
300-
} ]
301-
} ]
301+
"temperature" : 1,
302+
"top_p" : 1,
303+
"stream" : false,
304+
"presence_penalty" : 0,
305+
"frequency_penalty" : 0,
306+
"messages" : [ {
307+
"content" : "You are a helpful AI",
308+
"role" : "system"
309+
}, {
310+
"content" : "Hello World! Why is this phrase so famous?",
311+
"role" : "user"
312+
} ],
313+
"logprobs" : false,
314+
"n" : 1,
315+
"parallel_tool_calls" : true,
316+
"tools" : [ ],
317+
"functions" : [ ]
302318
}""")));
303319
}
304320
}
@@ -322,16 +338,23 @@ void history() {
322338
equalToJson(
323339
"""
324340
{
325-
"messages" : [ {
326-
"role" : "system",
327-
"content" : "system prompt"
328-
}, {
329-
"role" : "user",
330-
"content" : [ {
331-
"type" : "text",
332-
"text" : "chat completion 1"
333-
} ]
334-
} ]
341+
"temperature" : 1,
342+
"top_p" : 1,
343+
"stream" : false,
344+
"presence_penalty" : 0,
345+
"frequency_penalty" : 0,
346+
"messages" : [ {
347+
"content" : "system prompt",
348+
"role" : "system"
349+
}, {
350+
"content" : "chat completion 1",
351+
"role" : "user"
352+
} ],
353+
"logprobs" : false,
354+
"n" : 1,
355+
"parallel_tool_calls" : true,
356+
"tools" : [ ],
357+
"functions" : [ ]
335358
}""")));
336359

337360
client.withSystemPrompt("system prompt").chatCompletion("chat completion 2");
@@ -343,16 +366,23 @@ void history() {
343366
equalToJson(
344367
"""
345368
{
346-
"messages" : [ {
347-
"role" : "system",
348-
"content" : "system prompt"
349-
}, {
350-
"role" : "user",
351-
"content" : [ {
352-
"type" : "text",
353-
"text" : "chat completion 2"
354-
} ]
355-
} ]
369+
"temperature" : 1,
370+
"top_p" : 1,
371+
"stream" : false,
372+
"presence_penalty" : 0,
373+
"frequency_penalty" : 0,
374+
"messages" : [ {
375+
"content" : "system prompt",
376+
"role" : "system"
377+
}, {
378+
"content" : "chat completion 2",
379+
"role" : "user"
380+
} ],
381+
"logprobs" : false,
382+
"n" : 1,
383+
"parallel_tool_calls" : true,
384+
"tools" : [ ],
385+
"functions" : [ ]
356386
}""")));
357387
}
358388

@@ -511,7 +541,7 @@ void streamChatCompletionDeltas() throws IOException {
511541
assertThat(delta0.getId()).isEqualTo("");
512542
assertThat(delta0.getCreated()).isEqualTo(0);
513543
assertThat(delta0.getModel()).isEqualTo("");
514-
assertThat(delta0.getObject()).isEqualTo("");
544+
assertThat(delta0.getObject()).isEqualTo(UNKNOWN_DEFAULT_OPEN_API);
515545
// assertThat(delta0.getUsage()).isNull();
516546
assertThat(delta0.getChoices()).isEmpty();
517547
// prompt filter results are only present in delta 0
@@ -526,17 +556,17 @@ void streamChatCompletionDeltas() throws IOException {
526556
assertThat(delta2.getId()).isEqualTo("chatcmpl-A16EvnkgEm6AdxY0NoOmGPjsJucQ1");
527557
assertThat(delta2.getCreated()).isEqualTo(1724825677);
528558
assertThat(delta2.getModel()).isEqualTo("gpt-35-turbo");
529-
assertThat(delta2.getObject()).isEqualTo("chat.completion.chunk");
559+
assertThat(delta2.getObject()).isEqualTo(CHAT_COMPLETION_CHUNK);
530560
// assertThat(delta2.getUsage()).isNull();
531561
// assertThat(delta2.getPromptFilterResults()).isNull();
532562
final var choices2 = delta2.getChoices().get(0);
533563
assertThat(choices2.getIndex()).isEqualTo(0);
534564
assertThat(choices2.getFinishReason()).isNull();
535565
assertThat(choices2.getDelta()).isNotNull();
536-
// the role is only defined in delta 1, but it defaults to "assistant" for all deltas
537-
assertThat(choices2.getDelta().getRole()).isEqualTo("assistant");
566+
// the role is only defined in delta 1
567+
assertThat(choices2.getDelta().getRole()).isNull();
538568
assertThat(choices2.getDelta().getContent()).isEqualTo("Sure");
539-
assertThat(choices2.getDelta().getToolCalls()).isNull();
569+
assertThat(choices2.getDelta().getToolCalls()).isNotNull().isEmpty();
540570
// final var filter2 = choices2.getContentFilterResults();
541571
// assertFilter(filter2);
542572

@@ -545,12 +575,12 @@ void streamChatCompletionDeltas() throws IOException {
545575

546576
final var delta4 = (CreateChatCompletionStreamResponse) deltaList.get(4).getOriginalResponse();
547577
final var delta4Choice = delta4.getChoices().get(0);
548-
assertThat(delta4Choice.getFinishReason()).isEqualTo("stop");
549-
assertThat(delta4Choice.getDelta().getContent()).isNotNull();
550-
// the role is only defined in delta 1, but it defaults to "assistant" for all deltas
551-
assertThat(delta4Choice.getDelta().getRole()).isEqualTo("assistant");
578+
assertThat(delta4Choice.getFinishReason()).isEqualTo(CreateChatCompletionStreamResponseChoicesInner.FinishReasonEnum.STOP);
552579
assertThat(delta4Choice.getDelta().getContent()).isNull();
553-
assertThat(delta4Choice.getDelta().getToolCalls()).isNull();
580+
// the role is only defined in delta 1
581+
assertThat(delta4Choice.getDelta().getRole()).isNull();
582+
assertThat(delta4Choice.getDelta().getContent()).isNull();
583+
assertThat(delta4Choice.getDelta().getToolCalls()).isEmpty();
554584
// assertThat(totalOutput.getChoices()).hasSize(1);
555585
// final var choice = totalOutput.getChoices().get(0);
556586
// assertThat(choice.getFinishReason()).isEqualTo("stop");

0 commit comments

Comments
 (0)