-
Notifications
You must be signed in to change notification settings - Fork 189
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[C#] feat: Add Kernel Memory Data source to Teams Chef Bot (#1222)
## Linked issues closes: #1200 (issue number) ## Details * Add KernelMemory data source into Teams Chef Bot * Fix minor bug in `ChatMessage` ## Attestation Checklist - [x] My code follows the style guidelines of this project - I have checked for/fixed spelling, linting, and other errors - I have commented my code for clarity - I have made corresponding changes to the documentation (updating the doc strings in the code is sufficient) - My changes generate no new warnings - I have added tests that validates my changes, and provides sufficient test coverage. I have tested with: - Local testing - E2E testing in Teams - New and existing unit tests pass locally with my changes
- Loading branch information
Showing
27 changed files
with
1,852 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
125 changes: 125 additions & 0 deletions
125
dotnet/samples/04.ai.a.teamsChefBot/KernelMemoryDataSource.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
using Microsoft.Bot.Builder; | ||
using Microsoft.KernelMemory; | ||
using Microsoft.Teams.AI.AI.DataSources; | ||
using Microsoft.Teams.AI.AI.Prompts.Sections; | ||
using Microsoft.Teams.AI.AI.Tokenizers; | ||
using Microsoft.Teams.AI.State; | ||
using System.Text; | ||
|
||
namespace TeamsChefBot | ||
{ | ||
/// <summary> | ||
/// The class connects the Kernel Memory library data source to the bot. | ||
/// Kernel Memory is a library that allows you to index and query any data using LLM and natural language, | ||
/// tracking sources and showing citations (https://github.com/microsoft/kernel-memory). | ||
/// </summary> | ||
public class KernelMemoryDataSource : IDataSource | ||
{ | ||
private readonly IKernelMemory _kernelMemory; | ||
private readonly Task? _ingestTask; | ||
|
||
public KernelMemoryDataSource(string name, IKernelMemory memoryInstance) | ||
{ | ||
ArgumentNullException.ThrowIfNull(memoryInstance); | ||
|
||
this._kernelMemory = memoryInstance; | ||
this.Name = name; | ||
|
||
if (memoryInstance.GetDocumentStatusAsync("doc-1").Result?.Completed != true) | ||
{ | ||
// Ingest documents on construction | ||
this._ingestTask = this.IngestAsync(); | ||
} | ||
} | ||
|
||
public string Name { get; } | ||
|
||
/// <summary> | ||
/// Loads documents from the 'files' folder into Kernel Memory's in-memory vector database. | ||
/// </summary> | ||
/// <returns></returns> | ||
private async Task IngestAsync() | ||
{ | ||
Console.WriteLine("Loading documents from the 'files' folder into Kernel Memory's in-memory vector database"); | ||
|
||
var importTasks = new List<Task>(); | ||
string[] Documents = Directory.GetFiles("files"); | ||
|
||
int i = 0; | ||
foreach (string doc in Documents) | ||
{ | ||
importTasks.Add(this._kernelMemory.ImportDocumentAsync(doc, documentId: $"doc-{i}")); | ||
i++; | ||
} | ||
|
||
await Task.WhenAll(importTasks); | ||
} | ||
|
||
public async Task<RenderedPromptSection<string>> RenderDataAsync(ITurnContext context, IMemory memory, ITokenizer tokenizer, int maxTokens, CancellationToken cancellationToken = default) | ||
{ | ||
if (this._ingestTask?.IsCompleted == false) | ||
{ | ||
// Wait for ingestion to complete | ||
await _ingestTask; | ||
} | ||
|
||
string? ask = memory.GetValue("temp.input") as string; | ||
|
||
if (ask == null) | ||
{ | ||
return new RenderedPromptSection<string>(string.Empty, 0); | ||
} | ||
|
||
// Query index for all relevant documents | ||
SearchResult result = await this._kernelMemory.SearchAsync(ask); | ||
|
||
if (result.NoResult) | ||
{ | ||
Console.WriteLine("No results when querying Kernel Memory found"); | ||
return new RenderedPromptSection<string>(string.Empty, 0); | ||
} | ||
|
||
List<Citation> citations = result.Results; | ||
|
||
// Add documents until you run out of tokens | ||
int length = 0; | ||
StringBuilder output = new(); | ||
string connector = ""; | ||
bool maxTokensReached = false; | ||
foreach (Citation citation in citations) | ||
{ | ||
// Start a new doc | ||
StringBuilder doc = new(); | ||
doc.Append($"{connector}<context>\n"); | ||
length += tokenizer.Encode($"{connector}<context>\n").Count; | ||
// Add ending tag count to token count | ||
length += tokenizer.Encode("</context>\n").Count; | ||
|
||
foreach (var partition in citation.Partitions) | ||
{ | ||
// Add the partition to the doc | ||
int partitionLength = tokenizer.Encode(partition.Text).Count; | ||
int remainingTokens = maxTokens - (length + partitionLength); | ||
if (remainingTokens < 0) | ||
{ | ||
maxTokensReached = true; | ||
break; | ||
} | ||
length += partitionLength; | ||
doc.Append($"{partition.Text}\n"); | ||
} | ||
|
||
doc.Append("</context>\n"); | ||
output.Append(doc.ToString()); | ||
connector = "\n\n"; | ||
|
||
if (maxTokensReached) | ||
{ | ||
break; | ||
} | ||
} | ||
|
||
return new RenderedPromptSection<string>(output.ToString(), length, length > maxTokens); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Each document in this folder is a markdown file that was scraped from the Teams AI Github repository. This knowledge base will be used by the Teams Chef bot to answer questions about the Teams AI library. |
Oops, something went wrong.