Skip to content

Commit 106c5cd

Browse files
committed
Minimum integration of messaging convenience
- Add user, assistant and system conv on par with orchestration - Adapt sample app service class for image input (new api) - Adapt toDTO to account for OpenAI gen model architecture
1 parent a4f0f32 commit 106c5cd

File tree

13 files changed

+364
-68
lines changed

13 files changed

+364
-68
lines changed
Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
package com.sap.ai.sdk.foundationmodels.openai;
22

3+
import com.google.common.annotations.Beta;
34
import com.sap.ai.sdk.foundationmodels.openai.model2.ChatCompletionRequestAssistantMessage;
45
import com.sap.ai.sdk.foundationmodels.openai.model2.ChatCompletionRequestAssistantMessageContent;
6+
import com.sap.ai.sdk.foundationmodels.openai.model2.ChatCompletionRequestAssistantMessageContentPart;
7+
import com.sap.ai.sdk.foundationmodels.openai.model2.ChatCompletionRequestMessageContentPartText;
8+
import java.util.LinkedList;
9+
import java.util.List;
510
import javax.annotation.Nonnull;
11+
import lombok.Getter;
612
import lombok.Value;
713
import lombok.experimental.Accessors;
814

@@ -13,23 +19,53 @@
1319
*/
1420
@Value
1521
@Accessors(fluent = true)
16-
class OpenAiAssistantMessage implements OpenAiMessage {
22+
public class OpenAiAssistantMessage implements OpenAiMessage {
1723

18-
/** The role of the message. */
24+
/** The role associated with this message. */
1925
@Nonnull String role = "assistant";
2026

2127
/** The content of the message. */
22-
@Nonnull String content;
28+
@Getter(onMethod_ = @Beta)
29+
@Nonnull
30+
OpenAiMessageContent content;
31+
32+
/**
33+
* Creates a new assistant message with the given single message.
34+
*
35+
* @param singleMessage the single message.
36+
*/
37+
public OpenAiAssistantMessage(@Nonnull final String singleMessage) {
38+
content = new OpenAiMessageContent(List.of(new OpenAiTextItem(singleMessage)));
39+
}
2340

2441
/**
2542
* Converts the message to a serializable object.
2643
*
27-
* @return the corresponding {@code ChatCompletionRequestAssistantMessage} object.
44+
* @return the corresponding serializable object.
2845
*/
2946
@Nonnull
30-
public ChatCompletionRequestAssistantMessage createDTO() {
47+
public ChatCompletionRequestAssistantMessage createChatCompletionRequestMessage()
48+
throws IllegalArgumentException {
49+
final var itemList = this.content().items();
50+
if (itemList.size() == 1 && itemList.get(0) instanceof OpenAiTextItem textItem) {
51+
return new ChatCompletionRequestAssistantMessage()
52+
.role(ChatCompletionRequestAssistantMessage.RoleEnum.fromValue(role()))
53+
.content(ChatCompletionRequestAssistantMessageContent.create(textItem.text()));
54+
}
55+
56+
final var contentList = new LinkedList<ChatCompletionRequestAssistantMessageContentPart>();
57+
for (final OpenAiContentItem item : itemList) {
58+
if (item instanceof OpenAiTextItem textItem) {
59+
contentList.add(
60+
new ChatCompletionRequestMessageContentPartText()
61+
.type(ChatCompletionRequestMessageContentPartText.TypeEnum.TEXT)
62+
.text(textItem.text()));
63+
} else if (item instanceof OpenAiImageItem) {
64+
throw new IllegalArgumentException("Image items are not supported in assistant messages");
65+
}
66+
}
3167
return new ChatCompletionRequestAssistantMessage()
3268
.role(ChatCompletionRequestAssistantMessage.RoleEnum.fromValue(role()))
33-
.content(ChatCompletionRequestAssistantMessageContent.create(content));
69+
.content(ChatCompletionRequestAssistantMessageContent.create(contentList));
3470
}
3571
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,8 @@ public OpenAiChatCompletionRequest stop(
124124

125125
CreateChatCompletionRequest toCreateChatCompletionRequest() {
126126
final var request = new CreateChatCompletionRequest();
127-
this.messages().forEach(message -> request.addMessagesItem(message.createDTO()));
127+
this.messages()
128+
.forEach(message -> request.addMessagesItem(message.createChatCompletionRequestMessage()));
128129

129130
request.stop(
130131
this.stop() != null ? CreateChatCompletionRequestAllOfStop.create(this.stop()) : null);
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.sap.ai.sdk.foundationmodels.openai;
2+
3+
/**
4+
* Represents an item in a {@link OpenAiMessageContent} object.
5+
*
6+
* @since 1.3.0
7+
*/
8+
public sealed interface OpenAiContentItem permits OpenAiTextItem, OpenAiImageItem {}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package com.sap.ai.sdk.foundationmodels.openai;
2+
3+
import java.util.Locale;
4+
import javax.annotation.Nonnull;
5+
6+
/**
7+
* Represents an image item in a {@link OpenAiMessageContent} object.
8+
*
9+
* @param imageUrl the URL of the image
10+
* @param detailLevel the detail level of the image (optional)
11+
* @since 1.3.0
12+
*/
13+
public record OpenAiImageItem(@Nonnull String imageUrl, @Nonnull DetailLevel detailLevel)
14+
implements OpenAiContentItem {
15+
16+
/**
17+
* Creates a new image item with the given image URL.
18+
*
19+
* @param imageUrl the URL of the image
20+
* @since 1.3.0
21+
*/
22+
public OpenAiImageItem(@Nonnull final String imageUrl) {
23+
this(imageUrl, DetailLevel.AUTO);
24+
}
25+
26+
/**
27+
* The detail level of the image.
28+
*
29+
* @since 1.3.0
30+
*/
31+
public enum DetailLevel {
32+
/** Low detail level. */
33+
LOW("low"),
34+
/** High detail level. */
35+
HIGH("high"),
36+
/** Automatic detail level. */
37+
AUTO("auto");
38+
39+
private final String level;
40+
41+
/**
42+
* Converts a string to a detail level.
43+
*
44+
* @param str the string to convert
45+
* @return the detail level
46+
* @since 1.3.0
47+
*/
48+
@Nonnull
49+
static DetailLevel fromString(@Nonnull final String str) {
50+
return DetailLevel.valueOf(str.toUpperCase(Locale.ENGLISH));
51+
}
52+
53+
/**
54+
* Get the string representation of the DetailLevel
55+
*
56+
* @return the DetailLevel as string
57+
* @since 1.3.0
58+
*/
59+
@Nonnull
60+
public String toString() {
61+
return level;
62+
}
63+
64+
DetailLevel(@Nonnull final String level) {
65+
this.level = level;
66+
}
67+
}
68+
}
Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,85 @@
11
package com.sap.ai.sdk.foundationmodels.openai;
22

3+
import com.google.common.annotations.Beta;
34
import com.sap.ai.sdk.foundationmodels.openai.model2.ChatCompletionRequestMessage;
5+
import java.util.List;
46
import javax.annotation.Nonnull;
57

68
/**
79
* Interface representing convenience wrappers of chat message to the openai service.
810
*
911
* @since 1.3.0
1012
*/
11-
public interface OpenAiMessage {
13+
public sealed interface OpenAiMessage
14+
permits OpenAiUserMessage, OpenAiAssistantMessage, OpenAiSystemMessage {
1215

1316
/**
1417
* A convenience method to create a user message.
1518
*
16-
* @param msg the message content.
19+
* @param message the message content.
1720
* @return the user message.
1821
*/
1922
@Nonnull
20-
static OpenAiMessage user(@Nonnull final String msg) {
21-
return new OpenAiUserMessage(msg);
23+
static OpenAiUserMessage user(@Nonnull final String message) {
24+
return new OpenAiUserMessage(message);
25+
}
26+
27+
/**
28+
* A convenience method to create a user message containing only an image.
29+
*
30+
* @param openAiImageItem the message content.
31+
* @return the user message.
32+
* @since 1.3.0
33+
*/
34+
@Nonnull
35+
static OpenAiUserMessage user(@Nonnull final OpenAiImageItem openAiImageItem) {
36+
return new OpenAiUserMessage(new OpenAiMessageContent(List.of(openAiImageItem)));
2237
}
2338

2439
/**
2540
* A convenience method to create an assistant message.
2641
*
27-
* @param msg the message content.
42+
* @param message the message content.
2843
* @return the assistant message.
2944
*/
3045
@Nonnull
31-
static OpenAiMessage assistant(@Nonnull final String msg) {
32-
return new OpenAiAssistantMessage(msg);
46+
static OpenAiAssistantMessage assistant(@Nonnull final String message) {
47+
return new OpenAiAssistantMessage(message);
3348
}
3449

3550
/**
3651
* A convenience method to create a system message.
3752
*
38-
* @param msg the message content.
53+
* @param message the message content.
3954
* @return the system message.
4055
*/
4156
@Nonnull
42-
static OpenAiMessage system(@Nonnull final String msg) {
43-
return new OpenAiSystemMessage(msg);
57+
static OpenAiSystemMessage system(@Nonnull final String message) {
58+
return new OpenAiSystemMessage(message);
4459
}
4560

61+
/**
62+
* Returns the role associated with the message.
63+
*
64+
* @return the role.
65+
*/
66+
@Nonnull
67+
String role();
68+
69+
/**
70+
* Returns the content of the message.
71+
*
72+
* @return the content.
73+
*/
74+
@Nonnull
75+
@Beta
76+
OpenAiMessageContent content();
77+
4678
/**
4779
* Converts the message to a serializable object.
4880
*
4981
* @return the corresponding serializable object.
5082
*/
5183
@Nonnull
52-
ChatCompletionRequestMessage createDTO();
84+
ChatCompletionRequestMessage createChatCompletionRequestMessage() throws IllegalArgumentException;
5385
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.sap.ai.sdk.foundationmodels.openai;
2+
3+
import java.util.List;
4+
import javax.annotation.Nonnull;
5+
6+
/**
7+
* Represents the content of a chat message.
8+
*
9+
* @param items a list of the content items
10+
* @since 1.3.0
11+
*/
12+
public record OpenAiMessageContent(@Nonnull List<OpenAiContentItem> items) {}
Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
package com.sap.ai.sdk.foundationmodels.openai;
22

3+
import com.google.common.annotations.Beta;
4+
import com.sap.ai.sdk.foundationmodels.openai.model2.ChatCompletionRequestMessageContentPartText;
35
import com.sap.ai.sdk.foundationmodels.openai.model2.ChatCompletionRequestSystemMessage;
46
import com.sap.ai.sdk.foundationmodels.openai.model2.ChatCompletionRequestSystemMessageContent;
7+
import com.sap.ai.sdk.foundationmodels.openai.model2.ChatCompletionRequestSystemMessageContentPart;
8+
import java.util.LinkedList;
9+
import java.util.List;
510
import javax.annotation.Nonnull;
11+
import lombok.Getter;
612
import lombok.Value;
713
import lombok.experimental.Accessors;
14+
import lombok.experimental.Tolerate;
815

916
/**
1017
* Represents a chat message as 'system' to OpenAI service. *
@@ -13,23 +20,68 @@
1320
*/
1421
@Value
1522
@Accessors(fluent = true)
16-
class OpenAiSystemMessage implements OpenAiMessage {
23+
public class OpenAiSystemMessage implements OpenAiMessage {
1724

18-
/** The role of the message. */
25+
/** The role associated with this message. */
1926
@Nonnull String role = "system";
2027

2128
/** The content of the message. */
22-
@Nonnull String content;
29+
@Getter(onMethod_ = @Beta)
30+
@Nonnull
31+
OpenAiMessageContent content;
32+
33+
/**
34+
* Creates a new system message from a string.
35+
*
36+
* @param message the first message.
37+
*/
38+
@Tolerate
39+
public OpenAiSystemMessage(@Nonnull final String message) {
40+
content = new OpenAiMessageContent(List.of(new OpenAiTextItem(message)));
41+
}
42+
43+
/**
44+
* Add text to the message.
45+
*
46+
* @param message the text to add.
47+
* @return the new message.
48+
* @since 1.3.0
49+
*/
50+
@Nonnull
51+
public OpenAiSystemMessage withText(@Nonnull final String message) {
52+
final var contentItems = new LinkedList<>(content.items());
53+
contentItems.add(new OpenAiTextItem(message));
54+
return new OpenAiSystemMessage(new OpenAiMessageContent(contentItems));
55+
}
2356

2457
/**
2558
* Converts the message to a serializable object.
2659
*
27-
* @return the corresponding {@code ChatCompletionRequestSystemMessage} object.
60+
* @return the corresponding serializable object.
2861
*/
2962
@Nonnull
30-
public ChatCompletionRequestSystemMessage createDTO() {
63+
public ChatCompletionRequestSystemMessage createChatCompletionRequestMessage()
64+
throws IllegalArgumentException {
65+
final var itemList = this.content().items();
66+
if (itemList.size() == 1 && itemList.get(0) instanceof OpenAiTextItem textItem) {
67+
return new ChatCompletionRequestSystemMessage()
68+
.role(ChatCompletionRequestSystemMessage.RoleEnum.fromValue(role()))
69+
.content(ChatCompletionRequestSystemMessageContent.create(textItem.text()));
70+
}
71+
72+
final var contentList = new LinkedList<ChatCompletionRequestSystemMessageContentPart>();
73+
for (final OpenAiContentItem item : itemList) {
74+
if (item instanceof OpenAiTextItem textItem) {
75+
contentList.add(
76+
new ChatCompletionRequestMessageContentPartText()
77+
.type(ChatCompletionRequestMessageContentPartText.TypeEnum.TEXT)
78+
.text(textItem.text()));
79+
} else if (item instanceof OpenAiImageItem) {
80+
throw new IllegalArgumentException("Image items are not yet supported in system messages");
81+
}
82+
}
3183
return new ChatCompletionRequestSystemMessage()
3284
.role(ChatCompletionRequestSystemMessage.RoleEnum.fromValue(role()))
33-
.content(ChatCompletionRequestSystemMessageContent.create(content()));
85+
.content(ChatCompletionRequestSystemMessageContent.create(contentList));
3486
}
3587
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.sap.ai.sdk.foundationmodels.openai;
2+
3+
import javax.annotation.Nonnull;
4+
5+
/**
6+
* Represents a text item in a {@link OpenAiMessageContent} object.
7+
*
8+
* @param text the text of the item
9+
* @since 1.3.0
10+
*/
11+
public record OpenAiTextItem(@Nonnull String text) implements OpenAiContentItem {}

0 commit comments

Comments
 (0)