diff --git a/samples/apps/copilot-chat-app/webapi/Config/AzureCognitiveSearchOptions.cs b/samples/apps/copilot-chat-app/webapi/Config/AzureCognitiveSearchOptions.cs new file mode 100644 index 000000000000..07cb960ddff5 --- /dev/null +++ b/samples/apps/copilot-chat-app/webapi/Config/AzureCognitiveSearchOptions.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft. All rights reserved. + +using System.ComponentModel.DataAnnotations; + +namespace SemanticKernel.Service.Config; + +/// +/// Configuration settings for connecting to Azure Cognitive Search. +/// +public class AzureCognitiveSearchOptions +{ + /// + /// Gets or sets the endpoint protocol and host (e.g. https://contoso.search.windows.net). + /// + [Required, Url] + public string Endpoint { get; set; } = string.Empty; + + /// + /// Key to access Azure Cognitive Search. + /// + [Required, NotEmptyOrWhitespace] + public string Key { get; set; } = string.Empty; +} diff --git a/samples/apps/copilot-chat-app/webapi/Config/MemoriesStoreOptions.cs b/samples/apps/copilot-chat-app/webapi/Config/MemoriesStoreOptions.cs index c60f070ef16f..633799146a95 100644 --- a/samples/apps/copilot-chat-app/webapi/Config/MemoriesStoreOptions.cs +++ b/samples/apps/copilot-chat-app/webapi/Config/MemoriesStoreOptions.cs @@ -22,7 +22,12 @@ public enum MemoriesStoreType /// /// Qdrant based persistent memories store. /// - Qdrant + Qdrant, + + /// + /// Azure Cognitive Search persistent memories store. + /// + AzureCognitiveSearch } /// @@ -35,4 +40,10 @@ public enum MemoriesStoreType /// [RequiredOnPropertyValue(nameof(Type), MemoriesStoreType.Qdrant)] public QdrantOptions? Qdrant { get; set; } + + /// + /// Gets or sets the configuration for the Azure Cognitive Search memories store. + /// + [RequiredOnPropertyValue(nameof(Type), MemoriesStoreType.AzureCognitiveSearch)] + public AzureCognitiveSearchOptions? AzureCognitiveSearch { get; set; } } diff --git a/samples/apps/copilot-chat-app/webapi/CopilotChatApi.csproj b/samples/apps/copilot-chat-app/webapi/CopilotChatApi.csproj index 3f2f94e366fd..eabb1cf0c9bc 100644 --- a/samples/apps/copilot-chat-app/webapi/CopilotChatApi.csproj +++ b/samples/apps/copilot-chat-app/webapi/CopilotChatApi.csproj @@ -29,6 +29,7 @@ + diff --git a/samples/apps/copilot-chat-app/webapi/SemanticKernelExtensions.cs b/samples/apps/copilot-chat-app/webapi/SemanticKernelExtensions.cs index e24833208dc0..95c7c53356c9 100644 --- a/samples/apps/copilot-chat-app/webapi/SemanticKernelExtensions.cs +++ b/samples/apps/copilot-chat-app/webapi/SemanticKernelExtensions.cs @@ -6,6 +6,7 @@ using Microsoft.SemanticKernel; using Microsoft.SemanticKernel.AI.Embeddings; using Microsoft.SemanticKernel.Connectors.AI.OpenAI.TextEmbedding; +using Microsoft.SemanticKernel.Connectors.Memory.AzureCognitiveSearch; using Microsoft.SemanticKernel.Connectors.Memory.Qdrant; using Microsoft.SemanticKernel.Memory; using Microsoft.SemanticKernel.SkillDefinition; @@ -22,7 +23,7 @@ internal static class SemanticKernelExtensions /// internal static IServiceCollection AddSemanticKernelServices(this IServiceCollection services) { - // The chat skill's prompts are stored in a separate file. + // Load the chat skill's prompts from the prompt configuration file. services.AddSingleton(sp => { string promptsConfigPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "prompts.json"); @@ -34,38 +35,7 @@ internal static IServiceCollection AddSemanticKernelServices(this IServiceCollec services.AddSingleton(); // Add the semantic memory with backing memory store. - services.AddSingleton(serviceProvider => - { - MemoriesStoreOptions config = serviceProvider.GetRequiredService>().Value; - - switch (config.Type) - { - case MemoriesStoreOptions.MemoriesStoreType.Volatile: - return new VolatileMemoryStore(); - - case MemoriesStoreOptions.MemoriesStoreType.Qdrant: - if (config.Qdrant is null) - { - throw new InvalidOperationException( - $"MemoriesStore:Qdrant is required when MemoriesStore:Type is '{MemoriesStoreOptions.MemoriesStoreType.Qdrant}'"); - } - - return new QdrantMemoryStore( - host: config.Qdrant.Host, - port: config.Qdrant.Port, - vectorSize: config.Qdrant.VectorSize, - logger: serviceProvider.GetRequiredService>()); - - default: - throw new InvalidOperationException($"Invalid 'MemoriesStore' type '{config.Type}'."); - } - }); - - services.AddScoped(serviceProvider - => new SemanticTextMemory( - serviceProvider.GetRequiredService(), - serviceProvider.GetRequiredService>().Get(AIServiceOptions.EmbeddingPropertyName) - .ToTextEmbeddingsService(logger: serviceProvider.GetRequiredService>()))); + services.AddScoped(CreateSemanticTextMemory); // Add the planner. services.AddScoped(sp => @@ -96,10 +66,38 @@ internal static IServiceCollection AddSemanticKernelServices(this IServiceCollec return services; } + /// + /// Create the semantic memory with backing memory store. + /// + private static ISemanticTextMemory CreateSemanticTextMemory(this IServiceProvider serviceProvider) + { + MemoriesStoreOptions config = serviceProvider.GetRequiredService>().Value; + switch (config.Type) + { + case MemoriesStoreOptions.MemoriesStoreType.Volatile: + return new SemanticTextMemory( + new VolatileMemoryStore(), + serviceProvider.GetRequiredService>().Get(AIServiceOptions.EmbeddingPropertyName) + .ToTextEmbeddingsService(logger: serviceProvider.GetRequiredService>())); + + case MemoriesStoreOptions.MemoriesStoreType.Qdrant: + return new SemanticTextMemory( + new QdrantMemoryStore(config.Qdrant!.Host, config.Qdrant.Port, config.Qdrant.VectorSize, serviceProvider.GetRequiredService>()), + serviceProvider.GetRequiredService>().Get(AIServiceOptions.EmbeddingPropertyName) + .ToTextEmbeddingsService(logger: serviceProvider.GetRequiredService>())); + + case MemoriesStoreOptions.MemoriesStoreType.AzureCognitiveSearch: + return new AzureCognitiveSearchMemory(config.AzureCognitiveSearch!.Endpoint, config.AzureCognitiveSearch.Key); + + default: + throw new InvalidOperationException($"Invalid 'MemoriesStore' type '{config.Type}'."); + } + } + /// /// Add the completion backend to the kernel config /// - internal static KernelConfig AddCompletionBackend(this KernelConfig kernelConfig, AIServiceOptions aiServiceOptions) + private static KernelConfig AddCompletionBackend(this KernelConfig kernelConfig, AIServiceOptions aiServiceOptions) { switch (aiServiceOptions.AIService) { @@ -126,7 +124,7 @@ internal static KernelConfig AddCompletionBackend(this KernelConfig kernelConfig /// /// Add the embedding backend to the kernel config /// - internal static KernelConfig AddEmbeddingBackend(this KernelConfig kernelConfig, AIServiceOptions aiServiceOptions) + private static KernelConfig AddEmbeddingBackend(this KernelConfig kernelConfig, AIServiceOptions aiServiceOptions) { switch (aiServiceOptions.AIService) { @@ -158,7 +156,7 @@ internal static KernelConfig AddEmbeddingBackend(this KernelConfig kernelConfig, /// The service configuration /// Custom for HTTP requests. /// Application logger - internal static IEmbeddingGeneration ToTextEmbeddingsService(this AIServiceOptions serviceConfig, + private static IEmbeddingGeneration ToTextEmbeddingsService(this AIServiceOptions serviceConfig, HttpClient? httpClient = null, ILogger? logger = null) { diff --git a/samples/apps/copilot-chat-app/webapi/appsettings.json b/samples/apps/copilot-chat-app/webapi/appsettings.json index db2c30bc001a..273f92c1c0c2 100644 --- a/samples/apps/copilot-chat-app/webapi/appsettings.json +++ b/samples/apps/copilot-chat-app/webapi/appsettings.json @@ -44,6 +44,7 @@ // // Embeddings are used for semantically encoding memories. + // This section is ignored when MemoriesStore:Type is set to Azure Cognitive Search. // https://platform.openai.com/docs/guides/embeddings // To use Azure OpenAI as the AI embedding service: // - Set "AIService" to "AzureOpenAI" @@ -109,15 +110,21 @@ // // Memories stores are used for storing new memories and retrieving semantically similar memories. - // - Supported Types are "volatile" or "qdrant". - // - When using Qdrant, see ./README.md for local deployment instructions. + // - Supported Types are "volatile", "qdrant", or "azurecognitivesearch". + // - When using Qdrant or Azure Cognitive Search, see ./README.md for deployment instructions. + // - The "Semantic Search" feature must be enabled on Azure Cognitive Search. + // - The Embedding configuration above will not be used when Azure Cognitive Search is selected. // "MemoriesStore": { "Type": "volatile", "Qdrant": { - "Host": "http://localhost", // Endpoint of the Qdrant server - "Port": "6333", // Port of the Qdrant server - "VectorSize": 1536 // Size of the vectors used by the Qdrant server + "Host": "http://localhost", + "Port": "6333", + "VectorSize": 1536 + }, + "AzureCognitiveSearch": { + "Endpoint": "" + // "Key": "" // dotnet user-secrets set "MemoriesStore:AzureCognitiveSearch:Key" "MY_ACS_KEY" } },