From 3f894eada10862e5b47d45ca82ffb6dda0dfeae5 Mon Sep 17 00:00:00 2001 From: John Oliver <1615532+johnoliver@users.noreply.github.com> Date: Tue, 7 Nov 2023 12:00:42 +0000 Subject: [PATCH] Java: Allow Semantic Kernel to obtain credentials via Managed identity and azure cli. Fix some tests (#3298) ### Motivation and Context ### Description ### Contribution Checklist - [ ] 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 :smile: --- .../pom.xml | 5 + .../pom.xml | 13 +- .../semantickernel-settings-loader/pom.xml | 5 + .../ai/openai/util/AzureCredentialType.java | 97 +++++++ .../ai/openai/util/AzureOpenAISettings.java | 13 + .../ai/openai/util/OpenAIClientProvider.java | 33 ++- java/samples/sample-code/README.md | 23 +- java/samples/sample-code/pom.xml | 4 + ...mple04_CombineLLMPromptsAndNativeCode.java | 10 +- .../Example12_SequentialPlanner.java | 6 +- .../Example14_SemanticMemory.java | 254 ++++++++++-------- .../syntaxexamples/Example17_ChatGPT.java | 4 +- .../Example28_ActionPlanner.java | 2 +- .../semantickernel/SkillExecutor.java | 3 +- .../extensions/KernelExtensions.java | 27 +- java/semantickernel-bom/pom.xml | 5 + .../semantickernel/DefaultKernel.java | 3 +- 17 files changed, 355 insertions(+), 152 deletions(-) create mode 100644 java/extensions/semantickernel-settings-loader/src/main/java/com/microsoft/semantickernel/connectors/ai/openai/util/AzureCredentialType.java diff --git a/java/connectors/semantickernel-connectors-ai-openai/pom.xml b/java/connectors/semantickernel-connectors-ai-openai/pom.xml index be62a3ccc9..99d083502d 100644 --- a/java/connectors/semantickernel-connectors-ai-openai/pom.xml +++ b/java/connectors/semantickernel-connectors-ai-openai/pom.xml @@ -20,6 +20,11 @@ com.microsoft.semantic-kernel semantickernel-api + + com.azure + azure-identity + true + jakarta.inject jakarta.inject-api diff --git a/java/connectors/semantickernel-connectors-memory-azurecognitivesearch/pom.xml b/java/connectors/semantickernel-connectors-memory-azurecognitivesearch/pom.xml index 3ab6a1fb58..d585d275d9 100644 --- a/java/connectors/semantickernel-connectors-memory-azurecognitivesearch/pom.xml +++ b/java/connectors/semantickernel-connectors-memory-azurecognitivesearch/pom.xml @@ -1,6 +1,7 @@ - + 4.0.0 @@ -28,6 +29,16 @@ com.azure azure-search-documents + + + + com.azure + azure-core-serializer-json-jackson + + org.mockito diff --git a/java/extensions/semantickernel-settings-loader/pom.xml b/java/extensions/semantickernel-settings-loader/pom.xml index 68052d2d15..08363ff41a 100644 --- a/java/extensions/semantickernel-settings-loader/pom.xml +++ b/java/extensions/semantickernel-settings-loader/pom.xml @@ -28,5 +28,10 @@ org.junit.jupiter junit-jupiter + + com.azure + azure-identity + true + diff --git a/java/extensions/semantickernel-settings-loader/src/main/java/com/microsoft/semantickernel/connectors/ai/openai/util/AzureCredentialType.java b/java/extensions/semantickernel-settings-loader/src/main/java/com/microsoft/semantickernel/connectors/ai/openai/util/AzureCredentialType.java new file mode 100644 index 0000000000..ba903a6530 --- /dev/null +++ b/java/extensions/semantickernel-settings-loader/src/main/java/com/microsoft/semantickernel/connectors/ai/openai/util/AzureCredentialType.java @@ -0,0 +1,97 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.semantickernel.connectors.ai.openai.util; + +import com.azure.core.credential.TokenCredential; +import com.microsoft.semantickernel.exceptions.ConfigurationException; +import java.io.File; +import java.util.List; +import java.util.Map; +import javax.annotation.Nullable; +import org.slf4j.Logger; + +/** Defines the type of azure credential used for authenticating to this resource */ +public enum AzureCredentialType { + KEY { + @Nullable + @Override + public TokenCredential getTokenCredential() { + return null; + } + }, + MANAGED_IDENTITY { + @Nullable + @Override + public TokenCredential getTokenCredential() { + if (classIsPresent("com.azure.identity.ManagedIdentityCredentialBuilder")) { + return new com.azure.identity.ManagedIdentityCredentialBuilder().build(); + } + return null; + } + }, + AZURE_CLI { + @Nullable + @Override + public TokenCredential getTokenCredential() { + if (classIsPresent("com.azure.identity.AzureCliCredentialBuilder")) { + return new com.azure.identity.AzureCliCredentialBuilder().build(); + } + return null; + } + }; + + private static final Logger LOGGER = + org.slf4j.LoggerFactory.getLogger(AzureCredentialType.class); + + /** + * Create a TokenCredential instance. + * + * @return TokenCredential instance or null if not found + */ + @Nullable + public abstract TokenCredential getTokenCredential(); + + /** + * Create a TokenCredential instance, uses the default settings locations (see {@link + * SettingsMap} for details). + * + *

Set the 'client.azureopenai.credentialtype' environment variable within settings to + * determine the token type. {@link AzureCredentialType} + * + * @return TokenCredential instance or null if not found + */ + @Nullable + public static TokenCredential getCredential() throws ConfigurationException { + return getCredential((List) null); + } + + /** + * Create a TokenCredential instance, uses the provided settings locations (see {@link + * SettingsMap} for details). + * + *

Set the 'client.azureopenai.credentialtype' environment variable within settings to + * determine the token type. {@link AzureCredentialType} + * + * @return TokenCredential instance or null if not found + */ + @Nullable + public static TokenCredential getCredential(@Nullable List propertyFileLocations) + throws ConfigurationException { + Map settings = OpenAIClientProvider.getSettings(propertyFileLocations); + return new AzureOpenAISettings(settings) + .getAzureOpenAiCredentialsType() + .getTokenCredential(); + } + + private static boolean classIsPresent(String className) { + try { + Class.forName(className, false, Thread.currentThread().getContextClassLoader()); + + return true; + } catch (ClassNotFoundException e) { + LOGGER.warn( + "Requested Managed Identity or Azure CLI authentication, however the" + + " azure-identity library is not available on the classpath"); + return false; + } + } +} diff --git a/java/extensions/semantickernel-settings-loader/src/main/java/com/microsoft/semantickernel/connectors/ai/openai/util/AzureOpenAISettings.java b/java/extensions/semantickernel-settings-loader/src/main/java/com/microsoft/semantickernel/connectors/ai/openai/util/AzureOpenAISettings.java index 789f129cb9..d2c2409a24 100644 --- a/java/extensions/semantickernel-settings-loader/src/main/java/com/microsoft/semantickernel/connectors/ai/openai/util/AzureOpenAISettings.java +++ b/java/extensions/semantickernel-settings-loader/src/main/java/com/microsoft/semantickernel/connectors/ai/openai/util/AzureOpenAISettings.java @@ -7,15 +7,18 @@ import javax.annotation.Nullable; /** Settings for Azure OpenAI client */ public class AzureOpenAISettings extends AbstractOpenAIClientSettings { + private static final String DEFAULT_SETTINGS_PREFIX = "client.azureopenai"; private static final String AZURE_OPEN_AI_ENDPOINT_SUFFIX = "endpoint"; private static final String AZURE_OPEN_AI_DEPLOYMENT_NAME_SUFFIX = "deploymentname"; + private static final String AZURE_OPEN_AI_CREDENTIALS_TYPE = "credentialtype"; @Nullable private final String key; @Nullable private final String endpoint; @Nullable private final String deploymentName; + @Nullable private final AzureCredentialType credentialType; private final String settingsPrefix; public AzureOpenAISettings(Map settings) { @@ -27,6 +30,12 @@ public class AzureOpenAISettings extends AbstractOpenAIClientSettings { key = settings.get(settingsPrefix + "." + KEY_SUFFIX); endpoint = settings.get(settingsPrefix + "." + AZURE_OPEN_AI_ENDPOINT_SUFFIX); deploymentName = settings.get(settingsPrefix + "." + AZURE_OPEN_AI_DEPLOYMENT_NAME_SUFFIX); + + String credType = + settings.getOrDefault(settingsPrefix + "." + AZURE_OPEN_AI_CREDENTIALS_TYPE, "key") + .toUpperCase(); + + credentialType = AzureCredentialType.valueOf(credType); } /** @@ -65,6 +74,10 @@ public class AzureOpenAISettings extends AbstractOpenAIClientSettings { return key; } + public AzureCredentialType getAzureOpenAiCredentialsType() { + return credentialType; + } + @Override public boolean assertIsValid() throws ConfigurationException { if (key == null) { diff --git a/java/extensions/semantickernel-settings-loader/src/main/java/com/microsoft/semantickernel/connectors/ai/openai/util/OpenAIClientProvider.java b/java/extensions/semantickernel-settings-loader/src/main/java/com/microsoft/semantickernel/connectors/ai/openai/util/OpenAIClientProvider.java index 0904b8cc92..95015d3320 100644 --- a/java/extensions/semantickernel-settings-loader/src/main/java/com/microsoft/semantickernel/connectors/ai/openai/util/OpenAIClientProvider.java +++ b/java/extensions/semantickernel-settings-loader/src/main/java/com/microsoft/semantickernel/connectors/ai/openai/util/OpenAIClientProvider.java @@ -7,6 +7,7 @@ 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.azure.core.credential.TokenCredential; import com.azure.core.util.ClientOptions; import com.microsoft.semantickernel.SemanticKernelHttpSettings; import com.microsoft.semantickernel.exceptions.ConfigurationException; @@ -79,7 +80,7 @@ public class OpenAIClientProvider { return new OpenAIClientProvider(settings, clientType); } - private static Map getSettings(@Nullable List propertyFileLocations) + static Map getSettings(@Nullable List propertyFileLocations) throws ConfigurationException { Map settings; @@ -235,19 +236,27 @@ public class OpenAIClientProvider { private OpenAIAsyncClient buildAzureOpenAIClient() throws ConfigurationException { AzureOpenAISettings settings = new AzureOpenAISettings(configuredSettings); - try { - settings.assertIsValid(); - } catch (ConfigurationException e) { - LOGGER.warn("Could not instantiate Azure OpenAI client"); - LOGGER.warn(e.getMessage()); - throw e; + OpenAIClientBuilder builder = new OpenAIClientBuilder().endpoint(settings.getEndpoint()); + + TokenCredential tokenCredential = null; + + if (settings.getAzureOpenAiCredentialsType() != null) { + tokenCredential = settings.getAzureOpenAiCredentialsType().getTokenCredential(); } - OpenAIClientBuilder builder = - new OpenAIClientBuilder() - .endpoint(settings.getEndpoint()) - .clientOptions(clientOptions) - .credential(new AzureKeyCredential(settings.getKey())); + if (tokenCredential != null) { + builder.credential(tokenCredential); + } else { + try { + settings.assertIsValid(); + } catch (ConfigurationException e) { + LOGGER.warn("Could not instantiate Azure OpenAI client"); + LOGGER.warn(e.getMessage()); + throw e; + } + + builder.credential(new AzureKeyCredential(settings.getKey())); + } return builder.buildAsyncClient(); } diff --git a/java/samples/sample-code/README.md b/java/samples/sample-code/README.md index 56c951268b..afb693b24f 100644 --- a/java/samples/sample-code/README.md +++ b/java/samples/sample-code/README.md @@ -34,10 +34,14 @@ They can then be run by: # Configuration -You can define the provider of Open AI by setting the `OPENAI_CLIENT_TYPE` +By default, the samples will use the Open AI client, but you can also use the Azure Open AI client. + +## Open AI client type + +You can define the provider of Open AI (openai.com or Azure), this can be done by setting the `OPENAI_CLIENT_TYPE` property or environment variable to either [`OPENAI`](https://openai.com/api/) -or [`AZURE_OPEN_AI`](https://learn.microsoft.com/azure/cognitive-services/openai/). -By default, the samples will use the Open AI client. +or [`AZURE_OPEN_AI`](https://learn.microsoft.com/azure/cognitive-services/openai/). By default, the samples will use the +Open AI client. ```shell OPENAI_CLIENT_TYPE=OPEN_AI ../../mvnw exec:java -Dsample=Example04_CombineLLMPromptsAndNativeCode @@ -55,7 +59,6 @@ The samples search for the client settings in the following order: 1. Properties file at `java/samples/conf.properties`. 1. Properties file at `~/.sk/conf.properties`. - ## Properties File You can set the location of a properties file, by setting the `CONF_PROPERTIES` property or environment variable, ie: @@ -123,3 +126,15 @@ OPEN_AI_KEY="my-key" \ OPEN_AI_ORGANIZATION_ID="organisation id" \ ../../mvnw clean package exec:java -Dsample=Example04_CombineLLMPromptsAndNativeCode ``` + +## Managed Identity and Azure CLI Credentials (Azure only) + +The `credentialtype` setting (i.e `client.openai.credentialtype`): + +- `managed_identity`: will attempt to obtain credentials via Azure's managed identity. +- `azure_cli`: will attempt to obtain credentials via Azure's CLI, to use this you must have logged in to the az client + for instance by running `az login`. + +To use either of these settings, the `azure-identity` dependency must be available to the application. Additionally, you +must have the "Cognitive Services User" role assigned to your identity. + diff --git a/java/samples/sample-code/pom.xml b/java/samples/sample-code/pom.xml index fcef47df95..a833c3d59a 100644 --- a/java/samples/sample-code/pom.xml +++ b/java/samples/sample-code/pom.xml @@ -76,6 +76,10 @@ com.microsoft.semantic-kernel semantickernel-settings-loader + + com.azure + azure-identity + diff --git a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example04_CombineLLMPromptsAndNativeCode.java b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example04_CombineLLMPromptsAndNativeCode.java index 42bec80b52..4cd9f86132 100644 --- a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example04_CombineLLMPromptsAndNativeCode.java +++ b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example04_CombineLLMPromptsAndNativeCode.java @@ -34,24 +34,20 @@ public class Example04_CombineLLMPromptsAndNativeCode { public static void main(String[] args) throws ConfigurationException { OpenAIAsyncClient client = SamplesConfig.getClient(); - TextCompletion textCompletion = SKBuilders.textCompletion() - .withModelId("text-davinci-003") + TextCompletion textCompletion = SKBuilders.chatCompletion() + .withModelId("gpt-35-turbo-2") .withOpenAIClient(client) .build(); - Kernel kernel = SKBuilders.kernel().withDefaultAIService(textCompletion).build(); + Kernel kernel = SKBuilders.kernel().withDefaultAIService(textCompletion).build(); kernel.importSkill(new SearchEngineSkill(), null); kernel.importSkillFromDirectory("SummarizeSkill", SampleSkillsUtil.detectSkillDirLocation(), "SummarizeSkill"); - // Run String ask = "What's the tallest building in South America?"; Mono result = - kernel.runAsync(ask, kernel.getSkills().getFunction("Search", null)); - - result = kernel.runAsync( ask, kernel.getSkills().getFunction("Search", null), diff --git a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example12_SequentialPlanner.java b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example12_SequentialPlanner.java index 68cb569d01..6c87efffde 100644 --- a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example12_SequentialPlanner.java +++ b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example12_SequentialPlanner.java @@ -183,16 +183,16 @@ public class Example12_SequentialPlanner { private static Kernel initializeKernel() throws ConfigurationException { OpenAIAsyncClient client = SamplesConfig.getClient(); var kernel = SKBuilders.kernel() - .withDefaultAIService(SKBuilders.chatCompletion() + .withDefaultAIService(SKBuilders.textCompletion() .withOpenAIClient(client) - .withModelId("gpt-35-turbo") + .withModelId("gpt-35-turbo-instruct") .build()) .withMemory(SKBuilders .semanticTextMemory() .withEmbeddingGenerator( SKBuilders.textEmbeddingGeneration() .withOpenAIClient(client) - .withModelId("gpt-35-turbo") + .withModelId("text-embedding-ada-002") .build() ) .withStorage(new VolatileMemoryStore()) diff --git a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example14_SemanticMemory.java b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example14_SemanticMemory.java index d01b55c8e7..b989658dab 100644 --- a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example14_SemanticMemory.java +++ b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example14_SemanticMemory.java @@ -1,17 +1,20 @@ // Copyright (c) Microsoft. All rights reserved. package com.microsoft.semantickernel.samples.syntaxexamples; +import com.azure.core.credential.TokenCredential; import com.microsoft.semantickernel.Kernel; import com.microsoft.semantickernel.SKBuilders; import com.microsoft.semantickernel.SamplesConfig; +import com.microsoft.semantickernel.connectors.ai.openai.util.AzureCredentialType; import com.microsoft.semantickernel.connectors.memory.azurecognitivesearch.AzureCognitiveSearchMemoryStore; +import com.microsoft.semantickernel.exceptions.ConfigurationException; import com.microsoft.semantickernel.memory.VolatileMemoryStore; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - +import com.microsoft.semantickernel.settings.SettingsMap; import java.util.Arrays; import java.util.Map; import java.util.stream.Collectors; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; /** @@ -32,75 +35,102 @@ import java.util.stream.Collectors; * README for configuring your environment to run the examples. */ public class Example14_SemanticMemory { - private static final String MEMORY_COLLECTION_NAME = "SKGitHub"; - public static void main(String[] args) throws Exception { - System.out.println("=============================================================="); - System.out.println("======== Semantic Memory using Azure Cognitive Search ========"); - System.out.println("=============================================================="); + private static final String MEMORY_COLLECTION_NAME = "SKGitHub"; - var openAIAsyncClient = SamplesConfig.getClient(); + public static void main(String[] args) throws Exception { + System.out.println("=============================================================="); + System.out.println("======== Semantic Memory using Azure Cognitive Search ========"); + System.out.println("=============================================================="); - /* This example leverages Azure Cognitive Search to provide SK with Semantic Memory. - * - * Azure Cognitive Search automatically indexes your data semantically, so you don't - * need to worry about embedding generation. - */ - var kernelWithACS = SKBuilders.kernel() - .withMemoryStorage( - new AzureCognitiveSearchMemoryStore(System.getenv("ACS_ENDPOINT"), System.getenv("ACS_API_KEY"))) - .withDefaultAIService(SKBuilders.textEmbeddingGeneration() - .withOpenAIClient(openAIAsyncClient) - .withModelId("text-embedding-ada-002") - .build()) - .build(); + var openAIAsyncClient = SamplesConfig.getClient(); - runExampleAsync(kernelWithACS).block(); + AzureCognitiveSearchMemoryStore memoryStore = buildAzureCognitiveSearchMemoryStore(); + /* This example leverages Azure Cognitive Search to provide SK with Semantic Memory. + * + * Azure Cognitive Search automatically indexes your data semantically, so you don't + * need to worry about embedding generation. + */ + var kernelWithACS = SKBuilders.kernel() + .withMemoryStorage(memoryStore) + .withDefaultAIService(SKBuilders.textEmbeddingGeneration() + .withOpenAIClient(openAIAsyncClient) + .withModelId("text-embedding-ada-002") + .build()) + .build(); - System.out.println("===================================================="); - System.out.println("======== Semantic Memory (volatile, in RAM) ========"); - System.out.println("===================================================="); + runExampleAsync(kernelWithACS).block(); - /* You can build your own semantic memory combining an Embedding Generator - * with a Memory storage that supports search by similarity (ie semantic search). - * - * In this example we use a volatile memory, a local simulation of a vector DB. - * - * You can replace VolatileMemoryStore with Qdrant (see QdrantMemoryStore connector) - * or implement your connectors for Pinecone, Vespa, Postgres + pgvector, SQLite VSS, etc. - */ + System.out.println("===================================================="); + System.out.println("======== Semantic Memory (volatile, in RAM) ========"); + System.out.println("===================================================="); - var kernelWithCustomDb = SKBuilders.kernel() - .withDefaultAIService(SKBuilders.textEmbeddingGeneration() - .withOpenAIClient(openAIAsyncClient) - .withModelId("text-embedding-ada-002") - .build()) - .withMemoryStorage(new VolatileMemoryStore.Builder().build()) - .build(); + /* You can build your own semantic memory combining an Embedding Generator + * with a Memory storage that supports search by similarity (ie semantic search). + * + * In this example we use a volatile memory, a local simulation of a vector DB. + * + * You can replace VolatileMemoryStore with Qdrant (see QdrantMemoryStore connector) + * or implement your connectors for Pinecone, Vespa, Postgres + pgvector, SQLite VSS, etc. + */ - runExampleAsync(kernelWithCustomDb).block(); + var kernelWithCustomDb = SKBuilders.kernel() + .withDefaultAIService(SKBuilders.textEmbeddingGeneration() + .withOpenAIClient(openAIAsyncClient) + .withModelId("text-embedding-ada-002") + .build()) + .withMemoryStorage(new VolatileMemoryStore.Builder().build()) + .build(); + + runExampleAsync(kernelWithCustomDb).block(); + } + + private static AzureCognitiveSearchMemoryStore buildAzureCognitiveSearchMemoryStore() + throws ConfigurationException { + Map settings = SettingsMap.getDefault(); + + AzureCognitiveSearchMemoryStore memoryStore; + + if (settings.get("cognativesearch.token") == null) { + // Attempt to obtain token via + TokenCredential token = AzureCredentialType.getCredential(); + if (token == null) { + throw new IllegalStateException( + "Unable to obtain token credentials. Please provide a key for Azure Cognitive Search, or log in to az."); + } + memoryStore = new AzureCognitiveSearchMemoryStore( + settings.get("cognativesearch.endpoint"), + token + ); + } else { + memoryStore = new AzureCognitiveSearchMemoryStore( + settings.get("cognativesearch.endpoint"), + settings.get("cognativesearch.token") + ); } + return memoryStore; + } - public static Mono runExampleAsync(Kernel kernel) { - return storeMemoryAsync(kernel) - .then(searchMemoryAsync(kernel, "How do I get started?")) + public static Mono runExampleAsync(Kernel kernel) { + return storeMemoryAsync(kernel) + .then(searchMemoryAsync(kernel, "How do I get started?")) - /* - Output: + /* + Output: - Query: How do I get started? + Query: How do I get started? - Result 1: - URL: : https://github.com/microsoft/semantic-kernel/blob/main/README.md - Title : README: Installation, getting started, and how to contribute + Result 1: + URL: : https://github.com/microsoft/semantic-kernel/blob/main/README.md + Title : README: Installation, getting started, and how to contribute - Result 2: - URL: : https://github.com/microsoft/semantic-kernel/blob/main/samples/dotnet-jupyter-notebooks/00-getting-started.ipynb - Title : Jupyter notebook describing how to get started with the Semantic Kernel + Result 2: + URL: : https://github.com/microsoft/semantic-kernel/blob/main/samples/dotnet-jupyter-notebooks/00-getting-started.ipynb + Title : Jupyter notebook describing how to get started with the Semantic Kernel - */ + */ - .then(searchMemoryAsync(kernel, "Can I build a chat with SK?")); + .then(searchMemoryAsync(kernel, "Can I build a chat with SK?")); /* Output: @@ -116,60 +146,68 @@ public class Example14_SemanticMemory { Title : README: README associated with a sample chat summary react-based webapp */ - } + } - private static Mono searchMemoryAsync(Kernel kernel, String query) { - return kernel.getMemory().searchAsync(MEMORY_COLLECTION_NAME, query, 2, 0.5f, false) - .mapNotNull(memories -> { - System.out.println("\nQuery: " + query + "\n"); - for (int n = 0; n < memories.size(); n++) { - var memory = memories.get(n); - System.out.println("Result " + (n + 1) + ":"); - System.out.println(" URL: : " + memory.getMetadata().getId()); - System.out.println(" Title : " + memory.getMetadata().getDescription()); - System.out.println(); - } - System.out.println("----------------------"); - return null; - }); - } + private static Mono searchMemoryAsync(Kernel kernel, String query) { + return kernel.getMemory().searchAsync(MEMORY_COLLECTION_NAME, query, 2, 0.5f, false) + .mapNotNull(memories -> { + System.out.println("\nQuery: " + query + "\n"); + for (int n = 0; n < memories.size(); n++) { + var memory = memories.get(n); + System.out.println("Result " + (n + 1) + ":"); + System.out.println(" URL: : " + memory.getMetadata().getId()); + System.out.println(" Title : " + memory.getMetadata().getDescription()); + System.out.println(); + } + System.out.println("----------------------"); + return null; + }); + } - private static Mono storeMemoryAsync(Kernel kernel) { - /* Store some data in the semantic memory. - * - * When using Azure Cognitive Search the data is automatically indexed on write. - * - * When using the combination of VolatileStore and Embedding generation, SK takes - * care of creating and storing the index - */ + private static Mono storeMemoryAsync(Kernel kernel) { + /* Store some data in the semantic memory. + * + * When using Azure Cognitive Search the data is automatically indexed on write. + * + * When using the combination of VolatileStore and Embedding generation, SK takes + * care of creating and storing the index + */ - return Flux.fromIterable(sampleData().entrySet()) - .doFirst(() -> System.out.println("\nAdding some GitHub file URLs and their descriptions to the semantic memory.")) - .map(entry -> { - System.out.println("Save '" + entry.getKey() + "' to memory."); - return kernel.getMemory().saveReferenceAsync( - MEMORY_COLLECTION_NAME, - entry.getValue(), - entry.getKey(), - "GitHub", - entry.getValue(), - null); - } - ) - .mapNotNull(Mono::block) - .doFinally(signalType -> System.out.println("\n----------------------")) - .then(); - } + return Flux.fromIterable(sampleData().entrySet()) + .doFirst(() -> System.out.println( + "\nAdding some GitHub file URLs and their descriptions to the semantic memory.")) + .map(entry -> { + System.out.println("Save '" + entry.getKey() + "' to memory."); + return kernel.getMemory().saveReferenceAsync( + MEMORY_COLLECTION_NAME, + entry.getValue(), + entry.getKey(), + "GitHub", + entry.getValue(), + null); + } + ) + .mapNotNull(Mono::block) + .doFinally(signalType -> System.out.println("\n----------------------")) + .then(); + } - private static Map sampleData() { - return Arrays.stream(new String[][]{ - {"https://github.com/microsoft/semantic-kernel/blob/main/README.md", "README: Installation, getting started, and how to contribute"}, - {"https://github.com/microsoft/semantic-kernel/blob/main/samples/notebooks/dotnet/02-running-prompts-from-file.ipynb", "Jupyter notebook describing how to pass prompts from a file to a semantic skill or function"}, - {"https://github.com/microsoft/semantic-kernel/blob/main/samples/notebooks/dotnet/00-getting-started.ipynb", "Jupyter notebook describing how to get started with the Semantic Kernel"}, - {"https://github.com/microsoft/semantic-kernel/tree/main/samples/skills/ChatSkill/ChatGPT", "Sample demonstrating how to create a chat skill interfacing with ChatGPT"}, - {"https://github.com/microsoft/semantic-kernel/blob/main/dotnet/src/SemanticKernel/Memory/VolatileMemoryStore.cs", "C# class that defines a volatile embedding store"}, - {"https://github.com/microsoft/semantic-kernel/blob/main/samples/dotnet/KernelHttpServer/README.md", "README: How to set up a Semantic Kernel Service API using Azure Function Runtime v4"}, - {"https://github.com/microsoft/semantic-kernel/blob/main/samples/apps/chat-summary-webapp-react/README.md", "README: README associated with a sample chat summary react-based webapp"}, - }).collect(Collectors.toMap(element -> element[0], element -> element[1])); - } + private static Map sampleData() { + return Arrays.stream(new String[][]{ + {"https://github.com/microsoft/semantic-kernel/blob/main/README.md", + "README: Installation, getting started, and how to contribute"}, + {"https://github.com/microsoft/semantic-kernel/blob/main/samples/notebooks/dotnet/02-running-prompts-from-file.ipynb", + "Jupyter notebook describing how to pass prompts from a file to a semantic skill or function"}, + {"https://github.com/microsoft/semantic-kernel/blob/main/samples/notebooks/dotnet/00-getting-started.ipynb", + "Jupyter notebook describing how to get started with the Semantic Kernel"}, + {"https://github.com/microsoft/semantic-kernel/tree/main/samples/skills/ChatSkill/ChatGPT", + "Sample demonstrating how to create a chat skill interfacing with ChatGPT"}, + {"https://github.com/microsoft/semantic-kernel/blob/main/dotnet/src/SemanticKernel/Memory/VolatileMemoryStore.cs", + "C# class that defines a volatile embedding store"}, + {"https://github.com/microsoft/semantic-kernel/blob/main/samples/dotnet/KernelHttpServer/README.md", + "README: How to set up a Semantic Kernel Service API using Azure Function Runtime v4"}, + {"https://github.com/microsoft/semantic-kernel/blob/main/samples/apps/chat-summary-webapp-react/README.md", + "README: README associated with a sample chat summary react-based webapp"}, + }).collect(Collectors.toMap(element -> element[0], element -> element[1])); + } } diff --git a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example17_ChatGPT.java b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example17_ChatGPT.java index ee93e82787..e99286ce33 100644 --- a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example17_ChatGPT.java +++ b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example17_ChatGPT.java @@ -24,10 +24,10 @@ public class Example17_ChatGPT { Kernel kernel = SKBuilders.kernel() .withAIService( - "chat-test", + "gpt-35-turbo", SKBuilders.chatCompletion() .withOpenAIClient(client) - .withModelId("chat-test") + .withModelId("gpt-35-turbo") .build(), true, ChatCompletion.class diff --git a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example28_ActionPlanner.java b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example28_ActionPlanner.java index 4e95324e4c..79d35bf0a6 100644 --- a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example28_ActionPlanner.java +++ b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example28_ActionPlanner.java @@ -25,7 +25,7 @@ public class Example28_ActionPlanner { var kernel = SKBuilders.kernel() .withDefaultAIService(SKBuilders.textCompletion() - .withModelId("text-davinci-002") + .withModelId("text-davinci-003") .withOpenAIClient(client) .build()) .build(); diff --git a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/SkillExecutor.java b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/SkillExecutor.java index a58d129550..d816ac0d59 100644 --- a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/SkillExecutor.java +++ b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/SkillExecutor.java @@ -75,7 +75,8 @@ public interface SkillExecutor { * @throws KernelException if it is not possible to correctly load the skill */ ReadOnlyFunctionCollection importSkillFromResources( - String pluginDirectory, String skillName, String functionName, @Nullable Class clazz) throws KernelException; + String pluginDirectory, String skillName, String functionName, @Nullable Class clazz) + throws KernelException; /** * Imports the native functions annotated on the given object as a skill. diff --git a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/extensions/KernelExtensions.java b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/extensions/KernelExtensions.java index f5cfaf4d6c..efe9879c18 100644 --- a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/extensions/KernelExtensions.java +++ b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/extensions/KernelExtensions.java @@ -97,7 +97,8 @@ public class KernelExtensions { String pluginName, String functionName, @Nullable Class clazz, - PromptTemplateEngine promptTemplateEngine) throws KernelException { + PromptTemplateEngine promptTemplateEngine) + throws KernelException { PromptTemplateConfig config = getPromptTemplateConfig(pluginDirectory, pluginName, functionName, clazz); @@ -150,7 +151,8 @@ public class KernelExtensions { } private static PromptTemplateConfig getPromptTemplateConfig( - String pluginDirectory, String pluginName, String functionName, @Nullable Class clazz) throws KernelException { + String pluginDirectory, String pluginName, String functionName, @Nullable Class clazz) + throws KernelException { String configFileName = pluginDirectory + File.separator @@ -169,18 +171,19 @@ public class KernelExtensions { ResourceLocation.CLASSPATH, ResourceLocation.FILESYSTEM); - return new ObjectMapper().readValue(config, PromptTemplateConfig.class); + return new ObjectMapper().readValue(config, PromptTemplateConfig.class); } catch (IOException e) { - if (e instanceof JsonMappingException) { - LOGGER.error("Failed to parse config file " + configFileName, e); + if (e instanceof JsonMappingException) { + LOGGER.error("Failed to parse config file " + configFileName, e); - throw new KernelException( - ErrorCodes.FUNCTION_CONFIGURATION_ERROR, - "Failed to parse config file " + configFileName, e); - } else { - LOGGER.debug("No config for " + functionName + " in " + pluginName); - } - return null; + throw new KernelException( + ErrorCodes.FUNCTION_CONFIGURATION_ERROR, + "Failed to parse config file " + configFileName, + e); + } else { + LOGGER.debug("No config for " + functionName + " in " + pluginName); + } + return null; } } } diff --git a/java/semantickernel-bom/pom.xml b/java/semantickernel-bom/pom.xml index 4803fc433f..aff08a1164 100644 --- a/java/semantickernel-bom/pom.xml +++ b/java/semantickernel-bom/pom.xml @@ -106,6 +106,11 @@ azure-ai-openai 1.0.0-beta.5 + + com.azure + azure-identity + 1.10.4 + org.slf4j slf4j-api diff --git a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/DefaultKernel.java b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/DefaultKernel.java index 7f19344c31..21c38589e6 100644 --- a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/DefaultKernel.java +++ b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/DefaultKernel.java @@ -235,7 +235,8 @@ public class DefaultKernel implements Kernel { @Override public ReadOnlyFunctionCollection importSkillFromResources( - String pluginDirectory, String skillName, String functionName, @Nullable Class clazz) throws KernelException { + String pluginDirectory, String skillName, String functionName, @Nullable Class clazz) + throws KernelException { Map skills = KernelExtensions.importSemanticSkillFromResourcesDirectory( pluginDirectory, skillName, functionName, clazz, promptTemplateEngine);