Skip to content

Commit f3e23d6

Browse files
authored
Merge pull request #139 from drasticactions/embeddings-semantickernel
Add TextEmbedding for Semantic Kernel
2 parents 037472c + ab63308 commit f3e23d6

File tree

6 files changed

+250
-0
lines changed

6 files changed

+250
-0
lines changed

LLama.Examples/LLama.Examples.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
</PropertyGroup>
2828

2929
<ItemGroup>
30+
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" />
3031
<PackageReference Include="Microsoft.SemanticKernel" Version="0.21.230828.2-preview" />
3132
</ItemGroup>
3233

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
using Microsoft.SemanticKernel.Memory;
2+
using Microsoft.SemanticKernel;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using System.Text;
7+
using System.Threading.Tasks;
8+
using LLama.Common;
9+
using LLamaSharp.SemanticKernel.TextEmbedding;
10+
using Microsoft.SemanticKernel.AI.Embeddings;
11+
12+
namespace LLama.Examples.NewVersion
13+
{
14+
public class SemanticKernelMemory
15+
{
16+
private const string MemoryCollectionName = "SKGitHub";
17+
18+
public static async Task Run()
19+
{
20+
var loggerFactory = ConsoleLogger.LoggerFactory;
21+
Console.WriteLine("Example from: https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/KernelSyntaxExamples/Example14_SemanticMemory.cs");
22+
Console.Write("Please input your model path: ");
23+
var modelPath = Console.ReadLine();
24+
25+
var seed = 1337;
26+
// Load weights into memory
27+
var parameters = new ModelParams(modelPath)
28+
{
29+
Seed = seed,
30+
EmbeddingMode = true
31+
};
32+
33+
using var model = LLamaWeights.LoadFromFile(parameters);
34+
var embedding = new LLamaEmbedder(model, parameters);
35+
36+
Console.WriteLine("====================================================");
37+
Console.WriteLine("======== Semantic Memory (volatile, in RAM) ========");
38+
Console.WriteLine("====================================================");
39+
40+
/* You can build your own semantic memory combining an Embedding Generator
41+
* with a Memory storage that supports search by similarity (ie semantic search).
42+
*
43+
* In this example we use a volatile memory, a local simulation of a vector DB.
44+
*
45+
* You can replace VolatileMemoryStore with Qdrant (see QdrantMemoryStore connector)
46+
* or implement your connectors for Pinecone, Vespa, Postgres + pgvector, SQLite VSS, etc.
47+
*/
48+
49+
var kernelWithCustomDb = Kernel.Builder
50+
.WithLoggerFactory(ConsoleLogger.LoggerFactory)
51+
.WithAIService<ITextEmbeddingGeneration>("local-llama-embed", new LLamaSharpEmbeddingGeneration(embedding), true)
52+
.WithMemoryStorage(new VolatileMemoryStore())
53+
.Build();
54+
55+
await RunExampleAsync(kernelWithCustomDb);
56+
}
57+
58+
private static async Task RunExampleAsync(IKernel kernel)
59+
{
60+
await StoreMemoryAsync(kernel);
61+
62+
await SearchMemoryAsync(kernel, "How do I get started?");
63+
64+
/*
65+
Output:
66+
67+
Query: How do I get started?
68+
69+
Result 1:
70+
URL: : https://github.com/microsoft/semantic-kernel/blob/main/README.md
71+
Title : README: Installation, getting started, and how to contribute
72+
73+
Result 2:
74+
URL: : https://github.com/microsoft/semantic-kernel/blob/main/samples/dotnet-jupyter-notebooks/00-getting-started.ipynb
75+
Title : Jupyter notebook describing how to get started with the Semantic Kernel
76+
77+
*/
78+
79+
await SearchMemoryAsync(kernel, "Can I build a chat with SK?");
80+
81+
/*
82+
Output:
83+
84+
Query: Can I build a chat with SK?
85+
86+
Result 1:
87+
URL: : https://github.com/microsoft/semantic-kernel/tree/main/samples/skills/ChatSkill/ChatGPT
88+
Title : Sample demonstrating how to create a chat skill interfacing with ChatGPT
89+
90+
Result 2:
91+
URL: : https://github.com/microsoft/semantic-kernel/blob/main/samples/apps/chat-summary-webapp-react/README.md
92+
Title : README: README associated with a sample chat summary react-based webapp
93+
94+
*/
95+
96+
await SearchMemoryAsync(kernel, "Jupyter notebook");
97+
98+
await SearchMemoryAsync(kernel, "README: README associated with a sample chat summary react-based webapp");
99+
100+
await SearchMemoryAsync(kernel, "Jupyter notebook describing how to pass prompts from a file to a semantic skill or function");
101+
}
102+
103+
private static async Task SearchMemoryAsync(IKernel kernel, string query)
104+
{
105+
Console.WriteLine("\nQuery: " + query + "\n");
106+
107+
var memories = kernel.Memory.SearchAsync(MemoryCollectionName, query, limit: 10, minRelevanceScore: 0.5);
108+
109+
int i = 0;
110+
await foreach (MemoryQueryResult memory in memories)
111+
{
112+
Console.WriteLine($"Result {++i}:");
113+
Console.WriteLine(" URL: : " + memory.Metadata.Id);
114+
Console.WriteLine(" Title : " + memory.Metadata.Description);
115+
Console.WriteLine(" Relevance: " + memory.Relevance);
116+
Console.WriteLine();
117+
}
118+
119+
Console.WriteLine("----------------------");
120+
}
121+
122+
private static async Task StoreMemoryAsync(IKernel kernel)
123+
{
124+
/* Store some data in the semantic memory.
125+
*
126+
* When using Azure Cognitive Search the data is automatically indexed on write.
127+
*
128+
* When using the combination of VolatileStore and Embedding generation, SK takes
129+
* care of creating and storing the index
130+
*/
131+
132+
Console.WriteLine("\nAdding some GitHub file URLs and their descriptions to the semantic memory.");
133+
var githubFiles = SampleData();
134+
var i = 0;
135+
foreach (var entry in githubFiles)
136+
{
137+
var result = await kernel.Memory.SaveReferenceAsync(
138+
collection: MemoryCollectionName,
139+
externalSourceName: "GitHub",
140+
externalId: entry.Key,
141+
description: entry.Value,
142+
text: entry.Value);
143+
144+
Console.WriteLine($"#{++i} saved.");
145+
Console.WriteLine(result);
146+
}
147+
148+
Console.WriteLine("\n----------------------");
149+
}
150+
151+
private static Dictionary<string, string> SampleData()
152+
{
153+
return new Dictionary<string, string>
154+
{
155+
["https://github.com/microsoft/semantic-kernel/blob/main/README.md"]
156+
= "README: Installation, getting started, and how to contribute",
157+
["https://github.com/microsoft/semantic-kernel/blob/main/dotnet/notebooks/02-running-prompts-from-file.ipynb"]
158+
= "Jupyter notebook describing how to pass prompts from a file to a semantic skill or function",
159+
["https://github.com/microsoft/semantic-kernel/blob/main/dotnet/notebooks//00-getting-started.ipynb"]
160+
= "Jupyter notebook describing how to get started with the Semantic Kernel",
161+
["https://github.com/microsoft/semantic-kernel/tree/main/samples/skills/ChatSkill/ChatGPT"]
162+
= "Sample demonstrating how to create a chat skill interfacing with ChatGPT",
163+
["https://github.com/microsoft/semantic-kernel/blob/main/dotnet/src/SemanticKernel/Memory/VolatileMemoryStore.cs"]
164+
= "C# class that defines a volatile embedding store",
165+
["https://github.com/microsoft/semantic-kernel/blob/main/samples/dotnet/KernelHttpServer/README.md"]
166+
= "README: How to set up a Semantic Kernel Service API using Azure Function Runtime v4",
167+
["https://github.com/microsoft/semantic-kernel/blob/main/samples/apps/chat-summary-webapp-react/README.md"]
168+
= "README: README associated with a sample chat summary react-based webapp",
169+
};
170+
}
171+
}
172+
}

LLama.Examples/NewVersion/TestRunner.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public static async Task Run()
2020
Console.WriteLine("10: Constrain response to json format using grammar.");
2121
Console.WriteLine("11: Semantic Kernel Prompt.");
2222
Console.WriteLine("12: Semantic Kernel Chat.");
23+
Console.WriteLine("13: Semantic Kernel Memory.");
2324

2425
while (true)
2526
{
@@ -78,6 +79,10 @@ public static async Task Run()
7879
{
7980
await SemanticKernelChat.Run();
8081
}
82+
else if (choice == 13)
83+
{
84+
await SemanticKernelMemory.Run();
85+
}
8186
else
8287
{
8388
Console.WriteLine("Cannot parse your choice. Please select again.");

LLama.Examples/RepoUtils.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using Microsoft.Extensions.Logging;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
8+
namespace LLama.Examples
9+
{
10+
/// <summary>
11+
/// Basic logger printing to console
12+
/// </summary>
13+
internal static class ConsoleLogger
14+
{
15+
internal static ILogger Logger => LoggerFactory.CreateLogger<object>();
16+
17+
internal static ILoggerFactory LoggerFactory => s_loggerFactory.Value;
18+
19+
private static readonly Lazy<ILoggerFactory> s_loggerFactory = new(LogBuilder);
20+
21+
private static ILoggerFactory LogBuilder()
22+
{
23+
return Microsoft.Extensions.Logging.LoggerFactory.Create(builder =>
24+
{
25+
builder.SetMinimumLevel(LogLevel.Warning);
26+
27+
builder.AddFilter("Microsoft", LogLevel.Trace);
28+
builder.AddFilter("Microsoft", LogLevel.Debug);
29+
builder.AddFilter("Microsoft", LogLevel.Information);
30+
builder.AddFilter("Microsoft", LogLevel.Warning);
31+
builder.AddFilter("Microsoft", LogLevel.Error);
32+
33+
builder.AddFilter("Microsoft", LogLevel.Warning);
34+
builder.AddFilter("System", LogLevel.Warning);
35+
36+
builder.AddConsole();
37+
});
38+
}
39+
}
40+
}

LLama.SemanticKernel/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ For reference on how to implement it, view the following examples:
66

77
- [SemanticKernelChat](../LLama.Examples/NewVersion/SemanticKernelChat.cs)
88
- [SemanticKernelPrompt](../LLama.Examples/NewVersion/SemanticKernelPrompt.cs)
9+
- [SemanticKernelMemory](../LLama.Examples/NewVersion/SemanticKernelMemory.cs)
910

1011
## ITextCompletion
1112
```csharp
@@ -24,3 +25,14 @@ using var context = model.CreateContext(parameters);
2425
var ex = new InteractiveExecutor(context);
2526
var chatGPT = new LLamaSharpChatCompletion(ex);
2627
```
28+
29+
## ITextEmbeddingGeneration
30+
```csharp
31+
using var model = LLamaWeights.LoadFromFile(parameters);
32+
var embedding = new LLamaEmbedder(model, parameters);
33+
var kernelWithCustomDb = Kernel.Builder
34+
.WithLoggerFactory(ConsoleLogger.LoggerFactory)
35+
.WithAIService<ITextEmbeddingGeneration>("local-llama-embed", new LLamaSharpEmbeddingGeneration(embedding), true)
36+
.WithMemoryStorage(new VolatileMemoryStore())
37+
.Build();
38+
```
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using LLama;
2+
using Microsoft.SemanticKernel.AI.Embeddings;
3+
4+
namespace LLamaSharp.SemanticKernel.TextEmbedding;
5+
6+
public sealed class LLamaSharpEmbeddingGeneration : ITextEmbeddingGeneration
7+
{
8+
private LLamaEmbedder _embedder;
9+
10+
public LLamaSharpEmbeddingGeneration(LLamaEmbedder embedder)
11+
{
12+
_embedder = embedder;
13+
}
14+
15+
/// <inheritdoc/>
16+
public async Task<IList<ReadOnlyMemory<float>>> GenerateEmbeddingsAsync(IList<string> data, CancellationToken cancellationToken = default)
17+
{
18+
return data.Select(text => new ReadOnlyMemory<float>(_embedder.GetEmbeddings(text))).ToList();
19+
}
20+
}

0 commit comments

Comments
 (0)