Skip to content

Commit

Permalink
Added console chat app. uses semantic kernel, kernel memory and plugins.
Browse files Browse the repository at this point in the history
  • Loading branch information
goncalvesj committed Feb 18, 2024
1 parent 6c82c01 commit cef888e
Show file tree
Hide file tree
Showing 4 changed files with 249 additions and 0 deletions.
24 changes: 24 additions & 0 deletions Dotnet-SK-MemoryPlugin-ChatConsole/Chat.SK.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NoWarn>SKEXP0042</NoWarn>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.KernelMemory.Core" Version="0.28.240212.1" />
<PackageReference Include="Microsoft.KernelMemory.MemoryDb.AzureAISearch" Version="0.28.240212.1" />
<PackageReference Include="Microsoft.KernelMemory.SemanticKernelPlugin" Version="0.28.240212.1" />
<PackageReference Include="Microsoft.SemanticKernel" Version="1.3.0" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.AzureAISearch" Version="1.3.1-alpha" />
<PackageReference Include="Microsoft.SemanticKernel.Functions.OpenAPI" Version="1.0.0-beta8" />
<PackageReference Include="Microsoft.SemanticKernel.Planners.Handlebars" Version="1.3.0-preview" />
<PackageReference Include="Microsoft.SemanticKernel.Planners.OpenAI" Version="1.3.0-preview" />
<PackageReference Include="Microsoft.SemanticKernel.Plugins.Memory" Version="1.3.1-alpha" />
<PackageReference Include="Microsoft.SemanticKernel.Plugins.OpenApi" Version="1.3.0-alpha" />
</ItemGroup>

</Project>
25 changes: 25 additions & 0 deletions Dotnet-SK-MemoryPlugin-ChatConsole/Chat.SK.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.8.34511.84
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Chat.SK", "Chat.SK.csproj", "{F9E08994-3C60-4BA5-8A12-2636BB57E200}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F9E08994-3C60-4BA5-8A12-2636BB57E200}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F9E08994-3C60-4BA5-8A12-2636BB57E200}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F9E08994-3C60-4BA5-8A12-2636BB57E200}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F9E08994-3C60-4BA5-8A12-2636BB57E200}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3B750AC7-CD92-407F-AB2D-FA821171F64A}
EndGlobalSection
EndGlobal
168 changes: 168 additions & 0 deletions Dotnet-SK-MemoryPlugin-ChatConsole/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
using Microsoft.KernelMemory;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using System.ComponentModel;

// Disable warnings related to Semantic Kernel
#pragma warning disable SKEXP0003
#pragma warning disable SKEXP0010
#pragma warning disable SKEXP0011
#pragma warning disable SKEXP0021
#pragma warning disable SKEXP0052
#pragma warning disable SKEXP0060
#pragma warning disable SKEXP0061

// Azure OpenAI Variables
var apiKey = "";
var deploymentChatName = "";
var deploymentEmbeddingName = "";
var endpoint = "";

// Azure AI Search Variables
string searchApiKey = "";
string searchEndpoint = "";


var builder = Kernel.CreateBuilder();

builder
.AddAzureOpenAIChatCompletion(
deploymentChatName,
endpoint,
apiKey);

var kernel = builder.Build();

var embeddingConfig = new AzureOpenAIConfig
{
APIKey = apiKey,
Deployment = deploymentEmbeddingName,
Endpoint = endpoint,
APIType = AzureOpenAIConfig.APITypes.EmbeddingGeneration,
Auth = AzureOpenAIConfig.AuthTypes.APIKey
};

var chatConfig = new AzureOpenAIConfig
{
APIKey = apiKey,
Deployment = deploymentChatName,
Endpoint = endpoint,
APIType = AzureOpenAIConfig.APITypes.ChatCompletion,
Auth = AzureOpenAIConfig.AuthTypes.APIKey
};

var kernelMemory = new KernelMemoryBuilder()
.WithAzureOpenAITextGeneration(chatConfig)
.WithAzureOpenAITextEmbeddingGeneration(embeddingConfig)
.WithAzureAISearchMemoryDb(searchEndpoint, searchApiKey)
.Build<MemoryServerless>();

// Import a document to the memory, e.g. Expense Policy PDF document
await kernelMemory.ImportDocumentAsync("CHANGE_ME: FILE_LOCATION.pdf", documentId: "doc001");

// Import the memory plugin
var plugin = new MemoryPlugin(kernelMemory, waitForIngestionToComplete: true);
kernel.ImportPluginFromObject(plugin, "memory");

// Import the VCard plugin
kernel.ImportPluginFromType<VCardPlugin>();

ChatHistory history = [];

var chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();

Console.WriteLine("Hello! This is a chat console.");
Console.WriteLine(string.Empty);

var system = $@"
CHANGE_ME: WRITE YOUR ASSISTANT SYSTEM PROMPT HERE
";

history.AddMessage(AuthorRole.System, system);

// Enable auto function calling
OpenAIPromptExecutionSettings openAIPromptExecutionSettings = new()
{
ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions
};

while (true)
{
Console.WriteLine(string.Empty);
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write("Input > ");
var message = Console.ReadLine();
Console.ResetColor();

// Prompt the message to the kernel memory
var prompt = $@"
Question to Kernel Memory: {message}
Kernel Memory Answer: {{memory.ask}}
";

history.AddMessage(AuthorRole.User, prompt);

var result = await chatCompletionService.GetChatMessageContentAsync(history, openAIPromptExecutionSettings, kernel);

Console.WriteLine(string.Empty);
Console.WriteLine(string.Empty);
Console.Write("Assistant > ");
Console.WriteLine(result.Content);

history.AddMessage(AuthorRole.Assistant, result.Content);
}

public class VCardPlugin
{
const string FunctionModelDescription = @"
- This function creates a request for a Virtual Card.
- You must always ask for the user approval before creating a virtual card.
- You must always ask for the user policy details before creating a virtual card.
- You must always ask for the number of days of travel before creating a virtual card.
- You must always request the ammount to be created.
- If the ammount is bigger than the allowed from the policy deny the request.
";

[KernelFunction, Description(FunctionModelDescription)]
public string CreateCard(int ammount, int days)
{
Random random = new Random();
string cardNumber = "5" + random.Next(1, 6).ToString() + string.Concat(Enumerable.Range(0, 14).Select(n => random.Next(0, 10).ToString()));

// Calculate the Luhn check digit
int sum = 0;
for (int i = 0; i < 15; i++)
{
int digit = int.Parse(cardNumber[i].ToString());
if (i % 2 == 0)
{
digit *= 2;
if (digit > 9)
{
digit -= 9;
}
}
sum += digit;
}

int checkDigit = (10 - (sum % 10)) % 10;
cardNumber += checkDigit.ToString();

// Generate a random expiry date in the future
int expiryMonth = random.Next(1, 13); // Month is between 1 and 12
int expiryYear = DateTime.Now.Year + random.Next(1, 6); // Year is between now and 5 years from now

// Generate a random 3-digit CVC
int cvc = random.Next(100, 1000); // CVC is a 3-digit number

Console.ForegroundColor = ConsoleColor.DarkBlue;
Console.WriteLine($"[Card created with ammount {ammount} for {days} days]");
Console.WriteLine($"Card Number: {cardNumber}");
Console.WriteLine($"Expiry Date: {expiryMonth:D2}/{expiryYear}");
Console.WriteLine($"CVC: {cvc}");
Console.ResetColor();

return "Virtual Card created successfully.";
}
}
32 changes: 32 additions & 0 deletions Dotnet-SK-MemoryPlugin-ChatConsole/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Intro

This application is a .NET console chat application.

The application replicates a chat application where the AI assistant uses techniques like RAG and automatic function calling to assist the user.
An example scenario would be an internal chat app where the user can ask questions about the companies expense/travel policies and request a creation of virtual card to use in a trip.

The main goal is to:

- Integrate a semantic kernel memory into the application, which will allow the LLM to remember and recall information from Azure AI Search.
- Demonstrate how to implement plugins in a semantic kernel enabled app.

Requirements:

- a Azure OpenAI Service.
- a Azure AI Search Service.
- some public document to be indexed in the Azure AI Search Service.

## Main Project Structure

### Chat.SK

Main project that contains the chat application. It uses the Semantic Kernel and Kernel Memory nuget packages.

## Running the Application

Steps:

1. Update the variables for Azure Open Ai and AI Search in `Program.cs`.
1. Update location of the location of the public document in `Program.cs` to be imported to the Kernel Memory.
1. Add an example system prompt.
1. Run with `dotnet run` or `F5`.

0 comments on commit cef888e

Please sign in to comment.