mirror of
https://github.com/microsoft/semantic-kernel.git
synced 2026-10-12 02:19:06 +00:00
Java: Add documentation examples (#5595)
### Motivation and Context Fixes https://github.com/microsoft/semantic-kernel/issues/5205 Fixes https://github.com/microsoft/semantic-kernel/issues/5209 Fixes https://github.com/microsoft/semantic-kernel/issues/5212 Fixes https://github.com/microsoft/semantic-kernel/issues/5213 Fixes https://github.com/microsoft/semantic-kernel/issues/5203 <!-- Thank you for your contribution to the semantic-kernel repo! Please help reviewers and future users, providing the following information: 1. Why is this change required? 2. What problem does it solve? 3. What scenario does it contribute to? 4. If it fixes an open issue, please link to the issue here. --> ### Description <!-- Describe your changes, the overall approach, the underlying design. These notes will help understanding how your code works. Thanks! --> ### Contribution Checklist <!-- Before submitting this PR, please make sure: --> - [ ] The code builds clean without any errors or warnings - [ ] The PR follows the [SK Contribution Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts) raises no violations - [ ] All unit tests pass, and I have added new tests where possible - [ ] I didn't break anyone 😄 --------- Co-authored-by: John Oliver <[email protected]>
This commit is contained in:
co-authored by
John Oliver
parent
9b181aba9a
commit
fa94b269e1
+46
-43
@@ -1,4 +1,3 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.documentationexamples;
|
||||
|
||||
import java.util.Scanner;
|
||||
@@ -9,6 +8,9 @@ import com.azure.core.credential.AzureKeyCredential;
|
||||
import com.azure.core.credential.KeyCredential;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion;
|
||||
import com.microsoft.semantickernel.contextvariables.ContextVariableType;
|
||||
import com.microsoft.semantickernel.contextvariables.ContextVariableTypes;
|
||||
import com.microsoft.semantickernel.orchestration.InvocationContext;
|
||||
import com.microsoft.semantickernel.orchestration.ToolCallBehavior;
|
||||
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
|
||||
import com.microsoft.semantickernel.samples.plugins.MathPlugin;
|
||||
@@ -23,8 +25,7 @@ public class CreatingFunctions {
|
||||
|
||||
// Only required if AZURE_CLIENT_KEY is set
|
||||
private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT");
|
||||
private static final String MODEL_ID = System.getenv().getOrDefault("MODEL_ID",
|
||||
"gpt-35-turbo-2");
|
||||
private static final String MODEL_ID = System.getenv().getOrDefault("MODEL_ID", "gpt-35-turbo-2");
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("======== Prompts ========");
|
||||
@@ -32,42 +33,45 @@ public class CreatingFunctions {
|
||||
|
||||
if (AZURE_CLIENT_KEY != null) {
|
||||
client = new OpenAIClientBuilder()
|
||||
.credential(new AzureKeyCredential(AZURE_CLIENT_KEY))
|
||||
.endpoint(CLIENT_ENDPOINT)
|
||||
.buildAsyncClient();
|
||||
.credential(new AzureKeyCredential(AZURE_CLIENT_KEY))
|
||||
.endpoint(CLIENT_ENDPOINT)
|
||||
.buildAsyncClient();
|
||||
} else {
|
||||
client = new OpenAIClientBuilder()
|
||||
.credential(new KeyCredential(CLIENT_KEY))
|
||||
.buildAsyncClient();
|
||||
.credential(new KeyCredential(CLIENT_KEY))
|
||||
.buildAsyncClient();
|
||||
}
|
||||
|
||||
// <RunNativeFunction>
|
||||
Kernel kernel = Kernel.builder()
|
||||
.withAIService(ChatCompletionService.class, ChatCompletionService.builder()
|
||||
.withModelId(MODEL_ID)
|
||||
.withOpenAIAsyncClient(client)
|
||||
.build())
|
||||
.withPlugin(KernelPluginFactory.createFromObject(new MathPlugin(), "MathPlugin"))
|
||||
.build();
|
||||
.withAIService(ChatCompletionService.class, ChatCompletionService.builder()
|
||||
.withModelId(MODEL_ID)
|
||||
.withOpenAIAsyncClient(client)
|
||||
.build())
|
||||
.withPlugin(KernelPluginFactory.createFromObject(new MathPlugin(), "MathPlugin"))
|
||||
.build();
|
||||
|
||||
// Test the math plugin
|
||||
var answer = kernel
|
||||
.invokeAsync(kernel.getFunction("MathPlugin", "sqrt"))
|
||||
.withArguments(KernelFunctionArguments
|
||||
.builder()
|
||||
.withVariable("number1", 12.0)
|
||||
.build())
|
||||
.block();
|
||||
.invokeAsync(kernel.getFunction("MathPlugin", "sqrt"))
|
||||
.withArguments(KernelFunctionArguments
|
||||
.builder()
|
||||
.withVariable("number1", 12.0)
|
||||
.build())
|
||||
.block();
|
||||
System.out.println("The square root of 12 is " + answer.getResult() + ".");
|
||||
// </RunNativeFunction>
|
||||
|
||||
// Create chat history
|
||||
ChatCompletionService chat = OpenAIChatCompletion.builder()
|
||||
.withModelId(MODEL_ID)
|
||||
.withOpenAIAsyncClient(client)
|
||||
.build();
|
||||
.withModelId(MODEL_ID)
|
||||
.withOpenAIAsyncClient(client)
|
||||
.build();
|
||||
|
||||
System.out.println("Chat content:");
|
||||
System.out.println("------------------------");
|
||||
|
||||
// <Conversation>
|
||||
ChatHistory history = new ChatHistory();
|
||||
|
||||
// Start the conversation
|
||||
@@ -77,26 +81,25 @@ public class CreatingFunctions {
|
||||
while (!(userInput = scanner.nextLine()).isEmpty()) {
|
||||
history.addUserMessage(userInput);
|
||||
|
||||
reply(chat, history);
|
||||
messageOutput(history);
|
||||
// Enable auto function calling
|
||||
var invocationContext = InvocationContext.builder()
|
||||
.withToolCallBehavior(
|
||||
ToolCallBehavior.allowAllKernelFunctions(true))
|
||||
.build();
|
||||
|
||||
// Get the response from the AI
|
||||
var reply = chat.getChatMessageContentsAsync(history, kernel, invocationContext)
|
||||
.block();
|
||||
|
||||
String message = reply.get(reply.size() - 1).getContent();
|
||||
System.out.println("Assistant" + " > " + message);
|
||||
|
||||
// Add the message from the agent to the chat history
|
||||
history.addAssistantMessage(message.toString());
|
||||
|
||||
// Get user input again
|
||||
System.out.print("User > ");
|
||||
}
|
||||
}
|
||||
|
||||
private static void reply(ChatCompletionService chatGPT, ChatHistory chatHistory) {
|
||||
// Enable auto function calling
|
||||
var toolCallBehavior = ToolCallBehavior.allowAllKernelFunctions(true);
|
||||
|
||||
var reply = chatGPT.getChatMessageContentsAsync(chatHistory, null, null)
|
||||
.block();
|
||||
|
||||
StringBuilder message = new StringBuilder();
|
||||
reply.forEach(chatMessageContent -> message.append(chatMessageContent.getContent()));
|
||||
chatHistory.addAssistantMessage(message.toString());
|
||||
}
|
||||
|
||||
private static void messageOutput(ChatHistory chatHistory) {
|
||||
var message = chatHistory.getLastMessage().get();
|
||||
System.out.println(message.getAuthorRole() + ": " + message.getContent());
|
||||
System.out.println("------------------------");
|
||||
// </Conversation>
|
||||
}
|
||||
}
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.documentationexamples;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.azure.ai.openai.OpenAIClientBuilder;
|
||||
import com.azure.core.credential.AzureKeyCredential;
|
||||
import com.azure.core.credential.KeyCredential;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.orchestration.InvocationContext;
|
||||
import com.microsoft.semantickernel.orchestration.ToolCallBehavior;
|
||||
import com.microsoft.semantickernel.plugin.KernelPlugin;
|
||||
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
|
||||
import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatHistory;
|
||||
import java.io.InputStream;
|
||||
import java.util.Scanner;
|
||||
|
||||
public class Plugin {
|
||||
// CLIENT_KEY is for an OpenAI client
|
||||
private static final String CLIENT_KEY = System.getenv("CLIENT_KEY");
|
||||
private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY");
|
||||
|
||||
// Only required if AZURE_CLIENT_KEY is set
|
||||
private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT");
|
||||
private static final String MODEL_ID = System.getenv().getOrDefault("MODEL_ID", "gpt-35-turbo-2");
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("======== Plugin ========");
|
||||
|
||||
OpenAIAsyncClient client;
|
||||
|
||||
if (AZURE_CLIENT_KEY != null && CLIENT_ENDPOINT != null) {
|
||||
// <build_client>
|
||||
client = new OpenAIClientBuilder()
|
||||
.credential(new AzureKeyCredential(AZURE_CLIENT_KEY))
|
||||
.endpoint(CLIENT_ENDPOINT)
|
||||
.buildAsyncClient();
|
||||
// </build_client>
|
||||
} else if (CLIENT_KEY != null) {
|
||||
client = new OpenAIClientBuilder()
|
||||
.credential(new KeyCredential(CLIENT_KEY))
|
||||
.buildAsyncClient();
|
||||
} else {
|
||||
System.out.println("No client key found");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// <KernelCreation>
|
||||
ChatCompletionService chatCompletionService = ChatCompletionService.builder()
|
||||
.withModelId(MODEL_ID)
|
||||
.withOpenAIAsyncClient(client)
|
||||
.build();
|
||||
|
||||
KernelPlugin plugin = KernelPluginFactory.createFromObject(
|
||||
new LightPlugin(), "LightPlugin");
|
||||
|
||||
Kernel kernel = Kernel.builder()
|
||||
.withAIService(ChatCompletionService.class, chatCompletionService)
|
||||
.withPlugin(plugin)
|
||||
.build();
|
||||
// </KernelCreation>
|
||||
|
||||
// <Chat>
|
||||
// Create chat history
|
||||
var history = new ChatHistory();
|
||||
|
||||
// Start the conversation
|
||||
System.out.print("User > ");
|
||||
Scanner scanner = new Scanner(System.in);
|
||||
String userInput;
|
||||
while (!(userInput = scanner.nextLine()).isEmpty()) {
|
||||
// Add user input to history
|
||||
history.addUserMessage(userInput);
|
||||
|
||||
// Enable auto function calling
|
||||
var invocationContext = InvocationContext.builder()
|
||||
.withToolCallBehavior(
|
||||
ToolCallBehavior.allowAllKernelFunctions(true))
|
||||
.build();
|
||||
|
||||
// Get the response from the AI
|
||||
var result = chatCompletionService
|
||||
.getChatMessageContentsAsync(
|
||||
history,
|
||||
kernel,
|
||||
invocationContext)
|
||||
.block();
|
||||
|
||||
String message = result.get(result.size() - 1).getContent();
|
||||
System.out.printf("Assistant > %s%n", message);
|
||||
|
||||
// Add the message from the agent to the chat history
|
||||
history.addAssistantMessage(message);
|
||||
}
|
||||
// </Chat>
|
||||
}
|
||||
|
||||
// <LightPlugin>
|
||||
public static class LightPlugin {
|
||||
|
||||
public boolean isOn = false;
|
||||
|
||||
@DefineKernelFunction(name = "getState", description = "Gets the state of the light.'")
|
||||
String getState() {
|
||||
return isOn ? "on" : "off";
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "changeState", description = "Changes the state of the light.'")
|
||||
public String changeState(
|
||||
@KernelFunctionParameter(name = "newState",
|
||||
description = "The new state of the light, boolean true==on, false==off.",
|
||||
type = boolean.class) boolean newState) {
|
||||
|
||||
this.isOn = newState;
|
||||
String state = getState();
|
||||
|
||||
// Print the state to the console
|
||||
System.out.printf("[Light is now %s]%n", state);
|
||||
return state;
|
||||
}
|
||||
}
|
||||
// </LightPlugin>
|
||||
}
|
||||
+40
-40
@@ -1,4 +1,3 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.documentationexamples;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
@@ -14,8 +13,7 @@ public class Prompts {
|
||||
|
||||
// Only required if AZURE_CLIENT_KEY is set
|
||||
private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT");
|
||||
private static final String MODEL_ID = System.getenv().getOrDefault("MODEL_ID",
|
||||
"gpt-3.5-turbo");
|
||||
private static final String MODEL_ID = System.getenv().getOrDefault("MODEL_ID", "gpt-35-turbo-2");
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("======== Prompts ========");
|
||||
@@ -23,45 +21,40 @@ public class Prompts {
|
||||
|
||||
if (AZURE_CLIENT_KEY != null) {
|
||||
client = new OpenAIClientBuilder()
|
||||
.credential(new AzureKeyCredential(AZURE_CLIENT_KEY))
|
||||
.endpoint(CLIENT_ENDPOINT)
|
||||
.buildAsyncClient();
|
||||
.credential(new AzureKeyCredential(AZURE_CLIENT_KEY))
|
||||
.endpoint(CLIENT_ENDPOINT)
|
||||
.buildAsyncClient();
|
||||
} else {
|
||||
client = new OpenAIClientBuilder()
|
||||
.credential(new KeyCredential(CLIENT_KEY))
|
||||
.buildAsyncClient();
|
||||
.credential(new KeyCredential(CLIENT_KEY))
|
||||
.buildAsyncClient();
|
||||
}
|
||||
|
||||
// <KernelCreation>
|
||||
Kernel kernel = Kernel.builder()
|
||||
.withAIService(ChatCompletionService.class, ChatCompletionService.builder()
|
||||
.withModelId(MODEL_ID)
|
||||
.withOpenAIAsyncClient(client)
|
||||
.build())
|
||||
.build();
|
||||
.withAIService(ChatCompletionService.class, ChatCompletionService.builder()
|
||||
.withModelId(MODEL_ID)
|
||||
.withOpenAIAsyncClient(client)
|
||||
.build())
|
||||
.build();
|
||||
// </KernelCreation>
|
||||
|
||||
// 0.0 Initial prompt
|
||||
String request = "I want to send an email to the marketing team celebrating their recent milestone.";
|
||||
String prompt = """
|
||||
What is the intent of this request? %s
|
||||
""".formatted(request);
|
||||
String prompt = "What is the intent of this request? %s".formatted(request);
|
||||
|
||||
/*
|
||||
* Uncomment this block to make this example interactive
|
||||
* // <InitialPrompt>
|
||||
* System.out.println("Your request: ");
|
||||
* String request = new Scanner(System.in).nextLine();
|
||||
* String prompt = """
|
||||
* What is the intent of this request? %s
|
||||
* You can choose between SendEmail, SendMessage, CompleteTask, CreateDocument.
|
||||
* """.formatted(request);
|
||||
* // </InitialPrompt>
|
||||
/* Uncomment this block to make this example interactive
|
||||
// <InitialPrompt>
|
||||
System.out.println("Your request: ");
|
||||
String request = new Scanner(System.in).nextLine();
|
||||
String prompt = "What is the intent of this request? %s".formatted(request);
|
||||
// </InitialPrompt>
|
||||
*/
|
||||
|
||||
System.out.println("0.0 Initial prompt");
|
||||
// <InvokeInitialPrompt>
|
||||
System.out.println(kernel.invokePromptAsync(prompt).block().getResult());
|
||||
var result = kernel.invokePromptAsync(prompt).block().getResult();
|
||||
System.out.println(result);
|
||||
// </InvokeInitialPrompt>
|
||||
|
||||
// 1.0 Make the prompt more specific
|
||||
@@ -73,7 +66,8 @@ public class Prompts {
|
||||
""".formatted(request);
|
||||
// </MoreSpecificPrompt>
|
||||
System.out.println("1.0 Make the prompt more specific");
|
||||
System.out.println(kernel.invokePromptAsync(prompt).block().getResult());
|
||||
result = kernel.invokePromptAsync(prompt).block().getResult();
|
||||
System.out.println(result);
|
||||
|
||||
// 2.0 Add structure to the output with formatting
|
||||
/////////////////////////////////////////////////////////////////
|
||||
@@ -86,7 +80,8 @@ public class Prompts {
|
||||
""".formatted(request);
|
||||
// </StructuredPrompt>
|
||||
System.out.println("2.0 Add structure to the output with formatting");
|
||||
System.out.println(kernel.invokePromptAsync(prompt).block().getResult());
|
||||
result = kernel.invokePromptAsync(prompt).block().getResult();
|
||||
System.out.println(result);
|
||||
|
||||
// 2.1 Add structure to the output with formatting (using Markdown and JSON)
|
||||
/////////////////////////////////////////////////////////////////
|
||||
@@ -120,9 +115,9 @@ public class Prompts {
|
||||
## Intent
|
||||
""".formatted(request);
|
||||
// </FormattedPrompt>
|
||||
System.out
|
||||
.println("2.1 Add structure to the output with formatting (using Markdown and JSON)");
|
||||
System.out.println(kernel.invokePromptAsync(prompt).block().getResult());
|
||||
System.out.println("2.1 Add structure to the output with formatting (using Markdown and JSON)");
|
||||
result = kernel.invokePromptAsync(prompt).block().getResult();
|
||||
System.out.println(result);
|
||||
|
||||
// 3.0 Provide examples with few-shot prompting
|
||||
/////////////////////////////////////////////////////////////////
|
||||
@@ -142,7 +137,8 @@ public class Prompts {
|
||||
""".formatted(request);
|
||||
// </FewShotPrompt>
|
||||
System.out.println("3.0 Provide examples with few-shot prompting");
|
||||
System.out.println(kernel.invokePromptAsync(prompt).block().getResult());
|
||||
result = kernel.invokePromptAsync(prompt).block().getResult();
|
||||
System.out.println(result);
|
||||
|
||||
// 4.0 Tell the AI what to do to avoid doing something wrong
|
||||
/////////////////////////////////////////////////////////////////
|
||||
@@ -163,12 +159,13 @@ public class Prompts {
|
||||
""".formatted(request);
|
||||
// </AvoidPrompt>
|
||||
System.out.println("4.0 Tell the AI what to do to avoid doing something wrong");
|
||||
System.out.println(kernel.invokePromptAsync(prompt).block().getResult());
|
||||
result = kernel.invokePromptAsync(prompt).block().getResult();
|
||||
System.out.println(result);
|
||||
|
||||
// 5.0 Provide context to the AI
|
||||
/////////////////////////////////////////////////////////////////
|
||||
String history = "User input: I hate sending emails, no one ever reads them.\nAI response: I'm sorry to hear that. Messages may be a better way to communicate.";
|
||||
// <ContextPrompt>
|
||||
String history = "User input: I hate sending emails, no one ever reads them.\nAI response: I'm sorry to hear that. Messages may be a better way to communicate.";
|
||||
prompt = """
|
||||
Instructions: What is the intent of this request?
|
||||
If you don't know the intent, don't guess; instead respond with "Unknown".
|
||||
@@ -186,12 +183,13 @@ public class Prompts {
|
||||
""".formatted(history, request);
|
||||
// </ContextPrompt>
|
||||
System.out.println("5.0 Provide context to the AI");
|
||||
System.out.println(kernel.invokePromptAsync(prompt).block().getResult());
|
||||
result = kernel.invokePromptAsync(prompt).block().getResult();
|
||||
System.out.println(result);
|
||||
|
||||
// 6.0 Using message roles in chat completion prompts
|
||||
/////////////////////////////////////////////////////////////////
|
||||
history = "<message role=\"user\">I hate sending emails, no one ever reads them.</message>\n<message role=\"assistant\">I'm sorry to hear that. Messages may be a better way to communicate.</message>";
|
||||
// <RolePrompt>
|
||||
history = "<message role=\"user\">I hate sending emails, no one ever reads them.</message>\n<message role=\"assistant\">I'm sorry to hear that. Messages may be a better way to communicate.</message>";
|
||||
prompt = """
|
||||
<message role="system">Instructions: What is the intent of this request?
|
||||
If you don't know the intent, don't guess; instead respond with "Unknown".
|
||||
@@ -211,11 +209,12 @@ public class Prompts {
|
||||
""".formatted(history, request);
|
||||
// </RolePrompt>
|
||||
System.out.println("6.0 Using message roles in chat completion prompts");
|
||||
System.out.println(kernel.invokePromptAsync(prompt).block().getResult());
|
||||
result = kernel.invokePromptAsync(prompt).block().getResult();
|
||||
System.out.println(result);
|
||||
|
||||
// 7.0 Give your AI words of encouragement
|
||||
history = "<message role=\"user\">I hate sending emails, no one ever reads them.</message>\n<message role=\"assistant\">I'm sorry to hear that. Messages may be a better way to communicate.</message>";
|
||||
// <BonusPrompt>
|
||||
history = "<message role=\"user\">I hate sending emails, no one ever reads them.</message>\n<message role=\"assistant\">I'm sorry to hear that. Messages may be a better way to communicate.</message>";
|
||||
prompt = """
|
||||
<message role="system">Instructions: What is the intent of this request?
|
||||
If you don't know the intent, don't guess; instead respond with "Unknown".
|
||||
@@ -236,6 +235,7 @@ public class Prompts {
|
||||
""".formatted(history, request);
|
||||
// </BonusPrompt>
|
||||
System.out.println("7.0 Give your AI words of encouragement");
|
||||
System.out.println(kernel.invokePromptAsync(prompt).block().getResult());
|
||||
result = kernel.invokePromptAsync(prompt).block().getResult();
|
||||
System.out.println(result);
|
||||
}
|
||||
}
|
||||
+77
-27
@@ -1,4 +1,3 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.documentationexamples;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
@@ -6,8 +5,22 @@ import com.azure.ai.openai.OpenAIClientBuilder;
|
||||
import com.azure.core.credential.AzureKeyCredential;
|
||||
import com.azure.core.credential.KeyCredential;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.orchestration.InvocationContext;
|
||||
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
|
||||
import com.microsoft.semantickernel.samples.plugins.ConversationSummaryPlugin;
|
||||
import com.microsoft.semantickernel.semanticfunctions.HandlebarsPromptTemplateFactory;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionYaml;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.AuthorRole;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatHistory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
@@ -18,45 +31,63 @@ public class SerializingPrompts {
|
||||
|
||||
// Only required if AZURE_CLIENT_KEY is set
|
||||
private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT");
|
||||
private static final String MODEL_ID = System.getenv().getOrDefault("MODEL_ID",
|
||||
"gpt-35-turbo-2");
|
||||
private static final String MODEL_ID = System.getenv().getOrDefault("MODEL_ID", "gpt-35-turbo-2");
|
||||
|
||||
public static void main(String[] args) {
|
||||
private static final String PLUGINS_DIR = "java/samples/sample-code/src/main/resources/Plugins";
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
System.out.println("======== Serializing Prompts ========");
|
||||
OpenAIAsyncClient client;
|
||||
|
||||
if (AZURE_CLIENT_KEY != null) {
|
||||
client = new OpenAIClientBuilder()
|
||||
.credential(new AzureKeyCredential(AZURE_CLIENT_KEY))
|
||||
.endpoint(CLIENT_ENDPOINT)
|
||||
.buildAsyncClient();
|
||||
.credential(new AzureKeyCredential(AZURE_CLIENT_KEY))
|
||||
.endpoint(CLIENT_ENDPOINT)
|
||||
.buildAsyncClient();
|
||||
} else {
|
||||
client = new OpenAIClientBuilder()
|
||||
.credential(new KeyCredential(CLIENT_KEY))
|
||||
.buildAsyncClient();
|
||||
.credential(new KeyCredential(CLIENT_KEY))
|
||||
.buildAsyncClient();
|
||||
}
|
||||
|
||||
// Create few-shot examples
|
||||
ChatHistory continueConversation = new ChatHistory(false);
|
||||
continueConversation.addMessage(AuthorRole.USER, "Can you send a very quick approval to the marketing team?");
|
||||
continueConversation.addMessage(AuthorRole.SYSTEM, "Intent:");
|
||||
continueConversation.addMessage(AuthorRole.ASSISTANT, "ContinueConversation");
|
||||
ChatHistory endConversation = new ChatHistory(false);
|
||||
endConversation.addMessage(AuthorRole.USER, "Can you send the full update to the marketing team?");
|
||||
endConversation.addMessage(AuthorRole.SYSTEM, "Intent:");
|
||||
endConversation.addMessage(AuthorRole.ASSISTANT, "EndConversation");
|
||||
|
||||
List<ChatHistory> fewShotExamples = List.of(continueConversation, endConversation);
|
||||
|
||||
// <InvokeSerializedPrompts>
|
||||
// Create Kernel
|
||||
Kernel kernel = Kernel.builder()
|
||||
.withAIService(ChatCompletionService.class, ChatCompletionService.builder()
|
||||
.withModelId(MODEL_ID)
|
||||
.withOpenAIAsyncClient(client)
|
||||
.build())
|
||||
.build();
|
||||
.withAIService(ChatCompletionService.class, ChatCompletionService.builder()
|
||||
.withModelId(MODEL_ID)
|
||||
.withOpenAIAsyncClient(client)
|
||||
.build())
|
||||
.withPlugin(KernelPluginFactory.createFromObject(new ConversationSummaryPlugin(), "ConversationSummaryPlugin"))
|
||||
.build();
|
||||
|
||||
// Load prompts
|
||||
// This part is omitted as it requires a specific implementation to load prompts from a directory
|
||||
var prompts = KernelPluginFactory.importPluginFromDirectory(
|
||||
Path.of(PLUGINS_DIR), "Prompts", null);
|
||||
|
||||
// Load prompt from YAML
|
||||
// This part is omitted as it requires a specific implementation to load prompts from a YAML file
|
||||
// <LoadPromptFromYAML>
|
||||
var getIntent = KernelFunctionYaml.fromPromptYaml(
|
||||
Files.readString(Path.of(PLUGINS_DIR, "Prompts", "getIntent.prompt.yaml")),
|
||||
new HandlebarsPromptTemplateFactory());
|
||||
// </LoadPromptFromYAML>
|
||||
|
||||
// Create choices
|
||||
List<String> choices = Arrays.asList("ContinueConversation", "EndConversation");
|
||||
|
||||
// Create few-shot examples
|
||||
// This part is omitted as it requires a specific implementation to create few-shot examples
|
||||
|
||||
// Create chat history
|
||||
// This part is omitted as it requires a specific implementation to create chat history
|
||||
ChatHistory history = new ChatHistory();
|
||||
|
||||
// Start the chat loop
|
||||
Scanner scanner = new Scanner(System.in);
|
||||
@@ -64,22 +95,41 @@ public class SerializingPrompts {
|
||||
String userInput;
|
||||
while (!(userInput = scanner.nextLine()).isEmpty()) {
|
||||
// Invoke handlebars prompt
|
||||
// This part is omitted as it requires a specific implementation to invoke a prompt
|
||||
|
||||
// <InvokePromptFromYaml>
|
||||
var intent = kernel.invokeAsync(getIntent)
|
||||
.withArguments(KernelFunctionArguments.builder()
|
||||
.withVariable("request", userInput)
|
||||
.withVariable("choices", choices)
|
||||
.withVariable("history", history)
|
||||
.withVariable("fewShotExamples", fewShotExamples)
|
||||
.build())
|
||||
.block();
|
||||
// </InvokePromptFromYaml>
|
||||
|
||||
// End the chat if the intent is "Stop"
|
||||
// This part is omitted as it requires a specific implementation to handle the intent
|
||||
if (intent.getResult().equals("EndConversation")) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Get chat response
|
||||
// This part is omitted as it requires a specific implementation to get the chat response
|
||||
var reply = kernel.invokeAsync(prompts.get("Chat"))
|
||||
.withArguments(KernelFunctionArguments.builder()
|
||||
.withVariable("request", userInput)
|
||||
.withVariable("history",
|
||||
String.join("\n", history.getMessages().stream().map(m -> m.getAuthorRole() + " > " + m.getContent()).toList()))
|
||||
.build())
|
||||
.withResultType(String.class)
|
||||
.block().getResult();
|
||||
|
||||
// Stream the response
|
||||
// This part is omitted as it requires a specific implementation to stream the response
|
||||
System.out.println("Assistant" + " > " + reply);
|
||||
|
||||
// Append to history
|
||||
// This part is omitted as it requires a specific implementation to append to the history
|
||||
history.addUserMessage(userInput);
|
||||
history.addAssistantMessage(reply);
|
||||
|
||||
// Get user input again
|
||||
System.out.print("User > ");
|
||||
}
|
||||
// </InvokeSerializedPrompts>
|
||||
}
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.documentationexamples;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.azure.ai.openai.OpenAIClientBuilder;
|
||||
import com.azure.core.credential.AzureKeyCredential;
|
||||
import com.azure.core.credential.KeyCredential;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.plugin.KernelPlugin;
|
||||
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
|
||||
import com.microsoft.semantickernel.samples.plugins.MathPlugin;
|
||||
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
|
||||
import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;
|
||||
|
||||
public class UsingTheKernel {
|
||||
|
||||
// CLIENT_KEY is for an OpenAI client
|
||||
private static final String CLIENT_KEY = System.getenv("CLIENT_KEY");
|
||||
|
||||
// AZURE_CLIENT_KEY and CLIENT_ENDPOINT are for an Azure client
|
||||
// CLIENT_ENDPOINT required if AZURE_CLIENT_KEY is set
|
||||
private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY");
|
||||
private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT");
|
||||
|
||||
private static final String MODEL_ID = System.getenv()
|
||||
.getOrDefault("MODEL_ID", "gpt-3.5-turbo");
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("======== UsingTheKernel ========");
|
||||
|
||||
OpenAIAsyncClient client;
|
||||
|
||||
if (AZURE_CLIENT_KEY != null && CLIENT_ENDPOINT != null) {
|
||||
// <build_client>
|
||||
client = new OpenAIClientBuilder()
|
||||
.credential(new AzureKeyCredential(AZURE_CLIENT_KEY))
|
||||
.endpoint(CLIENT_ENDPOINT)
|
||||
.buildAsyncClient();
|
||||
// </build_client>
|
||||
} else if (CLIENT_KEY != null) {
|
||||
client = new OpenAIClientBuilder()
|
||||
.credential(new KeyCredential(CLIENT_KEY))
|
||||
.buildAsyncClient();
|
||||
} else {
|
||||
System.out.println("No client key found");
|
||||
return;
|
||||
}
|
||||
|
||||
// <build_kernel>
|
||||
|
||||
ChatCompletionService chatCompletionService = ChatCompletionService.builder()
|
||||
.withModelId(MODEL_ID)
|
||||
.withOpenAIAsyncClient(client)
|
||||
.build();
|
||||
|
||||
KernelPlugin mathPlugin = KernelPluginFactory.createFromObject(
|
||||
new MathPlugin(), "MathPlugin");
|
||||
|
||||
var poemPlugin = KernelPluginFactory.importPluginFromResourcesDirectory(
|
||||
"Plugins",
|
||||
"WriterPlugin",
|
||||
"ShortPoem",
|
||||
null,
|
||||
String.class);
|
||||
|
||||
Kernel kernel = Kernel.builder()
|
||||
.withAIService(ChatCompletionService.class, chatCompletionService)
|
||||
.withPlugin(mathPlugin)
|
||||
.withPlugin(poemPlugin)
|
||||
.build();
|
||||
|
||||
// </build_kernel>
|
||||
|
||||
// <run_poem>
|
||||
var result = poemPlugin.get("ShortPoem")
|
||||
.invokeAsync(kernel)
|
||||
.withArguments(
|
||||
KernelFunctionArguments.builder()
|
||||
.withInput("The cat sat on a mat")
|
||||
.build())
|
||||
.withResultType(String.class)
|
||||
.block();
|
||||
System.out.println(result.getResult());
|
||||
// </run_poem>
|
||||
|
||||
// <run_math>
|
||||
var root = mathPlugin.get("sqrt")
|
||||
.invokeAsync(kernel)
|
||||
.withArguments(
|
||||
KernelFunctionArguments.builder()
|
||||
.withInput(12)
|
||||
.build())
|
||||
.withResultType(Double.class)
|
||||
.block();
|
||||
System.out.println("Square root of 12 is: " + root.getResult());
|
||||
// </run_math>
|
||||
}
|
||||
}
|
||||
+28
-25
@@ -1,117 +1,120 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.samples.plugins;
|
||||
|
||||
import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter;
|
||||
|
||||
// <KernelPlugin>
|
||||
public class MathPlugin {
|
||||
// </KernelPlugin>
|
||||
|
||||
// <KernelFunction>
|
||||
@DefineKernelFunction(name = "sqrt", description = "Take the square root of a number")
|
||||
public static double sqrt(
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take a square root of", type = double.class) double number1) {
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take a square root of", type = double.class) double number1) {
|
||||
return Math.sqrt(number1);
|
||||
}
|
||||
// </KernelFunction>
|
||||
|
||||
@DefineKernelFunction(name = "add", description = "Add two numbers")
|
||||
public static double add(
|
||||
@KernelFunctionParameter(name = "number1", description = "The first number to add", type = double.class) double number1,
|
||||
@KernelFunctionParameter(name = "number2", description = "The second number to add", type = double.class) double number2) {
|
||||
@KernelFunctionParameter(name = "number1", description = "The first number to add", type = double.class) double number1,
|
||||
@KernelFunctionParameter(name = "number2", description = "The second number to add", type = double.class) double number2) {
|
||||
return number1 + number2;
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "subtract", description = "Subtract two numbers")
|
||||
public static double subtract(
|
||||
@KernelFunctionParameter(name = "number1", description = "The first number to subtract from", type = double.class) double number1,
|
||||
@KernelFunctionParameter(name = "number2", description = "The second number to subtract away", type = double.class) double number2) {
|
||||
@KernelFunctionParameter(name = "number1", description = "The first number to subtract from", type = double.class) double number1,
|
||||
@KernelFunctionParameter(name = "number2", description = "The second number to subtract away", type = double.class) double number2) {
|
||||
return number1 - number2;
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "multiply", description = "Multiply two numbers. When increasing by a percentage, don't forget to add 1 to the percentage.")
|
||||
public static double multiply(
|
||||
@KernelFunctionParameter(name = "number1", description = "The first number to multiply", type = double.class) double number1,
|
||||
@KernelFunctionParameter(name = "number2", description = "The second number to multiply", type = double.class) double number2) {
|
||||
@KernelFunctionParameter(name = "number1", description = "The first number to multiply", type = double.class) double number1,
|
||||
@KernelFunctionParameter(name = "number2", description = "The second number to multiply", type = double.class) double number2) {
|
||||
return number1 * number2;
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "divide", description = "Divide two numbers")
|
||||
public static double divide(
|
||||
@KernelFunctionParameter(name = "number1", description = "The first number to divide from", type = double.class) double number1,
|
||||
@KernelFunctionParameter(name = "number2", description = "The second number to divide by", type = double.class) double number2) {
|
||||
@KernelFunctionParameter(name = "number1", description = "The first number to divide from", type = double.class) double number1,
|
||||
@KernelFunctionParameter(name = "number2", description = "The second number to divide by", type = double.class) double number2) {
|
||||
return number1 / number2;
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "power", description = "Raise a number to a power")
|
||||
public static double power(
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to raise", type = double.class) double number1,
|
||||
@KernelFunctionParameter(name = "number2", description = "The power to raise the number to", type = double.class) double number2) {
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to raise", type = double.class) double number1,
|
||||
@KernelFunctionParameter(name = "number2", description = "The power to raise the number to", type = double.class) double number2) {
|
||||
return Math.pow(number1, number2);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "log", description = "Take the log of a number")
|
||||
public static double log(
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the log of", type = double.class) double number1,
|
||||
@KernelFunctionParameter(name = "number2", description = "The base of the log", type = double.class) double number2) {
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the log of", type = double.class) double number1,
|
||||
@KernelFunctionParameter(name = "number2", description = "The base of the log", type = double.class) double number2) {
|
||||
return Math.log(number1) / Math.log(number2);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "round", description = "Round a number to the target number of decimal places")
|
||||
public static double round(
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to round", type = double.class) double number1,
|
||||
@KernelFunctionParameter(name = "number2", description = "The number of decimal places to round to", type = double.class) int number2) {
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to round", type = double.class) double number1,
|
||||
@KernelFunctionParameter(name = "number2", description = "The number of decimal places to round to", type = double.class) int number2) {
|
||||
return Math.round(number1 * Math.pow(10, number2)) / Math.pow(10, number2);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "abs", description = "Take the absolute value of a number")
|
||||
public static double abs(
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the absolute value of", type = double.class) double number1) {
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the absolute value of", type = double.class) double number1) {
|
||||
return Math.abs(number1);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "floor", description = "Take the floor of a number")
|
||||
public static double floor(
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the floor of", type = double.class) double number1) {
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the floor of", type = double.class) double number1) {
|
||||
return Math.floor(number1);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "ceiling", description = "Take the ceiling of a number")
|
||||
public static double ceiling(
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the ceiling of", type = double.class) double number1) {
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the ceiling of", type = double.class) double number1) {
|
||||
return Math.ceil(number1);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "sin", description = "Take the sine of a number")
|
||||
public static double sin(
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the sine of", type = double.class) double number1) {
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the sine of", type = double.class) double number1) {
|
||||
return Math.sin(number1);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "cos", description = "Take the cosine of a number")
|
||||
public static double cos(
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the cosine of", type = double.class) double number1) {
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the cosine of", type = double.class) double number1) {
|
||||
return Math.cos(number1);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "tan", description = "Take the tangent of a number")
|
||||
public static double tan(
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the tangent of", type = double.class) double number1) {
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the tangent of", type = double.class) double number1) {
|
||||
return Math.tan(number1);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "asin", description = "Take the arcsine of a number")
|
||||
public static double asin(
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the arcsine of", type = double.class) double number1) {
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the arcsine of", type = double.class) double number1) {
|
||||
return Math.asin(number1);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "acos", description = "Take the arccosine of a number")
|
||||
public static double acos(
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the arccosine of", type = double.class) double number1) {
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the arccosine of", type = double.class) double number1) {
|
||||
return Math.acos(number1);
|
||||
}
|
||||
|
||||
@DefineKernelFunction(name = "atan", description = "Take the arctangent of a number")
|
||||
public static double atan(
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the arctangent of", type = double.class) double number1) {
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take the arctangent of", type = double.class) double number1) {
|
||||
return Math.atan(number1);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-4
@@ -21,13 +21,11 @@
|
||||
"input_variables": [
|
||||
{
|
||||
"name": "request",
|
||||
"description": "The user's request.",
|
||||
"required": true
|
||||
"description": "The user's request."
|
||||
},
|
||||
{
|
||||
"name": "history",
|
||||
"description": "The history of the conversation.",
|
||||
"required": true
|
||||
"description": "The history of the conversation."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
name: getIntent
|
||||
description: Gets the intent of the user.
|
||||
template: |
|
||||
<message role="system">Instructions: What is the intent of this request?
|
||||
Do not explain the reasoning, just reply back with the intent. If you are unsure, reply with {{choices.[0]}}.
|
||||
Choices: {{choices}}.</message>
|
||||
|
||||
BEGIN EXAMPLES
|
||||
{{#each fewShotExamples}}
|
||||
{{#each this}}
|
||||
<message role="{{role}}">{{content}}</message>
|
||||
{{/each}}
|
||||
{{/each}}
|
||||
END EXAMPLES
|
||||
|
||||
{{ConversationSummaryPlugin.SummarizeConversation history}}
|
||||
|
||||
<message role="user">{{request}}</message>
|
||||
<message role="system">Intent:</message>
|
||||
template_format: handlebars
|
||||
input_variables:
|
||||
- name: choices
|
||||
description: The choices for the AI to choose from
|
||||
default: ContinueConversation, EndConversation
|
||||
- name: fewShotExamples
|
||||
description: Few shot examples for the AI to learn from
|
||||
is_required: true
|
||||
- name: request
|
||||
description: The user's request
|
||||
is_required: true
|
||||
execution_settings:
|
||||
default:
|
||||
max_tokens: 10
|
||||
temperature: 0
|
||||
gpt-3.5-turbo:
|
||||
model_id: gpt-35-turbo-2
|
||||
max_tokens: 10
|
||||
temperature: 0.2
|
||||
gpt-4:
|
||||
model_id: gpt-4-1106-preview
|
||||
max_tokens: 10
|
||||
temperature: 0.2
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"schema": 1,
|
||||
"type": "completion",
|
||||
"description": "Turn a scenario into a short and entertaining poem.",
|
||||
"completion": {
|
||||
"max_tokens": 200,
|
||||
"temperature": 0.5,
|
||||
"top_p": 0.0,
|
||||
"presence_penalty": 0.0,
|
||||
"frequency_penalty": 0.0
|
||||
},
|
||||
"input": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "input",
|
||||
"description": "The scenario to turn into a poem.",
|
||||
"defaultValue": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
Generate a short funny poem or limerick to explain the given event. Be creative and be funny. Let your imagination run wild.
|
||||
Event: {{$input}}
|
||||
+4
-1
@@ -9,6 +9,7 @@ import com.microsoft.semantickernel.contextvariables.converters.CompletionUsageC
|
||||
import com.microsoft.semantickernel.contextvariables.converters.DateTimeContextVariableTypeConverter;
|
||||
import com.microsoft.semantickernel.contextvariables.converters.InstantContextVariableTypeConverter;
|
||||
import com.microsoft.semantickernel.contextvariables.converters.NumberVariableContextVariableTypeConverter;
|
||||
import com.microsoft.semantickernel.contextvariables.converters.PrimitiveBooleanVariableContextVariableTypeConverter;
|
||||
import com.microsoft.semantickernel.contextvariables.converters.StringVariableContextVariableTypeConverter;
|
||||
import com.microsoft.semantickernel.contextvariables.converters.TextContentVariableContextVariableTypeConverter;
|
||||
import com.microsoft.semantickernel.contextvariables.converters.VoidVariableContextVariableTypeConverter;
|
||||
@@ -29,7 +30,6 @@ public class ContextVariableTypes {
|
||||
static {
|
||||
List<ContextVariableTypeConverter<?>> types = Arrays.asList(
|
||||
new CharacterVariableContextVariableTypeConverter(),
|
||||
new BooleanVariableContextVariableTypeConverter(),
|
||||
new ChatHistoryVariableContextVariableTypeConverter(),
|
||||
new TextContentVariableContextVariableTypeConverter(),
|
||||
new StringVariableContextVariableTypeConverter(),
|
||||
@@ -40,6 +40,9 @@ public class ContextVariableTypes {
|
||||
new InstantContextVariableTypeConverter(),
|
||||
new CompletionUsageContextVariableTypeConverter(),
|
||||
|
||||
new BooleanVariableContextVariableTypeConverter(),
|
||||
new PrimitiveBooleanVariableContextVariableTypeConverter(),
|
||||
|
||||
new NumberVariableContextVariableTypeConverter<>(Byte.class, Byte::parseByte,
|
||||
Number::byteValue),
|
||||
new NumberVariableContextVariableTypeConverter<>(byte.class, Byte::parseByte,
|
||||
|
||||
+10
-58
@@ -1,12 +1,9 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.contextvariables.converters;
|
||||
|
||||
import static com.microsoft.semantickernel.contextvariables.ContextVariableTypes.convert;
|
||||
|
||||
import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter;
|
||||
import com.microsoft.semantickernel.contextvariables.ContextVariableTypes;
|
||||
import java.util.function.Function;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* A {@link ContextVariableTypeConverter} for {@code java.lang.Number} type variables. Use, for
|
||||
@@ -17,9 +14,7 @@ import javax.annotation.Nullable;
|
||||
* @see ContextVariableTypes#getGlobalVariableTypeForClass(Class)
|
||||
*/
|
||||
public class NumberVariableContextVariableTypeConverter<T extends Number> extends
|
||||
ContextVariableTypeConverter<T> {
|
||||
|
||||
private final Function<Number, T> fromNumber;
|
||||
PrimitiveVariableContextVariableTypeConverter<T> {
|
||||
|
||||
/**
|
||||
* Creates a new instance of the {@link NumberVariableContextVariableTypeConverter} class.
|
||||
@@ -34,58 +29,15 @@ public class NumberVariableContextVariableTypeConverter<T extends Number> extend
|
||||
Function<Number, T> fromNumber) {
|
||||
super(
|
||||
clazz,
|
||||
s -> convert(s, clazz),
|
||||
Number::toString,
|
||||
fromPromptString);
|
||||
this.fromNumber = fromNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public <U> U toObject(@Nullable Object t, Class<U> clazz) {
|
||||
if (t == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Let the parent class have a crack at it first
|
||||
// since someone may have installed a special converter.
|
||||
U obj = super.toObject(t, clazz);
|
||||
if (obj != null) {
|
||||
return obj;
|
||||
}
|
||||
// If the type is a string, and the object is of the same type as the
|
||||
// converter, then we can convert with the toPromptString method.
|
||||
if (clazz == String.class && t.getClass() == super.getType()) {
|
||||
return clazz.cast(toPromptString(getType().cast(t)));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public T fromObject(@Nullable Object s) {
|
||||
T obj = super.fromObject(s);
|
||||
if (obj != null) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
if (s instanceof Number) {
|
||||
return fromNumber.apply((Number) s);
|
||||
}
|
||||
|
||||
if (s instanceof String) {
|
||||
return fromPromptString((String) s);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public T fromPromptString(@Nullable String s) {
|
||||
if (s != null && !s.isEmpty()) {
|
||||
return super.fromPromptString(s);
|
||||
}
|
||||
return null;
|
||||
fromPromptString,
|
||||
num -> {
|
||||
if (num instanceof Number) {
|
||||
return fromNumber.apply((Number) num);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
Number::toString);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.contextvariables.converters;
|
||||
|
||||
import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter;
|
||||
import com.microsoft.semantickernel.contextvariables.ContextVariableTypes;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* A {@link ContextVariableTypeConverter} for {@link Boolean} variables. Use
|
||||
* {@code ContextVariableTypes.getDefaultVariableTypeForClass(Boolean.class)} to get an instance of
|
||||
* this class.
|
||||
*
|
||||
* @see ContextVariableTypes#getGlobalVariableTypeForClass(Class)
|
||||
*/
|
||||
public class PrimitiveBooleanVariableContextVariableTypeConverter extends
|
||||
PrimitiveVariableContextVariableTypeConverter {
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the
|
||||
* {@link PrimitiveBooleanVariableContextVariableTypeConverter} class.
|
||||
*/
|
||||
public PrimitiveBooleanVariableContextVariableTypeConverter() {
|
||||
super(
|
||||
boolean.class,
|
||||
s -> {
|
||||
switch (((String) s).toLowerCase(Locale.ROOT).trim()) {
|
||||
case "true":
|
||||
case "on":
|
||||
case "1":
|
||||
case "yes":
|
||||
case "y":
|
||||
case "t":
|
||||
case "enable":
|
||||
return true;
|
||||
case "false":
|
||||
case "off":
|
||||
case "0":
|
||||
case "no":
|
||||
case "n":
|
||||
case "f":
|
||||
case "disable":
|
||||
return false;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
},
|
||||
s -> {
|
||||
if (s instanceof Boolean || boolean.class.isInstance(s)) {
|
||||
return s;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
s -> {
|
||||
if (s == null) {
|
||||
return null;
|
||||
}
|
||||
return ((Boolean) s).toString();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.contextvariables.converters;
|
||||
|
||||
import static com.microsoft.semantickernel.contextvariables.ContextVariableTypes.convert;
|
||||
|
||||
import com.microsoft.semantickernel.contextvariables.ContextVariable;
|
||||
import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter;
|
||||
import java.util.function.Function;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* A {@link ContextVariableTypeConverter} for primative variables.
|
||||
*/
|
||||
public class PrimitiveVariableContextVariableTypeConverter<T> extends
|
||||
ContextVariableTypeConverter<T> {
|
||||
|
||||
private final Function<Object, T> fromObject;
|
||||
|
||||
/**
|
||||
* Creates a new instance of the {@link PrimitiveVariableContextVariableTypeConverter} class.
|
||||
*
|
||||
* @param clazz the class
|
||||
* @param fromPromptString the function to convert from a prompt string
|
||||
* @param fromObject the function to convert from an object to primative
|
||||
*/
|
||||
public PrimitiveVariableContextVariableTypeConverter(
|
||||
Class<T> clazz,
|
||||
Function<String, T> fromPromptString,
|
||||
Function<Object, T> fromObject,
|
||||
Function<T, String> toPromptString) {
|
||||
super(
|
||||
clazz,
|
||||
s -> convert(s, clazz),
|
||||
toPromptString,
|
||||
fromPromptString);
|
||||
this.fromObject = fromObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public <U> U toObject(@Nullable Object t, Class<U> clazz) {
|
||||
if (t == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Let the parent class have a crack at it first
|
||||
// since someone may have installed a special converter.
|
||||
U obj = super.toObject(t, clazz);
|
||||
if (obj != null) {
|
||||
return obj;
|
||||
}
|
||||
// If the type is a string, and the object is of the same type as the
|
||||
// converter, then we can convert with the toPromptString method.
|
||||
if (clazz == String.class && t.getClass() == super.getType()) {
|
||||
return clazz.cast(toPromptString(getType().cast(t)));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public T fromObject(@Nullable Object s) {
|
||||
if (s instanceof ContextVariable) {
|
||||
s = ((ContextVariable) s).getValue();
|
||||
}
|
||||
|
||||
T obj = super.fromObject(s);
|
||||
if (obj != null) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
try {
|
||||
T result = fromObject.apply(s);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
if (s instanceof String) {
|
||||
return fromPromptString((String) s);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public T fromPromptString(@Nullable String s) {
|
||||
if (s != null && !s.isEmpty()) {
|
||||
return super.fromPromptString(s);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
+11
@@ -180,6 +180,17 @@ public class FunctionInvocation<T> extends Mono<FunctionResult<T>> {
|
||||
.withTypes(contextVariableTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Supply the result type of function invocation. Uses the global context variable types.
|
||||
*
|
||||
* @param resultType The arguments to supply to the function invocation.
|
||||
* @param <U> The type of the result of the function invocation.
|
||||
* @return A new {@code FunctionInvocation} for fluent chaining.
|
||||
*/
|
||||
public <U> FunctionInvocation<U> withResultType(Class<U> resultType) {
|
||||
return withResultType(ContextVariableTypes.getGlobalVariableTypeForClass(resultType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a kernel hook to the function invocation.
|
||||
*
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.semanticfunctions;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAlias;
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
|
||||
@@ -35,7 +36,7 @@ public class InputVariable {
|
||||
@JsonProperty("type") String type,
|
||||
@JsonProperty("description") @Nullable String description,
|
||||
@JsonProperty("default") @Nullable String defaultValue,
|
||||
@JsonProperty("is_required") boolean isRequired) {
|
||||
@JsonAlias({ "required", "is_required" }) @JsonProperty("is_required") boolean isRequired) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.defaultValue = defaultValue;
|
||||
|
||||
+1
-1
@@ -274,7 +274,7 @@ public class HandlebarsPromptTemplate implements PromptTemplate {
|
||||
String functionName = kernelFunction.getName();
|
||||
String pluginName = plugin.getName();
|
||||
handlebars.registerHelper(
|
||||
ToolCallBehavior.formFullFunctionName(pluginName, functionName),
|
||||
String.format("%s.%s", pluginName, functionName),
|
||||
functionInvokeHelper(kernel, kernelFunction, context));
|
||||
});
|
||||
|
||||
|
||||
+8
@@ -3,6 +3,7 @@ package com.microsoft.semantickernel.contextvariables.converters;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.microsoft.semantickernel.contextvariables.ContextVariable;
|
||||
import com.microsoft.semantickernel.contextvariables.ContextVariableType;
|
||||
import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter;
|
||||
import com.microsoft.semantickernel.contextvariables.ContextVariableTypes;
|
||||
@@ -92,4 +93,11 @@ public class NumberVariableContextVariableTypeConverterTest {
|
||||
assertEquals(expResult, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFromStringToDouble() {
|
||||
Object s = "12.0";
|
||||
double expResult = 12.0d;
|
||||
ContextVariable<Double> result = ContextVariable.convert(s, double.class, null);
|
||||
assertEquals(expResult, result.getValue());
|
||||
}
|
||||
}
|
||||
+37
@@ -3,9 +3,17 @@ package com.microsoft.semantickernel.semanticfunctions;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.contextvariables.ContextVariableTypes;
|
||||
import com.microsoft.semantickernel.orchestration.FunctionResult;
|
||||
import com.microsoft.semantickernel.plugin.KernelPlugin;
|
||||
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
|
||||
import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction;
|
||||
import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
@@ -15,6 +23,35 @@ public class KernelFunctionFromMethodTest {
|
||||
public KernelFunctionFromMethodTest() {
|
||||
}
|
||||
|
||||
public static class ExamplePlugin {
|
||||
|
||||
@DefineKernelFunction(name = "sqrt", description = "Take the square root of a number")
|
||||
public static double sqrt(
|
||||
@KernelFunctionParameter(name = "number1", description = "The number to take a square root of", type = double.class) double number1) {
|
||||
return Math.sqrt(number1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void typeConversionOnMethodCall() {
|
||||
KernelPlugin plugin = KernelPluginFactory.createFromObject(
|
||||
new ExamplePlugin(), "ExamplePlugin");
|
||||
|
||||
Kernel kernel = Kernel.builder().build();
|
||||
|
||||
FunctionResult<String> result = plugin
|
||||
.get("sqrt")
|
||||
.invokeAsync(kernel)
|
||||
.withResultType(ContextVariableTypes.getGlobalVariableTypeForClass(String.class))
|
||||
.withArguments(
|
||||
KernelFunctionArguments.builder()
|
||||
.withVariable("number1", "12.0")
|
||||
.build())
|
||||
.block();
|
||||
|
||||
Assertions.assertEquals("3.4641016151377544", result.getResult());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreate() throws Exception {
|
||||
Method method = String.class.getMethod("concat", String.class);
|
||||
|
||||
Reference in New Issue
Block a user