55import static com .sap .ai .sdk .foundationmodels .openai .OpenAiModel .TEXT_EMBEDDING_ADA_002 ;
66import static com .sap .ai .sdk .foundationmodels .openai .model .OpenAiChatCompletionTool .ToolType .FUNCTION ;
77
8- import com .fasterxml .jackson .core .JsonProcessingException ;
9- import com .fasterxml .jackson .databind .ObjectMapper ;
108import com .sap .ai .sdk .core .AiCoreService ;
119import com .sap .ai .sdk .foundationmodels .openai .OpenAiClient ;
10+ import com .sap .ai .sdk .foundationmodels .openai .model .OpenAiChatCompletionDelta ;
1211import com .sap .ai .sdk .foundationmodels .openai .model .OpenAiChatCompletionFunction ;
1312import com .sap .ai .sdk .foundationmodels .openai .model .OpenAiChatCompletionOutput ;
1413import com .sap .ai .sdk .foundationmodels .openai .model .OpenAiChatCompletionParameters ;
1514import com .sap .ai .sdk .foundationmodels .openai .model .OpenAiChatCompletionTool ;
1615import com .sap .ai .sdk .foundationmodels .openai .model .OpenAiChatMessage ;
1716import com .sap .ai .sdk .foundationmodels .openai .model .OpenAiEmbeddingOutput ;
1817import com .sap .ai .sdk .foundationmodels .openai .model .OpenAiEmbeddingParameters ;
19- import com .sap .cloud .sdk .cloudplatform .thread .ThreadContextExecutors ;
20- import java .io .IOException ;
21- import java .util .Arrays ;
2218import java .util .List ;
2319import java .util .Map ;
20+ import java .util .stream .Stream ;
2421import javax .annotation .Nonnull ;
2522import lombok .extern .slf4j .Slf4j ;
26- import org .springframework .http .MediaType ;
27- import org .springframework .http .ResponseEntity ;
2823import org .springframework .stereotype .Service ;
29- import org .springframework .web .servlet .mvc .method .annotation .ResponseBodyEmitter ;
3024
3125/** Service class for OpenAI service */
3226@ Service
@@ -50,34 +44,13 @@ public OpenAiChatCompletionOutput chatCompletion(@Nonnull final String prompt) {
5044 * @return the emitter that streams the assistant message response
5145 */
5246 @ Nonnull
53- public ResponseEntity < ResponseBodyEmitter > streamChatCompletionDeltas (
47+ public Stream < OpenAiChatCompletionDelta > streamChatCompletionDeltas (
5448 @ Nonnull final String message ) {
5549 final var request =
5650 new OpenAiChatCompletionParameters ()
5751 .addMessages (new OpenAiChatMessage .OpenAiChatUserMessage ().addText (message ));
5852
59- final var stream = OpenAiClient .forModel (GPT_35_TURBO ).streamChatCompletionDeltas (request );
60-
61- final var emitter = new ResponseBodyEmitter ();
62-
63- final Runnable consumeStream =
64- () -> {
65- final var totalOutput = new OpenAiChatCompletionOutput ();
66- // try-with-resources ensures the stream is closed
67- try (stream ) {
68- stream
69- .peek (totalOutput ::addDelta )
70- .forEach (delta -> send (emitter , delta .getDeltaContent ()));
71- } finally {
72- send (emitter , "\n \n -----Total Output-----\n \n " + objectToJson (totalOutput ));
73- emitter .complete ();
74- }
75- };
76-
77- ThreadContextExecutors .getExecutor ().execute (consumeStream );
78-
79- // TEXT_EVENT_STREAM allows the browser to display the content as it is streamed
80- return ResponseEntity .ok ().contentType (MediaType .TEXT_EVENT_STREAM ).body (emitter );
53+ return OpenAiClient .forModel (GPT_35_TURBO ).streamChatCompletionDeltas (request );
8154 }
8255
8356 /**
@@ -86,50 +59,10 @@ public ResponseEntity<ResponseBodyEmitter> streamChatCompletionDeltas(
8659 * @return the emitter that streams the assistant message response
8760 */
8861 @ Nonnull
89- public ResponseEntity <ResponseBodyEmitter > streamChatCompletion (@ Nonnull final String message ) {
90- final var stream =
91- OpenAiClient .forModel (GPT_35_TURBO )
92- .withSystemPrompt ("Be a good, honest AI and answer the following question:" )
93- .streamChatCompletion (message );
94-
95- final var emitter = new ResponseBodyEmitter ();
96-
97- final Runnable consumeStream =
98- () -> {
99- try (stream ) {
100- stream .forEach (deltaMessage -> send (emitter , deltaMessage ));
101- } finally {
102- emitter .complete ();
103- }
104- };
105-
106- ThreadContextExecutors .getExecutor ().execute (consumeStream );
107-
108- // TEXT_EVENT_STREAM allows the browser to display the content as it is streamed
109- return ResponseEntity .ok ().contentType (MediaType .TEXT_EVENT_STREAM ).body (emitter );
110- }
111-
112- private static String objectToJson (@ Nonnull final Object obj ) {
113- try {
114- return new ObjectMapper ().writerWithDefaultPrettyPrinter ().writeValueAsString (obj );
115- } catch (final JsonProcessingException ignored ) {
116- return "Could not parse object to JSON" ;
117- }
118- }
119-
120- /**
121- * Send a chunk to the emitter
122- *
123- * @param emitter The emitter to send the chunk to
124- * @param chunk The chunk to send
125- */
126- public static void send (@ Nonnull final ResponseBodyEmitter emitter , @ Nonnull final String chunk ) {
127- try {
128- emitter .send (chunk );
129- } catch (final IOException e ) {
130- log .error (Arrays .toString (e .getStackTrace ()));
131- emitter .completeWithError (e );
132- }
62+ public Stream <String > streamChatCompletion (@ Nonnull final String message ) {
63+ return OpenAiClient .forModel (GPT_35_TURBO )
64+ .withSystemPrompt ("Be a good, honest AI and answer the following question:" )
65+ .streamChatCompletion (message );
13366 }
13467
13568 /**
0 commit comments