mirror of
https://github.com/microsoft/semantic-kernel.git
synced 2026-10-12 02:19:06 +00:00
Fix formatting (#1492)
This commit is contained in:
+2
-2
@@ -1,12 +1,12 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.ai.embeddings;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** Interface for text embedding generation services */
|
||||
public interface EmbeddingGeneration<TValue, TEmbedding extends Number> {
|
||||
/**
|
||||
|
||||
+3
-3
@@ -1,17 +1,17 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.chatcompletion;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public interface ChatCompletion<ChatHistoryType extends ChatHistory> {
|
||||
/**
|
||||
* Generate a new chat message
|
||||
*
|
||||
* @param chat Chat history
|
||||
* @param chat Chat history
|
||||
* @param requestSettings AI request settings
|
||||
* @return Generated chat message in string format
|
||||
*/
|
||||
|
||||
+4
-5
@@ -1,12 +1,12 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.textcompletion;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** Interface for text completion services */
|
||||
public interface TextCompletion {
|
||||
// TODO: Support Cancellation Token
|
||||
@@ -14,15 +14,14 @@ public interface TextCompletion {
|
||||
/**
|
||||
* Creates a completion for the prompt and settings.
|
||||
*
|
||||
* @param text The prompt to complete.
|
||||
* @param text The prompt to complete.
|
||||
* @param requestSettings Request settings for the completion API
|
||||
* @return Text generated by the remote model
|
||||
*/
|
||||
Mono<List<String>> completeAsync(String text, CompletionRequestSettings requestSettings);
|
||||
|
||||
abstract class Builder {
|
||||
protected Builder() {
|
||||
}
|
||||
protected Builder() {}
|
||||
|
||||
public abstract TextCompletion build(OpenAIAsyncClient client, String modelId);
|
||||
}
|
||||
|
||||
+16
-16
@@ -1,11 +1,6 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.connectors.ai.openai.chatcompletion;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.azure.ai.openai.models.ChatCompletionsOptions;
|
||||
import com.azure.ai.openai.models.ChatMessage;
|
||||
@@ -19,6 +14,11 @@ import com.microsoft.semantickernel.connectors.ai.openai.azuresdk.ClientBase;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** OpenAI chat completion client. */
|
||||
public class OpenAIChatCompletion extends ClientBase implements ChatCompletion<OpenAIChatHistory> {
|
||||
public OpenAIChatCompletion(OpenAIAsyncClient client, String modelId) {
|
||||
@@ -26,8 +26,7 @@ public class OpenAIChatCompletion extends ClientBase implements ChatCompletion<O
|
||||
}
|
||||
|
||||
public static class Builder implements ChatCompletion.Builder {
|
||||
public Builder() {
|
||||
}
|
||||
public Builder() {}
|
||||
|
||||
public ChatCompletion<OpenAIChatHistory> build(OpenAIAsyncClient client, String modelId) {
|
||||
return new OpenAIChatCompletion(client, modelId);
|
||||
@@ -37,7 +36,7 @@ public class OpenAIChatCompletion extends ClientBase implements ChatCompletion<O
|
||||
/**
|
||||
* Generate a new chat message
|
||||
*
|
||||
* @param chat Chat history
|
||||
* @param chat Chat history
|
||||
* @param requestSettings AI request settings
|
||||
* @return The response generated by the request
|
||||
*/
|
||||
@@ -53,7 +52,7 @@ public class OpenAIChatCompletion extends ClientBase implements ChatCompletion<O
|
||||
/**
|
||||
* Generate a new chat message
|
||||
*
|
||||
* @param chat Chat history
|
||||
* @param chat Chat history
|
||||
* @param requestSettings AI request settings
|
||||
* @return The response generated by the request
|
||||
*/
|
||||
@@ -83,13 +82,14 @@ public class OpenAIChatCompletion extends ClientBase implements ChatCompletion<O
|
||||
|
||||
private static ChatCompletionsOptions createChatCompletionsOptions(
|
||||
ChatRequestSettings requestSettings, ChatHistory chat) {
|
||||
List<ChatMessage> messages = chat.getMessages().stream()
|
||||
.map(
|
||||
it -> {
|
||||
return new ChatMessage(toChatRole(it.getAuthorRoles()))
|
||||
.setContent(it.getContent());
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
List<ChatMessage> messages =
|
||||
chat.getMessages().stream()
|
||||
.map(
|
||||
it -> {
|
||||
return new ChatMessage(toChatRole(it.getAuthorRoles()))
|
||||
.setContent(it.getContent());
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
ChatCompletionsOptions options = new ChatCompletionsOptions(messages);
|
||||
|
||||
|
||||
+10
-9
@@ -1,12 +1,12 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.connectors.ai.openai.textcompletion;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.azure.ai.openai.models.Choice;
|
||||
import com.azure.ai.openai.models.Completions;
|
||||
import com.azure.ai.openai.models.CompletionsOptions;
|
||||
import com.microsoft.semantickernel.ai.AIException;
|
||||
import com.microsoft.semantickernel.connectors.ai.openai.azuresdk.ClientBase;
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionRequestSettings;
|
||||
import com.microsoft.semantickernel.textcompletion.TextCompletion;
|
||||
|
||||
@@ -51,14 +51,15 @@ public class OpenAITextCompletion extends ClientBase implements TextCompletion {
|
||||
throw new AIException(AIException.ErrorCodes.InvalidRequest, "Max tokens must be >0");
|
||||
}
|
||||
|
||||
CompletionsOptions completionsOptions = new CompletionsOptions(Collections.singletonList(text))
|
||||
.setMaxTokens(requestSettings.getMaxTokens())
|
||||
.setTemperature(requestSettings.getTemperature())
|
||||
.setTopP(requestSettings.getTopP())
|
||||
.setFrequencyPenalty(requestSettings.getFrequencyPenalty())
|
||||
.setPresencePenalty(requestSettings.getPresencePenalty())
|
||||
.setModel(getModelId())
|
||||
.setUser(null);
|
||||
CompletionsOptions completionsOptions =
|
||||
new CompletionsOptions(Collections.singletonList(text))
|
||||
.setMaxTokens(requestSettings.getMaxTokens())
|
||||
.setTemperature(requestSettings.getTemperature())
|
||||
.setTopP(requestSettings.getTopP())
|
||||
.setFrequencyPenalty(requestSettings.getFrequencyPenalty())
|
||||
.setPresencePenalty(requestSettings.getPresencePenalty())
|
||||
.setModel(getModelId())
|
||||
.setUser(null);
|
||||
|
||||
return getClient()
|
||||
.getCompletions(getModelId(), completionsOptions)
|
||||
|
||||
+7
-6
@@ -1,9 +1,6 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.connectors.ai.openai.textembeddings;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.azure.ai.openai.models.EmbeddingItem;
|
||||
import com.azure.ai.openai.models.Embeddings;
|
||||
@@ -14,6 +11,9 @@ import com.microsoft.semantickernel.connectors.ai.openai.azuresdk.ClientBase;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class OpenAITextEmbeddingGeneration extends ClientBase
|
||||
implements EmbeddingGeneration<String, Float> {
|
||||
|
||||
@@ -34,9 +34,10 @@ public class OpenAITextEmbeddingGeneration extends ClientBase
|
||||
.flatMapIterable(Embeddings::getData)
|
||||
.mapNotNull(EmbeddingItem::getEmbedding)
|
||||
.map(
|
||||
embedding -> embedding.stream()
|
||||
.map(Double::floatValue)
|
||||
.collect(Collectors.toList()))
|
||||
embedding ->
|
||||
embedding.stream()
|
||||
.map(Double::floatValue)
|
||||
.collect(Collectors.toList()))
|
||||
.mapNotNull(Embedding::new)
|
||||
.collectList();
|
||||
}
|
||||
|
||||
+3
-9
@@ -260,9 +260,7 @@ public class TextChunkerTest {
|
||||
"This is only a test",
|
||||
"We repeat, this is only a test, A unit test",
|
||||
"A small note, And another, And once again, Seriously,",
|
||||
"this is the end, We're finished, All set, Bye."
|
||||
+ "\n"
|
||||
+ "Done.");
|
||||
"this is the end, We're finished, All set, Bye." + "\n" + "Done.");
|
||||
|
||||
List<String> result = TextChunker.splitPlainTextParagraphs(input, 15);
|
||||
|
||||
@@ -307,9 +305,7 @@ public class TextChunkerTest {
|
||||
"broadcast system-This is only a test",
|
||||
"We repeat-this is only a test-A unit test",
|
||||
"A small note-And another-And once again-Seriously,",
|
||||
"this is the end-We're finished-All set-Bye."
|
||||
+ "\n"
|
||||
+ "Done.");
|
||||
"this is the end-We're finished-All set-Bye." + "\n" + "Done.");
|
||||
|
||||
List<String> result = TextChunker.splitPlainTextParagraphs(input, 15);
|
||||
|
||||
@@ -327,9 +323,7 @@ public class TextChunkerTest {
|
||||
"SeriouslythisistheendWe'refinishedAllsetByeDoneThisOneWillBeSplitToMeetTheLimit");
|
||||
List<String> expected =
|
||||
Arrays.asList(
|
||||
"Thisisatestoftheemergencybroadcastsystem"
|
||||
+ "\n"
|
||||
+ "Thisisonlyatest",
|
||||
"Thisisatestoftheemergencybroadcastsystem" + "\n" + "Thisisonlyatest",
|
||||
"WerepeatthisisonlyatestAunittest",
|
||||
"AsmallnoteAndanotherAndonceagain",
|
||||
"SeriouslythisistheendWe'refinishedAllse",
|
||||
|
||||
+196
-189
@@ -1,17 +1,6 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentMatcher;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.azure.ai.openai.models.Choice;
|
||||
import com.azure.ai.openai.models.Completions;
|
||||
@@ -26,219 +15,237 @@ import com.microsoft.semantickernel.textcompletion.CompletionSKContext;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
import com.microsoft.semantickernel.textcompletion.TextCompletion;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentMatcher;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.function.Tuple2;
|
||||
import reactor.util.function.Tuples;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class DefaultKernelTest {
|
||||
|
||||
@Test
|
||||
void contextVariableTest() {
|
||||
String model = "a-model";
|
||||
@Test
|
||||
void contextVariableTest() {
|
||||
String model = "a-model";
|
||||
|
||||
OpenAIAsyncClient client = mockCompletionOpenAIAsyncClient(
|
||||
Tuples.of("A", "a"), Tuples.of("user: Aauser: B", "b"));
|
||||
OpenAIAsyncClient client =
|
||||
mockCompletionOpenAIAsyncClient(
|
||||
Tuples.of("A", "a"), Tuples.of("user: Aauser: B", "b"));
|
||||
|
||||
Kernel kernel = buildKernel(model, client);
|
||||
Kernel kernel = buildKernel(model, client);
|
||||
|
||||
String prompt = "{{$history}}user: {{$user_input}}\n";
|
||||
String prompt = "{{$history}}user: {{$user_input}}\n";
|
||||
|
||||
CompletionSKFunction chat = kernel.getSemanticFunctionBuilder()
|
||||
.createFunction(
|
||||
prompt,
|
||||
"ChatBot",
|
||||
null,
|
||||
null,
|
||||
new PromptTemplateConfig.CompletionConfig(
|
||||
0.7, 0.5, 0, 0, 2000, new ArrayList<>()));
|
||||
CompletionSKFunction chat =
|
||||
kernel.getSemanticFunctionBuilder()
|
||||
.createFunction(
|
||||
prompt,
|
||||
"ChatBot",
|
||||
null,
|
||||
null,
|
||||
new PromptTemplateConfig.CompletionConfig(
|
||||
0.7, 0.5, 0, 0, 2000, new ArrayList<>()));
|
||||
|
||||
ContextVariables variables = SKBuilders.variables().build();
|
||||
ContextVariables variables = SKBuilders.variables().build();
|
||||
|
||||
CompletionSKContext readOnlySkContext = chat.buildContext(variables, null, null)
|
||||
.setVariable("history", "")
|
||||
.setVariable("user_input", "A");
|
||||
CompletionSKContext readOnlySkContext =
|
||||
chat.buildContext(variables, null, null)
|
||||
.setVariable("history", "")
|
||||
.setVariable("user_input", "A");
|
||||
|
||||
CompletionSKContext result = chat.invokeAsync(readOnlySkContext, null).block();
|
||||
CompletionSKContext result = chat.invokeAsync(readOnlySkContext, null).block();
|
||||
|
||||
if (result == null) {
|
||||
Assertions.fail();
|
||||
}
|
||||
|
||||
Assertions.assertEquals("a", result.getResult());
|
||||
|
||||
result = result.appendToVariable("history", "user: A" + result.getResult())
|
||||
.setVariable("user_input", "B");
|
||||
|
||||
result = chat.invokeAsync(result, null).block();
|
||||
if (result == null) {
|
||||
Assertions.fail();
|
||||
}
|
||||
Assertions.assertEquals("b", result.getResult());
|
||||
if (result == null) {
|
||||
Assertions.fail();
|
||||
}
|
||||
|
||||
@Test
|
||||
void tellAJoke() {
|
||||
String expectedResponse = "a result joke";
|
||||
OpenAIAsyncClient client = mockCompletionOpenAIAsyncClient("WRITE", expectedResponse);
|
||||
String model = "a-model-name";
|
||||
Kernel kernel = buildKernel(model, client);
|
||||
Assertions.assertEquals("a", result.getResult());
|
||||
|
||||
CompletionSKFunction function = kernel.importSkill(
|
||||
result =
|
||||
result.appendToVariable("history", "user: A" + result.getResult())
|
||||
.setVariable("user_input", "B");
|
||||
|
||||
result = chat.invokeAsync(result, null).block();
|
||||
if (result == null) {
|
||||
Assertions.fail();
|
||||
}
|
||||
Assertions.assertEquals("b", result.getResult());
|
||||
}
|
||||
|
||||
@Test
|
||||
void tellAJoke() {
|
||||
String expectedResponse = "a result joke";
|
||||
OpenAIAsyncClient client = mockCompletionOpenAIAsyncClient("WRITE", expectedResponse);
|
||||
String model = "a-model-name";
|
||||
Kernel kernel = buildKernel(model, client);
|
||||
|
||||
CompletionSKFunction function =
|
||||
kernel.importSkill(
|
||||
"FunSkill",
|
||||
KernelExtensions.importSemanticSkillFromDirectory(
|
||||
"../../samples/skills", "FunSkill"))
|
||||
.getFunction("joke", CompletionSKFunction.class);
|
||||
"../../samples/skills", "FunSkill"))
|
||||
.getFunction("joke", CompletionSKFunction.class);
|
||||
|
||||
Mono<CompletionSKContext> mono = function.invokeAsync("time travel to dinosaur age");
|
||||
CompletionSKContext result = mono.block();
|
||||
Mono<CompletionSKContext> mono = function.invokeAsync("time travel to dinosaur age");
|
||||
CompletionSKContext result = mono.block();
|
||||
|
||||
String expected = "WRITE EXACTLY ONE JOKE or HUMOROUS STORY ABOUT THE TOPIC BELOW\n"
|
||||
+ "\n"
|
||||
+ "JOKE MUST BE:\n"
|
||||
+ "- G RATED\n"
|
||||
+ "- WORKPLACE/FAMILY SAFE\n"
|
||||
+ "NO SEXISM, RACISM OR OTHER BIAS/BIGOTRY\n"
|
||||
+ "\n"
|
||||
+ "BE CREATIVE AND FUNNY. I WANT TO LAUGH.\n"
|
||||
+ "\n"
|
||||
+ "+++++\n"
|
||||
+ "\n"
|
||||
+ "time travel to dinosaur age\n"
|
||||
+ "+++++\n";
|
||||
String expected =
|
||||
"WRITE EXACTLY ONE JOKE or HUMOROUS STORY ABOUT THE TOPIC BELOW\n"
|
||||
+ "\n"
|
||||
+ "JOKE MUST BE:\n"
|
||||
+ "- G RATED\n"
|
||||
+ "- WORKPLACE/FAMILY SAFE\n"
|
||||
+ "NO SEXISM, RACISM OR OTHER BIAS/BIGOTRY\n"
|
||||
+ "\n"
|
||||
+ "BE CREATIVE AND FUNNY. I WANT TO LAUGH.\n"
|
||||
+ "\n"
|
||||
+ "+++++\n"
|
||||
+ "\n"
|
||||
+ "time travel to dinosaur age\n"
|
||||
+ "+++++\n";
|
||||
|
||||
assertCompletionsWasCalledWithModelAndText(client, model, expected);
|
||||
assertCompletionsWasCalledWithModelAndText(client, model, expected);
|
||||
|
||||
assertTheResultEquals(result, expectedResponse);
|
||||
assertTheResultEquals(result, expectedResponse);
|
||||
}
|
||||
|
||||
public static Kernel buildKernel(String model, OpenAIAsyncClient client) {
|
||||
|
||||
TextCompletion textCompletion = new OpenAITextCompletion(client, model);
|
||||
|
||||
KernelConfig kernelConfig =
|
||||
SKBuilders.kernelConfig()
|
||||
.addTextCompletionService(model, kernel -> textCompletion)
|
||||
.build();
|
||||
|
||||
return SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
}
|
||||
|
||||
private static OpenAIAsyncClient mockCompletionOpenAIAsyncClient(String arg, String response) {
|
||||
List<Tuple2<String, String>> responses =
|
||||
Collections.singletonList(Tuples.of(arg, response));
|
||||
|
||||
return mockCompletionOpenAIAsyncClient(responses.toArray(new Tuple2[0]));
|
||||
}
|
||||
|
||||
/*
|
||||
* Mocks a Text Completion client where if the prompt matches it will return the
|
||||
* first arg it will return the response,
|
||||
* i.e:
|
||||
*
|
||||
* mockCompletionOpenAIAsyncClient(
|
||||
* List.<>of(
|
||||
* Tuples.of("Tell me a joke", "This is a joke")
|
||||
* )
|
||||
* );
|
||||
*
|
||||
* This if the client is prompted with "Tell me a joke", the mocked client would
|
||||
* respond with "This is a joke"
|
||||
*/
|
||||
|
||||
public static OpenAIAsyncClient mockCompletionOpenAIAsyncClient(
|
||||
Tuple2<String, String>... responses) {
|
||||
|
||||
List<Tuple2<ArgumentMatcher<String>, String>> matchers =
|
||||
Arrays.stream(responses)
|
||||
.map(
|
||||
response ->
|
||||
Tuples.<ArgumentMatcher<String>, String>of(
|
||||
arg -> arg.contains(response.getT1()),
|
||||
response.getT2()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return mockCompletionOpenAIAsyncClientMatchers(matchers.toArray(new Tuple2[0]));
|
||||
}
|
||||
|
||||
public static OpenAIAsyncClient mockCompletionOpenAIAsyncClientMatchers(
|
||||
Tuple2<ArgumentMatcher<String>, String>... responses) {
|
||||
OpenAIAsyncClient openAIAsyncClient = Mockito.mock(OpenAIAsyncClient.class);
|
||||
|
||||
for (Tuple2<ArgumentMatcher<String>, String> response : responses) {
|
||||
|
||||
Choice choice = Mockito.mock(Choice.class);
|
||||
Mockito.when(choice.getText()).thenReturn(response.getT2());
|
||||
|
||||
Completions completions = Mockito.mock(Completions.class);
|
||||
|
||||
Mockito.when(completions.getChoices()).thenReturn(Collections.singletonList(choice));
|
||||
|
||||
Mockito.when(
|
||||
openAIAsyncClient.getCompletions(
|
||||
Mockito.any(String.class),
|
||||
Mockito.<CompletionsOptions>argThat(
|
||||
it -> response.getT1().matches(it.getPrompt().get(0)))))
|
||||
.thenReturn(Mono.just(completions));
|
||||
|
||||
Mockito.when(
|
||||
openAIAsyncClient.getCompletions(
|
||||
Mockito.any(String.class),
|
||||
Mockito.<String>argThat(it -> response.getT1().matches(it))))
|
||||
.thenReturn(Mono.just(completions));
|
||||
}
|
||||
return openAIAsyncClient;
|
||||
}
|
||||
|
||||
public static Kernel buildKernel(String model, OpenAIAsyncClient client) {
|
||||
@Test
|
||||
void inlineFunctionTest() {
|
||||
|
||||
TextCompletion textCompletion = new OpenAITextCompletion(client, model);
|
||||
String model = "a-model";
|
||||
|
||||
KernelConfig kernelConfig = SKBuilders.kernelConfig()
|
||||
.addTextCompletionService(model, kernel -> textCompletion)
|
||||
.build();
|
||||
String expectedResponse = "foo";
|
||||
OpenAIAsyncClient openAIAsyncClient =
|
||||
mockCompletionOpenAIAsyncClient("block", expectedResponse);
|
||||
|
||||
return SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
}
|
||||
Kernel kernel = buildKernel(model, openAIAsyncClient);
|
||||
|
||||
private static OpenAIAsyncClient mockCompletionOpenAIAsyncClient(String arg, String response) {
|
||||
List<Tuple2<String, String>> responses = Collections.singletonList(Tuples.of(arg, response));
|
||||
String text = "A block of text\n";
|
||||
|
||||
return mockCompletionOpenAIAsyncClient(responses.toArray(new Tuple2[0]));
|
||||
}
|
||||
String prompt = "{{$input}}\n" + "Summarize the content above.";
|
||||
|
||||
/*
|
||||
* Mocks a Text Completion client where if the prompt matches it will return the
|
||||
* first arg it will return the response,
|
||||
* i.e:
|
||||
*
|
||||
* mockCompletionOpenAIAsyncClient(
|
||||
* List.<>of(
|
||||
* Tuples.of("Tell me a joke", "This is a joke")
|
||||
* )
|
||||
* );
|
||||
*
|
||||
* This if the client is prompted with "Tell me a joke", the mocked client would
|
||||
* respond with "This is a joke"
|
||||
*/
|
||||
CompletionSKFunction summarize =
|
||||
SKBuilders.completionFunctions()
|
||||
.createFunction(
|
||||
prompt,
|
||||
"summarize",
|
||||
null,
|
||||
null,
|
||||
new PromptTemplateConfig.CompletionConfig(
|
||||
0.2, 0.5, 0, 0, 2000, new ArrayList<>()));
|
||||
kernel.registerSemanticFunction(summarize);
|
||||
|
||||
public static OpenAIAsyncClient mockCompletionOpenAIAsyncClient(
|
||||
Tuple2<String, String>... responses) {
|
||||
Mono<CompletionSKContext> mono = summarize.invokeAsync(text);
|
||||
CompletionSKContext result = mono.block();
|
||||
|
||||
List<Tuple2<ArgumentMatcher<String>, String>> matchers = Arrays.stream(responses)
|
||||
.map(
|
||||
response -> Tuples.<ArgumentMatcher<String>, String>of(
|
||||
arg -> arg.contains(response.getT1()),
|
||||
response.getT2()))
|
||||
.collect(Collectors.toList());
|
||||
String expected = "A block of text\n\nSummarize the content above.";
|
||||
|
||||
return mockCompletionOpenAIAsyncClientMatchers(matchers.toArray(new Tuple2[0]));
|
||||
}
|
||||
assertCompletionsWasCalledWithModelAndText(openAIAsyncClient, model, expected);
|
||||
assertTheResultEquals(result, expectedResponse);
|
||||
}
|
||||
|
||||
public static OpenAIAsyncClient mockCompletionOpenAIAsyncClientMatchers(
|
||||
Tuple2<ArgumentMatcher<String>, String>... responses) {
|
||||
OpenAIAsyncClient openAIAsyncClient = Mockito
|
||||
.mock(OpenAIAsyncClient.class);
|
||||
private void assertTheResultEquals(SKContext result, String expected) {
|
||||
Assertions.assertEquals(expected, result.getResult());
|
||||
}
|
||||
|
||||
for (Tuple2<ArgumentMatcher<String>, String> response : responses) {
|
||||
private static void assertCompletionsWasCalledWithModelAndText(
|
||||
OpenAIAsyncClient openAIAsyncClient, String model, String expected) {
|
||||
|
||||
Choice choice = Mockito.mock(Choice.class);
|
||||
Mockito.when(choice.getText()).thenReturn(response.getT2());
|
||||
|
||||
Completions completions = Mockito.mock(Completions.class);
|
||||
|
||||
Mockito.when(completions.getChoices()).thenReturn(Collections.singletonList(choice));
|
||||
|
||||
Mockito.when(
|
||||
openAIAsyncClient.getCompletions(
|
||||
Mockito.any(String.class),
|
||||
Mockito.<CompletionsOptions>argThat(
|
||||
it -> response.getT1().matches(
|
||||
it.getPrompt().get(0)))))
|
||||
.thenReturn(Mono.just(completions));
|
||||
|
||||
Mockito.when(
|
||||
openAIAsyncClient.getCompletions(
|
||||
Mockito.any(String.class),
|
||||
Mockito.<String>argThat(
|
||||
it -> response.getT1().matches(it))))
|
||||
.thenReturn(Mono.just(completions));
|
||||
|
||||
}
|
||||
return openAIAsyncClient;
|
||||
}
|
||||
|
||||
@Test
|
||||
void inlineFunctionTest() {
|
||||
|
||||
String model = "a-model";
|
||||
|
||||
String expectedResponse = "foo";
|
||||
OpenAIAsyncClient openAIAsyncClient = mockCompletionOpenAIAsyncClient("block", expectedResponse);
|
||||
|
||||
Kernel kernel = buildKernel(model, openAIAsyncClient);
|
||||
|
||||
String text = "A block of text\n";
|
||||
|
||||
String prompt = "{{$input}}\n" + "Summarize the content above.";
|
||||
|
||||
CompletionSKFunction summarize = SKBuilders.completionFunctions()
|
||||
.createFunction(
|
||||
prompt,
|
||||
"summarize",
|
||||
null,
|
||||
null,
|
||||
new PromptTemplateConfig.CompletionConfig(
|
||||
0.2, 0.5, 0, 0, 2000, new ArrayList<>()));
|
||||
kernel.registerSemanticFunction(summarize);
|
||||
|
||||
Mono<CompletionSKContext> mono = summarize.invokeAsync(text);
|
||||
CompletionSKContext result = mono.block();
|
||||
|
||||
String expected = "A block of text\n\nSummarize the content above.";
|
||||
|
||||
assertCompletionsWasCalledWithModelAndText(openAIAsyncClient, model, expected);
|
||||
assertTheResultEquals(result, expectedResponse);
|
||||
}
|
||||
|
||||
private void assertTheResultEquals(SKContext result, String expected) {
|
||||
Assertions.assertEquals(expected, result.getResult());
|
||||
}
|
||||
|
||||
private static void assertCompletionsWasCalledWithModelAndText(
|
||||
OpenAIAsyncClient openAIAsyncClient, String model, String expected) {
|
||||
|
||||
Mockito.verify(openAIAsyncClient, Mockito.times(1))
|
||||
.getCompletions(
|
||||
Mockito.matches(model),
|
||||
Mockito.<CompletionsOptions>argThat(
|
||||
completionsOptions -> completionsOptions
|
||||
.getPrompt()
|
||||
.size() == 1
|
||||
&& completionsOptions
|
||||
.getPrompt()
|
||||
.get(0)
|
||||
.equals(expected)));
|
||||
}
|
||||
Mockito.verify(openAIAsyncClient, Mockito.times(1))
|
||||
.getCompletions(
|
||||
Mockito.matches(model),
|
||||
Mockito.<CompletionsOptions>argThat(
|
||||
completionsOptions ->
|
||||
completionsOptions.getPrompt().size() == 1
|
||||
&& completionsOptions
|
||||
.getPrompt()
|
||||
.get(0)
|
||||
.equals(expected)));
|
||||
}
|
||||
}
|
||||
|
||||
+45
-45
@@ -1,67 +1,67 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.azure.ai.openai.models.EmbeddingItem;
|
||||
import com.azure.ai.openai.models.Embeddings;
|
||||
import com.microsoft.semantickernel.ai.embeddings.EmbeddingGeneration;
|
||||
import com.microsoft.semantickernel.connectors.ai.openai.textembeddings.OpenAITextEmbeddingGeneration;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class TextEmbeddingsTest {
|
||||
|
||||
private static OpenAIAsyncClient mockEmbeddingOpenAIAsyncClient() {
|
||||
OpenAIAsyncClient openAIAsyncClient = Mockito.mock(OpenAIAsyncClient.class);
|
||||
Embeddings embeddings = Mockito.mock(Embeddings.class);
|
||||
EmbeddingItem embeddingItem = Mockito.mock(EmbeddingItem.class);
|
||||
private static OpenAIAsyncClient mockEmbeddingOpenAIAsyncClient() {
|
||||
OpenAIAsyncClient openAIAsyncClient = Mockito.mock(OpenAIAsyncClient.class);
|
||||
Embeddings embeddings = Mockito.mock(Embeddings.class);
|
||||
EmbeddingItem embeddingItem = Mockito.mock(EmbeddingItem.class);
|
||||
|
||||
Mockito.when(embeddingItem.getEmbedding()).thenReturn(Collections.singletonList(1.0));
|
||||
Mockito.when(embeddingItem.getEmbedding()).thenReturn(Collections.singletonList(1.0));
|
||||
|
||||
Mockito.when(embeddings.getData()).thenReturn(Collections.singletonList(embeddingItem));
|
||||
Mockito.when(embeddings.getData()).thenReturn(Collections.singletonList(embeddingItem));
|
||||
|
||||
Mockito.when(
|
||||
openAIAsyncClient.getEmbeddings(
|
||||
Mockito.any(String.class),
|
||||
Mockito.argThat(
|
||||
it -> it != null
|
||||
&& it.getModel()
|
||||
.equals("text-embedding-ada-002"))))
|
||||
.thenReturn(Mono.just(embeddings));
|
||||
Mockito.when(
|
||||
openAIAsyncClient.getEmbeddings(
|
||||
Mockito.any(String.class),
|
||||
Mockito.argThat(
|
||||
it ->
|
||||
it != null
|
||||
&& it.getModel()
|
||||
.equals("text-embedding-ada-002"))))
|
||||
.thenReturn(Mono.just(embeddings));
|
||||
|
||||
return openAIAsyncClient;
|
||||
}
|
||||
return openAIAsyncClient;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmbedding() {
|
||||
testEmbeddingGeneration(mockEmbeddingOpenAIAsyncClient(), 1);
|
||||
}
|
||||
@Test
|
||||
public void testEmbedding() {
|
||||
testEmbeddingGeneration(mockEmbeddingOpenAIAsyncClient(), 1);
|
||||
}
|
||||
|
||||
public void testEmbeddingGeneration(OpenAIAsyncClient client, int expectedEmbeddingSize) {
|
||||
String model = "text-embedding-ada-002";
|
||||
EmbeddingGeneration<String, Float> embeddingGeneration = new OpenAITextEmbeddingGeneration(client,
|
||||
model);
|
||||
public void testEmbeddingGeneration(OpenAIAsyncClient client, int expectedEmbeddingSize) {
|
||||
String model = "text-embedding-ada-002";
|
||||
EmbeddingGeneration<String, Float> embeddingGeneration =
|
||||
new OpenAITextEmbeddingGeneration(client, model);
|
||||
|
||||
List<String> data = new ArrayList<>();
|
||||
data.add("This is just");
|
||||
data.add("a test");
|
||||
List<String> data = new ArrayList<>();
|
||||
data.add("This is just");
|
||||
data.add("a test");
|
||||
|
||||
embeddingGeneration
|
||||
.generateEmbeddingsAsync(data)
|
||||
.block()
|
||||
.forEach(
|
||||
embedding -> {
|
||||
Assertions.assertEquals(
|
||||
expectedEmbeddingSize,
|
||||
embedding.getVector().size());
|
||||
});
|
||||
}
|
||||
embeddingGeneration
|
||||
.generateEmbeddingsAsync(data)
|
||||
.block()
|
||||
.forEach(
|
||||
embedding -> {
|
||||
Assertions.assertEquals(
|
||||
expectedEmbeddingSize, embedding.getVector().size());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+73
-70
@@ -3,15 +3,9 @@ package com.microsoft.semantickernel.connectors.ai.openai.chatcompletion;
|
||||
|
||||
import static com.microsoft.semantickernel.DefaultKernelTest.mockCompletionOpenAIAsyncClient;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.azure.ai.openai.models.ChatCompletionsOptions;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.azure.ai.openai.models.ChatCompletions;
|
||||
import com.azure.ai.openai.models.ChatCompletionsOptions;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.KernelConfig;
|
||||
import com.microsoft.semantickernel.ai.AIException;
|
||||
@@ -20,79 +14,88 @@ import com.microsoft.semantickernel.chatcompletion.ChatCompletion;
|
||||
import com.microsoft.semantickernel.chatcompletion.ChatHistory;
|
||||
import com.microsoft.semantickernel.syntaxexamples.Example17ChatGPTTest;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.function.Tuples;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class OpenAIChatCompletionTest {
|
||||
@Test
|
||||
public void azureOpenAIChatSampleAsync() {
|
||||
OpenAIAsyncClient client = mockCompletionOpenAIAsyncClient(Tuples.of("Today is", "A-RESULT"));
|
||||
@Test
|
||||
public void azureOpenAIChatSampleAsync() {
|
||||
OpenAIAsyncClient client =
|
||||
mockCompletionOpenAIAsyncClient(Tuples.of("Today is", "A-RESULT"));
|
||||
|
||||
String message = "Hi, I'm looking for book suggestions";
|
||||
Example17ChatGPTTest.mockResponse(client, message, "1st response");
|
||||
String message = "Hi, I'm looking for book suggestions";
|
||||
Example17ChatGPTTest.mockResponse(client, message, "1st response");
|
||||
|
||||
String result = getRunExample(client, message);
|
||||
Assertions.assertEquals("1st response", result);
|
||||
String result = getRunExample(client, message);
|
||||
Assertions.assertEquals("1st response", result);
|
||||
}
|
||||
|
||||
private static String getRunExample(OpenAIAsyncClient client, String message) {
|
||||
KernelConfig kernelConfig =
|
||||
SKBuilders.kernelConfig()
|
||||
.addChatCompletionService(
|
||||
"gpt-3.5-turbo-0301",
|
||||
kernel ->
|
||||
SKBuilders.chatCompletion()
|
||||
.build(client, "gpt-3.5-turbo-0301"))
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
|
||||
ChatCompletion<OpenAIChatHistory> chatGPT = kernel.getService(null, ChatCompletion.class);
|
||||
|
||||
OpenAIChatHistory chatHistory =
|
||||
chatGPT.createNewChat("You are a librarian, expert about books");
|
||||
|
||||
// First user message
|
||||
chatHistory.addUserMessage(message);
|
||||
ChatHistory.Message createdMessage = chatHistory.getLastMessage().get();
|
||||
Assertions.assertEquals(ChatHistory.AuthorRoles.User, createdMessage.getAuthorRoles());
|
||||
Assertions.assertEquals(message, createdMessage.getContent());
|
||||
|
||||
// First bot assistant message
|
||||
return chatGPT.generateMessageAsync(chatHistory, null).block();
|
||||
}
|
||||
|
||||
private static class runExample {
|
||||
public final OpenAIChatHistory chatHistory;
|
||||
public final String reply;
|
||||
|
||||
public runExample(OpenAIChatHistory chatHistory, String reply) {
|
||||
this.chatHistory = chatHistory;
|
||||
this.reply = reply;
|
||||
}
|
||||
}
|
||||
|
||||
private static String getRunExample(OpenAIAsyncClient client, String message) {
|
||||
KernelConfig kernelConfig = SKBuilders.kernelConfig()
|
||||
.addChatCompletionService(
|
||||
"gpt-3.5-turbo-0301",
|
||||
kernel -> SKBuilders.chatCompletion()
|
||||
.build(client, "gpt-3.5-turbo-0301"))
|
||||
.build();
|
||||
@Test
|
||||
public void emptyResponseThrowsError() {
|
||||
OpenAIAsyncClient client =
|
||||
mockCompletionOpenAIAsyncClient(Tuples.of("Today is", "A-RESULT"));
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
String message = "Hi, I'm looking for book suggestions";
|
||||
|
||||
ChatCompletion<OpenAIChatHistory> chatGPT = kernel.getService(null, ChatCompletion.class);
|
||||
ChatCompletions completion = Mockito.mock(ChatCompletions.class);
|
||||
Mockito.when(completion.getChoices()).thenReturn(new ArrayList<>());
|
||||
|
||||
OpenAIChatHistory chatHistory = chatGPT.createNewChat("You are a librarian, expert about books");
|
||||
Mockito.when(
|
||||
client.getChatCompletions(
|
||||
Mockito.any(),
|
||||
Mockito.<ChatCompletionsOptions>argThat(
|
||||
msg -> {
|
||||
return msg != null
|
||||
&& msg.getMessages()
|
||||
.get(msg.getMessages().size() - 1)
|
||||
.getContent()
|
||||
.equals(message);
|
||||
})))
|
||||
.thenReturn(Mono.just(completion));
|
||||
|
||||
// First user message
|
||||
chatHistory.addUserMessage(message);
|
||||
ChatHistory.Message createdMessage = chatHistory.getLastMessage().get();
|
||||
Assertions.assertEquals(ChatHistory.AuthorRoles.User, createdMessage.getAuthorRoles());
|
||||
Assertions.assertEquals(message, createdMessage.getContent());
|
||||
|
||||
// First bot assistant message
|
||||
return chatGPT.generateMessageAsync(chatHistory, null).block();
|
||||
}
|
||||
|
||||
private static class runExample {
|
||||
public final OpenAIChatHistory chatHistory;
|
||||
public final String reply;
|
||||
|
||||
public runExample(OpenAIChatHistory chatHistory, String reply) {
|
||||
this.chatHistory = chatHistory;
|
||||
this.reply = reply;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void emptyResponseThrowsError() {
|
||||
OpenAIAsyncClient client = mockCompletionOpenAIAsyncClient(Tuples.of("Today is", "A-RESULT"));
|
||||
|
||||
String message = "Hi, I'm looking for book suggestions";
|
||||
|
||||
ChatCompletions completion = Mockito.mock(ChatCompletions.class);
|
||||
Mockito.when(completion.getChoices()).thenReturn(new ArrayList<>());
|
||||
|
||||
Mockito.when(
|
||||
client.getChatCompletions(
|
||||
Mockito.any(),
|
||||
Mockito.<ChatCompletionsOptions>argThat(
|
||||
msg -> {
|
||||
return msg != null
|
||||
&& msg.getMessages()
|
||||
.get(msg.getMessages()
|
||||
.size()
|
||||
- 1)
|
||||
.getContent()
|
||||
.equals(message);
|
||||
})))
|
||||
.thenReturn(Mono.just(completion));
|
||||
|
||||
Assertions.assertThrows(AIException.class, () -> getRunExample(client, message));
|
||||
}
|
||||
Assertions.assertThrows(AIException.class, () -> getRunExample(client, message));
|
||||
}
|
||||
}
|
||||
|
||||
+9
-8
@@ -1,9 +1,6 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.syntaxexamples;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.DefaultKernelTest;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
@@ -11,6 +8,9 @@ import com.microsoft.semantickernel.coreskills.TextSkill;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlyFunctionCollection;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public class Example02PipelineTest {
|
||||
@@ -22,11 +22,12 @@ public class Example02PipelineTest {
|
||||
// Load native skill
|
||||
ReadOnlyFunctionCollection text = kernel.importSkill(new TextSkill(), null);
|
||||
|
||||
Mono<SKContext<?>> result = kernel.runAsync(
|
||||
" i n f i n i t e s p a c e ",
|
||||
text.getFunction("LStrip"),
|
||||
text.getFunction("RStrip"),
|
||||
text.getFunction("Uppercase"));
|
||||
Mono<SKContext<?>> result =
|
||||
kernel.runAsync(
|
||||
" i n f i n i t e s p a c e ",
|
||||
text.getFunction("LStrip"),
|
||||
text.getFunction("RStrip"),
|
||||
text.getFunction("Uppercase"));
|
||||
|
||||
Assertions.assertEquals("I N F I N I T E S P A C E", result.block().getResult());
|
||||
}
|
||||
|
||||
+22
-19
@@ -1,9 +1,6 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.syntaxexamples;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.DefaultKernelTest;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
@@ -13,27 +10,33 @@ import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlyFunctionCollection;
|
||||
import com.microsoft.semantickernel.syntaxexamples.skills.StaticTextSkill;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public class Example03VariablesTest {
|
||||
@Test
|
||||
public void run() {
|
||||
OpenAIAsyncClient client = DefaultKernelTest.mockCompletionOpenAIAsyncClient();
|
||||
Kernel kernel = DefaultKernelTest.buildKernel("model", client);
|
||||
@Test
|
||||
public void run() {
|
||||
OpenAIAsyncClient client = DefaultKernelTest.mockCompletionOpenAIAsyncClient();
|
||||
Kernel kernel = DefaultKernelTest.buildKernel("model", client);
|
||||
|
||||
// Load native skill
|
||||
ReadOnlyFunctionCollection functionCollection = kernel.importSkill(new StaticTextSkill(), "text");
|
||||
// Load native skill
|
||||
ReadOnlyFunctionCollection functionCollection =
|
||||
kernel.importSkill(new StaticTextSkill(), "text");
|
||||
|
||||
ContextVariables variables = SKBuilders.variables()
|
||||
.build("Today is: ")
|
||||
.writableClone()
|
||||
.setVariable("day", "Monday");
|
||||
ContextVariables variables =
|
||||
SKBuilders.variables()
|
||||
.build("Today is: ")
|
||||
.writableClone()
|
||||
.setVariable("day", "Monday");
|
||||
|
||||
Mono<SKContext<?>> result = kernel.runAsync(
|
||||
variables,
|
||||
functionCollection.getFunction("AppendDay"),
|
||||
functionCollection.getFunction("Uppercase"));
|
||||
Mono<SKContext<?>> result =
|
||||
kernel.runAsync(
|
||||
variables,
|
||||
functionCollection.getFunction("AppendDay"),
|
||||
functionCollection.getFunction("Uppercase"));
|
||||
|
||||
Assertions.assertEquals("TODAY IS: MONDAY", result.block().getResult());
|
||||
}
|
||||
Assertions.assertEquals("TODAY IS: MONDAY", result.block().getResult());
|
||||
}
|
||||
}
|
||||
|
||||
+44
-40
@@ -3,9 +3,6 @@ package com.microsoft.semantickernel.syntaxexamples;
|
||||
|
||||
import static com.microsoft.semantickernel.DefaultKernelTest.mockCompletionOpenAIAsyncClient;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.KernelConfig;
|
||||
@@ -15,49 +12,56 @@ import com.microsoft.semantickernel.extensions.KernelExtensions;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.syntaxexamples.skills.SearchEngineSkill;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.function.Tuples;
|
||||
|
||||
public class Example04CombineLLMPromptsAndNativeCodeTest {
|
||||
|
||||
@Test
|
||||
public void run() {
|
||||
OpenAIAsyncClient client = mockCompletionOpenAIAsyncClient(
|
||||
Tuples.of(
|
||||
"Gran Torre Santiago is the tallest building in South America",
|
||||
"A-SUMMARY"));
|
||||
|
||||
KernelConfig kernelConfig = SKBuilders.kernelConfig()
|
||||
.addTextCompletionService(
|
||||
"text-davinci-002",
|
||||
kernel -> new OpenAITextCompletion(client, "text-davinci-002"))
|
||||
.addTextCompletionService(
|
||||
"text-davinci-003",
|
||||
kernel -> new OpenAITextCompletion(client, "text-davinci-003"))
|
||||
.setDefaultTextCompletionService("text-davinci-003")
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
kernel.importSkill(new SearchEngineSkill(), null);
|
||||
kernel.importSkill(
|
||||
"SummarizeSkill",
|
||||
KernelExtensions.importSemanticSkillFromDirectory(
|
||||
"../../samples/skills", "SummarizeSkill"));
|
||||
|
||||
// Run
|
||||
String ask = "What's the tallest building in South America?";
|
||||
|
||||
Mono<SKContext<?>> result = kernel.runAsync(ask, kernel.getSkills().getFunction("Search", null));
|
||||
|
||||
Assertions.assertEquals(
|
||||
@Test
|
||||
public void run() {
|
||||
OpenAIAsyncClient client =
|
||||
mockCompletionOpenAIAsyncClient(
|
||||
Tuples.of(
|
||||
"Gran Torre Santiago is the tallest building in South America",
|
||||
result.block().getResult());
|
||||
"A-SUMMARY"));
|
||||
|
||||
result = kernel.runAsync(
|
||||
ask,
|
||||
kernel.getSkills().getFunction("Search", null),
|
||||
kernel.getSkill("SummarizeSkill").getFunction("Summarize", null));
|
||||
KernelConfig kernelConfig =
|
||||
SKBuilders.kernelConfig()
|
||||
.addTextCompletionService(
|
||||
"text-davinci-002",
|
||||
kernel -> new OpenAITextCompletion(client, "text-davinci-002"))
|
||||
.addTextCompletionService(
|
||||
"text-davinci-003",
|
||||
kernel -> new OpenAITextCompletion(client, "text-davinci-003"))
|
||||
.setDefaultTextCompletionService("text-davinci-003")
|
||||
.build();
|
||||
|
||||
Assertions.assertEquals("A-SUMMARY", result.block().getResult());
|
||||
}
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
kernel.importSkill(new SearchEngineSkill(), null);
|
||||
kernel.importSkill(
|
||||
"SummarizeSkill",
|
||||
KernelExtensions.importSemanticSkillFromDirectory(
|
||||
"../../samples/skills", "SummarizeSkill"));
|
||||
|
||||
// Run
|
||||
String ask = "What's the tallest building in South America?";
|
||||
|
||||
Mono<SKContext<?>> result =
|
||||
kernel.runAsync(ask, kernel.getSkills().getFunction("Search", null));
|
||||
|
||||
Assertions.assertEquals(
|
||||
"Gran Torre Santiago is the tallest building in South America",
|
||||
result.block().getResult());
|
||||
|
||||
result =
|
||||
kernel.runAsync(
|
||||
ask,
|
||||
kernel.getSkills().getFunction("Search", null),
|
||||
kernel.getSkill("SummarizeSkill").getFunction("Summarize", null));
|
||||
|
||||
Assertions.assertEquals("A-SUMMARY", result.block().getResult());
|
||||
}
|
||||
}
|
||||
|
||||
+38
-34
@@ -3,9 +3,6 @@ package com.microsoft.semantickernel.syntaxexamples;
|
||||
|
||||
import static com.microsoft.semantickernel.DefaultKernelTest.mockCompletionOpenAIAsyncClientMatchers;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentMatcher;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.KernelConfig;
|
||||
@@ -13,46 +10,53 @@ import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.extensions.KernelExtensions;
|
||||
import com.microsoft.semantickernel.planner.sequentialplanner.SequentialPlanner;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentMatcher;
|
||||
|
||||
import reactor.util.function.Tuples;
|
||||
|
||||
public class Example05UsingThePlannerTest {
|
||||
|
||||
public static SequentialPlanner getPlanner(Kernel kernel) {
|
||||
kernel.importSkill(
|
||||
"SummarizeSkill",
|
||||
KernelExtensions.importSemanticSkillFromDirectory(
|
||||
"../../samples/skills", "SummarizeSkill"));
|
||||
kernel.importSkill(
|
||||
"WriterSkill",
|
||||
KernelExtensions.importSemanticSkillFromDirectory(
|
||||
"../../samples/skills", "WriterSkill"));
|
||||
public static SequentialPlanner getPlanner(Kernel kernel) {
|
||||
kernel.importSkill(
|
||||
"SummarizeSkill",
|
||||
KernelExtensions.importSemanticSkillFromDirectory(
|
||||
"../../samples/skills", "SummarizeSkill"));
|
||||
kernel.importSkill(
|
||||
"WriterSkill",
|
||||
KernelExtensions.importSemanticSkillFromDirectory(
|
||||
"../../samples/skills", "WriterSkill"));
|
||||
|
||||
return new SequentialPlanner(kernel, null, null);
|
||||
}
|
||||
return new SequentialPlanner(kernel, null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void run() {
|
||||
ArgumentMatcher<String> matcher = prompt -> {
|
||||
return prompt.contains(
|
||||
"Create an XML plan step by step, to satisfy the goal given");
|
||||
@Test
|
||||
public void run() {
|
||||
ArgumentMatcher<String> matcher =
|
||||
prompt -> {
|
||||
return prompt.contains(
|
||||
"Create an XML plan step by step, to satisfy the goal given");
|
||||
};
|
||||
|
||||
OpenAIAsyncClient client = mockCompletionOpenAIAsyncClientMatchers(Tuples.of(matcher, "A-PLAN"));
|
||||
OpenAIAsyncClient client =
|
||||
mockCompletionOpenAIAsyncClientMatchers(Tuples.of(matcher, "A-PLAN"));
|
||||
|
||||
KernelConfig config = SKBuilders.kernelConfig()
|
||||
.addTextCompletionService(
|
||||
"davinci",
|
||||
kernel -> SKBuilders.textCompletionService()
|
||||
.build(client, "text-davinci-003"))
|
||||
.build();
|
||||
KernelConfig config =
|
||||
SKBuilders.kernelConfig()
|
||||
.addTextCompletionService(
|
||||
"davinci",
|
||||
kernel ->
|
||||
SKBuilders.textCompletionService()
|
||||
.build(client, "text-davinci-003"))
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(config).build();
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(config).build();
|
||||
|
||||
SequentialPlanner planner = getPlanner(kernel);
|
||||
System.out.println(
|
||||
planner.createPlanAsync(
|
||||
"Write a poem about John Doe, then translate it into Italian.")
|
||||
.block()
|
||||
.getResult());
|
||||
}
|
||||
SequentialPlanner planner = getPlanner(kernel);
|
||||
System.out.println(
|
||||
planner.createPlanAsync(
|
||||
"Write a poem about John Doe, then translate it into Italian.")
|
||||
.block()
|
||||
.getResult());
|
||||
}
|
||||
}
|
||||
|
||||
+57
-51
@@ -3,11 +3,6 @@ package com.microsoft.semantickernel.syntaxexamples;
|
||||
|
||||
import static com.microsoft.semantickernel.DefaultKernelTest.mockCompletionOpenAIAsyncClient;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.KernelConfig;
|
||||
@@ -19,66 +14,77 @@ import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
|
||||
import com.microsoft.semantickernel.templateengine.PromptTemplateEngine;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.function.Tuples;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class Example06TemplateLanguageTest {
|
||||
|
||||
@Test
|
||||
public void run() {
|
||||
OpenAIAsyncClient client = mockCompletionOpenAIAsyncClient(Tuples.of("Today is", "A-RESULT"));
|
||||
@Test
|
||||
public void run() {
|
||||
OpenAIAsyncClient client =
|
||||
mockCompletionOpenAIAsyncClient(Tuples.of("Today is", "A-RESULT"));
|
||||
|
||||
KernelConfig kernelConfig = SKBuilders.kernelConfig()
|
||||
.addTextCompletionService(
|
||||
"text-davinci-003",
|
||||
kernel -> SKBuilders.textCompletionService()
|
||||
.build(client, "text-davinci-003"))
|
||||
.addTextEmbeddingsGenerationService(
|
||||
"text-embedding-ada-002",
|
||||
kernel -> SKBuilders.textEmbeddingGenerationService()
|
||||
.build(client, "text-embedding-ada-002"))
|
||||
.build();
|
||||
KernelConfig kernelConfig =
|
||||
SKBuilders.kernelConfig()
|
||||
.addTextCompletionService(
|
||||
"text-davinci-003",
|
||||
kernel ->
|
||||
SKBuilders.textCompletionService()
|
||||
.build(client, "text-davinci-003"))
|
||||
.addTextEmbeddingsGenerationService(
|
||||
"text-embedding-ada-002",
|
||||
kernel ->
|
||||
SKBuilders.textEmbeddingGenerationService()
|
||||
.build(client, "text-embedding-ada-002"))
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
|
||||
// Load native skill into the kernel skill collection, sharing its functions
|
||||
// with prompt
|
||||
// templates
|
||||
// Functions loaded here are available as "time.*"
|
||||
kernel.importSkill(new TimeSkill(), "time");
|
||||
// Load native skill into the kernel skill collection, sharing its functions
|
||||
// with prompt
|
||||
// templates
|
||||
// Functions loaded here are available as "time.*"
|
||||
kernel.importSkill(new TimeSkill(), "time");
|
||||
|
||||
// Semantic Function invoking time.Date and time.Time native functions
|
||||
String functionDefinition = "\n"
|
||||
+ "Today is: {{time.Date}}\n"
|
||||
+ "Current time is: {{time.Time}}\n"
|
||||
+ "\n"
|
||||
+ "Answer to the following questions using JSON syntax, including the data"
|
||||
+ " used.\n"
|
||||
+ "Is it morning, afternoon, evening, or night"
|
||||
+ " (morning/afternoon/evening/night)?\n"
|
||||
+ "Is it weekend time (weekend/not weekend)?";
|
||||
// Semantic Function invoking time.Date and time.Time native functions
|
||||
String functionDefinition =
|
||||
"\n"
|
||||
+ "Today is: {{time.Date}}\n"
|
||||
+ "Current time is: {{time.Time}}\n"
|
||||
+ "\n"
|
||||
+ "Answer to the following questions using JSON syntax, including the data"
|
||||
+ " used.\n"
|
||||
+ "Is it morning, afternoon, evening, or night"
|
||||
+ " (morning/afternoon/evening/night)?\n"
|
||||
+ "Is it weekend time (weekend/not weekend)?";
|
||||
|
||||
PromptTemplate promptRenderer = SKBuilders.promptTemplate().build(functionDefinition, null);
|
||||
PromptTemplate promptRenderer = SKBuilders.promptTemplate().build(functionDefinition, null);
|
||||
|
||||
SKContext skContext = SKBuilders.context().build(kernel.getSkills());
|
||||
SKContext skContext = SKBuilders.context().build(kernel.getSkills());
|
||||
|
||||
PromptTemplateEngine promptTemplateEngine = SKBuilders.promptTemplateEngine().build();
|
||||
PromptTemplateEngine promptTemplateEngine = SKBuilders.promptTemplateEngine().build();
|
||||
|
||||
Mono<String> renderedPrompt = promptRenderer.renderAsync(skContext, promptTemplateEngine);
|
||||
Mono<String> renderedPrompt = promptRenderer.renderAsync(skContext, promptTemplateEngine);
|
||||
|
||||
// Check that it has been rendered
|
||||
Assertions.assertTrue(!renderedPrompt.block().contains("time.Date"));
|
||||
// Check that it has been rendered
|
||||
Assertions.assertTrue(!renderedPrompt.block().contains("time.Date"));
|
||||
|
||||
// Run the prompt / semantic function
|
||||
CompletionSKFunction kindOfDay = kernel.getSemanticFunctionBuilder()
|
||||
.createFunction(
|
||||
functionDefinition,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
new PromptTemplateConfig.CompletionConfig(
|
||||
0, 0, 0, 0, 256, new ArrayList<>()));
|
||||
// Run the prompt / semantic function
|
||||
CompletionSKFunction kindOfDay =
|
||||
kernel.getSemanticFunctionBuilder()
|
||||
.createFunction(
|
||||
functionDefinition,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
new PromptTemplateConfig.CompletionConfig(
|
||||
0, 0, 0, 0, 256, new ArrayList<>()));
|
||||
|
||||
Assertions.assertEquals("A-RESULT", kindOfDay.invokeAsync("").block().getResult());
|
||||
}
|
||||
Assertions.assertEquals("A-RESULT", kindOfDay.invokeAsync("").block().getResult());
|
||||
}
|
||||
}
|
||||
|
||||
+64
-61
@@ -3,12 +3,6 @@ package com.microsoft.semantickernel.syntaxexamples;
|
||||
|
||||
import static com.microsoft.semantickernel.DefaultKernelTest.mockCompletionOpenAIAsyncClient;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.azure.ai.openai.models.ChatChoice;
|
||||
import com.azure.ai.openai.models.ChatCompletions;
|
||||
@@ -20,80 +14,89 @@ import com.microsoft.semantickernel.chatcompletion.ChatCompletion;
|
||||
import com.microsoft.semantickernel.chatcompletion.ChatHistory;
|
||||
import com.microsoft.semantickernel.connectors.ai.openai.chatcompletion.OpenAIChatHistory;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.function.Tuples;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class Example17ChatGPTTest {
|
||||
|
||||
@Test
|
||||
public void azureOpenAIChatSampleAsync() {
|
||||
@Test
|
||||
public void azureOpenAIChatSampleAsync() {
|
||||
|
||||
OpenAIAsyncClient client = mockCompletionOpenAIAsyncClient(Tuples.of("Today is", "A-RESULT"));
|
||||
OpenAIAsyncClient client =
|
||||
mockCompletionOpenAIAsyncClient(Tuples.of("Today is", "A-RESULT"));
|
||||
|
||||
String message = "Hi, I'm looking for book suggestions";
|
||||
String secondMessage = "I love history and philosophy, I'd like to learn something new about Greece, any"
|
||||
+ " suggestion?";
|
||||
String message = "Hi, I'm looking for book suggestions";
|
||||
String secondMessage =
|
||||
"I love history and philosophy, I'd like to learn something new about Greece, any"
|
||||
+ " suggestion?";
|
||||
|
||||
mockResponse(client, message, "1st response");
|
||||
mockResponse(client, secondMessage, "2nd response");
|
||||
mockResponse(client, message, "1st response");
|
||||
mockResponse(client, secondMessage, "2nd response");
|
||||
|
||||
KernelConfig kernelConfig = SKBuilders.kernelConfig()
|
||||
.addChatCompletionService(
|
||||
"gpt-3.5-turbo-0301",
|
||||
kernel -> SKBuilders.chatCompletion()
|
||||
.build(client, "gpt-3.5-turbo-0301"))
|
||||
.build();
|
||||
KernelConfig kernelConfig =
|
||||
SKBuilders.kernelConfig()
|
||||
.addChatCompletionService(
|
||||
"gpt-3.5-turbo-0301",
|
||||
kernel ->
|
||||
SKBuilders.chatCompletion()
|
||||
.build(client, "gpt-3.5-turbo-0301"))
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
|
||||
ChatCompletion<OpenAIChatHistory> chatGPT = kernel.getService(null, ChatCompletion.class);
|
||||
ChatCompletion<OpenAIChatHistory> chatGPT = kernel.getService(null, ChatCompletion.class);
|
||||
|
||||
OpenAIChatHistory chatHistory = chatGPT.createNewChat("You are a librarian, expert about books");
|
||||
OpenAIChatHistory chatHistory =
|
||||
chatGPT.createNewChat("You are a librarian, expert about books");
|
||||
|
||||
// First user message
|
||||
chatHistory.addUserMessage(message);
|
||||
ChatHistory.Message createdMessage = chatHistory.getMessages()
|
||||
.get(chatHistory.getMessages().size() - 1);
|
||||
Assertions.assertEquals(ChatHistory.AuthorRoles.User, createdMessage.getAuthorRoles());
|
||||
Assertions.assertEquals(message, createdMessage.getContent());
|
||||
// First user message
|
||||
chatHistory.addUserMessage(message);
|
||||
ChatHistory.Message createdMessage =
|
||||
chatHistory.getMessages().get(chatHistory.getMessages().size() - 1);
|
||||
Assertions.assertEquals(ChatHistory.AuthorRoles.User, createdMessage.getAuthorRoles());
|
||||
Assertions.assertEquals(message, createdMessage.getContent());
|
||||
|
||||
// First bot assistant message
|
||||
String reply = chatGPT.generateMessageAsync(chatHistory, null).block();
|
||||
Assertions.assertEquals("1st response", reply);
|
||||
chatHistory.addAssistantMessage(reply);
|
||||
// First bot assistant message
|
||||
String reply = chatGPT.generateMessageAsync(chatHistory, null).block();
|
||||
Assertions.assertEquals("1st response", reply);
|
||||
chatHistory.addAssistantMessage(reply);
|
||||
|
||||
// Second user message
|
||||
chatHistory.addUserMessage(secondMessage);
|
||||
// Second user message
|
||||
chatHistory.addUserMessage(secondMessage);
|
||||
|
||||
// Second bot assistant message
|
||||
reply = chatGPT.generateMessageAsync(chatHistory, null).block();
|
||||
Assertions.assertEquals("2nd response", reply);
|
||||
}
|
||||
// Second bot assistant message
|
||||
reply = chatGPT.generateMessageAsync(chatHistory, null).block();
|
||||
Assertions.assertEquals("2nd response", reply);
|
||||
}
|
||||
|
||||
public static void mockResponse(OpenAIAsyncClient client, String message, String response) {
|
||||
ChatMessage chatMessage = Mockito.mock(ChatMessage.class);
|
||||
ChatChoice chatChoice = Mockito.mock(ChatChoice.class);
|
||||
ChatCompletions completion = Mockito.mock(ChatCompletions.class);
|
||||
public static void mockResponse(OpenAIAsyncClient client, String message, String response) {
|
||||
ChatMessage chatMessage = Mockito.mock(ChatMessage.class);
|
||||
ChatChoice chatChoice = Mockito.mock(ChatChoice.class);
|
||||
ChatCompletions completion = Mockito.mock(ChatCompletions.class);
|
||||
|
||||
Mockito.when(completion.getChoices()).thenReturn(Arrays.asList(chatChoice));
|
||||
Mockito.when(completion.getChoices()).thenReturn(Arrays.asList(chatChoice));
|
||||
|
||||
Mockito.when(chatChoice.getMessage()).thenReturn(chatMessage);
|
||||
Mockito.when(chatChoice.getMessage()).thenReturn(chatMessage);
|
||||
|
||||
Mockito.when(chatMessage.getContent()).thenReturn(response);
|
||||
Mockito.when(chatMessage.getContent()).thenReturn(response);
|
||||
|
||||
Mockito.when(
|
||||
client.getChatCompletions(
|
||||
Mockito.any(),
|
||||
Mockito.argThat(
|
||||
msg -> {
|
||||
return msg != null
|
||||
&& msg.getMessages()
|
||||
.get(msg.getMessages()
|
||||
.size()
|
||||
- 1)
|
||||
.getContent()
|
||||
.equals(message);
|
||||
})))
|
||||
.thenReturn(Mono.just(completion));
|
||||
}
|
||||
Mockito.when(
|
||||
client.getChatCompletions(
|
||||
Mockito.any(),
|
||||
Mockito.argThat(
|
||||
msg -> {
|
||||
return msg != null
|
||||
&& msg.getMessages()
|
||||
.get(msg.getMessages().size() - 1)
|
||||
.getContent()
|
||||
.equals(message);
|
||||
})))
|
||||
.thenReturn(Mono.just(completion));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user