Skip to content

Commit 67a4854

Browse files
authored
CopilotChat: Add Azure Cog Search for Semantic Memory w/ IOptions fix (#866)
### Motivation and Context Previous change introduced bug with configuration. ### Description Changes ISemanticTextMemory from Singleton to Scoped.
1 parent dac05fc commit 67a4854

File tree

5 files changed

+82
-42
lines changed

5 files changed

+82
-42
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
3+
using System.ComponentModel.DataAnnotations;
4+
5+
namespace SemanticKernel.Service.Config;
6+
7+
/// <summary>
8+
/// Configuration settings for connecting to Azure Cognitive Search.
9+
/// </summary>
10+
public class AzureCognitiveSearchOptions
11+
{
12+
/// <summary>
13+
/// Gets or sets the endpoint protocol and host (e.g. https://contoso.search.windows.net).
14+
/// </summary>
15+
[Required, Url]
16+
public string Endpoint { get; set; } = string.Empty;
17+
18+
/// <summary>
19+
/// Key to access Azure Cognitive Search.
20+
/// </summary>
21+
[Required, NotEmptyOrWhitespace]
22+
public string Key { get; set; } = string.Empty;
23+
}

samples/apps/copilot-chat-app/webapi/Config/MemoriesStoreOptions.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,12 @@ public enum MemoriesStoreType
2222
/// <summary>
2323
/// Qdrant based persistent memories store.
2424
/// </summary>
25-
Qdrant
25+
Qdrant,
26+
27+
/// <summary>
28+
/// Azure Cognitive Search persistent memories store.
29+
/// </summary>
30+
AzureCognitiveSearch
2631
}
2732

2833
/// <summary>
@@ -35,4 +40,10 @@ public enum MemoriesStoreType
3540
/// </summary>
3641
[RequiredOnPropertyValue(nameof(Type), MemoriesStoreType.Qdrant)]
3742
public QdrantOptions? Qdrant { get; set; }
43+
44+
/// <summary>
45+
/// Gets or sets the configuration for the Azure Cognitive Search memories store.
46+
/// </summary>
47+
[RequiredOnPropertyValue(nameof(Type), MemoriesStoreType.AzureCognitiveSearch)]
48+
public AzureCognitiveSearchOptions? AzureCognitiveSearch { get; set; }
3849
}

samples/apps/copilot-chat-app/webapi/CopilotChatApi.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
<ItemGroup>
3131
<ProjectReference Include="..\..\..\..\dotnet\src\Connectors\Connectors.AI.OpenAI\Connectors.AI.OpenAI.csproj" />
32+
<ProjectReference Include="..\..\..\..\dotnet\src\Connectors\Connectors.Memory.AzureCognitiveSearch\Connectors.Memory.AzureCognitiveSearch.csproj" />
3233
<ProjectReference Include="..\..\..\..\dotnet\src\Skills\Skills.MsGraph\Skills.MsGraph.csproj" />
3334
<ProjectReference Include="..\..\..\..\dotnet\src\Skills\Skills.OpenAPI\Skills.OpenAPI.csproj" />
3435
<ProjectReference Include="..\..\..\..\dotnet\src\Connectors\Connectors.Memory.Qdrant\Connectors.Memory.Qdrant.csproj" />

samples/apps/copilot-chat-app/webapi/SemanticKernelExtensions.cs

Lines changed: 34 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Microsoft.SemanticKernel;
77
using Microsoft.SemanticKernel.AI.Embeddings;
88
using Microsoft.SemanticKernel.Connectors.AI.OpenAI.TextEmbedding;
9+
using Microsoft.SemanticKernel.Connectors.Memory.AzureCognitiveSearch;
910
using Microsoft.SemanticKernel.Connectors.Memory.Qdrant;
1011
using Microsoft.SemanticKernel.Memory;
1112
using Microsoft.SemanticKernel.SkillDefinition;
@@ -22,7 +23,7 @@ internal static class SemanticKernelExtensions
2223
/// </summary>
2324
internal static IServiceCollection AddSemanticKernelServices(this IServiceCollection services)
2425
{
25-
// The chat skill's prompts are stored in a separate file.
26+
// Load the chat skill's prompts from the prompt configuration file.
2627
services.AddSingleton<PromptsConfig>(sp =>
2728
{
2829
string promptsConfigPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "prompts.json");
@@ -34,38 +35,7 @@ internal static IServiceCollection AddSemanticKernelServices(this IServiceCollec
3435
services.AddSingleton<PromptSettings>();
3536

3637
// Add the semantic memory with backing memory store.
37-
services.AddSingleton<IMemoryStore>(serviceProvider =>
38-
{
39-
MemoriesStoreOptions config = serviceProvider.GetRequiredService<IOptions<MemoriesStoreOptions>>().Value;
40-
41-
switch (config.Type)
42-
{
43-
case MemoriesStoreOptions.MemoriesStoreType.Volatile:
44-
return new VolatileMemoryStore();
45-
46-
case MemoriesStoreOptions.MemoriesStoreType.Qdrant:
47-
if (config.Qdrant is null)
48-
{
49-
throw new InvalidOperationException(
50-
$"MemoriesStore:Qdrant is required when MemoriesStore:Type is '{MemoriesStoreOptions.MemoriesStoreType.Qdrant}'");
51-
}
52-
53-
return new QdrantMemoryStore(
54-
host: config.Qdrant.Host,
55-
port: config.Qdrant.Port,
56-
vectorSize: config.Qdrant.VectorSize,
57-
logger: serviceProvider.GetRequiredService<ILogger<QdrantMemoryStore>>());
58-
59-
default:
60-
throw new InvalidOperationException($"Invalid 'MemoriesStore' type '{config.Type}'.");
61-
}
62-
});
63-
64-
services.AddScoped<ISemanticTextMemory>(serviceProvider
65-
=> new SemanticTextMemory(
66-
serviceProvider.GetRequiredService<IMemoryStore>(),
67-
serviceProvider.GetRequiredService<IOptionsSnapshot<AIServiceOptions>>().Get(AIServiceOptions.EmbeddingPropertyName)
68-
.ToTextEmbeddingsService(logger: serviceProvider.GetRequiredService<ILogger<AIServiceOptions>>())));
38+
services.AddScoped<ISemanticTextMemory>(CreateSemanticTextMemory);
6939

7040
// Add the planner.
7141
services.AddScoped<CopilotChatPlanner>(sp =>
@@ -96,10 +66,38 @@ internal static IServiceCollection AddSemanticKernelServices(this IServiceCollec
9666
return services;
9767
}
9868

69+
/// <summary>
70+
/// Create the semantic memory with backing memory store.
71+
/// </summary>
72+
private static ISemanticTextMemory CreateSemanticTextMemory(this IServiceProvider serviceProvider)
73+
{
74+
MemoriesStoreOptions config = serviceProvider.GetRequiredService<IOptions<MemoriesStoreOptions>>().Value;
75+
switch (config.Type)
76+
{
77+
case MemoriesStoreOptions.MemoriesStoreType.Volatile:
78+
return new SemanticTextMemory(
79+
new VolatileMemoryStore(),
80+
serviceProvider.GetRequiredService<IOptionsSnapshot<AIServiceOptions>>().Get(AIServiceOptions.EmbeddingPropertyName)
81+
.ToTextEmbeddingsService(logger: serviceProvider.GetRequiredService<ILogger<AIServiceOptions>>()));
82+
83+
case MemoriesStoreOptions.MemoriesStoreType.Qdrant:
84+
return new SemanticTextMemory(
85+
new QdrantMemoryStore(config.Qdrant!.Host, config.Qdrant.Port, config.Qdrant.VectorSize, serviceProvider.GetRequiredService<ILogger<QdrantMemoryStore>>()),
86+
serviceProvider.GetRequiredService<IOptionsSnapshot<AIServiceOptions>>().Get(AIServiceOptions.EmbeddingPropertyName)
87+
.ToTextEmbeddingsService(logger: serviceProvider.GetRequiredService<ILogger<AIServiceOptions>>()));
88+
89+
case MemoriesStoreOptions.MemoriesStoreType.AzureCognitiveSearch:
90+
return new AzureCognitiveSearchMemory(config.AzureCognitiveSearch!.Endpoint, config.AzureCognitiveSearch.Key);
91+
92+
default:
93+
throw new InvalidOperationException($"Invalid 'MemoriesStore' type '{config.Type}'.");
94+
}
95+
}
96+
9997
/// <summary>
10098
/// Add the completion backend to the kernel config
10199
/// </summary>
102-
internal static KernelConfig AddCompletionBackend(this KernelConfig kernelConfig, AIServiceOptions aiServiceOptions)
100+
private static KernelConfig AddCompletionBackend(this KernelConfig kernelConfig, AIServiceOptions aiServiceOptions)
103101
{
104102
switch (aiServiceOptions.AIService)
105103
{
@@ -126,7 +124,7 @@ internal static KernelConfig AddCompletionBackend(this KernelConfig kernelConfig
126124
/// <summary>
127125
/// Add the embedding backend to the kernel config
128126
/// </summary>
129-
internal static KernelConfig AddEmbeddingBackend(this KernelConfig kernelConfig, AIServiceOptions aiServiceOptions)
127+
private static KernelConfig AddEmbeddingBackend(this KernelConfig kernelConfig, AIServiceOptions aiServiceOptions)
130128
{
131129
switch (aiServiceOptions.AIService)
132130
{
@@ -158,7 +156,7 @@ internal static KernelConfig AddEmbeddingBackend(this KernelConfig kernelConfig,
158156
/// <param name="serviceConfig">The service configuration</param>
159157
/// <param name="httpClient">Custom <see cref="HttpClient"/> for HTTP requests.</param>
160158
/// <param name="logger">Application logger</param>
161-
internal static IEmbeddingGeneration<string, float> ToTextEmbeddingsService(this AIServiceOptions serviceConfig,
159+
private static IEmbeddingGeneration<string, float> ToTextEmbeddingsService(this AIServiceOptions serviceConfig,
162160
HttpClient? httpClient = null,
163161
ILogger? logger = null)
164162
{

samples/apps/copilot-chat-app/webapi/appsettings.json

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444

4545
//
4646
// Embeddings are used for semantically encoding memories.
47+
// This section is ignored when MemoriesStore:Type is set to Azure Cognitive Search.
4748
// https://platform.openai.com/docs/guides/embeddings
4849
// To use Azure OpenAI as the AI embedding service:
4950
// - Set "AIService" to "AzureOpenAI"
@@ -109,15 +110,21 @@
109110

110111
//
111112
// Memories stores are used for storing new memories and retrieving semantically similar memories.
112-
// - Supported Types are "volatile" or "qdrant".
113-
// - When using Qdrant, see ./README.md for local deployment instructions.
113+
// - Supported Types are "volatile", "qdrant", or "azurecognitivesearch".
114+
// - When using Qdrant or Azure Cognitive Search, see ./README.md for deployment instructions.
115+
// - The "Semantic Search" feature must be enabled on Azure Cognitive Search.
116+
// - The Embedding configuration above will not be used when Azure Cognitive Search is selected.
114117
//
115118
"MemoriesStore": {
116119
"Type": "volatile",
117120
"Qdrant": {
118-
"Host": "http://localhost", // Endpoint of the Qdrant server
119-
"Port": "6333", // Port of the Qdrant server
120-
"VectorSize": 1536 // Size of the vectors used by the Qdrant server
121+
"Host": "http://localhost",
122+
"Port": "6333",
123+
"VectorSize": 1536
124+
},
125+
"AzureCognitiveSearch": {
126+
"Endpoint": ""
127+
// "Key": "" // dotnet user-secrets set "MemoriesStore:AzureCognitiveSearch:Key" "MY_ACS_KEY"
121128
}
122129
},
123130

0 commit comments

Comments
 (0)