| @@ -27,6 +27,7 @@ | |||
| </PropertyGroup> | |||
| <ItemGroup> | |||
| <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" /> | |||
| <PackageReference Include="Microsoft.SemanticKernel" Version="0.21.230828.2-preview" /> | |||
| </ItemGroup> | |||
| @@ -0,0 +1,167 @@ | |||
| using Microsoft.SemanticKernel.Memory; | |||
| using Microsoft.SemanticKernel; | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Linq; | |||
| using System.Text; | |||
| using System.Threading.Tasks; | |||
| using LLama.Common; | |||
| using LLamaSharp.SemanticKernel.TextEmbedding; | |||
| using Microsoft.SemanticKernel.AI.Embeddings; | |||
| namespace LLama.Examples.NewVersion | |||
| { | |||
| public class SemanticKernelMemory | |||
| { | |||
| private const string MemoryCollectionName = "SKGitHub"; | |||
| public static async Task Run() | |||
| { | |||
| var loggerFactory = ConsoleLogger.LoggerFactory; | |||
| Console.WriteLine("Example from: https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/KernelSyntaxExamples/Example14_SemanticMemory.cs"); | |||
| Console.Write("Please input your model path: "); | |||
| var modelPath = Console.ReadLine(); | |||
| var seed = 1337; | |||
| // Load weights into memory | |||
| var parameters = new ModelParams(modelPath) | |||
| { | |||
| Seed = seed, | |||
| EmbeddingMode = true, | |||
| GpuLayerCount = 50, | |||
| }; | |||
| using var model = LLamaWeights.LoadFromFile(parameters); | |||
| var embedding = new LLamaEmbedder(model, parameters); | |||
| Console.WriteLine("===================================================="); | |||
| Console.WriteLine("======== Semantic Memory (volatile, in RAM) ========"); | |||
| Console.WriteLine("===================================================="); | |||
| /* 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. | |||
| */ | |||
| var kernelWithCustomDb = Kernel.Builder | |||
| .WithLoggerFactory(ConsoleLogger.LoggerFactory) | |||
| .WithAIService<ITextEmbeddingGeneration>("local-llama-embed", new LLamaSharpEmbeddingGeneration(embedding), true) | |||
| .WithMemoryStorage(new VolatileMemoryStore()) | |||
| .Build(); | |||
| await RunExampleAsync(kernelWithCustomDb); | |||
| } | |||
| private static async Task RunExampleAsync(IKernel kernel) | |||
| { | |||
| await StoreMemoryAsync(kernel); | |||
| await SearchMemoryAsync(kernel, "How do I get started?"); | |||
| /* | |||
| Output: | |||
| 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 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 | |||
| */ | |||
| await SearchMemoryAsync(kernel, "Can I build a chat with SK?"); | |||
| /* | |||
| Output: | |||
| Query: Can I build a chat with SK? | |||
| Result 1: | |||
| URL: : https://github.com/microsoft/semantic-kernel/tree/main/samples/skills/ChatSkill/ChatGPT | |||
| Title : Sample demonstrating how to create a chat skill interfacing with ChatGPT | |||
| Result 2: | |||
| URL: : https://github.com/microsoft/semantic-kernel/blob/main/samples/apps/chat-summary-webapp-react/README.md | |||
| Title : README: README associated with a sample chat summary react-based webapp | |||
| */ | |||
| } | |||
| private static async Task SearchMemoryAsync(IKernel kernel, string query) | |||
| { | |||
| Console.WriteLine("\nQuery: " + query + "\n"); | |||
| var memories = kernel.Memory.SearchAsync(MemoryCollectionName, query, limit: 2, minRelevanceScore: 0.5); | |||
| int i = 0; | |||
| await foreach (MemoryQueryResult memory in memories) | |||
| { | |||
| Console.WriteLine($"Result {++i}:"); | |||
| Console.WriteLine(" URL: : " + memory.Metadata.Id); | |||
| Console.WriteLine(" Title : " + memory.Metadata.Description); | |||
| Console.WriteLine(" Relevance: " + memory.Relevance); | |||
| Console.WriteLine(); | |||
| } | |||
| Console.WriteLine("----------------------"); | |||
| } | |||
| private static async Task StoreMemoryAsync(IKernel 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 | |||
| */ | |||
| Console.WriteLine("\nAdding some GitHub file URLs and their descriptions to the semantic memory."); | |||
| var githubFiles = SampleData(); | |||
| var i = 0; | |||
| foreach (var entry in githubFiles) | |||
| { | |||
| var result = await kernel.Memory.SaveReferenceAsync( | |||
| collection: MemoryCollectionName, | |||
| externalSourceName: "GitHub", | |||
| externalId: entry.Key, | |||
| description: entry.Value, | |||
| text: entry.Value); | |||
| Console.WriteLine($"#{++i} saved."); | |||
| Console.WriteLine(result); | |||
| } | |||
| Console.WriteLine("\n----------------------"); | |||
| } | |||
| private static Dictionary<string, string> SampleData() | |||
| { | |||
| return new Dictionary<string, 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/dotnet/notebooks/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/dotnet/notebooks//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", | |||
| }; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,184 @@ | |||
| using System.Reflection.Metadata; | |||
| using System.Security.Cryptography; | |||
| using System.Text; | |||
| using LLama.Abstractions; | |||
| using LLama.Common; | |||
| using LLamaSharp.SemanticKernel.TextCompletion; | |||
| using LLamaSharp.SemanticKernel.TextEmbedding; | |||
| using Microsoft.Extensions.Logging; | |||
| using Microsoft.SemanticKernel; | |||
| using Microsoft.SemanticKernel.AI.ChatCompletion; | |||
| using Microsoft.SemanticKernel.AI.Embeddings; | |||
| using Microsoft.SemanticKernel.AI.TextCompletion; | |||
| using Microsoft.SemanticKernel.Memory; | |||
| using Microsoft.SemanticKernel.Skills.Core; | |||
| namespace LLama.Examples.NewVersion | |||
| { | |||
| public class SemanticKernelMemorySkill | |||
| { | |||
| private const string MemoryCollectionName = "aboutMe"; | |||
| public static async Task Run() | |||
| { | |||
| var loggerFactory = ConsoleLogger.LoggerFactory; | |||
| Console.WriteLine("Example from: https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/KernelSyntaxExamples/Example15_MemorySkill.cs"); | |||
| Console.Write("Please input your model path: "); | |||
| var modelPath = Console.ReadLine(); | |||
| var seed = 1337; | |||
| // Load weights into memory | |||
| var parameters = new ModelParams(modelPath) | |||
| { | |||
| Seed = seed, | |||
| EmbeddingMode = true, | |||
| GpuLayerCount = 50, | |||
| }; | |||
| using var model = LLamaWeights.LoadFromFile(parameters); | |||
| var embedding = new LLamaEmbedder(model, parameters); | |||
| using var context = model.CreateContext(parameters); | |||
| // TODO: This executor is most likely incorrect. | |||
| var ex = new InteractiveExecutor(context); | |||
| var builder = new KernelBuilder(); | |||
| builder.WithLoggerFactory(loggerFactory); | |||
| builder.WithAIService<ITextCompletion>("local-llama-text", new LLamaSharpTextCompletion(ex), true); | |||
| builder.WithAIService<ITextEmbeddingGeneration>("local-llama-embed", new LLamaSharpEmbeddingGeneration(embedding), true); | |||
| builder.WithMemoryStorage(new VolatileMemoryStore()); | |||
| var kernel = builder.Build(); | |||
| // ========= Store memories using the kernel ========= | |||
| await kernel.Memory.SaveInformationAsync(MemoryCollectionName, id: "info1", text: "My name is Andrea"); | |||
| await kernel.Memory.SaveInformationAsync(MemoryCollectionName, id: "info2", text: "I work as a tourist operator"); | |||
| await kernel.Memory.SaveInformationAsync(MemoryCollectionName, id: "info3", text: "I've been living in Seattle since 2005"); | |||
| await kernel.Memory.SaveInformationAsync(MemoryCollectionName, id: "info4", text: "I visited France and Italy five times since 2015"); | |||
| // ========= Store memories using semantic function ========= | |||
| // Add Memory as a skill for other functions | |||
| var memorySkill = new TextMemorySkill(kernel.Memory); | |||
| kernel.ImportSkill(memorySkill); | |||
| // Build a semantic function that saves info to memory | |||
| const string SaveFunctionDefinition = "{{save $info}}"; | |||
| var memorySaver = kernel.CreateSemanticFunction(SaveFunctionDefinition); | |||
| //await kernel.RunAsync(memorySaver, new() | |||
| //{ | |||
| // [TextMemorySkill.CollectionParam] = MemoryCollectionName, | |||
| // [TextMemorySkill.KeyParam] = "info5", | |||
| // ["info"] = "My family is from New York" | |||
| //}); | |||
| // ========= Test memory remember ========= | |||
| Console.WriteLine("========= Example: Recalling a Memory ========="); | |||
| var answer = await memorySkill.RetrieveAsync(MemoryCollectionName, "info1", loggerFactory); | |||
| Console.WriteLine("Memory associated with 'info1': {0}", answer); | |||
| answer = await memorySkill.RetrieveAsync(MemoryCollectionName, "info2", loggerFactory); | |||
| Console.WriteLine("Memory associated with 'info2': {0}", answer); | |||
| answer = await memorySkill.RetrieveAsync(MemoryCollectionName, "info3", loggerFactory); | |||
| Console.WriteLine("Memory associated with 'info3': {0}", answer); | |||
| answer = await memorySkill.RetrieveAsync(MemoryCollectionName, "info4", loggerFactory); | |||
| Console.WriteLine("Memory associated with 'info4': {0}", answer); | |||
| //answer = await memorySkill.RetrieveAsync(MemoryCollectionName, "info5", loggerFactory); | |||
| //Console.WriteLine("Memory associated with 'info5': {0}", answer); | |||
| // ========= Test memory recall ========= | |||
| Console.WriteLine("========= Example: Recalling an Idea ========="); | |||
| answer = await memorySkill.RecallAsync("where did I grow up?", MemoryCollectionName, relevance: null, limit: 2, null); | |||
| Console.WriteLine("Ask: where did I grow up?"); | |||
| Console.WriteLine("Answer:\n{0}", answer); | |||
| answer = await memorySkill.RecallAsync("where do I live?", MemoryCollectionName, relevance: null, limit: 2, null); | |||
| Console.WriteLine("Ask: where do I live?"); | |||
| Console.WriteLine("Answer:\n{0}", answer); | |||
| /* | |||
| Output: | |||
| Ask: where did I grow up? | |||
| Answer: | |||
| ["My family is from New York","I\u0027ve been living in Seattle since 2005"] | |||
| Ask: where do I live? | |||
| Answer: | |||
| ["I\u0027ve been living in Seattle since 2005","My family is from New York"] | |||
| */ | |||
| // ========= Use memory in a semantic function ========= | |||
| Console.WriteLine("========= Example: Using Recall in a Semantic Function ========="); | |||
| // Build a semantic function that uses memory to find facts | |||
| const string RecallFunctionDefinition = @" | |||
| Consider only the facts below when answering questions. | |||
| About me: {{recall 'where did I grow up?'}} | |||
| About me: {{recall 'where do I live?'}} | |||
| Question: {{$input}} | |||
| Answer: | |||
| "; | |||
| var aboutMeOracle = kernel.CreateSemanticFunction(RecallFunctionDefinition, maxTokens: 100); | |||
| var result = await kernel.RunAsync(aboutMeOracle, new("Do I live in the same town where I grew up?") | |||
| { | |||
| [TextMemorySkill.CollectionParam] = MemoryCollectionName, | |||
| [TextMemorySkill.RelevanceParam] = "0.8" | |||
| }); | |||
| Console.WriteLine("Do I live in the same town where I grew up?\n"); | |||
| Console.WriteLine(result); | |||
| /* | |||
| Output: | |||
| Do I live in the same town where I grew up? | |||
| No, I do not live in the same town where I grew up since my family is from New York and I have been living in Seattle since 2005. | |||
| */ | |||
| // ========= Remove a memory ========= | |||
| Console.WriteLine("========= Example: Forgetting a Memory ========="); | |||
| result = await kernel.RunAsync(aboutMeOracle, new("Tell me a bit about myself") | |||
| { | |||
| ["fact1"] = "What is my name?", | |||
| ["fact2"] = "What do I do for a living?", | |||
| [TextMemorySkill.RelevanceParam] = ".75" | |||
| }); | |||
| Console.WriteLine("Tell me a bit about myself\n"); | |||
| Console.WriteLine(result); | |||
| /* | |||
| Approximate Output: | |||
| Tell me a bit about myself | |||
| My name is Andrea and my family is from New York. I work as a tourist operator. | |||
| */ | |||
| await memorySkill.RemoveAsync(MemoryCollectionName, "info1", loggerFactory); | |||
| result = await kernel.RunAsync(aboutMeOracle, new("Tell me a bit about myself")); | |||
| Console.WriteLine("Tell me a bit about myself\n"); | |||
| Console.WriteLine(result); | |||
| /* | |||
| Approximate Output: | |||
| Tell me a bit about myself | |||
| I'm from a family originally from New York and I work as a tourist operator. I've been living in Seattle since 2005. | |||
| */ | |||
| } | |||
| } | |||
| } | |||
| @@ -20,6 +20,8 @@ | |||
| Console.WriteLine("10: Constrain response to json format using grammar."); | |||
| Console.WriteLine("11: Semantic Kernel Prompt."); | |||
| Console.WriteLine("12: Semantic Kernel Chat."); | |||
| Console.WriteLine("13: Semantic Kernel Memory."); | |||
| Console.WriteLine("14: Semantic Kernel Memory Skill."); | |||
| while (true) | |||
| { | |||
| @@ -78,6 +80,14 @@ | |||
| { | |||
| await SemanticKernelChat.Run(); | |||
| } | |||
| else if (choice == 13) | |||
| { | |||
| await SemanticKernelMemory.Run(); | |||
| } | |||
| else if (choice == 14) | |||
| { | |||
| await SemanticKernelMemorySkill.Run(); | |||
| } | |||
| else | |||
| { | |||
| Console.WriteLine("Cannot parse your choice. Please select again."); | |||
| @@ -0,0 +1,40 @@ | |||
| using Microsoft.Extensions.Logging; | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Linq; | |||
| using System.Text; | |||
| using System.Threading.Tasks; | |||
| namespace LLama.Examples | |||
| { | |||
| /// <summary> | |||
| /// Basic logger printing to console | |||
| /// </summary> | |||
| internal static class ConsoleLogger | |||
| { | |||
| internal static ILogger Logger => LoggerFactory.CreateLogger<object>(); | |||
| internal static ILoggerFactory LoggerFactory => s_loggerFactory.Value; | |||
| private static readonly Lazy<ILoggerFactory> s_loggerFactory = new(LogBuilder); | |||
| private static ILoggerFactory LogBuilder() | |||
| { | |||
| return Microsoft.Extensions.Logging.LoggerFactory.Create(builder => | |||
| { | |||
| builder.SetMinimumLevel(LogLevel.Warning); | |||
| builder.AddFilter("Microsoft", LogLevel.Trace); | |||
| builder.AddFilter("Microsoft", LogLevel.Debug); | |||
| builder.AddFilter("Microsoft", LogLevel.Information); | |||
| builder.AddFilter("Microsoft", LogLevel.Warning); | |||
| builder.AddFilter("Microsoft", LogLevel.Error); | |||
| builder.AddFilter("Microsoft", LogLevel.Warning); | |||
| builder.AddFilter("System", LogLevel.Warning); | |||
| builder.AddConsole(); | |||
| }); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,20 @@ | |||
| using LLama; | |||
| using Microsoft.SemanticKernel.AI.Embeddings; | |||
| namespace LLamaSharp.SemanticKernel.TextEmbedding; | |||
| public sealed class LLamaSharpEmbeddingGeneration : ITextEmbeddingGeneration | |||
| { | |||
| private LLamaEmbedder _embedder; | |||
| public LLamaSharpEmbeddingGeneration(LLamaEmbedder embedder) | |||
| { | |||
| _embedder = embedder; | |||
| } | |||
| /// <inheritdoc/> | |||
| public async Task<IList<ReadOnlyMemory<float>>> GenerateEmbeddingsAsync(IList<string> data, CancellationToken cancellationToken = default) | |||
| { | |||
| return data.Select(text => new ReadOnlyMemory<float>(_embedder.GetEmbeddings(text))).ToList(); | |||
| } | |||
| } | |||