-
Notifications
You must be signed in to change notification settings - Fork 15
feat: Orchestration image support #294
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
77b6637
026771b
09816d2
54a2c19
98ba774
75afed1
38f3fd4
f8ea4d0
cd20ca8
a2fe90f
ec899a4
f173057
c57bd1d
0524fd7
60e8120
3754d9c
8ab1514
e99d7b9
7c05d89
5a72a33
6100502
85d077f
7113283
60b97b0
fa1add0
682794a
b671bc7
3bd521c
a152c2f
0f928a8
6ee7290
57330d4
65d01c6
8a0c79d
13c0387
f95c4d3
eaf2632
be70506
fb0a89f
8357b89
8d32086
dff4fb8
b0e6701
29ceee1
d8fd060
bcf0d99
162cb6b
adf81da
a099ee0
4899f36
837fd66
3dd3085
d91ca3b
e438330
a87fa5d
27a1033
b505272
72f66b5
dc69ad1
3d8315e
cd08312
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package com.sap.ai.sdk.orchestration; | ||
|
|
||
| /** | ||
| * Represents an item in a {@link MessageContent} object. | ||
| * | ||
| * @since 1.3.0 | ||
| */ | ||
| public sealed interface ContentItem permits TextItem, ImageItem {} | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| package com.sap.ai.sdk.orchestration; | ||
|
|
||
| import java.util.Locale; | ||
| import javax.annotation.Nonnull; | ||
|
|
||
| /** | ||
| * Represents an image item in a {@link MessageContent} object. | ||
| * | ||
| * @param imageUrl the URL of the image | ||
| * @param detailLevel the detail level of the image (optional) | ||
| * @since 1.3.0 | ||
| */ | ||
| public record ImageItem(@Nonnull String imageUrl, @Nonnull DetailLevel detailLevel) | ||
| implements ContentItem { | ||
|
|
||
| /** | ||
| * Creates a new image item with the given image URL. | ||
| * | ||
| * @param imageUrl the URL of the image | ||
| * @since 1.3.0 | ||
| */ | ||
| public ImageItem(@Nonnull final String imageUrl) { | ||
| this(imageUrl, DetailLevel.AUTO); | ||
| } | ||
|
|
||
| /** | ||
| * The detail level of the image. | ||
| * | ||
| * @since 1.3.0 | ||
| */ | ||
| public enum DetailLevel { | ||
| /** Low detail level. */ | ||
| LOW("low"), | ||
| /** High detail level. */ | ||
| HIGH("high"), | ||
| /** Automatic detail level. */ | ||
| AUTO("auto"); | ||
|
|
||
| private final String level; | ||
|
|
||
| /** | ||
| * Converts a string to a detail level. | ||
| * | ||
| * @param str the string to convert | ||
| * @return the detail level | ||
| * @since 1.3.0 | ||
| */ | ||
| @Nonnull | ||
| static DetailLevel fromString(@Nonnull final String str) { | ||
| return DetailLevel.valueOf(str.toUpperCase(Locale.ENGLISH)); | ||
| } | ||
|
|
||
| /** | ||
| * Get the string representation of the DetailLevel | ||
| * | ||
| * @return the DetailLevel as string | ||
| * @since 1.3.0 | ||
| */ | ||
| @Nonnull | ||
| public String toString() { | ||
| return level; | ||
| } | ||
|
|
||
| DetailLevel(@Nonnull final String level) { | ||
| this.level = level; | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,43 +2,62 @@ | |
|
|
||
| import com.google.common.annotations.Beta; | ||
| import com.sap.ai.sdk.orchestration.model.ChatMessage; | ||
| import com.sap.ai.sdk.orchestration.model.ImageContent; | ||
| import com.sap.ai.sdk.orchestration.model.ImageContentImageUrl; | ||
| import com.sap.ai.sdk.orchestration.model.MultiChatMessage; | ||
| import com.sap.ai.sdk.orchestration.model.MultiChatMessageContent; | ||
| import com.sap.ai.sdk.orchestration.model.SingleChatMessage; | ||
| import com.sap.ai.sdk.orchestration.model.TextContent; | ||
| import java.util.LinkedList; | ||
| import java.util.List; | ||
| import javax.annotation.Nonnull; | ||
|
|
||
| /** Interface representing convenience wrappers of chat message to the orchestration service. */ | ||
| public sealed interface Message permits UserMessage, AssistantMessage, SystemMessage { | ||
|
|
||
| /** | ||
| * A convenience method to create a user message. | ||
| * A convenience method to create a user message from a string. | ||
| * | ||
| * @param msg the message content. | ||
| * @param message the message content. | ||
| * @return the user message. | ||
| */ | ||
| @Nonnull | ||
| static UserMessage user(@Nonnull final String msg) { | ||
| return new UserMessage(msg); | ||
| static UserMessage user(@Nonnull final String message) { | ||
| return new UserMessage(message); | ||
| } | ||
|
|
||
| /** | ||
| * A convenience method to create a user message containing only an image. | ||
| * | ||
| * @param imageItem the message content. | ||
| * @return the user message. | ||
| * @since 1.3.0 | ||
| */ | ||
| @Nonnull | ||
| static UserMessage user(@Nonnull final ImageItem imageItem) { | ||
| return new UserMessage(new MessageContent(List.of(imageItem))); | ||
| } | ||
|
|
||
| /** | ||
| * A convenience method to create an assistant message. | ||
| * | ||
| * @param msg the message content. | ||
| * @param message the message content. | ||
| * @return the assistant message. | ||
| */ | ||
| @Nonnull | ||
| static AssistantMessage assistant(@Nonnull final String msg) { | ||
| return new AssistantMessage(msg); | ||
| static AssistantMessage assistant(@Nonnull final String message) { | ||
| return new AssistantMessage(message); | ||
| } | ||
|
|
||
| /** | ||
| * A convenience method to create a system message. | ||
| * A convenience method to create a system message from a string. | ||
| * | ||
| * @param msg the message content. | ||
| * @param message the message content. | ||
| * @return the system message. | ||
| */ | ||
| @Nonnull | ||
| static SystemMessage system(@Nonnull final String msg) { | ||
| return new SystemMessage(msg); | ||
| static SystemMessage system(@Nonnull final String message) { | ||
| return new SystemMessage(message); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -48,7 +67,21 @@ static SystemMessage system(@Nonnull final String msg) { | |
| */ | ||
| @Nonnull | ||
| default ChatMessage createChatMessage() { | ||
| return SingleChatMessage.create().role(role()).content(content()); | ||
| final var itemList = this.content().items(); | ||
| if (itemList.size() == 1 && itemList.get(0) instanceof TextItem textItem) { | ||
| return SingleChatMessage.create().role(role()).content(textItem.text()); | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here we cannot discern between
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Users can use the constructors instead should this ever matter, right?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The constructor is protected, but the |
||
| } | ||
| final var contentList = new LinkedList<MultiChatMessageContent>(); | ||
| for (final ContentItem item : itemList) { | ||
| if (item instanceof TextItem textItem) { | ||
| contentList.add(TextContent.create().type(TextContent.TypeEnum.TEXT).text(textItem.text())); | ||
| } else if (item instanceof ImageItem imageItem) { | ||
| final var detail = imageItem.detailLevel().toString(); | ||
| final var img = ImageContentImageUrl.create().url(imageItem.imageUrl()).detail(detail); | ||
| contentList.add(ImageContent.create().type(ImageContent.TypeEnum.IMAGE_URL).imageUrl(img)); | ||
| } | ||
| } | ||
| return MultiChatMessage.create().role(role()).content(contentList); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -66,5 +99,5 @@ default ChatMessage createChatMessage() { | |
| */ | ||
| @Nonnull | ||
| @Beta | ||
| String content(); | ||
| MessageContent content(); | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a breaking change. (Note that the corresponding methods in We discussed in the meetings that we do not want to offer a convenience method that returns a string representation of messages anymore. Users can/will use
Jonas-Isr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| package com.sap.ai.sdk.orchestration; | ||
|
|
||
| import com.sap.ai.sdk.orchestration.model.ImageContent; | ||
| import com.sap.ai.sdk.orchestration.model.MultiChatMessageContent; | ||
| import com.sap.ai.sdk.orchestration.model.TextContent; | ||
| import java.util.List; | ||
| import javax.annotation.Nonnull; | ||
|
|
||
| /** | ||
| * Represents the content of a chat message. | ||
| * | ||
| * @param items a list of the content items | ||
| * @since 1.3.0 | ||
| */ | ||
| public record MessageContent(@Nonnull List<ContentItem> items) { | ||
| @Nonnull | ||
| static MessageContent fromMCMContentList( | ||
| @Nonnull final List<MultiChatMessageContent> mCMContentList) { | ||
| final var itemList = | ||
| mCMContentList.stream() | ||
| .map( | ||
| content -> { | ||
| if (content instanceof TextContent text) { | ||
| return new TextItem(text.getText()); | ||
| } else { | ||
| final var imageUrl = ((ImageContent) content).getImageUrl(); | ||
| return (ContentItem) | ||
| new ImageItem( | ||
| imageUrl.getUrl(), | ||
| ImageItem.DetailLevel.fromString(imageUrl.getDetail())); | ||
| } | ||
| }) | ||
| .toList(); | ||
| return new MessageContent(itemList); | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.