chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>SemanticKernel.AotCompatibility</RootNamespace>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<PublishAot>true</PublishAot>
|
||||
<TrimmerSingleWarn>false</TrimmerSingleWarn>
|
||||
<NoWarn>VSTHRD111,CA2007;IDE1006,SKEXP0120</NoWarn>
|
||||
<UserSecretsId>5ee045b0-aea3-4f08-8d31-32d1a6f8fed0</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\src\Connectors\Connectors.Onnx\Connectors.Onnx.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\SemanticKernel.Abstractions\SemanticKernel.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\SemanticKernel.Core\SemanticKernel.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
using SemanticKernel.AotCompatibility.Plugins;
|
||||
|
||||
namespace SemanticKernel.AotCompatibility.JsonSerializerContexts;
|
||||
|
||||
[JsonSerializable(typeof(Location))]
|
||||
internal sealed partial class LocationJsonSerializerContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
using SemanticKernel.AotCompatibility.Plugins;
|
||||
|
||||
namespace SemanticKernel.AotCompatibility.JsonSerializerContexts;
|
||||
|
||||
[JsonSerializable(typeof(Weather))]
|
||||
internal sealed partial class WeatherJsonSerializerContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.SemanticKernel;
|
||||
using SemanticKernel.AotCompatibility.JsonSerializerContexts;
|
||||
using SemanticKernel.AotCompatibility.Plugins;
|
||||
|
||||
namespace SemanticKernel.AotCompatibility;
|
||||
|
||||
/// <summary>
|
||||
/// This class contains samples of how to create and invoke kernel functions in AOT applications.
|
||||
/// </summary>
|
||||
internal static class KernelFunctionSamples
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a kernel function from a lambda and invokes it.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Other overloads of KernelFunctionFactory.CreateFromMethod can also be used to create functions,
|
||||
/// as well as the Kernel.CreateFunctionFromMethod extension methods.
|
||||
/// </remarks>
|
||||
public static async Task CreateFunctionFromLambda(IConfigurationRoot _)
|
||||
{
|
||||
Kernel kernel = new();
|
||||
|
||||
// Create JsonSerializerOptions with custom JsonSerializerContexts for the Location and Weather types that are used in the lambda below.
|
||||
// This is necessary for JsonSerializer to infer the type information for these types in AOT applications.
|
||||
JsonSerializerOptions options = new();
|
||||
options.TypeInfoResolverChain.Add(WeatherJsonSerializerContext.Default);
|
||||
options.TypeInfoResolverChain.Add(LocationJsonSerializerContext.Default);
|
||||
|
||||
// Create a kernel function.
|
||||
KernelFunction function = KernelFunctionFactory.CreateFromMethod(
|
||||
method: (Location location) => location.City == "Boston" ? new Weather { Temperature = 61, Condition = "rainy" } : throw new NotImplementedException(),
|
||||
jsonSerializerOptions: options);
|
||||
|
||||
// Invoke the function
|
||||
KernelArguments arguments = new() { ["location"] = new Location("USA", "Boston") };
|
||||
|
||||
FunctionResult functionResult = await function.InvokeAsync(kernel, arguments);
|
||||
|
||||
// Display the result
|
||||
Weather weather = functionResult.GetValue<Weather>()!;
|
||||
Console.WriteLine($"Temperature: {weather.Temperature}, Condition: {weather.Condition}");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.SemanticKernel;
|
||||
using SemanticKernel.AotCompatibility.JsonSerializerContexts;
|
||||
using SemanticKernel.AotCompatibility.Plugins;
|
||||
|
||||
namespace SemanticKernel.AotCompatibility;
|
||||
|
||||
/// <summary>
|
||||
/// This class contains samples of how to create, import and add kernel plugins and invoke their functions in AOT applications.
|
||||
/// </summary>
|
||||
internal static class KernelPluginSamples
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a kernel plugin from a type and invokes its function.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The KernelPluginFactory class provides other methods such as CreateFromObject and CreateFromFunctions,
|
||||
/// which can be used to create a plugin from a class instance or a list of functions.
|
||||
/// Additionally, the Kernel.CreatePluginFrom* extension methods are available for similar purposes.
|
||||
/// </remarks>
|
||||
public static async Task CreatePluginFromType(IConfigurationRoot _)
|
||||
{
|
||||
Kernel kernel = new();
|
||||
|
||||
// Create JsonSerializerOptions with custom JsonSerializerContexts for the Location and Weather types that are used by the plugin below.
|
||||
// This is necessary for JsonSerializer to infer the type information for these types in AOT applications.
|
||||
JsonSerializerOptions options = new();
|
||||
options.TypeInfoResolverChain.Add(WeatherJsonSerializerContext.Default);
|
||||
options.TypeInfoResolverChain.Add(LocationJsonSerializerContext.Default);
|
||||
|
||||
// Create a kernel plugin
|
||||
KernelPlugin plugin = KernelPluginFactory.CreateFromType<WeatherPlugin>(options, "weather_utils");
|
||||
|
||||
// Invoke the function
|
||||
KernelFunction function = plugin["GetCurrentWeather"];
|
||||
KernelArguments arguments = new() { ["location"] = new Location("USA", "Boston") };
|
||||
|
||||
FunctionResult functionResult = await function.InvokeAsync(kernel, arguments);
|
||||
|
||||
// Display the result
|
||||
Weather weather = functionResult.GetValue<Weather>()!;
|
||||
Console.WriteLine($"Temperature: {weather.Temperature}, Condition: {weather.Condition}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Imports a kernel plugin into the kernel's plugin collection from a type and invokes its function.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The kernel provides extension methods like ImportFromObject, ImportFromFunctions and ImportPluginFromPromptDirectory,
|
||||
/// allowing the import of a plugin from a class instance, a collection of functions or a prompt directory.
|
||||
/// </remarks>
|
||||
public static async Task ImportPluginFromType(IConfigurationRoot _)
|
||||
{
|
||||
Kernel kernel = new();
|
||||
|
||||
// Create JsonSerializerOptions with custom JsonSerializerContexts for the Location and Weather types that are used by the plugin below.
|
||||
// This is necessary for JsonSerializer to infer the type information for these types in AOT applications.
|
||||
JsonSerializerOptions options = new();
|
||||
options.TypeInfoResolverChain.Add(WeatherJsonSerializerContext.Default);
|
||||
options.TypeInfoResolverChain.Add(LocationJsonSerializerContext.Default);
|
||||
|
||||
// Create a kernel plugin
|
||||
KernelPlugin plugin = kernel.ImportPluginFromType<WeatherPlugin>(options, "weather_utils");
|
||||
|
||||
// Invoke the function
|
||||
KernelFunction function = kernel.Plugins["weather_utils"]["GetCurrentWeather"];
|
||||
KernelArguments arguments = new() { ["location"] = new Location("USA", "Boston") };
|
||||
|
||||
FunctionResult functionResult = await function.InvokeAsync(kernel, arguments);
|
||||
|
||||
// Display the result
|
||||
Weather weather = functionResult.GetValue<Weather>()!;
|
||||
Console.WriteLine($"Temperature: {weather.Temperature}, Condition: {weather.Condition}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a kernel plugin into the kernel's plugin collection from a type and invokes its function.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Other extension methods like AddFromObject, AddFromFunctions
|
||||
/// can be used to create a plugin and add it to the kernel's plugins collection.
|
||||
/// </remarks>
|
||||
public static async Task AddPluginFromType(IConfigurationRoot _)
|
||||
{
|
||||
Kernel kernel = new();
|
||||
|
||||
// Create JsonSerializerOptions with custom JsonSerializerContexts for the Location and Weather types that are used by the plugin below.
|
||||
// This is necessary for JsonSerializer to infer the type information for these types in AOT applications.
|
||||
JsonSerializerOptions options = new();
|
||||
options.TypeInfoResolverChain.Add(WeatherJsonSerializerContext.Default);
|
||||
options.TypeInfoResolverChain.Add(LocationJsonSerializerContext.Default);
|
||||
|
||||
// Create a kernel plugin
|
||||
KernelPlugin plugin = kernel.Plugins.AddFromType<WeatherPlugin>(options, "weather_utils");
|
||||
|
||||
// Invoke the function
|
||||
KernelFunction function = kernel.Plugins["weather_utils"]["GetCurrentWeather"];
|
||||
KernelArguments arguments = new() { ["location"] = new Location("USA", "Boston") };
|
||||
|
||||
FunctionResult functionResult = await function.InvokeAsync(kernel, arguments);
|
||||
|
||||
// Display the result
|
||||
Weather weather = functionResult.GetValue<Weather>()!;
|
||||
Console.WriteLine($"Temperature: {weather.Temperature}, Condition: {weather.Condition}");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using Microsoft.SemanticKernel.Connectors.Onnx;
|
||||
|
||||
namespace SemanticKernel.AotCompatibility;
|
||||
|
||||
/// <summary>
|
||||
/// This class contains samples of how to use ONNX chat completion service in AOT applications.
|
||||
/// </summary>
|
||||
internal static class OnnxChatCompletionSamples
|
||||
{
|
||||
/// <summary>
|
||||
/// Sends a prompt to the ONNX model and gets the chat message content.
|
||||
/// </summary>
|
||||
public static async Task GetChatMessageContent(IConfigurationRoot config)
|
||||
{
|
||||
string chatModelPath = config["Onnx:ModelPath"]!;
|
||||
string chatModelId = config["Onnx:ModelId"] ?? "phi-3";
|
||||
|
||||
// Create kernel builder and add OnnxRuntimeGenAIChatCompletion service.
|
||||
// If you plan to use the service with Non-ONNX prompt execution settings,
|
||||
// supply JSON serializer options with a JSON serializer context for this setup.
|
||||
IKernelBuilder builder = Kernel.CreateBuilder()
|
||||
.AddOnnxRuntimeGenAIChatCompletion(chatModelId, chatModelPath);
|
||||
|
||||
// Build kernel and get the service instance
|
||||
Kernel kernel = builder.Build();
|
||||
IChatCompletionService chatService = kernel.GetRequiredService<IChatCompletionService>();
|
||||
|
||||
string prompt = "Hello, what is the weather in Boston, USA now?";
|
||||
|
||||
OnnxRuntimeGenAIPromptExecutionSettings executionSettings = new()
|
||||
{
|
||||
Temperature = 0.7f, // Adjusts creativity level
|
||||
TopP = 0.9f // Limits token choice diversity
|
||||
};
|
||||
|
||||
// Prompt the ONNX model
|
||||
ChatMessageContent messageContent = await chatService.GetChatMessageContentAsync(prompt, executionSettings);
|
||||
|
||||
// Display the result
|
||||
Console.WriteLine(messageContent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a prompt to the ONNX model and gets the chat message content in a streaming fashion.
|
||||
/// </summary>
|
||||
public static async Task GetStreamingChatMessageContents(IConfigurationRoot config)
|
||||
{
|
||||
string chatModelPath = config["Onnx:ModelPath"]!;
|
||||
string chatModelId = config["Onnx:ModelId"] ?? "phi-3";
|
||||
|
||||
// Create kernel builder and add OnnxRuntimeGenAIChatCompletion service.
|
||||
// If you plan to use the service with Non-ONNX prompt execution settings,
|
||||
// supply JSON serializer options with a JSON serializer context for this setup.
|
||||
IKernelBuilder builder = Kernel.CreateBuilder()
|
||||
.AddOnnxRuntimeGenAIChatCompletion(chatModelId, chatModelPath);
|
||||
|
||||
// Build kernel and get the service instance
|
||||
Kernel kernel = builder.Build();
|
||||
IChatCompletionService chatService = kernel.GetRequiredService<IChatCompletionService>();
|
||||
|
||||
string prompt = "Hello, what is the weather in Boston, USA now?";
|
||||
|
||||
OnnxRuntimeGenAIPromptExecutionSettings executionSettings = new()
|
||||
{
|
||||
Temperature = 0.7f, // Adjusts creativity level
|
||||
TopP = 0.9f // Limits token choice diversity
|
||||
};
|
||||
|
||||
// Prompt the ONNX model
|
||||
await foreach (StreamingChatMessageContent messageContent in chatService.GetStreamingChatMessageContentsAsync(prompt, executionSettings))
|
||||
{
|
||||
// Display the result
|
||||
Console.WriteLine(messageContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
namespace SemanticKernel.AotCompatibility.Plugins;
|
||||
|
||||
internal sealed class Location
|
||||
{
|
||||
public string Country { get; set; }
|
||||
|
||||
public string City { get; set; }
|
||||
|
||||
public Location(string country, string city)
|
||||
{
|
||||
this.Country = country;
|
||||
this.City = city;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
namespace SemanticKernel.AotCompatibility.Plugins;
|
||||
|
||||
internal sealed class Weather
|
||||
{
|
||||
public int? Temperature { get; set; }
|
||||
public string? Condition { get; set; }
|
||||
|
||||
public override string ToString() => $"Current weather(temperature: {this.Temperature}F, condition: {this.Condition})";
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.ComponentModel;
|
||||
using Microsoft.SemanticKernel;
|
||||
|
||||
namespace SemanticKernel.AotCompatibility.Plugins;
|
||||
|
||||
internal sealed class WeatherPlugin
|
||||
{
|
||||
[KernelFunction]
|
||||
[Description("Get the current weather in a given location.")]
|
||||
public Weather GetCurrentWeather(Location location)
|
||||
{
|
||||
return location.City switch
|
||||
{
|
||||
"Boston" => new Weather { Temperature = 61, Condition = "rainy" },
|
||||
"London" => new Weather { Temperature = 55, Condition = "cloudy" },
|
||||
"Miami" => new Weather { Temperature = 80, Condition = "sunny" },
|
||||
"Tokyo" => new Weather { Temperature = 50, Condition = "sunny" },
|
||||
"Sydney" => new Weather { Temperature = 75, Condition = "sunny" },
|
||||
_ => new Weather { Temperature = 31, Condition = "snowing" }
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace SemanticKernel.AotCompatibility;
|
||||
|
||||
/// <summary>
|
||||
/// This application demonstrates how to use the Semantic Kernel in AOT applications.
|
||||
/// </summary>
|
||||
internal sealed class Program
|
||||
{
|
||||
private static async Task<int> Main(string[] args)
|
||||
{
|
||||
var config = new ConfigurationBuilder().AddUserSecrets<Program>().Build();
|
||||
|
||||
bool success = await RunAsync(s_samples, config);
|
||||
|
||||
return success ? 1 : 0;
|
||||
}
|
||||
|
||||
private static readonly Func<IConfigurationRoot, Task>[] s_samples =
|
||||
[
|
||||
// Samples showing how to create a kernel function and invoke it in AOT applications.
|
||||
KernelFunctionSamples.CreateFunctionFromLambda,
|
||||
|
||||
// Samples showing how to create, import and add a kernel plugin and invoke its functions in AOT applications.
|
||||
KernelPluginSamples.CreatePluginFromType,
|
||||
KernelPluginSamples.ImportPluginFromType,
|
||||
KernelPluginSamples.AddPluginFromType,
|
||||
|
||||
// Samples showing how to use ONNX chat completion service in AOT applications.
|
||||
OnnxChatCompletionSamples.GetChatMessageContent,
|
||||
OnnxChatCompletionSamples.GetStreamingChatMessageContents
|
||||
];
|
||||
|
||||
private static async Task<bool> RunAsync(IEnumerable<Func<IConfigurationRoot, Task>> functionsToRun, IConfigurationRoot config)
|
||||
{
|
||||
bool failed = false;
|
||||
|
||||
foreach (var function in functionsToRun)
|
||||
{
|
||||
Console.Write($"Running - {function.Method.DeclaringType?.Name}.{function.Method.Name}");
|
||||
|
||||
try
|
||||
{
|
||||
await function(config);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return failed;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
# Native-AOT Samples
|
||||
This application demonstrates how to use the Semantic Kernel Native-AOT compatible API in a Native-AOT application.
|
||||
|
||||
## Running Samples
|
||||
The samples be run either in a debug mode by just setting a break point and pressing `F5` in Visual Studio (make sure the `AotCompatibility` project is set as the startup project) in which case they are run in a regular CoreCLR application and not in Native-AOT one. This might be useful to understand how the API works and how to use it.
|
||||
|
||||
To run the samples in a Native-AOT application, first publish it using the following command: `dotnet publish -r win-x64`. Then, execute the application by running the following command in the terminal: `.\bin\Release\net8.0\win-x64\publish\AotCompatibility.exe`.
|
||||
|
||||
## Samples
|
||||
Most of the samples don't require any additional setup, and can be run as is. However, some of them might require additional configuration.
|
||||
|
||||
### 1. [ONNX Chat Completion Service](./OnnxChatCompletionSamples.cs)
|
||||
To configure the sample, you need to download the ONNX model from the Hugging Face repository. Go to a directory of your choice where the model should be downloaded and run the following command:
|
||||
```powershell
|
||||
git clone https://huggingface.co/microsoft/Phi-3-mini-4k-instruct-onnx
|
||||
```
|
||||
|
||||
> [!IMPORTANT]
|
||||
The `Phi-3` model may be too large to download using the `git clone` command unless you have the [git-lfs extension](https://git-lfs.com/) installed.
|
||||
You might need to download it manually using the following link: [Phi-3-Mini-4k CPU](https://huggingface.co/microsoft/Phi-3-mini-4k-instruct-onnx/resolve/main/cpu_and_mobile/cpu-int4-rtn-block-32/phi3-mini-4k-instruct-cpu-int4-rtn-block-32.onnx.data?download=true) (approximately 2.7 GB).
|
||||
|
||||
After downloading the model, you need to configure the sample by setting the `Onnx:ModelPath` and `Onnx:ModelId` secrets.
|
||||
The `Onnx:ModelPath` should point to the directory where the model was downloaded, and the `Onnx:ModelId` should be set to `phi-3`.
|
||||
The secrets can be set using [Secret Manager](https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets#secret-manager) in the following way:
|
||||
```powershell
|
||||
dotnet user-secrets set "Onnx:ModelId" "phi-3"
|
||||
dotnet user-secrets set "Onnx:ModelPath" "C:\path\to\huggingface\Phi-3-mini-4k-instruct-onnx\cpu_and_mobile\cpu-int4-rtn-block-32"
|
||||
```
|
||||
|
||||
### AOT Compatibility
|
||||
At the moment, the following Semantic Kernel packages are AOT compatible:
|
||||
|
||||
| Package | AOT compatible |
|
||||
|--------------------------|----------------|
|
||||
| SemanticKernel.Abstractions | ✔️ |
|
||||
| SemanticKernel.Core | ✔️ |
|
||||
| Connectors.Onnx | ✔️ |
|
||||
|
||||
Other packages are not AOT compatible yet, but we plan to make them compatible in the future.
|
||||
Reference in New Issue
Block a user