diff --git a/sample-code/spring-app/pom.xml b/sample-code/spring-app/pom.xml
index d9343a33b..1185aa27a 100644
--- a/sample-code/spring-app/pom.xml
+++ b/sample-code/spring-app/pom.xml
@@ -95,6 +95,11 @@
spring-webmvc
${springframework.version}
+
+ org.springframework
+ spring-beans
+ ${springframework.version}
+
com.google.code.findbugs
jsr305
@@ -111,6 +116,10 @@
com.fasterxml.jackson.core
jackson-core
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+
ch.qos.logback
diff --git a/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/controllers/OpenAiController.java b/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/controllers/OpenAiController.java
index 2c843c2a9..c48f739e3 100644
--- a/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/controllers/OpenAiController.java
+++ b/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/controllers/OpenAiController.java
@@ -34,7 +34,7 @@
/** Endpoints for OpenAI operations */
@Slf4j
@RestController
-class OpenAiController {
+public class OpenAiController {
/**
* Chat request to OpenAI
*
@@ -123,7 +123,13 @@ ResponseEntity streamChatCompletion() {
return ResponseEntity.ok().contentType(MediaType.TEXT_EVENT_STREAM).body(emitter);
}
- static void send(@Nonnull final ResponseBodyEmitter emitter, @Nonnull final String chunk) {
+ /**
+ * Send a chunk to the emitter
+ *
+ * @param emitter The emitter to send the chunk to
+ * @param chunk The chunk to send
+ */
+ public static void send(@Nonnull final ResponseBodyEmitter emitter, @Nonnull final String chunk) {
try {
emitter.send(chunk);
} catch (final IOException e) {
diff --git a/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/controllers/OrchestrationController.java b/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/controllers/OrchestrationController.java
index 42437073d..b6d3cefda 100644
--- a/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/controllers/OrchestrationController.java
+++ b/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/controllers/OrchestrationController.java
@@ -1,33 +1,20 @@
package com.sap.ai.sdk.app.controllers;
-import static com.sap.ai.sdk.app.controllers.OpenAiController.send;
-import static com.sap.ai.sdk.orchestration.OrchestrationAiModel.GEMINI_1_5_FLASH;
-import static com.sap.ai.sdk.orchestration.OrchestrationAiModel.Parameter.TEMPERATURE;
-
-import com.sap.ai.sdk.core.AiCoreService;
-import com.sap.ai.sdk.orchestration.AzureContentFilter;
+import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.sap.ai.sdk.app.services.OrchestrationService;
import com.sap.ai.sdk.orchestration.AzureFilterThreshold;
-import com.sap.ai.sdk.orchestration.DpiMasking;
-import com.sap.ai.sdk.orchestration.Message;
-import com.sap.ai.sdk.orchestration.OrchestrationChatResponse;
-import com.sap.ai.sdk.orchestration.OrchestrationClient;
-import com.sap.ai.sdk.orchestration.OrchestrationModuleConfig;
-import com.sap.ai.sdk.orchestration.OrchestrationPrompt;
import com.sap.ai.sdk.orchestration.model.DPIEntities;
-import com.sap.ai.sdk.orchestration.model.DataRepositoryType;
-import com.sap.ai.sdk.orchestration.model.DocumentGroundingFilter;
-import com.sap.ai.sdk.orchestration.model.GroundingModuleConfig;
-import com.sap.ai.sdk.orchestration.model.GroundingModuleConfigConfig;
-import com.sap.ai.sdk.orchestration.model.Template;
-import com.sap.cloud.sdk.cloudplatform.thread.ThreadContextExecutors;
-import java.util.List;
-import java.util.Map;
import javax.annotation.Nonnull;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;
@@ -35,27 +22,30 @@
/** Endpoints for the Orchestration service */
@RestController
@Slf4j
+@SuppressWarnings("unused")
@RequestMapping("/orchestration")
class OrchestrationController {
- private final OrchestrationClient client = new OrchestrationClient();
- OrchestrationModuleConfig config =
- new OrchestrationModuleConfig().withLlmConfig(GEMINI_1_5_FLASH.withParam(TEMPERATURE, 0.0));
+ @Autowired private OrchestrationService service;
+ private final ObjectMapper mapper =
+ new ObjectMapper().setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
/**
* Chat request to OpenAI through the Orchestration service with a simple prompt.
*
- * @return the result object
+ * @return a ResponseEntity with the response content
*/
@GetMapping("/completion")
@Nonnull
- OrchestrationChatResponse completion() {
- final var prompt = new OrchestrationPrompt("Hello world! Why is this phrase so famous?");
-
- final var result = client.chatCompletion(prompt, config);
-
- log.info("Our trusty AI answered with: {}", result.getContent());
-
- return result;
+ ResponseEntity completion(
+ @RequestHeader(value = "accept", required = false) final String accept)
+ throws JsonProcessingException {
+ final var response = service.completion("HelloWorld!");
+ if (accept.equals("application/json")) {
+ return ResponseEntity.ok()
+ .contentType(MediaType.APPLICATION_JSON)
+ .body(mapper.writeValueAsString(response));
+ }
+ return ResponseEntity.ok(response.getContent());
}
/**
@@ -63,33 +53,10 @@ OrchestrationChatResponse completion() {
*
* @return the emitter that streams the assistant message response
*/
- @SuppressWarnings("unused") // The end-to-end test doesn't use this method
@GetMapping("/streamChatCompletion")
@Nonnull
- public ResponseEntity streamChatCompletion() {
- final var prompt =
- new OrchestrationPrompt("Can you give me the first 100 numbers of the Fibonacci sequence?");
- final var stream = client.streamChatCompletion(prompt, config);
-
- final var emitter = new ResponseBodyEmitter();
-
- final Runnable consumeStream =
- () -> {
- try (stream) {
- stream.forEach(
- deltaMessage -> {
- log.info("Controller: {}", deltaMessage);
- send(emitter, deltaMessage);
- });
- } finally {
- emitter.complete();
- }
- };
-
- ThreadContextExecutors.getExecutor().execute(consumeStream);
-
- // TEXT_EVENT_STREAM allows the browser to display the content as it is streamed
- return ResponseEntity.ok().contentType(MediaType.TEXT_EVENT_STREAM).body(emitter);
+ ResponseEntity streamChatCompletion() {
+ return service.streamChatCompletion(100);
}
/**
@@ -97,40 +64,39 @@ public ResponseEntity streamChatCompletion() {
*
* @link SAP
* AI Core: Orchestration - Templating
- * @return the result object
+ * @return a ResponseEntity with the response content
*/
@GetMapping("/template")
@Nonnull
- OrchestrationChatResponse template() {
- final var template =
- Message.user("Reply with 'Orchestration Service is working!' in {{?language}}");
- final var templatingConfig = Template.create().template(List.of(template.createChatMessage()));
- final var configWithTemplate = config.withTemplateConfig(templatingConfig);
-
- final var inputParams = Map.of("language", "German");
- final var prompt = new OrchestrationPrompt(inputParams);
-
- return client.chatCompletion(prompt, configWithTemplate);
+ ResponseEntity