Skip to content

Commit ee85ece

Browse files
author
Milder Hernandez Cagua
committed
Add streaming to sk chat
1 parent 319d617 commit ee85ece

File tree

1 file changed

+49
-7
lines changed

1 file changed

+49
-7
lines changed

app/backend/src/main/java/com/microsoft/openai/samples/rag/chat/approaches/semantickernel/JavaSemanticKernelWithMemoryChatApproach.java

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,29 @@
44
import com.azure.core.credential.TokenCredential;
55
import com.azure.search.documents.SearchAsyncClient;
66
import com.azure.search.documents.SearchDocument;
7+
import com.fasterxml.jackson.databind.ObjectMapper;
78
import com.microsoft.openai.samples.rag.approaches.ContentSource;
89
import com.microsoft.openai.samples.rag.approaches.RAGApproach;
910
import com.microsoft.openai.samples.rag.approaches.RAGOptions;
1011
import com.microsoft.openai.samples.rag.approaches.RAGResponse;
1112
import com.microsoft.openai.samples.rag.ask.approaches.semantickernel.memory.CustomAzureCognitiveSearchMemoryStore;
1213
import com.microsoft.openai.samples.rag.common.ChatGPTConversation;
13-
import com.microsoft.openai.samples.rag.common.ChatGPTMessage;
1414
import com.microsoft.openai.samples.rag.common.ChatGPTUtils;
15+
import com.microsoft.openai.samples.rag.controller.ChatResponse;
1516
import com.microsoft.semantickernel.Kernel;
1617
import com.microsoft.semantickernel.SKBuilders;
1718
import com.microsoft.semantickernel.ai.embeddings.Embedding;
18-
import com.microsoft.semantickernel.chatcompletion.ChatCompletion;
19-
import com.microsoft.semantickernel.connectors.ai.openai.chatcompletion.OpenAIChatCompletion;
20-
import com.microsoft.semantickernel.connectors.ai.openai.chatcompletion.OpenAIChatHistory;
2119
import com.microsoft.semantickernel.memory.MemoryQueryResult;
2220
import com.microsoft.semantickernel.memory.MemoryRecord;
2321
import com.microsoft.semantickernel.orchestration.SKContext;
2422
import com.microsoft.semantickernel.orchestration.SKFunction;
25-
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
2623
import org.slf4j.Logger;
2724
import org.slf4j.LoggerFactory;
2825
import org.springframework.beans.factory.annotation.Value;
2926
import org.springframework.stereotype.Component;
3027
import reactor.core.publisher.Mono;
3128

29+
import java.io.IOException;
3230
import java.io.OutputStream;
3331
import java.util.List;
3432
import java.util.function.Function;
@@ -47,6 +45,8 @@ public class JavaSemanticKernelWithMemoryChatApproach implements RAGApproach<Cha
4745

4846
private final SearchAsyncClient searchAsyncClient;
4947

48+
private final ObjectMapper objectMapper;
49+
5050
private final String EMBEDDING_FIELD_NAME = "embedding";
5151

5252
@Value("${cognitive.search.service}")
@@ -58,10 +58,11 @@ public class JavaSemanticKernelWithMemoryChatApproach implements RAGApproach<Cha
5858

5959
@Value("${openai.embedding.deployment}")
6060
private String embeddingDeploymentModelId;
61-
public JavaSemanticKernelWithMemoryChatApproach(TokenCredential tokenCredential, OpenAIAsyncClient openAIAsyncClient, SearchAsyncClient searchAsyncClient) {
61+
public JavaSemanticKernelWithMemoryChatApproach(TokenCredential tokenCredential, OpenAIAsyncClient openAIAsyncClient, SearchAsyncClient searchAsyncClient, ObjectMapper objectMapper) {
6262
this.tokenCredential = tokenCredential;
6363
this.openAIAsyncClient = openAIAsyncClient;
6464
this.searchAsyncClient = searchAsyncClient;
65+
this.objectMapper = objectMapper;
6566
}
6667

6768
@Override
@@ -101,7 +102,48 @@ public RAGResponse run(ChatGPTConversation questionOrConversation, RAGOptions op
101102

102103
@Override
103104
public void runStreaming(ChatGPTConversation questionOrConversation, RAGOptions options, OutputStream outputStream) {
104-
throw new IllegalStateException("Streaming not supported for this approach");
105+
String question = ChatGPTUtils.getLastUserQuestion(questionOrConversation.getMessages());
106+
107+
// STEP 1: Build semantic kernel with Azure Cognitive Search as memory store. AnswerQuestion skill is imported from resources.
108+
Kernel semanticKernel = buildSemanticKernel(options);
109+
110+
// STEP 2: Retrieve relevant documents using keywords extracted from the chat history
111+
String conversation = ChatGPTUtils.formatAsChatML(questionOrConversation.toOpenAIChatMessages());
112+
List<MemoryQueryResult> sourcesResult = getSourcesFromConversation(conversation, semanticKernel, options);
113+
114+
LOGGER.info("Total {} sources found in cognitive vector store for search query[{}]", sourcesResult.size(), question);
115+
116+
String sources = buildSourcesText(sourcesResult);
117+
List<ContentSource> sourcesList = buildSources(sourcesResult);
118+
119+
// STEP 3: Generate a contextual and content specific answer using the search results and chat history
120+
SKFunction answerConversation = semanticKernel.getFunction("RAG", "AnswerConversation");
121+
SKContext skcontext = SKBuilders.context().build()
122+
.setVariable("sources", sources)
123+
.setVariable("conversation", conversation)
124+
.setVariable("suggestions", String.valueOf(options.isSuggestFollowupQuestions()))
125+
.setVariable("input", question);
126+
127+
SKContext reply = (SKContext) answerConversation.invokeAsync(skcontext).block();
128+
129+
RAGResponse ragResponse =
130+
new RAGResponse.Builder()
131+
.question(
132+
ChatGPTUtils.getLastUserQuestion(
133+
questionOrConversation.getMessages()))
134+
.prompt("placeholders for prompt")
135+
.answer(reply.getResult())
136+
.sources(sourcesList)
137+
.sourcesAsText(sources)
138+
.build();
139+
140+
try {
141+
String value = objectMapper.writeValueAsString(ChatResponse.buildChatResponse(ragResponse)) + "\n";
142+
outputStream.write(value.getBytes());
143+
outputStream.flush();
144+
} catch (IOException e) {
145+
throw new RuntimeException(e);
146+
}
105147
}
106148

107149
private List<MemoryQueryResult> getSourcesFromConversation (String conversation, Kernel kernel, RAGOptions options) {

0 commit comments

Comments
 (0)