Skip to content

Commit 0af197c

Browse files
Merge branch 'main' into spring-ai🍃tools
2 parents 9d8b240 + 285960b commit 0af197c

File tree

22 files changed

+2245
-369
lines changed

22 files changed

+2245
-369
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.JsonTypeInfo;
4+
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
5+
import com.sap.ai.sdk.foundationmodels.openai.generated.model.CreateChatCompletionStreamResponse;
6+
import lombok.AccessLevel;
7+
import lombok.NoArgsConstructor;
8+
9+
/**
10+
* This class contains Jackson Mixins for customizing the serialization and deserialization behavior
11+
* of certain classes in the OpenAI SDK.
12+
*/
13+
@NoArgsConstructor(access = AccessLevel.PRIVATE)
14+
final class JacksonMixins {
15+
16+
/**
17+
* Mixin interface to customize the deserialization of CreateChatCompletionStreamResponse.
18+
*
19+
* <p>Disables type information inclusion and specifies the concrete class to use for
20+
* deserialization.
21+
*/
22+
@JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
23+
@JsonDeserialize(as = CreateChatCompletionStreamResponse.class)
24+
interface DefaultChatCompletionCreate200ResponseMixIn {}
25+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.sap.ai.sdk.foundationmodels.openai;
2+
3+
import com.google.common.annotations.Beta;
4+
import com.sap.ai.sdk.foundationmodels.openai.generated.model.ChatCompletionRequestAssistantMessage;
5+
import com.sap.ai.sdk.foundationmodels.openai.generated.model.ChatCompletionRequestAssistantMessageContent;
6+
import javax.annotation.Nonnull;
7+
import lombok.Value;
8+
import lombok.experimental.Accessors;
9+
10+
/**
11+
* Represents a chat message as 'assistant' to OpenAI service.
12+
*
13+
* @since 1.4.0
14+
*/
15+
@Beta
16+
@Value
17+
@Accessors(fluent = true)
18+
class OpenAiAssistantMessage implements OpenAiMessage {
19+
20+
/** The role of the message. */
21+
@Nonnull String role = "assistant";
22+
23+
/** The content of the message. */
24+
@Nonnull String content;
25+
26+
/**
27+
* Converts the message to a serializable object.
28+
*
29+
* @return the corresponding {@code ChatCompletionRequestAssistantMessage} object.
30+
*/
31+
@Nonnull
32+
ChatCompletionRequestAssistantMessage createChatCompletionRequestMessage() {
33+
return new ChatCompletionRequestAssistantMessage()
34+
.role(ChatCompletionRequestAssistantMessage.RoleEnum.fromValue(role()))
35+
.content(ChatCompletionRequestAssistantMessageContent.create(content));
36+
}
37+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package com.sap.ai.sdk.foundationmodels.openai;
2+
3+
import static com.sap.ai.sdk.foundationmodels.openai.OpenAiUtils.getOpenAiObjectMapper;
4+
import static lombok.AccessLevel.PACKAGE;
5+
6+
import com.fasterxml.jackson.annotation.JsonCreator;
7+
import com.google.common.annotations.Beta;
8+
import com.sap.ai.sdk.core.common.StreamedDelta;
9+
import com.sap.ai.sdk.foundationmodels.openai.generated.model.CompletionUsage;
10+
import com.sap.ai.sdk.foundationmodels.openai.generated.model.CreateChatCompletionStreamResponse;
11+
import java.util.Map;
12+
import java.util.Objects;
13+
import javax.annotation.Nonnull;
14+
import javax.annotation.Nullable;
15+
import lombok.EqualsAndHashCode;
16+
import lombok.Getter;
17+
import lombok.RequiredArgsConstructor;
18+
import lombok.ToString;
19+
20+
/**
21+
* Represents an OpenAI chat completion output delta for streaming.
22+
*
23+
* @since 1.4.0
24+
*/
25+
@Beta
26+
@RequiredArgsConstructor(onConstructor_ = @JsonCreator, access = PACKAGE)
27+
@Getter
28+
@ToString
29+
@EqualsAndHashCode
30+
public class OpenAiChatCompletionDelta implements StreamedDelta {
31+
/** The original response from the chat completion stream. */
32+
@Nonnull private final CreateChatCompletionStreamResponse originalResponse;
33+
34+
@Nonnull
35+
@Override
36+
public String getDeltaContent() {
37+
final var choices = getOriginalResponse().getChoices();
38+
if (!choices.isEmpty() && choices.get(0).getIndex() == 0) {
39+
final var message = choices.get(0).getDelta();
40+
return Objects.requireNonNullElse(message.getContent(), "");
41+
}
42+
return "";
43+
}
44+
45+
@Nullable
46+
@Override
47+
public String getFinishReason() {
48+
final var choices = getOriginalResponse().getChoices();
49+
if (!choices.isEmpty()) {
50+
final var finishReason = choices.get(0).getFinishReason();
51+
return finishReason != null ? finishReason.getValue() : null;
52+
}
53+
return null;
54+
}
55+
56+
/**
57+
* Retrieves the completion usage from the response, or null if it is not available.
58+
*
59+
* @return The completion usage or null.
60+
*/
61+
@Nullable
62+
public CompletionUsage getCompletionUsage() {
63+
if (getOriginalResponse().getCustomFieldNames().contains("usage")
64+
&& getOriginalResponse().getCustomField("usage") instanceof Map<?, ?> usage) {
65+
return getOpenAiObjectMapper().convertValue(usage, CompletionUsage.class);
66+
}
67+
return null;
68+
}
69+
}

0 commit comments

Comments
 (0)