Skip to content

Commit 6720dcd

Browse files
committed
--> Deprecating OpenAiService and renaming OpenAiServiceV2.
--> Updating the OpenAiController to use updated OpenAiService class.
1 parent 9605b66 commit 6720dcd

File tree

6 files changed

+284
-292
lines changed

6 files changed

+284
-292
lines changed

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

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
import com.fasterxml.jackson.core.JsonProcessingException;
77
import com.fasterxml.jackson.databind.ObjectMapper;
8-
import com.google.common.annotations.Beta;
98
import com.sap.ai.sdk.core.AiCoreService;
109
import com.sap.ai.sdk.core.DeploymentResolutionException;
1110
import com.sap.ai.sdk.core.common.ClientResponseHandler;
@@ -73,7 +72,6 @@ public static OpenAiClient forModel(@Nonnull final OpenAiModel foundationModel)
7372
* @param apiVersion the API version to target.
7473
* @return a new client.
7574
*/
76-
@Beta
7775
@Nonnull
7876
public OpenAiClient withApiVersion(@Nonnull final String apiVersion) {
7977
final var newDestination =
@@ -101,7 +99,6 @@ public OpenAiClient withApiVersion(@Nonnull final String apiVersion) {
10199
* @see AiCoreService#getInferenceDestination(String)
102100
* @return a new OpenAI client.
103101
*/
104-
@Beta
105102
@Nonnull
106103
public static OpenAiClient withCustomDestination(@Nonnull final Destination destination) {
107104
final OpenAiClient client = new OpenAiClient(destination);
@@ -156,7 +153,6 @@ public OpenAiChatCompletionOutput chatCompletion(@Nonnull final String prompt)
156153
* @throws OpenAiClientException if the request fails
157154
* @since 1.4.0
158155
*/
159-
@Beta
160156
@Nonnull
161157
public OpenAiChatCompletionResponse chatCompletion(
162158
@Nonnull final OpenAiChatCompletionRequest request) throws OpenAiClientException {
@@ -173,7 +169,6 @@ public OpenAiChatCompletionResponse chatCompletion(
173169
* @throws OpenAiClientException if the request fails
174170
* @since 1.4.0
175171
*/
176-
@Beta
177172
@Nonnull
178173
public CreateChatCompletionResponse chatCompletion(
179174
@Nonnull final CreateChatCompletionRequest request) throws OpenAiClientException {
@@ -274,7 +269,6 @@ private static void throwOnContentFilter(@Nonnull final OpenAiChatCompletionDelt
274269
* @see #streamChatCompletion(String)
275270
* @since 1.4.0
276271
*/
277-
@Beta
278272
@Nonnull
279273
public Stream<OpenAiChatCompletionDelta> streamChatCompletionDeltas(
280274
@Nonnull final OpenAiChatCompletionRequest request) throws OpenAiClientException {
@@ -291,7 +285,6 @@ public Stream<OpenAiChatCompletionDelta> streamChatCompletionDeltas(
291285
* @see #streamChatCompletionDeltas(OpenAiChatCompletionRequest) for a higher-level API
292286
* @since 1.4.0
293287
*/
294-
@Beta
295288
@Nonnull
296289
public Stream<OpenAiChatCompletionDelta> streamChatCompletionDeltas(
297290
@Nonnull final CreateChatCompletionRequest request) throws OpenAiClientException {
@@ -358,7 +351,6 @@ private void warnIfUnsupportedUsage() {
358351
* @see #embedding(EmbeddingsCreateRequest) for full confgurability.
359352
* @since 1.4.0
360353
*/
361-
@Beta
362354
@Nonnull
363355
public OpenAiEmbeddingResponse embedding(@Nonnull final OpenAiEmbeddingRequest request)
364356
throws OpenAiClientException {
@@ -374,7 +366,6 @@ public OpenAiEmbeddingResponse embedding(@Nonnull final OpenAiEmbeddingRequest r
374366
* @see #embedding(OpenAiEmbeddingRequest) for conveninece api
375367
* @since 1.4.0
376368
*/
377-
@Beta
378369
@Nonnull
379370
public EmbeddingsCreate200Response embedding(@Nonnull final EmbeddingsCreateRequest request)
380371
throws OpenAiClientException {

sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/controllers/OpenAiController.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import com.fasterxml.jackson.annotation.PropertyAccessor;
55
import com.fasterxml.jackson.databind.ObjectMapper;
66
import com.sap.ai.sdk.app.services.OpenAiService;
7-
import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiUsage;
7+
import com.sap.ai.sdk.foundationmodels.openai.generated.model.CompletionUsage;
88
import com.sap.cloud.sdk.cloudplatform.thread.ThreadContextExecutors;
99
import java.io.IOException;
1010
import java.util.concurrent.atomic.AtomicReference;
@@ -47,14 +47,14 @@ ResponseEntity<ResponseBodyEmitter> streamChatCompletionDeltas() {
4747
final var message = "Can you give me the first 100 numbers of the Fibonacci sequence?";
4848
final var stream = service.streamChatCompletionDeltas(message);
4949
final var emitter = new ResponseBodyEmitter();
50-
final var totalUsage = new AtomicReference<OpenAiUsage>();
50+
final var totalUsage = new AtomicReference<CompletionUsage>();
5151
final Runnable consumeStream =
5252
() -> {
5353
try (stream) {
5454
stream.forEach(
5555
delta -> {
5656
// Instead of getCompletionUsage(MAPPER), we now use getUsage()
57-
final var usage = delta.getUsage();
57+
final var usage = delta.getCompletionUsage();
5858
totalUsage.compareAndExchange(null, usage);
5959
send(emitter, delta.getDeltaContent());
6060
});
@@ -116,7 +116,7 @@ Object chatCompletionImage(
116116
if ("json".equals(format)) {
117117
return response;
118118
}
119-
return response.getChoices().get(0).getMessage();
119+
return response.getChoice().getMessage();
120120
}
121121

122122
@GetMapping("/chatCompletionToolExecution")

sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OpenAiService.java

Lines changed: 73 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -3,47 +3,61 @@
33
import static com.sap.ai.sdk.foundationmodels.openai.OpenAiModel.GPT_4O;
44
import static com.sap.ai.sdk.foundationmodels.openai.OpenAiModel.GPT_4O_MINI;
55
import static com.sap.ai.sdk.foundationmodels.openai.OpenAiModel.TEXT_EMBEDDING_3_SMALL;
6-
import static com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatCompletionTool.ToolType.FUNCTION;
76

8-
import com.fasterxml.jackson.core.JsonProcessingException;
9-
import com.fasterxml.jackson.core.type.TypeReference;
10-
import com.fasterxml.jackson.databind.JsonMappingException;
11-
import com.fasterxml.jackson.databind.ObjectMapper;
12-
import com.fasterxml.jackson.module.jsonSchema.JsonSchemaGenerator;
137
import com.sap.ai.sdk.core.AiCoreService;
8+
import com.sap.ai.sdk.foundationmodels.openai.OpenAiChatCompletionDelta;
9+
import com.sap.ai.sdk.foundationmodels.openai.OpenAiChatCompletionRequest;
10+
import com.sap.ai.sdk.foundationmodels.openai.OpenAiChatCompletionResponse;
1411
import com.sap.ai.sdk.foundationmodels.openai.OpenAiClient;
15-
import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatCompletionDelta;
16-
import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatCompletionFunction;
17-
import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatCompletionOutput;
18-
import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatCompletionParameters;
19-
import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatCompletionTool;
20-
import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatMessage;
21-
import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatToolCall;
22-
import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiEmbeddingOutput;
23-
import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiEmbeddingParameters;
12+
import com.sap.ai.sdk.foundationmodels.openai.OpenAiEmbeddingRequest;
13+
import com.sap.ai.sdk.foundationmodels.openai.OpenAiEmbeddingResponse;
14+
import com.sap.ai.sdk.foundationmodels.openai.OpenAiImageItem;
15+
import com.sap.ai.sdk.foundationmodels.openai.OpenAiMessage;
16+
import com.sap.ai.sdk.foundationmodels.openai.OpenAiTool;
2417
import java.util.ArrayList;
2518
import java.util.List;
26-
import java.util.Map;
2719
import java.util.stream.Stream;
2820
import javax.annotation.Nonnull;
2921
import lombok.extern.slf4j.Slf4j;
22+
import lombok.val;
3023
import org.springframework.stereotype.Service;
3124

32-
/** Service class for OpenAI service */
25+
/** Service class for OpenAI service using latest convenience api */
3326
@Service
3427
@Slf4j
3528
public class OpenAiService {
36-
private static final ObjectMapper JACKSON = new ObjectMapper();
37-
3829
/**
3930
* Chat request to OpenAI
4031
*
4132
* @param prompt The prompt to send to the assistant
4233
* @return the assistant message response
4334
*/
4435
@Nonnull
45-
public OpenAiChatCompletionOutput chatCompletion(@Nonnull final String prompt) {
46-
return OpenAiClient.forModel(GPT_4O_MINI).chatCompletion(prompt);
36+
public OpenAiChatCompletionResponse chatCompletion(@Nonnull final String prompt) {
37+
return OpenAiClient.forModel(GPT_4O_MINI)
38+
.chatCompletion(new OpenAiChatCompletionRequest(prompt));
39+
}
40+
41+
/**
42+
* Chat requests to OpenAI and updating the messages history
43+
*
44+
* @param previousMessage The request to send to the assistant
45+
* @return the assistant message response
46+
*/
47+
@Nonnull
48+
public OpenAiChatCompletionResponse messagesHistory(@Nonnull final String previousMessage) {
49+
val messagesList = new ArrayList<OpenAiMessage>();
50+
messagesList.add(OpenAiMessage.user(previousMessage));
51+
52+
final OpenAiChatCompletionResponse result =
53+
OpenAiClient.forModel(GPT_4O_MINI)
54+
.chatCompletion(new OpenAiChatCompletionRequest(messagesList));
55+
56+
messagesList.add(result.getMessage());
57+
messagesList.add(OpenAiMessage.user("What is the typical food there?"));
58+
59+
return OpenAiClient.forModel(GPT_4O_MINI)
60+
.chatCompletion(new OpenAiChatCompletionRequest(messagesList));
4761
}
4862

4963
/**
@@ -55,9 +69,7 @@ public OpenAiChatCompletionOutput chatCompletion(@Nonnull final String prompt) {
5569
@Nonnull
5670
public Stream<OpenAiChatCompletionDelta> streamChatCompletionDeltas(
5771
@Nonnull final String message) {
58-
final var request =
59-
new OpenAiChatCompletionParameters()
60-
.addMessages(new OpenAiChatMessage.OpenAiChatUserMessage().addText(message));
72+
final var request = new OpenAiChatCompletionRequest(OpenAiMessage.user(message));
6173

6274
return OpenAiClient.forModel(GPT_4O_MINI).streamChatCompletionDeltas(request);
6375
}
@@ -82,93 +94,50 @@ public Stream<String> streamChatCompletion(@Nonnull final String message) {
8294
* @return the assistant message response
8395
*/
8496
@Nonnull
85-
public OpenAiChatCompletionOutput chatCompletionImage(@Nonnull final String linkToImage) {
86-
final var request =
87-
new OpenAiChatCompletionParameters()
88-
.addMessages(
89-
new OpenAiChatMessage.OpenAiChatUserMessage()
90-
.addText("Describe the following image.")
91-
.addImage(
92-
linkToImage,
93-
OpenAiChatMessage.OpenAiChatUserMessage.ImageDetailLevel.HIGH));
94-
95-
return OpenAiClient.forModel(GPT_4O).chatCompletion(request);
97+
public OpenAiChatCompletionResponse chatCompletionImage(@Nonnull final String linkToImage) {
98+
99+
final var userMessage =
100+
OpenAiMessage.user("Describe the following image.")
101+
.withImage(linkToImage, OpenAiImageItem.DetailLevel.HIGH);
102+
103+
return OpenAiClient.forModel(GPT_4O)
104+
.chatCompletion(new OpenAiChatCompletionRequest(userMessage));
96105
}
97106

98107
/**
99-
* Executes a chat completion request to OpenAI with a tool that calculates the weather.
108+
* Chat request to OpenAI with tool that gets the weather for a given location and unit. The tool
109+
* executed and the result is sent back to the assistant.
100110
*
101111
* @param location The location to get the weather for.
102112
* @param unit The unit of temperature to use.
103113
* @return The assistant message response.
104114
*/
105115
@Nonnull
106-
public OpenAiChatCompletionOutput chatCompletionToolExecution(
116+
public OpenAiChatCompletionResponse chatCompletionToolExecution(
107117
@Nonnull final String location, @Nonnull final String unit) {
118+
final OpenAiClient client = OpenAiClient.forModel(GPT_4O_MINI);
108119

109-
// 1. Define the function
110-
final Map<String, Object> schemaMap = generateSchema(WeatherMethod.Request.class);
111-
final var function =
112-
new OpenAiChatCompletionFunction()
113-
.setName("weather")
114-
.setDescription("Get the weather for the given location")
115-
.setParameters(schemaMap);
116-
final var tool = new OpenAiChatCompletionTool().setType(FUNCTION).setFunction(function);
117-
118-
final var messages = new ArrayList<OpenAiChatMessage>();
119-
messages.add(
120-
new OpenAiChatMessage.OpenAiChatUserMessage()
121-
.addText("What's the weather in %s in %s?".formatted(location, unit)));
122-
123-
// Assistant will call the function
124-
final var request =
125-
new OpenAiChatCompletionParameters()
126-
.addMessages(messages.toArray(OpenAiChatMessage[]::new))
127-
.setTools(List.of(tool));
128-
129-
final OpenAiChatCompletionOutput response =
130-
OpenAiClient.forModel(GPT_4O_MINI).chatCompletion(request);
131-
132-
// 2. Optionally, execute the function.
133-
final OpenAiChatToolCall toolCall =
134-
response.getChoices().get(0).getMessage().getToolCalls().get(0);
135-
final WeatherMethod.Request arguments =
136-
parseJson(toolCall.getFunction().getArguments(), WeatherMethod.Request.class);
137-
final WeatherMethod.Response currentWeather = WeatherMethod.getCurrentWeather(arguments);
138-
139-
final OpenAiChatMessage.OpenAiChatAssistantMessage assistantMessage =
140-
response.getChoices().get(0).getMessage();
141-
messages.add(assistantMessage);
142-
143-
final var toolMessage =
144-
new OpenAiChatMessage.OpenAiChatToolMessage()
145-
.setToolCallId(toolCall.getId())
146-
.setContent(currentWeather.toString());
147-
messages.add(toolMessage);
148-
149-
final var finalRequest =
150-
new OpenAiChatCompletionParameters()
151-
.addMessages(messages.toArray(OpenAiChatMessage[]::new));
152-
153-
return OpenAiClient.forModel(GPT_4O_MINI).chatCompletion(finalRequest);
154-
}
120+
final var messages = new ArrayList<OpenAiMessage>();
121+
messages.add(OpenAiMessage.user("What's the weather in %s in %s?".formatted(location, unit)));
155122

156-
private static <T> T parseJson(@Nonnull final String rawJson, @Nonnull final Class<T> clazz) {
157-
try {
158-
return JACKSON.readValue(rawJson, clazz);
159-
} catch (JsonProcessingException e) {
160-
throw new IllegalArgumentException("Failed to parse tool call arguments: " + rawJson, e);
161-
}
162-
}
163-
164-
private static Map<String, Object> generateSchema(@Nonnull final Class<?> clazz) {
165-
final var jsonSchemaGenerator = new JsonSchemaGenerator(JACKSON);
166-
try {
167-
final var schema = jsonSchemaGenerator.generateSchema(clazz);
168-
return JACKSON.convertValue(schema, new TypeReference<>() {});
169-
} catch (JsonMappingException e) {
170-
throw new IllegalArgumentException("Could not generate schema for " + clazz.getName(), e);
171-
}
123+
// 1. Define the function
124+
final List<OpenAiTool> tools =
125+
List.of(
126+
OpenAiTool.forFunction(WeatherMethod::getCurrentWeather)
127+
.withArgument(WeatherMethod.Request.class)
128+
.withName("weather")
129+
.withDescription("Get the weather for the given location"));
130+
131+
// 2. Assistant calls the function
132+
final var request = new OpenAiChatCompletionRequest(messages).withToolsExecutable(tools);
133+
final OpenAiChatCompletionResponse response = client.chatCompletion(request);
134+
135+
// 3. Execute the tool calls
136+
messages.add(response.getMessage());
137+
messages.addAll(response.executeTools());
138+
139+
// 4. Have model run the final request with incorporated tool results
140+
return client.chatCompletion(request.withMessages(messages));
172141
}
173142

174143
/**
@@ -178,8 +147,8 @@ private static Map<String, Object> generateSchema(@Nonnull final Class<?> clazz)
178147
* @return the embedding response
179148
*/
180149
@Nonnull
181-
public OpenAiEmbeddingOutput embedding(@Nonnull final String input) {
182-
final var request = new OpenAiEmbeddingParameters().setInput(input);
150+
public OpenAiEmbeddingResponse embedding(@Nonnull final String input) {
151+
final var request = new OpenAiEmbeddingRequest(List.of(input));
183152

184153
return OpenAiClient.forModel(TEXT_EMBEDDING_3_SMALL).embedding(request);
185154
}
@@ -192,12 +161,13 @@ public OpenAiEmbeddingOutput embedding(@Nonnull final String input) {
192161
* @return the assistant message response
193162
*/
194163
@Nonnull
195-
public OpenAiChatCompletionOutput chatCompletionWithResource(
164+
public OpenAiChatCompletionResponse chatCompletionWithResource(
196165
@Nonnull final String resourceGroup, @Nonnull final String prompt) {
197166

198167
final var destination =
199168
new AiCoreService().getInferenceDestination(resourceGroup).forModel(GPT_4O);
200169

201-
return OpenAiClient.withCustomDestination(destination).chatCompletion(prompt);
170+
return OpenAiClient.withCustomDestination(destination)
171+
.chatCompletion(new OpenAiChatCompletionRequest(prompt));
202172
}
203173
}

0 commit comments

Comments
 (0)