mirror of
https://github.com/microsoft/semantic-kernel.git
synced 2026-10-12 02:19:06 +00:00
Merge branch 'microsoft:main' into update-modelid
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
param (
|
||||
[string]$JsonReportPath,
|
||||
[double]$CoverageThreshold
|
||||
)
|
||||
|
||||
$jsonContent = Get-Content $JsonReportPath -Raw | ConvertFrom-Json
|
||||
$coverageBelowThreshold = $false
|
||||
|
||||
function Get-FormattedValue($number) {
|
||||
$formattedNumber = "{0:N1}" -f $number
|
||||
$icon = if ($number -ge $CoverageThreshold) { '✅' } else { '❌' }
|
||||
|
||||
return "$formattedNumber% $icon"
|
||||
}
|
||||
|
||||
$lineCoverage = $jsonContent.summary.linecoverage
|
||||
$branchCoverage = $jsonContent.summary.branchcoverage
|
||||
|
||||
if ($lineCoverage -lt $CoverageThreshold -or $branchCoverage -lt $CoverageThreshold) {
|
||||
$coverageBelowThreshold = $true
|
||||
}
|
||||
|
||||
$totalTableData = [PSCustomObject]@{
|
||||
'Metric' = 'Total Coverage'
|
||||
'Line Coverage' = Get-FormattedValue $lineCoverage
|
||||
'Branch Coverage' = Get-FormattedValue $branchCoverage
|
||||
}
|
||||
|
||||
$totalTableData | Format-Table -AutoSize
|
||||
|
||||
$assemblyTableData = @()
|
||||
|
||||
foreach ($assembly in $jsonContent.coverage.assemblies) {
|
||||
$assemblyName = $assembly.name
|
||||
$assemblyLineCoverage = $assembly.coverage
|
||||
$assemblyBranchCoverage = $assembly.branchcoverage
|
||||
|
||||
if ($assemblyLineCoverage -lt $CoverageThreshold -or $assemblyBranchCoverage -lt $CoverageThreshold) {
|
||||
$coverageBelowThreshold = $true
|
||||
}
|
||||
|
||||
$assemblyTableData += [PSCustomObject]@{
|
||||
'Assembly Name' = $assemblyName
|
||||
'Line' = Get-FormattedValue $assemblyLineCoverage
|
||||
'Branch' = Get-FormattedValue $assemblyBranchCoverage
|
||||
}
|
||||
}
|
||||
|
||||
$assemblyTableData | Format-Table -AutoSize
|
||||
|
||||
if ($coverageBelowThreshold) {
|
||||
Write-Host "Code coverage is lower than defined threshold: $CoverageThreshold. Stopping the task."
|
||||
exit 1
|
||||
}
|
||||
@@ -12,6 +12,9 @@ on:
|
||||
merge_group:
|
||||
branches: ["main"]
|
||||
|
||||
env:
|
||||
COVERAGE_THRESHOLD: 80
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
@@ -82,7 +85,7 @@ jobs:
|
||||
run: |
|
||||
export UT_PROJECTS=$(find ./dotnet -type f -name "*.UnitTests.csproj" | grep -v -E "(Planners.Core.UnitTests.csproj|Experimental.Orchestration.Flow.UnitTests.csproj|Experimental.Assistants.UnitTests.csproj)" | tr '\n' ' ')
|
||||
for project in $UT_PROJECTS; do
|
||||
dotnet test -c ${{ matrix.configuration }} $project --no-build -v Normal --logger trx
|
||||
dotnet test -c ${{ matrix.configuration }} $project --no-build -v Normal --logger trx --collect:"XPlat Code Coverage" --results-directory:"TestResults/Coverage/"
|
||||
done
|
||||
|
||||
- name: Run Integration Tests
|
||||
@@ -109,6 +112,20 @@ jobs:
|
||||
Bing__ApiKey: ${{ secrets.BING__APIKEY }}
|
||||
OpenAI__ApiKey: ${{ secrets.OPENAI__APIKEY }}
|
||||
|
||||
# Generate test reports and check coverage
|
||||
- name: Generate test reports
|
||||
uses: danielpalme/[email protected]
|
||||
with:
|
||||
reports: "./TestResults/Coverage/**/coverage.cobertura.xml"
|
||||
targetdir: "./TestResults/Reports"
|
||||
reporttypes: "JsonSummary"
|
||||
# Report for production packages only
|
||||
assemblyfilters: "+Microsoft.SemanticKernel.Abstractions;+Microsoft.SemanticKernel.Core;+Microsoft.SemanticKernel.PromptTemplates.Handlebars;+Microsoft.SemanticKernel.Connectors.OpenAI;+Microsoft.SemanticKernel.Yaml;"
|
||||
|
||||
- name: Check coverage
|
||||
shell: pwsh
|
||||
run: .github/workflows/check-coverage.ps1 -JsonReportPath "TestResults/Reports/Summary.json" -CoverageThreshold $env:COVERAGE_THRESHOLD
|
||||
|
||||
# This final job is required to satisfy the merge queue. It must only run (or succeed) if no tests failed
|
||||
dotnet-build-and-test-check:
|
||||
if: always()
|
||||
|
||||
@@ -50,7 +50,6 @@
|
||||
<PackageVersion Include="xunit.runner.visualstudio" Version="2.5.6" />
|
||||
<PackageVersion Include="xretry" Version="1.9.0" />
|
||||
<PackageVersion Include="coverlet.collector" Version="6.0.0" />
|
||||
<PackageVersion Include="Polly" Version="8.2.0" />
|
||||
<!-- Plugins -->
|
||||
<PackageVersion Include="DocumentFormat.OpenXml" Version="3.0.0" />
|
||||
<PackageVersion Include="Microsoft.Data.Sqlite" Version="8.0.0" />
|
||||
@@ -66,7 +65,6 @@
|
||||
<PackageVersion Include="Grpc.Net.Client" Version="2.60.0" />
|
||||
<PackageVersion Include="protobuf-net" Version="3.2.30" />
|
||||
<PackageVersion Include="protobuf-net.Reflection" Version="3.2.12" />
|
||||
<PackageVersion Include="CoreCLR-NCalc" Version="2.2.113" />
|
||||
<PackageVersion Include="YamlDotNet" Version="13.7.1" />
|
||||
<!-- Memory stores -->
|
||||
<PackageVersion Include="Pgvector" Version="0.2.0" />
|
||||
|
||||
@@ -118,9 +118,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "System", "System", "{3CDE10
|
||||
src\InternalUtilities\src\System\EnvExtensions.cs = src\InternalUtilities\src\System\EnvExtensions.cs
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Plugins.Core", "src\Plugins\Plugins.Core\Plugins.Core.csproj", "{0D0C4DAD-E6BC-4504-AE3A-EEA4E35920C1}"
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Type", "Type", "{E85EA4D0-BB7E-4DFD-882F-A76EB8C0B8FF}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
src\InternalUtilities\src\Type\TypeExtensions.cs = src\InternalUtilities\src\Type\TypeExtensions.cs
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NCalcPlugins", "samples\NCalcPlugins\NCalcPlugins.csproj", "{E6EDAB8F-3406-4DBF-9AAB-DF40DC2CA0FA}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Plugins.Core", "src\Plugins\Plugins.Core\Plugins.Core.csproj", "{0D0C4DAD-E6BC-4504-AE3A-EEA4E35920C1}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TelemetryExample", "samples\TelemetryExample\TelemetryExample.csproj", "{C754950A-E16C-4F96-9CC7-9328E361B5AF}"
|
||||
EndProject
|
||||
@@ -353,11 +356,6 @@ Global
|
||||
{0D0C4DAD-E6BC-4504-AE3A-EEA4E35920C1}.Publish|Any CPU.Build.0 = Publish|Any CPU
|
||||
{0D0C4DAD-E6BC-4504-AE3A-EEA4E35920C1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0D0C4DAD-E6BC-4504-AE3A-EEA4E35920C1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E6EDAB8F-3406-4DBF-9AAB-DF40DC2CA0FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E6EDAB8F-3406-4DBF-9AAB-DF40DC2CA0FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E6EDAB8F-3406-4DBF-9AAB-DF40DC2CA0FA}.Publish|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E6EDAB8F-3406-4DBF-9AAB-DF40DC2CA0FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E6EDAB8F-3406-4DBF-9AAB-DF40DC2CA0FA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C754950A-E16C-4F96-9CC7-9328E361B5AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C754950A-E16C-4F96-9CC7-9328E361B5AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C754950A-E16C-4F96-9CC7-9328E361B5AF}.Publish|Any CPU.ActiveCfg = Release|Any CPU
|
||||
@@ -500,8 +498,8 @@ Global
|
||||
{B00AD427-0047-4850-BEF9-BA8237EA9D8B} = {958AD708-F048-4FAF-94ED-D2F2B92748B9}
|
||||
{1C19D805-3573-4477-BF07-40180FCDE1BD} = {958AD708-F048-4FAF-94ED-D2F2B92748B9}
|
||||
{3CDE10B2-AE8F-4FC4-8D55-92D4AD32E144} = {958AD708-F048-4FAF-94ED-D2F2B92748B9}
|
||||
{E85EA4D0-BB7E-4DFD-882F-A76EB8C0B8FF} = {958AD708-F048-4FAF-94ED-D2F2B92748B9}
|
||||
{0D0C4DAD-E6BC-4504-AE3A-EEA4E35920C1} = {D6D598DF-C17C-46F4-B2B9-CDE82E2DE132}
|
||||
{E6EDAB8F-3406-4DBF-9AAB-DF40DC2CA0FA} = {FA3720F1-C99A-49B2-9577-A940257098BF}
|
||||
{C754950A-E16C-4F96-9CC7-9328E361B5AF} = {FA3720F1-C99A-49B2-9577-A940257098BF}
|
||||
{E07608CC-D710-4655-BB9E-D22CF3CDD193} = {24503383-A8C4-4255-9998-28D70FE8E99A}
|
||||
{D6D598DF-C17C-46F4-B2B9-CDE82E2DE132} = {831DDCA2-7D2C-4C31-80DB-6BDB3E1F7AE0}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
# This script is for local use to analyze code coverage in more detail using HTML report.
|
||||
|
||||
Param(
|
||||
[switch]$ProdPackagesOnly = $false
|
||||
)
|
||||
|
||||
# Generate a timestamp for the current date and time
|
||||
$timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
|
||||
|
||||
# Define paths
|
||||
$scriptPath = Get-Item -Path $PSScriptRoot
|
||||
$coverageOutputPath = Join-Path $scriptPath "TestResults\Coverage\$timestamp"
|
||||
$reportOutputPath = Join-Path $scriptPath "TestResults\Reports\$timestamp"
|
||||
|
||||
# Create output directories
|
||||
New-Item -ItemType Directory -Force -Path $coverageOutputPath
|
||||
New-Item -ItemType Directory -Force -Path $reportOutputPath
|
||||
|
||||
# Find tests for projects ending with 'UnitTests.csproj'
|
||||
$testProjects = Get-ChildItem $scriptPath -Filter "*UnitTests.csproj" -Recurse
|
||||
|
||||
foreach ($project in $testProjects) {
|
||||
$testProjectPath = $project.FullName
|
||||
Write-Host "Running tests for project: $($testProjectPath)"
|
||||
|
||||
# Run tests
|
||||
dotnet test $testProjectPath `
|
||||
--collect:"XPlat Code Coverage" `
|
||||
--results-directory:$coverageOutputPath `
|
||||
|
||||
}
|
||||
|
||||
# Install required tools
|
||||
& dotnet tool install -g coverlet.console
|
||||
& dotnet tool install -g dotnet-reportgenerator-globaltool
|
||||
|
||||
# Generate HTML report
|
||||
if ($ProdPackagesOnly) {
|
||||
$assemblies = @(
|
||||
"+Microsoft.SemanticKernel.Abstractions",
|
||||
"+Microsoft.SemanticKernel.Core",
|
||||
"+Microsoft.SemanticKernel.PromptTemplates.Handlebars",
|
||||
"+Microsoft.SemanticKernel.Connectors.OpenAI",
|
||||
"+Microsoft.SemanticKernel.Yaml"
|
||||
)
|
||||
|
||||
$assemblyFilters = $assemblies -join ";"
|
||||
|
||||
# Generate report for production assemblies only
|
||||
& reportgenerator -reports:"$coverageOutputPath/**/coverage.cobertura.xml" -targetdir:$reportOutputPath -reporttypes:Html -assemblyfilters:$assemblyFilters
|
||||
}
|
||||
else {
|
||||
& reportgenerator -reports:"$coverageOutputPath/**/coverage.cobertura.xml" -targetdir:$reportOutputPath -reporttypes:Html
|
||||
}
|
||||
|
||||
Write-Host "Code coverage report generated at: $reportOutputPath"
|
||||
|
||||
# Open report
|
||||
$reportIndexHtml = Join-Path $reportOutputPath "index.html"
|
||||
Invoke-Item -Path $reportIndexHtml
|
||||
@@ -21,4 +21,5 @@ resharper_condition_is_always_true_or_false_according_to_nullable_api_contract_h
|
||||
resharper_inconsistent_naming_highlighting = none # InconsistentNaming
|
||||
resharper_equal_expression_comparison_highlighting = none # EqualExpressionComparison
|
||||
resharper_check_namespace_highlighting = none # CheckNamespace
|
||||
resharper_arrange_object_creation_when_type_not_evident_highlighting = none # Disable "Arrange object creation when type is not evident" highlighting
|
||||
resharper_arrange_object_creation_when_type_not_evident_highlighting = none # Disable "Arrange object creation when type is not evident" highlighting
|
||||
resharper_arrange_this_qualifier_highlighting = none # Disable "Arrange 'this.' qualifier" highlighting
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using RepoUtils;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
public abstract class BaseTest
|
||||
{
|
||||
protected ITestOutputHelper Output { get; }
|
||||
|
||||
protected BaseTest(ITestOutputHelper output)
|
||||
{
|
||||
this.Output = output;
|
||||
LoadUserSecrets();
|
||||
}
|
||||
|
||||
private static void LoadUserSecrets()
|
||||
{
|
||||
IConfigurationRoot configRoot = new ConfigurationBuilder()
|
||||
.AddJsonFile("appsettings.Development.json", true)
|
||||
.AddEnvironmentVariables()
|
||||
.AddUserSecrets<Env>()
|
||||
.Build();
|
||||
|
||||
TestConfiguration.Initialize(configRoot);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method can be substituted by Console.WriteLine when used in Console apps.
|
||||
/// </summary>
|
||||
/// <param name="target">Target object to write</param>
|
||||
protected void WriteLine(object? target = null)
|
||||
{
|
||||
this.Output.WriteLine(target ?? string.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Current interface ITestOutputHelper does not have a Write method. This extension method adds it to make it analogous to Console.Write when used in Console apps.
|
||||
/// </summary>
|
||||
/// <param name="target">Target object to write</param>
|
||||
protected void Write(object? target = null)
|
||||
{
|
||||
this.Output.WriteLine(target ?? string.Empty);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,18 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel.Plugins.Core;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
public static class Example01_MethodFunctions
|
||||
namespace Examples;
|
||||
|
||||
public class Example01_MethodFunctions : BaseTest
|
||||
{
|
||||
public static Task RunAsync()
|
||||
[Fact]
|
||||
public Task RunAsync()
|
||||
{
|
||||
Console.WriteLine("======== Functions ========");
|
||||
this.WriteLine("======== Functions ========");
|
||||
|
||||
// Load native plugin
|
||||
var text = new TextPlugin();
|
||||
@@ -16,8 +20,12 @@ public static class Example01_MethodFunctions
|
||||
// Use function without kernel
|
||||
var result = text.Uppercase("ciao!");
|
||||
|
||||
Console.WriteLine(result);
|
||||
this.WriteLine(result);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Example01_MethodFunctions(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,13 +5,17 @@ using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Plugins;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
// This example shows how to use kernel arguments when invoking functions.
|
||||
public static class Example03_Arguments
|
||||
public class Example03_Arguments : BaseTest
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
Console.WriteLine("======== Arguments ========");
|
||||
this.WriteLine("======== Arguments ========");
|
||||
|
||||
Kernel kernel = new();
|
||||
var textPlugin = kernel.ImportPluginFromType<StaticTextPlugin>();
|
||||
@@ -26,16 +30,20 @@ public static class Example03_Arguments
|
||||
|
||||
// Specify and get the value type as generic parameter
|
||||
string? resultValue = await kernel.InvokeAsync<string>(textPlugin["AppendDay"], arguments);
|
||||
Console.WriteLine($"string -> {resultValue}");
|
||||
this.WriteLine($"string -> {resultValue}");
|
||||
|
||||
// If you need to access the result metadata, you can use the non-generic version to get the FunctionResult
|
||||
FunctionResult functionResult = await kernel.InvokeAsync(textPlugin["AppendDay"], arguments);
|
||||
var metadata = functionResult.Metadata;
|
||||
|
||||
// Specify the type from the FunctionResult
|
||||
Console.WriteLine($"FunctionResult.GetValue<string>() -> {functionResult.GetValue<string>()}");
|
||||
this.WriteLine($"FunctionResult.GetValue<string>() -> {functionResult.GetValue<string>()}");
|
||||
|
||||
// FunctionResult.ToString() automatically converts the result to string
|
||||
Console.WriteLine($"FunctionResult.ToString() -> {functionResult}");
|
||||
this.WriteLine($"FunctionResult.ToString() -> {functionResult}");
|
||||
}
|
||||
|
||||
public Example03_Arguments(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,19 +4,24 @@ using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
public static class Example05_InlineFunctionDefinition
|
||||
namespace Examples;
|
||||
|
||||
public class Example05_InlineFunctionDefinition : BaseTest
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
Console.WriteLine("======== Inline Function Definition ========");
|
||||
this.WriteLine("======== Inline Function Definition ========");
|
||||
|
||||
string openAIModelId = TestConfiguration.OpenAI.ChatModelId;
|
||||
string openAIApiKey = TestConfiguration.OpenAI.ApiKey;
|
||||
|
||||
if (openAIModelId is null || openAIApiKey is null)
|
||||
{
|
||||
Console.WriteLine("OpenAI credentials not found. Skipping example.");
|
||||
this.WriteLine("OpenAI credentials not found. Skipping example.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -49,14 +54,18 @@ Event: {{$input}}
|
||||
var excuseFunction = kernel.CreateFunctionFromPrompt(promptTemplate, new OpenAIPromptExecutionSettings() { MaxTokens = 100, Temperature = 0.4, TopP = 1 });
|
||||
|
||||
var result = await kernel.InvokeAsync(excuseFunction, new() { ["input"] = "I missed the F1 final race" });
|
||||
Console.WriteLine(result.GetValue<string>());
|
||||
this.WriteLine(result.GetValue<string>());
|
||||
|
||||
result = await kernel.InvokeAsync(excuseFunction, new() { ["input"] = "sorry I forgot your birthday" });
|
||||
Console.WriteLine(result.GetValue<string>());
|
||||
this.WriteLine(result.GetValue<string>());
|
||||
|
||||
var fixedFunction = kernel.CreateFunctionFromPrompt($"Translate this date {DateTimeOffset.Now:f} to French format", new OpenAIPromptExecutionSettings() { MaxTokens = 100 });
|
||||
|
||||
result = await kernel.InvokeAsync(fixedFunction);
|
||||
Console.WriteLine(result.GetValue<string>());
|
||||
this.WriteLine(result.GetValue<string>());
|
||||
}
|
||||
|
||||
public Example05_InlineFunctionDefinition(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,31 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Microsoft.SemanticKernel.Plugins.Core;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
public static class Example06_TemplateLanguage
|
||||
namespace Examples;
|
||||
|
||||
public class Example06_TemplateLanguage : BaseTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Show how to invoke a Method Function written in C#
|
||||
/// from a Prompt Function written in natural language
|
||||
/// </summary>
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
Console.WriteLine("======== TemplateLanguage ========");
|
||||
this.WriteLine("======== TemplateLanguage ========");
|
||||
|
||||
string openAIModelId = TestConfiguration.OpenAI.ChatModelId;
|
||||
string openAIApiKey = TestConfiguration.OpenAI.ApiKey;
|
||||
|
||||
if (openAIModelId == null || openAIApiKey == null)
|
||||
{
|
||||
Console.WriteLine("OpenAI credentials not found. Skipping example.");
|
||||
this.WriteLine("OpenAI credentials not found. Skipping example.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -46,19 +50,19 @@ Is it weekend time (weekend/not weekend)?
|
||||
";
|
||||
|
||||
// This allows to see the prompt before it's sent to OpenAI
|
||||
Console.WriteLine("--- Rendered Prompt");
|
||||
this.WriteLine("--- Rendered Prompt");
|
||||
var promptTemplateFactory = new KernelPromptTemplateFactory();
|
||||
var promptTemplate = promptTemplateFactory.Create(new PromptTemplateConfig(FunctionDefinition));
|
||||
var renderedPrompt = await promptTemplate.RenderAsync(kernel);
|
||||
Console.WriteLine(renderedPrompt);
|
||||
this.WriteLine(renderedPrompt);
|
||||
|
||||
// Run the prompt / prompt function
|
||||
var kindOfDay = kernel.CreateFunctionFromPrompt(FunctionDefinition, new OpenAIPromptExecutionSettings() { MaxTokens = 100 });
|
||||
|
||||
// Show the result
|
||||
Console.WriteLine("--- Prompt Function result");
|
||||
this.WriteLine("--- Prompt Function result");
|
||||
var result = await kernel.InvokeAsync(kindOfDay);
|
||||
Console.WriteLine(result.GetValue<string>());
|
||||
this.WriteLine(result.GetValue<string>());
|
||||
|
||||
/* OUTPUT:
|
||||
|
||||
@@ -81,4 +85,8 @@ Is it weekend time (weekend/not weekend)?
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public Example06_TemplateLanguage(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,22 +7,27 @@ using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Microsoft.SemanticKernel.Plugins.Web;
|
||||
using Microsoft.SemanticKernel.Plugins.Web.Bing;
|
||||
using Microsoft.SemanticKernel.Plugins.Web.Google;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
/// <summary>
|
||||
/// The example shows how to use Bing and Google to search for current data
|
||||
/// you might want to import into your system, e.g. providing AI prompts with
|
||||
/// recent information, or for AI to generate recent information to display to users.
|
||||
/// </summary>
|
||||
public static class Example07_BingAndGooglePlugins
|
||||
public class Example07_BingAndGooglePlugins : BaseTest
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
[Fact(Skip = "Setup Credentials")]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
string openAIModelId = TestConfiguration.OpenAI.ChatModelId;
|
||||
string openAIApiKey = TestConfiguration.OpenAI.ApiKey;
|
||||
|
||||
if (openAIModelId == null || openAIApiKey == null)
|
||||
{
|
||||
Console.WriteLine("OpenAI credentials not found. Skipping example.");
|
||||
this.WriteLine("OpenAI credentials not found. Skipping example.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -36,7 +41,7 @@ public static class Example07_BingAndGooglePlugins
|
||||
string bingApiKey = TestConfiguration.Bing.ApiKey;
|
||||
if (bingApiKey == null)
|
||||
{
|
||||
Console.WriteLine("Bing credentials not found. Skipping example.");
|
||||
this.WriteLine("Bing credentials not found. Skipping example.");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -53,7 +58,7 @@ public static class Example07_BingAndGooglePlugins
|
||||
|
||||
if (googleApiKey == null || googleSearchEngineId == null)
|
||||
{
|
||||
Console.WriteLine("Google credentials not found. Skipping example.");
|
||||
this.WriteLine("Google credentials not found. Skipping example.");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -62,22 +67,23 @@ public static class Example07_BingAndGooglePlugins
|
||||
searchEngineId: googleSearchEngineId);
|
||||
var google = new WebSearchEnginePlugin(googleConnector);
|
||||
kernel.ImportPluginFromObject(new WebSearchEnginePlugin(googleConnector), "google");
|
||||
// ReSharper disable once ArrangeThisQualifier
|
||||
await Example1Async(kernel, "google");
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task Example1Async(Kernel kernel, string searchPluginName)
|
||||
private async Task Example1Async(Kernel kernel, string searchPluginName)
|
||||
{
|
||||
Console.WriteLine("======== Bing and Google Search Plugins ========");
|
||||
this.WriteLine("======== Bing and Google Search Plugins ========");
|
||||
|
||||
// Run
|
||||
var question = "What's the largest building in the world?";
|
||||
var function = kernel.Plugins[searchPluginName]["search"];
|
||||
var result = await kernel.InvokeAsync(function, new() { ["query"] = question });
|
||||
|
||||
Console.WriteLine(question);
|
||||
Console.WriteLine($"----{searchPluginName}----");
|
||||
Console.WriteLine(result.GetValue<string>());
|
||||
this.WriteLine(question);
|
||||
this.WriteLine($"----{searchPluginName}----");
|
||||
this.WriteLine(result.GetValue<string>());
|
||||
|
||||
/* OUTPUT:
|
||||
|
||||
@@ -92,9 +98,9 @@ public static class Example07_BingAndGooglePlugins
|
||||
*/
|
||||
}
|
||||
|
||||
private static async Task Example2Async(Kernel kernel)
|
||||
private async Task Example2Async(Kernel kernel)
|
||||
{
|
||||
Console.WriteLine("======== Use Search Plugin to answer user questions ========");
|
||||
this.WriteLine("======== Use Search Plugin to answer user questions ========");
|
||||
|
||||
const string SemanticFunction = @"Answer questions only when you know the facts or the information is provided.
|
||||
When you don't have sufficient information you reply with a list of commands to find the information needed.
|
||||
@@ -130,7 +136,7 @@ Question: {{ $question }}.
|
||||
Answer: ";
|
||||
|
||||
var question = "Who is the most followed person on TikTok right now? What's the exchange rate EUR:USD?";
|
||||
Console.WriteLine(question);
|
||||
this.WriteLine(question);
|
||||
|
||||
var oracle = kernel.CreateFunctionFromPrompt(SemanticFunction, new OpenAIPromptExecutionSettings() { MaxTokens = 150, Temperature = 0, TopP = 1 });
|
||||
|
||||
@@ -148,11 +154,11 @@ Answer: ";
|
||||
var promptTemplateFactory = new KernelPromptTemplateFactory();
|
||||
var promptTemplate = promptTemplateFactory.Create(new PromptTemplateConfig(result));
|
||||
|
||||
Console.WriteLine("---- Fetching information from Bing...");
|
||||
this.WriteLine("---- Fetching information from Bing...");
|
||||
var information = await promptTemplate.RenderAsync(kernel);
|
||||
|
||||
Console.WriteLine("Information found:");
|
||||
Console.WriteLine(information);
|
||||
this.WriteLine("Information found:");
|
||||
this.WriteLine(information);
|
||||
|
||||
// Run the prompt function again, now including information from Bing
|
||||
answer = await kernel.InvokeAsync(oracle, new KernelArguments()
|
||||
@@ -164,11 +170,11 @@ Answer: ";
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("AI had all the information, no need to query Bing.");
|
||||
this.WriteLine("AI had all the information, no need to query Bing.");
|
||||
}
|
||||
|
||||
Console.WriteLine("---- ANSWER:");
|
||||
Console.WriteLine(answer.GetValue<string>());
|
||||
this.WriteLine("---- ANSWER:");
|
||||
this.WriteLine(answer.GetValue<string>());
|
||||
|
||||
/* OUTPUT:
|
||||
|
||||
@@ -188,4 +194,8 @@ Answer: ";
|
||||
* The exchange rate for EUR to USD is 1.1037097 US Dollars for 1 Euro.
|
||||
*/
|
||||
}
|
||||
|
||||
public Example07_BingAndGooglePlugins(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,11 +7,16 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Http.Resilience;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
// This example shows how to use a retry handler within a Semantic Kernel
|
||||
public static class Example08_RetryHandler
|
||||
public class Example08_RetryHandler : BaseTest
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
// Create a Kernel with the HttpClient
|
||||
IKernelBuilder builder = Kernel.CreateBuilder();
|
||||
@@ -29,7 +34,7 @@ public static class Example08_RetryHandler
|
||||
|
||||
var logger = kernel.LoggerFactory.CreateLogger(typeof(Example08_RetryHandler));
|
||||
|
||||
const string Question = "How popular is the Polly library?";
|
||||
const string Question = "How do I add a standard resilience handler in IHttpClientBuilder??";
|
||||
logger.LogInformation("Question: {Question}", Question);
|
||||
|
||||
// The call to OpenAI will fail and be retried a few times before eventually failing.
|
||||
@@ -49,4 +54,8 @@ public static class Example08_RetryHandler
|
||||
logger.LogInformation("Error: {Message}", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public Example08_RetryHandler(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,16 +11,22 @@ using Microsoft.Extensions.Logging;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using RepoUtils;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
public static class Example09_FunctionTypes
|
||||
namespace Examples;
|
||||
|
||||
public class Example09_FunctionTypes : BaseTest
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
Console.WriteLine("======== Method Function types ========");
|
||||
this.WriteLine("======== Method Function types ========");
|
||||
|
||||
var builder = Kernel.CreateBuilder()
|
||||
.AddOpenAIChatCompletion(TestConfiguration.OpenAI.ChatModelId, TestConfiguration.OpenAI.ApiKey);
|
||||
builder.Services.AddLogging(services => services.AddConsole().SetMinimumLevel(LogLevel.Warning));
|
||||
builder.Services.AddSingleton(this.Output);
|
||||
var kernel = builder.Build();
|
||||
kernel.Culture = new CultureInfo("pt-BR");
|
||||
|
||||
@@ -36,7 +42,7 @@ public static class Example09_FunctionTypes
|
||||
await kernel.InvokeAsync(plugin[nameof(LocalExamplePlugin.InputDateTimeWithStringResult)], new() { ["currentDate"] = DateTime.Now });
|
||||
await kernel.InvokeAsync(plugin[nameof(LocalExamplePlugin.NoInputTaskWithStringResult)]);
|
||||
await kernel.InvokeAsync(plugin[nameof(LocalExamplePlugin.MultipleInputsWithVoidResult)], new() { ["x"] = "x string", ["y"] = 100, ["z"] = 1.5 });
|
||||
await kernel.InvokeAsync(plugin[nameof(LocalExamplePlugin.ComplexInputWithStringResult)], new() { ["complexObject"] = new LocalExamplePlugin() });
|
||||
await kernel.InvokeAsync(plugin[nameof(LocalExamplePlugin.ComplexInputWithStringResult)], new() { ["complexObject"] = new LocalExamplePlugin(this.Output) });
|
||||
await kernel.InvokeAsync(plugin[nameof(LocalExamplePlugin.InputStringTaskWithStringResult)], new() { ["echoInput"] = "return this" });
|
||||
await kernel.InvokeAsync(plugin[nameof(LocalExamplePlugin.InputStringTaskWithVoidResult)], new() { ["x"] = "x input" });
|
||||
await kernel.InvokeAsync(plugin[nameof(LocalExamplePlugin.NoInputWithFunctionResult)]);
|
||||
@@ -60,19 +66,30 @@ public static class Example09_FunctionTypes
|
||||
// You can also use the kernel.Plugins collection to invoke a function
|
||||
await kernel.InvokeAsync(kernel.Plugins["Examples"][nameof(LocalExamplePlugin.NoInputWithVoidResult)]);
|
||||
}
|
||||
|
||||
public Example09_FunctionTypes(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
// Task functions when are imported as plugins loose the "Async" suffix if present.
|
||||
#pragma warning disable IDE1006 // Naming Styles
|
||||
|
||||
public class LocalExamplePlugin
|
||||
{
|
||||
private readonly ITestOutputHelper _output;
|
||||
|
||||
public LocalExamplePlugin(ITestOutputHelper output)
|
||||
{
|
||||
this._output = output;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Example of using a void function with no input
|
||||
/// </summary>
|
||||
[KernelFunction]
|
||||
public void NoInputWithVoidResult()
|
||||
{
|
||||
Console.WriteLine($"Running {nameof(this.NoInputWithVoidResult)} -> No input");
|
||||
this._output.WriteLine($"Running {nameof(this.NoInputWithVoidResult)} -> No input");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -81,7 +98,7 @@ public class LocalExamplePlugin
|
||||
[KernelFunction]
|
||||
public Task NoInputTaskWithVoidResult()
|
||||
{
|
||||
Console.WriteLine($"Running {nameof(this.NoInputTaskWithVoidResult)} -> No input");
|
||||
this._output.WriteLine($"Running {nameof(this.NoInputTaskWithVoidResult)} -> No input");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
@@ -92,7 +109,7 @@ public class LocalExamplePlugin
|
||||
public string InputDateTimeWithStringResult(DateTime currentDate)
|
||||
{
|
||||
var result = currentDate.ToString(CultureInfo.InvariantCulture);
|
||||
Console.WriteLine($"Running {nameof(this.InputDateTimeWithStringResult)} -> [currentDate = {currentDate}] -> result: {result}");
|
||||
this._output.WriteLine($"Running {nameof(this.InputDateTimeWithStringResult)} -> [currentDate = {currentDate}] -> result: {result}");
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -103,7 +120,7 @@ public class LocalExamplePlugin
|
||||
public Task<string> NoInputTaskWithStringResult()
|
||||
{
|
||||
var result = "string result";
|
||||
Console.WriteLine($"Running {nameof(this.NoInputTaskWithStringResult)} -> No input -> result: {result}");
|
||||
this._output.WriteLine($"Running {nameof(this.NoInputTaskWithStringResult)} -> No input -> result: {result}");
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
|
||||
@@ -113,7 +130,7 @@ public class LocalExamplePlugin
|
||||
[KernelFunction]
|
||||
public void MultipleInputsWithVoidResult(string x, int y, double z)
|
||||
{
|
||||
Console.WriteLine($"Running {nameof(this.MultipleInputsWithVoidResult)} -> input: [x = {x}, y = {y}, z = {z}]");
|
||||
this._output.WriteLine($"Running {nameof(this.MultipleInputsWithVoidResult)} -> input: [x = {x}, y = {y}, z = {z}]");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -123,7 +140,7 @@ public class LocalExamplePlugin
|
||||
public string ComplexInputWithStringResult(object complexObject)
|
||||
{
|
||||
var result = complexObject.GetType().Name;
|
||||
Console.WriteLine($"Running {nameof(this.ComplexInputWithStringResult)} -> input: [complexObject = {complexObject}] -> result: {result}");
|
||||
this._output.WriteLine($"Running {nameof(this.ComplexInputWithStringResult)} -> input: [complexObject = {complexObject}] -> result: {result}");
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -133,7 +150,7 @@ public class LocalExamplePlugin
|
||||
[KernelFunction]
|
||||
public Task<string> InputStringTaskWithStringResult(string echoInput)
|
||||
{
|
||||
Console.WriteLine($"Running {nameof(this.InputStringTaskWithStringResult)} -> input: [echoInput = {echoInput}] -> result: {echoInput}");
|
||||
this._output.WriteLine($"Running {nameof(this.InputStringTaskWithStringResult)} -> input: [echoInput = {echoInput}] -> result: {echoInput}");
|
||||
return Task.FromResult(echoInput);
|
||||
}
|
||||
|
||||
@@ -143,7 +160,7 @@ public class LocalExamplePlugin
|
||||
[KernelFunction]
|
||||
public Task InputStringTaskWithVoidResult(string x)
|
||||
{
|
||||
Console.WriteLine($"Running {nameof(this.InputStringTaskWithVoidResult)} -> input: [x = {x}]");
|
||||
this._output.WriteLine($"Running {nameof(this.InputStringTaskWithVoidResult)} -> input: [x = {x}]");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
@@ -155,7 +172,7 @@ public class LocalExamplePlugin
|
||||
{
|
||||
var myInternalFunction = KernelFunctionFactory.CreateFromMethod(() => { });
|
||||
var result = new FunctionResult(myInternalFunction);
|
||||
Console.WriteLine($"Running {nameof(this.NoInputWithFunctionResult)} -> No input -> result: {result.GetType().Name}");
|
||||
this._output.WriteLine($"Running {nameof(this.NoInputWithFunctionResult)} -> No input -> result: {result.GetType().Name}");
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -166,7 +183,7 @@ public class LocalExamplePlugin
|
||||
public async Task<FunctionResult> NoInputTaskWithFunctionResult(Kernel kernel)
|
||||
{
|
||||
var result = await kernel.InvokeAsync(kernel.Plugins["Examples"][nameof(this.NoInputWithVoidResult)]);
|
||||
Console.WriteLine($"Running {nameof(this.NoInputTaskWithFunctionResult)} -> Injected kernel -> result: {result.GetType().Name}");
|
||||
this._output.WriteLine($"Running {nameof(this.NoInputTaskWithFunctionResult)} -> Injected kernel -> result: {result.GetType().Name}");
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -178,7 +195,7 @@ public class LocalExamplePlugin
|
||||
public async Task<string> TaskInjectingKernelWithInputTextAndStringResult(Kernel kernel, string textToSummarize)
|
||||
{
|
||||
var summary = await kernel.InvokeAsync<string>(kernel.Plugins["SummarizePlugin"]["Summarize"], new() { ["input"] = textToSummarize });
|
||||
Console.WriteLine($"Running {nameof(this.TaskInjectingKernelWithInputTextAndStringResult)} -> Injected kernel + input: [textToSummarize: {textToSummarize[..15]}...{textToSummarize[^15..]}] -> result: {summary}");
|
||||
this._output.WriteLine($"Running {nameof(this.TaskInjectingKernelWithInputTextAndStringResult)} -> Injected kernel + input: [textToSummarize: {textToSummarize[..15]}...{textToSummarize[^15..]}] -> result: {summary}");
|
||||
return summary!;
|
||||
}
|
||||
|
||||
@@ -189,7 +206,7 @@ public class LocalExamplePlugin
|
||||
public async Task<string> TaskInjectingKernelFunctionWithStringResult(KernelFunction executingFunction)
|
||||
{
|
||||
var result = $"Name: {executingFunction.Name}, Description: {executingFunction.Description}";
|
||||
Console.WriteLine($"Running {nameof(this.TaskInjectingKernelWithInputTextAndStringResult)} -> Injected Function -> result: {result}");
|
||||
this._output.WriteLine($"Running {nameof(this.TaskInjectingKernelWithInputTextAndStringResult)} -> Injected Function -> result: {result}");
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -200,7 +217,7 @@ public class LocalExamplePlugin
|
||||
public Task TaskInjectingLoggerWithNoResult(ILogger logger)
|
||||
{
|
||||
logger.LogWarning("Running {FunctionName} -> Injected Logger", nameof(this.TaskInjectingLoggerWithNoResult));
|
||||
Console.WriteLine($"Running {nameof(this.TaskInjectingKernelWithInputTextAndStringResult)} -> Injected Logger");
|
||||
this._output.WriteLine($"Running {nameof(this.TaskInjectingKernelWithInputTextAndStringResult)} -> Injected Logger");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
@@ -214,7 +231,7 @@ public class LocalExamplePlugin
|
||||
.CreateLogger<LocalExamplePlugin>()
|
||||
.LogWarning("Running {FunctionName} -> Injected Logger", nameof(this.TaskInjectingLoggerWithNoResult));
|
||||
|
||||
Console.WriteLine($"Running {nameof(this.TaskInjectingKernelWithInputTextAndStringResult)} -> Injected Logger");
|
||||
this._output.WriteLine($"Running {nameof(this.TaskInjectingKernelWithInputTextAndStringResult)} -> Injected Logger");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
@@ -231,7 +248,7 @@ public class LocalExamplePlugin
|
||||
}
|
||||
|
||||
var result = chatMessageContent?.Content;
|
||||
Console.WriteLine($"Running {nameof(this.TaskInjectingKernelWithInputTextAndStringResult)} -> Injected Kernel, KernelFunction, KernelArguments, Service Selector -> result: {result}");
|
||||
this._output.WriteLine($"Running {nameof(this.TaskInjectingKernelWithInputTextAndStringResult)} -> Injected Kernel, KernelFunction, KernelArguments, Service Selector -> result: {result}");
|
||||
return result ?? string.Empty;
|
||||
}
|
||||
|
||||
@@ -242,7 +259,7 @@ public class LocalExamplePlugin
|
||||
public async Task<string> TaskInjectingCultureInfoOrIFormatProviderWithStringResult(CultureInfo cultureInfo, IFormatProvider formatProvider)
|
||||
{
|
||||
var result = $"Culture Name: {cultureInfo.Name}, FormatProvider Equals CultureInfo?: {formatProvider.Equals(cultureInfo)}";
|
||||
Console.WriteLine($"Running {nameof(this.TaskInjectingCultureInfoOrIFormatProviderWithStringResult)} -> Injected CultureInfo, IFormatProvider -> result: {result}");
|
||||
this._output.WriteLine($"Running {nameof(this.TaskInjectingCultureInfoOrIFormatProviderWithStringResult)} -> Injected CultureInfo, IFormatProvider -> result: {result}");
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -253,7 +270,7 @@ public class LocalExamplePlugin
|
||||
public async Task<string> TaskInjectingCancellationTokenWithStringResult(CancellationToken cancellationToken)
|
||||
{
|
||||
var result = $"Cancellation resquested: {cancellationToken.IsCancellationRequested}";
|
||||
Console.WriteLine($"Running {nameof(this.TaskInjectingCultureInfoOrIFormatProviderWithStringResult)} -> Injected Cancellation Token -> result: {result}");
|
||||
this._output.WriteLine($"Running {nameof(this.TaskInjectingCultureInfoOrIFormatProviderWithStringResult)} -> Injected Cancellation Token -> result: {result}");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel;
|
||||
@@ -8,15 +7,20 @@ using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Microsoft.SemanticKernel.Plugins.Core;
|
||||
using Plugins;
|
||||
using RepoUtils;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
public static class Example10_DescribeAllPluginsAndFunctions
|
||||
namespace Examples;
|
||||
|
||||
public class Example10_DescribeAllPluginsAndFunctions : BaseTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Print a list of all the functions imported into the kernel, including function descriptions,
|
||||
/// list of parameters, parameters descriptions, etc.
|
||||
/// See the end of the file for a sample of what the output looks like.
|
||||
/// </summary>
|
||||
public static Task RunAsync()
|
||||
[Fact]
|
||||
public Task RunAsync()
|
||||
{
|
||||
var kernel = Kernel.CreateBuilder()
|
||||
.AddOpenAIChatCompletion(
|
||||
@@ -46,10 +50,10 @@ public static class Example10_DescribeAllPluginsAndFunctions
|
||||
|
||||
var functions = kernel.Plugins.GetFunctionsMetadata();
|
||||
|
||||
Console.WriteLine("**********************************************");
|
||||
Console.WriteLine("****** Registered plugins and functions ******");
|
||||
Console.WriteLine("**********************************************");
|
||||
Console.WriteLine();
|
||||
WriteLine("**********************************************");
|
||||
WriteLine("****** Registered plugins and functions ******");
|
||||
WriteLine("**********************************************");
|
||||
WriteLine();
|
||||
|
||||
foreach (KernelFunctionMetadata func in functions)
|
||||
{
|
||||
@@ -59,22 +63,26 @@ public static class Example10_DescribeAllPluginsAndFunctions
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private static void PrintFunction(KernelFunctionMetadata func)
|
||||
private void PrintFunction(KernelFunctionMetadata func)
|
||||
{
|
||||
Console.WriteLine($"Plugin: {func.PluginName}");
|
||||
Console.WriteLine($" {func.Name}: {func.Description}");
|
||||
WriteLine($"Plugin: {func.PluginName}");
|
||||
WriteLine($" {func.Name}: {func.Description}");
|
||||
|
||||
if (func.Parameters.Count > 0)
|
||||
{
|
||||
Console.WriteLine(" Params:");
|
||||
WriteLine(" Params:");
|
||||
foreach (var p in func.Parameters)
|
||||
{
|
||||
Console.WriteLine($" - {p.Name}: {p.Description}");
|
||||
Console.WriteLine($" default: '{p.DefaultValue}'");
|
||||
WriteLine($" - {p.Name}: {p.Description}");
|
||||
WriteLine($" default: '{p.DefaultValue}'");
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
WriteLine();
|
||||
}
|
||||
|
||||
public Example10_DescribeAllPluginsAndFunctions(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Plugins.Web;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
public static class Example11_WebSearchQueries
|
||||
namespace Examples;
|
||||
|
||||
public class Example11_WebSearchQueries : BaseTest
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
Console.WriteLine("======== WebSearchQueries ========");
|
||||
WriteLine("======== WebSearchQueries ========");
|
||||
|
||||
Kernel kernel = new();
|
||||
|
||||
@@ -20,8 +24,8 @@ public static class Example11_WebSearchQueries
|
||||
var ask = "What's the tallest building in Europe?";
|
||||
var result = await kernel.InvokeAsync(bing["BingSearchUrl"], new() { ["query"] = ask });
|
||||
|
||||
Console.WriteLine(ask + "\n");
|
||||
Console.WriteLine(result.GetValue<string>());
|
||||
WriteLine(ask + "\n");
|
||||
WriteLine(result.GetValue<string>());
|
||||
|
||||
/* Expected output:
|
||||
* ======== WebSearchQueries ========
|
||||
@@ -31,4 +35,8 @@ public static class Example11_WebSearchQueries
|
||||
* == DONE ==
|
||||
*/
|
||||
}
|
||||
|
||||
public Example11_WebSearchQueries(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Plugins.Core;
|
||||
using xRetry;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
internal static class Example13_ConversationSummaryPlugin
|
||||
namespace Examples;
|
||||
|
||||
public class Example13_ConversationSummaryPlugin : BaseTest
|
||||
{
|
||||
private const string ChatTranscript =
|
||||
@"
|
||||
@@ -115,16 +118,17 @@ John: You're welcome. I'm glad we could help. Goodbye!
|
||||
Jane: Goodbye!
|
||||
";
|
||||
|
||||
public static async Task RunAsync()
|
||||
[RetryFact(typeof(HttpOperationException))]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
await ConversationSummaryPluginAsync();
|
||||
await GetConversationActionItemsAsync();
|
||||
await GetConversationTopicsAsync();
|
||||
}
|
||||
|
||||
private static async Task ConversationSummaryPluginAsync()
|
||||
private async Task ConversationSummaryPluginAsync()
|
||||
{
|
||||
Console.WriteLine("======== SamplePlugins - Conversation Summary Plugin - Summarize ========");
|
||||
WriteLine("======== SamplePlugins - Conversation Summary Plugin - Summarize ========");
|
||||
Kernel kernel = InitializeKernel();
|
||||
|
||||
KernelPlugin conversationSummaryPlugin = kernel.ImportPluginFromType<ConversationSummaryPlugin>();
|
||||
@@ -132,13 +136,13 @@ Jane: Goodbye!
|
||||
FunctionResult summary = await kernel.InvokeAsync(
|
||||
conversationSummaryPlugin["SummarizeConversation"], new() { ["input"] = ChatTranscript });
|
||||
|
||||
Console.WriteLine("Generated Summary:");
|
||||
Console.WriteLine(summary.GetValue<string>());
|
||||
WriteLine("Generated Summary:");
|
||||
WriteLine(summary.GetValue<string>());
|
||||
}
|
||||
|
||||
private static async Task GetConversationActionItemsAsync()
|
||||
private async Task GetConversationActionItemsAsync()
|
||||
{
|
||||
Console.WriteLine("======== SamplePlugins - Conversation Summary Plugin - Action Items ========");
|
||||
WriteLine("======== SamplePlugins - Conversation Summary Plugin - Action Items ========");
|
||||
Kernel kernel = InitializeKernel();
|
||||
|
||||
KernelPlugin conversationSummary = kernel.ImportPluginFromType<ConversationSummaryPlugin>();
|
||||
@@ -146,13 +150,13 @@ Jane: Goodbye!
|
||||
FunctionResult summary = await kernel.InvokeAsync(
|
||||
conversationSummary["GetConversationActionItems"], new() { ["input"] = ChatTranscript });
|
||||
|
||||
Console.WriteLine("Generated Action Items:");
|
||||
Console.WriteLine(summary.GetValue<string>());
|
||||
WriteLine("Generated Action Items:");
|
||||
WriteLine(summary.GetValue<string>());
|
||||
}
|
||||
|
||||
private static async Task GetConversationTopicsAsync()
|
||||
private async Task GetConversationTopicsAsync()
|
||||
{
|
||||
Console.WriteLine("======== SamplePlugins - Conversation Summary Plugin - Topics ========");
|
||||
WriteLine("======== SamplePlugins - Conversation Summary Plugin - Topics ========");
|
||||
Kernel kernel = InitializeKernel();
|
||||
|
||||
KernelPlugin conversationSummary = kernel.ImportPluginFromType<ConversationSummaryPlugin>();
|
||||
@@ -160,11 +164,11 @@ Jane: Goodbye!
|
||||
FunctionResult summary = await kernel.InvokeAsync(
|
||||
conversationSummary["GetConversationTopics"], new() { ["input"] = ChatTranscript });
|
||||
|
||||
Console.WriteLine("Generated Topics:");
|
||||
Console.WriteLine(summary.GetValue<string>());
|
||||
WriteLine("Generated Topics:");
|
||||
WriteLine(summary.GetValue<string>());
|
||||
}
|
||||
|
||||
private static Kernel InitializeKernel()
|
||||
private Kernel InitializeKernel()
|
||||
{
|
||||
Kernel kernel = Kernel.CreateBuilder()
|
||||
.AddAzureOpenAIChatCompletion(
|
||||
@@ -176,6 +180,10 @@ Jane: Goodbye!
|
||||
|
||||
return kernel;
|
||||
}
|
||||
|
||||
public Example13_ConversationSummaryPlugin(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/* Example Output:
|
||||
|
||||
@@ -6,6 +6,10 @@ using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel.Connectors.AzureAISearch;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Microsoft.SemanticKernel.Memory;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
/* The files contains two examples about SK Semantic Memory.
|
||||
*
|
||||
@@ -15,15 +19,16 @@ using Microsoft.SemanticKernel.Memory;
|
||||
* Semantic Memory allows to store your data like traditional DBs,
|
||||
* adding the ability to query it using natural language.
|
||||
*/
|
||||
public static class Example14_SemanticMemory
|
||||
public class Example14_SemanticMemory : BaseTest
|
||||
{
|
||||
private const string MemoryCollectionName = "SKGitHub";
|
||||
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
Console.WriteLine("==============================================================");
|
||||
Console.WriteLine("======== Semantic Memory using Azure AI Search ========");
|
||||
Console.WriteLine("==============================================================");
|
||||
WriteLine("==============================================================");
|
||||
WriteLine("======== Semantic Memory using Azure AI Search ========");
|
||||
WriteLine("==============================================================");
|
||||
|
||||
/* This example leverages Azure AI Search to provide SK with Semantic Memory.
|
||||
*
|
||||
@@ -38,9 +43,9 @@ public static class Example14_SemanticMemory
|
||||
|
||||
await RunExampleAsync(memoryWithACS);
|
||||
|
||||
Console.WriteLine("====================================================");
|
||||
Console.WriteLine("======== Semantic Memory (volatile, in RAM) ========");
|
||||
Console.WriteLine("====================================================");
|
||||
WriteLine("====================================================");
|
||||
WriteLine("======== Semantic Memory (volatile, in RAM) ========");
|
||||
WriteLine("====================================================");
|
||||
|
||||
/* You can build your own semantic memory combining an Embedding Generator
|
||||
* with a Memory storage that supports search by similarity (ie semantic search).
|
||||
@@ -59,7 +64,7 @@ public static class Example14_SemanticMemory
|
||||
await RunExampleAsync(memoryWithCustomDb);
|
||||
}
|
||||
|
||||
public static async Task RunExampleAsync(ISemanticTextMemory memory)
|
||||
private async Task RunExampleAsync(ISemanticTextMemory memory)
|
||||
{
|
||||
await StoreMemoryAsync(memory);
|
||||
|
||||
@@ -98,26 +103,26 @@ public static class Example14_SemanticMemory
|
||||
*/
|
||||
}
|
||||
|
||||
private static async Task SearchMemoryAsync(ISemanticTextMemory memory, string query)
|
||||
private async Task SearchMemoryAsync(ISemanticTextMemory memory, string query)
|
||||
{
|
||||
Console.WriteLine("\nQuery: " + query + "\n");
|
||||
WriteLine("\nQuery: " + query + "\n");
|
||||
|
||||
var memoryResults = memory.SearchAsync(MemoryCollectionName, query, limit: 2, minRelevanceScore: 0.5);
|
||||
|
||||
int i = 0;
|
||||
await foreach (MemoryQueryResult memoryResult in memoryResults)
|
||||
{
|
||||
Console.WriteLine($"Result {++i}:");
|
||||
Console.WriteLine(" URL: : " + memoryResult.Metadata.Id);
|
||||
Console.WriteLine(" Title : " + memoryResult.Metadata.Description);
|
||||
Console.WriteLine(" Relevance: " + memoryResult.Relevance);
|
||||
Console.WriteLine();
|
||||
WriteLine($"Result {++i}:");
|
||||
WriteLine(" URL: : " + memoryResult.Metadata.Id);
|
||||
WriteLine(" Title : " + memoryResult.Metadata.Description);
|
||||
WriteLine(" Relevance: " + memoryResult.Relevance);
|
||||
WriteLine();
|
||||
}
|
||||
|
||||
Console.WriteLine("----------------------");
|
||||
WriteLine("----------------------");
|
||||
}
|
||||
|
||||
private static async Task StoreMemoryAsync(ISemanticTextMemory memory)
|
||||
private async Task StoreMemoryAsync(ISemanticTextMemory memory)
|
||||
{
|
||||
/* Store some data in the semantic memory.
|
||||
*
|
||||
@@ -127,7 +132,7 @@ public static class Example14_SemanticMemory
|
||||
* care of creating and storing the index
|
||||
*/
|
||||
|
||||
Console.WriteLine("\nAdding some GitHub file URLs and their descriptions to the semantic memory.");
|
||||
WriteLine("\nAdding some GitHub file URLs and their descriptions to the semantic memory.");
|
||||
var githubFiles = SampleData();
|
||||
var i = 0;
|
||||
foreach (var entry in githubFiles)
|
||||
@@ -142,7 +147,7 @@ public static class Example14_SemanticMemory
|
||||
Console.Write($" #{++i} saved.");
|
||||
}
|
||||
|
||||
Console.WriteLine("\n----------------------");
|
||||
WriteLine("\n----------------------");
|
||||
}
|
||||
|
||||
private static Dictionary<string, string> SampleData()
|
||||
@@ -161,4 +166,8 @@ public static class Example14_SemanticMemory
|
||||
= "C# class that defines a volatile embedding store",
|
||||
};
|
||||
}
|
||||
|
||||
public Example14_SemanticMemory(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Connectors.AzureAISearch;
|
||||
@@ -21,12 +19,19 @@ using Microsoft.SemanticKernel.Plugins.Memory;
|
||||
using Npgsql;
|
||||
using RepoUtils;
|
||||
using StackExchange.Redis;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
public static class Example15_TextMemoryPlugin
|
||||
namespace Examples;
|
||||
|
||||
public class Example15_TextMemoryPlugin : BaseTest
|
||||
{
|
||||
private const string MemoryCollectionName = "aboutMe";
|
||||
|
||||
public static async Task RunAsync(CancellationToken cancellationToken = default)
|
||||
[Theory]
|
||||
[InlineData("Volatile")]
|
||||
[InlineData("AzureAISearch")]
|
||||
public async Task RunAsync(string provider)
|
||||
{
|
||||
IMemoryStore store;
|
||||
|
||||
@@ -35,7 +40,11 @@ public static class Example15_TextMemoryPlugin
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Volatile Memory Store - an in-memory store that is not persisted
|
||||
store = new VolatileMemoryStore();
|
||||
switch (provider)
|
||||
{
|
||||
case "AzureAISearch": store = CreateSampleAzureAISearchMemoryStore(); break;
|
||||
default: store = new VolatileMemoryStore(); break;
|
||||
}
|
||||
|
||||
// Sqlite Memory Store - a file-based store that persists data in a Sqlite database
|
||||
// store = await CreateSampleSqliteMemoryStoreAsync();
|
||||
@@ -70,58 +79,58 @@ public static class Example15_TextMemoryPlugin
|
||||
// Kusto Memory Store
|
||||
// store = CreateSampleKustoMemoryStore();
|
||||
|
||||
await RunWithStoreAsync(store, cancellationToken);
|
||||
await RunWithStoreAsync(store);
|
||||
}
|
||||
|
||||
private static async Task<IMemoryStore> CreateSampleSqliteMemoryStoreAsync()
|
||||
private async Task<IMemoryStore> CreateSampleSqliteMemoryStoreAsync()
|
||||
{
|
||||
IMemoryStore store = await SqliteMemoryStore.ConnectAsync("memories.sqlite");
|
||||
return store;
|
||||
}
|
||||
|
||||
private static async Task<IMemoryStore> CreateSampleDuckDbMemoryStoreAsync()
|
||||
private async Task<IMemoryStore> CreateSampleDuckDbMemoryStoreAsync()
|
||||
{
|
||||
IMemoryStore store = await DuckDBMemoryStore.ConnectAsync("memories.duckdb");
|
||||
return store;
|
||||
}
|
||||
|
||||
private static IMemoryStore CreateSampleMongoDBMemoryStore()
|
||||
private IMemoryStore CreateSampleMongoDBMemoryStore()
|
||||
{
|
||||
IMemoryStore store = new MongoDBMemoryStore(TestConfiguration.MongoDB.ConnectionString, "memoryPluginExample");
|
||||
return store;
|
||||
}
|
||||
|
||||
private static IMemoryStore CreateSampleAzureAISearchMemoryStore()
|
||||
private IMemoryStore CreateSampleAzureAISearchMemoryStore()
|
||||
{
|
||||
IMemoryStore store = new AzureAISearchMemoryStore(TestConfiguration.AzureAISearch.Endpoint, TestConfiguration.AzureAISearch.ApiKey);
|
||||
return store;
|
||||
}
|
||||
|
||||
private static IMemoryStore CreateSampleChromaMemoryStore()
|
||||
private IMemoryStore CreateSampleChromaMemoryStore()
|
||||
{
|
||||
IMemoryStore store = new ChromaMemoryStore(TestConfiguration.Chroma.Endpoint, ConsoleLogger.LoggerFactory);
|
||||
return store;
|
||||
}
|
||||
|
||||
private static IMemoryStore CreateSampleQdrantMemoryStore()
|
||||
private IMemoryStore CreateSampleQdrantMemoryStore()
|
||||
{
|
||||
IMemoryStore store = new QdrantMemoryStore(TestConfiguration.Qdrant.Endpoint, 1536, ConsoleLogger.LoggerFactory);
|
||||
return store;
|
||||
}
|
||||
|
||||
private static IMemoryStore CreateSamplePineconeMemoryStore()
|
||||
private IMemoryStore CreateSamplePineconeMemoryStore()
|
||||
{
|
||||
IMemoryStore store = new PineconeMemoryStore(TestConfiguration.Pinecone.Environment, TestConfiguration.Pinecone.ApiKey, ConsoleLogger.LoggerFactory);
|
||||
return store;
|
||||
}
|
||||
|
||||
private static IMemoryStore CreateSampleWeaviateMemoryStore()
|
||||
private IMemoryStore CreateSampleWeaviateMemoryStore()
|
||||
{
|
||||
IMemoryStore store = new WeaviateMemoryStore(TestConfiguration.Weaviate.Endpoint, TestConfiguration.Weaviate.ApiKey);
|
||||
return store;
|
||||
}
|
||||
|
||||
private static async Task<IMemoryStore> CreateSampleRedisMemoryStoreAsync()
|
||||
private async Task<IMemoryStore> CreateSampleRedisMemoryStoreAsync()
|
||||
{
|
||||
string configuration = TestConfiguration.Redis.Configuration;
|
||||
ConnectionMultiplexer connectionMultiplexer = await ConnectionMultiplexer.ConnectAsync(configuration);
|
||||
@@ -146,7 +155,7 @@ public static class Example15_TextMemoryPlugin
|
||||
return store;
|
||||
}
|
||||
|
||||
private static async Task RunWithStoreAsync(IMemoryStore memoryStore, CancellationToken cancellationToken)
|
||||
private async Task RunWithStoreAsync(IMemoryStore memoryStore)
|
||||
{
|
||||
var kernel = Kernel.CreateBuilder()
|
||||
.AddOpenAIChatCompletion(TestConfiguration.OpenAI.ChatModelId, TestConfiguration.OpenAI.ApiKey)
|
||||
@@ -165,25 +174,25 @@ public static class Example15_TextMemoryPlugin
|
||||
//
|
||||
// This is a simple way to store memories from a code perspective, without using the Kernel.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
Console.WriteLine("== PART 1a: Saving Memories through the ISemanticTextMemory object ==");
|
||||
WriteLine("== PART 1a: Saving Memories through the ISemanticTextMemory object ==");
|
||||
|
||||
Console.WriteLine("Saving memory with key 'info1': \"My name is Andrea\"");
|
||||
await textMemory.SaveInformationAsync(MemoryCollectionName, id: "info1", text: "My name is Andrea", cancellationToken: cancellationToken);
|
||||
WriteLine("Saving memory with key 'info1': \"My name is Andrea\"");
|
||||
await textMemory.SaveInformationAsync(MemoryCollectionName, id: "info1", text: "My name is Andrea");
|
||||
|
||||
Console.WriteLine("Saving memory with key 'info2': \"I work as a tourist operator\"");
|
||||
await textMemory.SaveInformationAsync(MemoryCollectionName, id: "info2", text: "I work as a tourist operator", cancellationToken: cancellationToken);
|
||||
WriteLine("Saving memory with key 'info2': \"I work as a tourist operator\"");
|
||||
await textMemory.SaveInformationAsync(MemoryCollectionName, id: "info2", text: "I work as a tourist operator");
|
||||
|
||||
Console.WriteLine("Saving memory with key 'info3': \"I've been living in Seattle since 2005\"");
|
||||
await textMemory.SaveInformationAsync(MemoryCollectionName, id: "info3", text: "I've been living in Seattle since 2005", cancellationToken: cancellationToken);
|
||||
WriteLine("Saving memory with key 'info3': \"I've been living in Seattle since 2005\"");
|
||||
await textMemory.SaveInformationAsync(MemoryCollectionName, id: "info3", text: "I've been living in Seattle since 2005");
|
||||
|
||||
Console.WriteLine("Saving memory with key 'info4': \"I visited France and Italy five times since 2015\"");
|
||||
await textMemory.SaveInformationAsync(MemoryCollectionName, id: "info4", text: "I visited France and Italy five times since 2015", cancellationToken: cancellationToken);
|
||||
WriteLine("Saving memory with key 'info4': \"I visited France and Italy five times since 2015\"");
|
||||
await textMemory.SaveInformationAsync(MemoryCollectionName, id: "info4", text: "I visited France and Italy five times since 2015");
|
||||
|
||||
// Retrieve a memory
|
||||
Console.WriteLine("== PART 1b: Retrieving Memories through the ISemanticTextMemory object ==");
|
||||
MemoryQueryResult? lookup = await textMemory.GetAsync(MemoryCollectionName, "info1", cancellationToken: cancellationToken);
|
||||
Console.WriteLine("Memory with key 'info1':" + lookup?.Metadata.Text ?? "ERROR: memory not found");
|
||||
Console.WriteLine();
|
||||
WriteLine("== PART 1b: Retrieving Memories through the ISemanticTextMemory object ==");
|
||||
MemoryQueryResult? lookup = await textMemory.GetAsync(MemoryCollectionName, "info1");
|
||||
WriteLine("Memory with key 'info1':" + lookup?.Metadata.Text ?? "ERROR: memory not found");
|
||||
WriteLine();
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PART 2: Create TextMemoryPlugin, store and retrieve memories through the Kernel.
|
||||
@@ -191,30 +200,30 @@ public static class Example15_TextMemoryPlugin
|
||||
// This enables prompt functions and the AI (via Planners) to access memories
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Console.WriteLine("== PART 2a: Saving Memories through the Kernel with TextMemoryPlugin and the 'Save' function ==");
|
||||
WriteLine("== PART 2a: Saving Memories through the Kernel with TextMemoryPlugin and the 'Save' function ==");
|
||||
|
||||
// Import the TextMemoryPlugin into the Kernel for other functions
|
||||
var memoryPlugin = kernel.ImportPluginFromObject(new TextMemoryPlugin(textMemory));
|
||||
|
||||
// Save a memory with the Kernel
|
||||
Console.WriteLine("Saving memory with key 'info5': \"My family is from New York\"");
|
||||
WriteLine("Saving memory with key 'info5': \"My family is from New York\"");
|
||||
await kernel.InvokeAsync(memoryPlugin["Save"], new()
|
||||
{
|
||||
[TextMemoryPlugin.InputParam] = "My family is from New York",
|
||||
[TextMemoryPlugin.CollectionParam] = MemoryCollectionName,
|
||||
[TextMemoryPlugin.KeyParam] = "info5",
|
||||
}, cancellationToken);
|
||||
});
|
||||
|
||||
// Retrieve a specific memory with the Kernel
|
||||
Console.WriteLine("== PART 2b: Retrieving Memories through the Kernel with TextMemoryPlugin and the 'Retrieve' function ==");
|
||||
WriteLine("== PART 2b: Retrieving Memories through the Kernel with TextMemoryPlugin and the 'Retrieve' function ==");
|
||||
var result = await kernel.InvokeAsync(memoryPlugin["Retrieve"], new KernelArguments()
|
||||
{
|
||||
[TextMemoryPlugin.CollectionParam] = MemoryCollectionName,
|
||||
[TextMemoryPlugin.KeyParam] = "info5"
|
||||
}, cancellationToken);
|
||||
});
|
||||
|
||||
Console.WriteLine("Memory with key 'info5':" + result.GetValue<string>() ?? "ERROR: memory not found");
|
||||
Console.WriteLine();
|
||||
WriteLine("Memory with key 'info5':" + result.GetValue<string>() ?? "ERROR: memory not found");
|
||||
WriteLine();
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PART 3: Recall similar ideas with semantic search
|
||||
@@ -222,24 +231,23 @@ public static class Example15_TextMemoryPlugin
|
||||
// Uses AI Embeddings for fuzzy lookup of memories based on intent, rather than a specific key.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Console.WriteLine("== PART 3: Recall (similarity search) with AI Embeddings ==");
|
||||
WriteLine("== PART 3: Recall (similarity search) with AI Embeddings ==");
|
||||
|
||||
Console.WriteLine("== PART 3a: Recall (similarity search) with ISemanticTextMemory ==");
|
||||
Console.WriteLine("Ask: where did I grow up?");
|
||||
WriteLine("== PART 3a: Recall (similarity search) with ISemanticTextMemory ==");
|
||||
WriteLine("Ask: where did I grow up?");
|
||||
|
||||
await foreach (var answer in textMemory.SearchAsync(
|
||||
collection: MemoryCollectionName,
|
||||
query: "where did I grow up?",
|
||||
limit: 2,
|
||||
minRelevanceScore: 0.79,
|
||||
withEmbeddings: true,
|
||||
cancellationToken: cancellationToken))
|
||||
withEmbeddings: true))
|
||||
{
|
||||
Console.WriteLine($"Answer: {answer.Metadata.Text}");
|
||||
WriteLine($"Answer: {answer.Metadata.Text}");
|
||||
}
|
||||
|
||||
Console.WriteLine("== PART 3b: Recall (similarity search) with Kernel and TextMemoryPlugin 'Recall' function ==");
|
||||
Console.WriteLine("Ask: where do I live?");
|
||||
WriteLine("== PART 3b: Recall (similarity search) with Kernel and TextMemoryPlugin 'Recall' function ==");
|
||||
WriteLine("Ask: where do I live?");
|
||||
|
||||
result = await kernel.InvokeAsync(memoryPlugin["Recall"], new()
|
||||
{
|
||||
@@ -247,10 +255,10 @@ public static class Example15_TextMemoryPlugin
|
||||
[TextMemoryPlugin.CollectionParam] = MemoryCollectionName,
|
||||
[TextMemoryPlugin.LimitParam] = "2",
|
||||
[TextMemoryPlugin.RelevanceParam] = "0.79",
|
||||
}, cancellationToken);
|
||||
});
|
||||
|
||||
Console.WriteLine($"Answer: {result.GetValue<string>()}");
|
||||
Console.WriteLine();
|
||||
WriteLine($"Answer: {result.GetValue<string>()}");
|
||||
WriteLine();
|
||||
|
||||
/*
|
||||
Output:
|
||||
@@ -271,7 +279,7 @@ public static class Example15_TextMemoryPlugin
|
||||
// the text generation model to answer a natural language query.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Console.WriteLine("== PART 4: Using TextMemoryPlugin 'Recall' function in a Prompt Function ==");
|
||||
WriteLine("== PART 4: Using TextMemoryPlugin 'Recall' function in a Prompt Function ==");
|
||||
|
||||
// Build a prompt function that uses memory to find facts
|
||||
const string RecallFunctionDefinition = @"
|
||||
@@ -295,10 +303,10 @@ Answer:
|
||||
[TextMemoryPlugin.CollectionParam] = MemoryCollectionName,
|
||||
[TextMemoryPlugin.LimitParam] = "2",
|
||||
[TextMemoryPlugin.RelevanceParam] = "0.79",
|
||||
}, cancellationToken);
|
||||
});
|
||||
|
||||
Console.WriteLine("Ask: Do I live in the same town where I grew up?");
|
||||
Console.WriteLine($"Answer: {result.GetValue<string>()}");
|
||||
WriteLine("Ask: Do I live in the same town where I grew up?");
|
||||
WriteLine($"Answer: {result.GetValue<string>()}");
|
||||
|
||||
/*
|
||||
Approximate Output:
|
||||
@@ -310,25 +318,29 @@ Answer:
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Console.WriteLine("== PART 5: Cleanup, deleting database collection ==");
|
||||
WriteLine("== PART 5: Cleanup, deleting database collection ==");
|
||||
|
||||
Console.WriteLine("Printing Collections in DB...");
|
||||
var collections = memoryStore.GetCollectionsAsync(cancellationToken);
|
||||
WriteLine("Printing Collections in DB...");
|
||||
var collections = memoryStore.GetCollectionsAsync();
|
||||
await foreach (var collection in collections)
|
||||
{
|
||||
Console.WriteLine(collection);
|
||||
WriteLine(collection);
|
||||
}
|
||||
Console.WriteLine();
|
||||
WriteLine();
|
||||
|
||||
Console.WriteLine("Removing Collection {0}", MemoryCollectionName);
|
||||
await memoryStore.DeleteCollectionAsync(MemoryCollectionName, cancellationToken);
|
||||
Console.WriteLine();
|
||||
WriteLine($"Removing Collection {MemoryCollectionName}");
|
||||
await memoryStore.DeleteCollectionAsync(MemoryCollectionName);
|
||||
WriteLine();
|
||||
|
||||
Console.WriteLine($"Printing Collections in DB (after removing {MemoryCollectionName})...");
|
||||
collections = memoryStore.GetCollectionsAsync(cancellationToken);
|
||||
WriteLine($"Printing Collections in DB (after removing {MemoryCollectionName})...");
|
||||
collections = memoryStore.GetCollectionsAsync();
|
||||
await foreach (var collection in collections)
|
||||
{
|
||||
Console.WriteLine(collection);
|
||||
WriteLine(collection);
|
||||
}
|
||||
}
|
||||
|
||||
public Example15_TextMemoryPlugin(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,10 @@ using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.TextGeneration;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
/**
|
||||
* The following example shows how to plug a custom text generation model into SK.
|
||||
@@ -24,18 +28,12 @@ using Microsoft.SemanticKernel.TextGeneration;
|
||||
*
|
||||
* Refer to example 33 for streaming chat completion.
|
||||
*/
|
||||
public static class Example16_CustomLLM
|
||||
public class Example16_CustomLLM : BaseTest
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task CustomTextGenerationWithKernelFunctionAsync()
|
||||
{
|
||||
await CustomTextGenerationWithKernelFunctionAsync();
|
||||
await CustomTextGenerationAsync();
|
||||
await CustomTextGenerationStreamAsync();
|
||||
}
|
||||
|
||||
private static async Task CustomTextGenerationWithKernelFunctionAsync()
|
||||
{
|
||||
Console.WriteLine("\n======== Custom LLM - Text Completion - KernelFunction ========");
|
||||
WriteLine("\n======== Custom LLM - Text Completion - KernelFunction ========");
|
||||
|
||||
IKernelBuilder builder = Kernel.CreateBuilder();
|
||||
// Add your text generation service as a singleton instance
|
||||
@@ -48,39 +46,41 @@ public static class Example16_CustomLLM
|
||||
var paragraphWritingFunction = kernel.CreateFunctionFromPrompt(FunctionDefinition);
|
||||
|
||||
const string Input = "Why AI is awesome";
|
||||
Console.WriteLine($"Function input: {Input}\n");
|
||||
WriteLine($"Function input: {Input}\n");
|
||||
var result = await paragraphWritingFunction.InvokeAsync(kernel, new() { ["input"] = Input });
|
||||
|
||||
Console.WriteLine(result);
|
||||
WriteLine(result);
|
||||
}
|
||||
|
||||
private static async Task CustomTextGenerationAsync()
|
||||
[Fact]
|
||||
public async Task CustomTextGenerationAsync()
|
||||
{
|
||||
Console.WriteLine("\n======== Custom LLM - Text Completion - Raw ========");
|
||||
WriteLine("\n======== Custom LLM - Text Completion - Raw ========");
|
||||
|
||||
const string Prompt = "Write one paragraph on why AI is awesome.";
|
||||
var completionService = new MyTextGenerationService();
|
||||
|
||||
Console.WriteLine($"Prompt: {Prompt}\n");
|
||||
WriteLine($"Prompt: {Prompt}\n");
|
||||
var result = await completionService.GetTextContentAsync(Prompt);
|
||||
|
||||
Console.WriteLine(result);
|
||||
WriteLine(result);
|
||||
}
|
||||
|
||||
private static async Task CustomTextGenerationStreamAsync()
|
||||
[Fact]
|
||||
public async Task CustomTextGenerationStreamAsync()
|
||||
{
|
||||
Console.WriteLine("\n======== Custom LLM - Text Completion - Raw Streaming ========");
|
||||
WriteLine("\n======== Custom LLM - Text Completion - Raw Streaming ========");
|
||||
|
||||
const string Prompt = "Write one paragraph on why AI is awesome.";
|
||||
var completionService = new MyTextGenerationService();
|
||||
|
||||
Console.WriteLine($"Prompt: {Prompt}\n");
|
||||
WriteLine($"Prompt: {Prompt}\n");
|
||||
await foreach (var message in completionService.GetStreamingTextContentsAsync(Prompt))
|
||||
{
|
||||
Console.Write(message);
|
||||
Write(message);
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
WriteLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -117,4 +117,8 @@ providing personalized recommendations, entertainment, and assistance. AI is awe
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public Example16_CustomLLM(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,25 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
// The following example shows how to use Semantic Kernel with OpenAI ChatGPT API
|
||||
public static class Example17_ChatGPT
|
||||
public class Example17_ChatGPT : BaseTest
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task OpenAIChatSampleAsync()
|
||||
{
|
||||
await AzureOpenAIChatSampleAsync();
|
||||
await OpenAIChatSampleAsync();
|
||||
WriteLine("======== Open AI - ChatGPT ========");
|
||||
|
||||
OpenAIChatCompletionService chatCompletionService = new(TestConfiguration.OpenAI.ChatModelId, TestConfiguration.OpenAI.ApiKey);
|
||||
|
||||
await StartChatAsync(chatCompletionService);
|
||||
|
||||
/* Output:
|
||||
|
||||
@@ -43,18 +50,10 @@ public static class Example17_ChatGPT
|
||||
*/
|
||||
}
|
||||
|
||||
private static async Task OpenAIChatSampleAsync()
|
||||
[Fact]
|
||||
public async Task AzureOpenAIChatSampleAsync()
|
||||
{
|
||||
Console.WriteLine("======== Open AI - ChatGPT ========");
|
||||
|
||||
OpenAIChatCompletionService chatCompletionService = new(TestConfiguration.OpenAI.ChatModelId, TestConfiguration.OpenAI.ApiKey);
|
||||
|
||||
await StartChatAsync(chatCompletionService);
|
||||
}
|
||||
|
||||
private static async Task AzureOpenAIChatSampleAsync()
|
||||
{
|
||||
Console.WriteLine("======== Azure Open AI - ChatGPT ========");
|
||||
WriteLine("======== Azure Open AI - ChatGPT ========");
|
||||
|
||||
AzureOpenAIChatCompletionService chatCompletionService = new(
|
||||
deploymentName: TestConfiguration.AzureOpenAI.ChatDeploymentName,
|
||||
@@ -65,10 +64,10 @@ public static class Example17_ChatGPT
|
||||
await StartChatAsync(chatCompletionService);
|
||||
}
|
||||
|
||||
private static async Task StartChatAsync(IChatCompletionService chatGPT)
|
||||
private async Task StartChatAsync(IChatCompletionService chatGPT)
|
||||
{
|
||||
Console.WriteLine("Chat content:");
|
||||
Console.WriteLine("------------------------");
|
||||
WriteLine("Chat content:");
|
||||
WriteLine("------------------------");
|
||||
|
||||
var chatHistory = new ChatHistory("You are a librarian, expert about books");
|
||||
|
||||
@@ -94,13 +93,17 @@ public static class Example17_ChatGPT
|
||||
/// <summary>
|
||||
/// Outputs the last message of the chat history
|
||||
/// </summary>
|
||||
private static Task MessageOutputAsync(ChatHistory chatHistory)
|
||||
private Task MessageOutputAsync(ChatHistory chatHistory)
|
||||
{
|
||||
var message = chatHistory.Last();
|
||||
|
||||
Console.WriteLine($"{message.Role}: {message.Content}");
|
||||
Console.WriteLine("------------------------");
|
||||
WriteLine($"{message.Role}: {message.Content}");
|
||||
WriteLine("------------------------");
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Example17_ChatGPT(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,19 +7,18 @@ using Microsoft.Extensions.Http.Resilience;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using Microsoft.SemanticKernel.TextToImage;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
// The following example shows how to use Semantic Kernel with OpenAI Dall-E 2 to create images
|
||||
public static class Example18_DallE
|
||||
public class Example18_DallE : BaseTest
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task OpenAIDallEAsync()
|
||||
{
|
||||
await OpenAIDallEAsync();
|
||||
await AzureOpenAIDallEAsync();
|
||||
}
|
||||
|
||||
private static async Task OpenAIDallEAsync()
|
||||
{
|
||||
Console.WriteLine("======== OpenAI Dall-E 2 Text To Image ========");
|
||||
WriteLine("======== OpenAI Dall-E 2 Text To Image ========");
|
||||
|
||||
Kernel kernel = Kernel.CreateBuilder()
|
||||
.AddOpenAITextToImage(TestConfiguration.OpenAI.ApiKey) // Add your text to image service
|
||||
@@ -31,8 +30,8 @@ public static class Example18_DallE
|
||||
var imageDescription = "A cute baby sea otter";
|
||||
var image = await dallE.GenerateImageAsync(imageDescription, 256, 256);
|
||||
|
||||
Console.WriteLine(imageDescription);
|
||||
Console.WriteLine("Image URL: " + image);
|
||||
WriteLine(imageDescription);
|
||||
WriteLine("Image URL: " + image);
|
||||
|
||||
/* Output:
|
||||
|
||||
@@ -41,7 +40,7 @@ public static class Example18_DallE
|
||||
|
||||
*/
|
||||
|
||||
Console.WriteLine("======== Chat with images ========");
|
||||
WriteLine("======== Chat with images ========");
|
||||
|
||||
var chatGPT = kernel.GetRequiredService<IChatCompletionService>();
|
||||
var chatHistory = new ChatHistory(
|
||||
@@ -52,23 +51,23 @@ public static class Example18_DallE
|
||||
|
||||
var msg = "Hi, I'm from Tokyo, where are you from?";
|
||||
chatHistory.AddUserMessage(msg);
|
||||
Console.WriteLine("User: " + msg);
|
||||
WriteLine("User: " + msg);
|
||||
|
||||
var reply = await chatGPT.GetChatMessageContentAsync(chatHistory);
|
||||
chatHistory.Add(reply);
|
||||
image = await dallE.GenerateImageAsync(reply.Content!, 256, 256);
|
||||
Console.WriteLine("Bot: " + image);
|
||||
Console.WriteLine("Img description: " + reply);
|
||||
WriteLine("Bot: " + image);
|
||||
WriteLine("Img description: " + reply);
|
||||
|
||||
msg = "Oh, wow. Not sure where that is, could you provide more details?";
|
||||
chatHistory.AddUserMessage(msg);
|
||||
Console.WriteLine("User: " + msg);
|
||||
WriteLine("User: " + msg);
|
||||
|
||||
reply = await chatGPT.GetChatMessageContentAsync(chatHistory);
|
||||
chatHistory.Add(reply);
|
||||
image = await dallE.GenerateImageAsync(reply.Content!, 256, 256);
|
||||
Console.WriteLine("Bot: " + image);
|
||||
Console.WriteLine("Img description: " + reply);
|
||||
WriteLine("Bot: " + image);
|
||||
WriteLine("Img description: " + reply);
|
||||
|
||||
/* Output:
|
||||
|
||||
@@ -83,9 +82,10 @@ public static class Example18_DallE
|
||||
*/
|
||||
}
|
||||
|
||||
public static async Task AzureOpenAIDallEAsync()
|
||||
[Fact(Skip = "Generating the Image can take too long and often break the test")]
|
||||
public async Task AzureOpenAIDallEAsync()
|
||||
{
|
||||
Console.WriteLine("========Azure OpenAI Dall-E 3 Text To Image ========");
|
||||
WriteLine("========Azure OpenAI Dall-E 3 Text To Image ========");
|
||||
|
||||
var builder = Kernel.CreateBuilder()
|
||||
.AddAzureOpenAITextToImage( // Add your text to image service
|
||||
@@ -105,6 +105,7 @@ public static class Example18_DallE
|
||||
c.AddStandardResilienceHandler().Configure(o =>
|
||||
{
|
||||
o.Retry.MaxRetryAttempts = 5;
|
||||
o.TotalRequestTimeout.Timeout = TimeSpan.FromSeconds(60);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -114,8 +115,8 @@ public static class Example18_DallE
|
||||
var imageDescription = "A cute baby sea otter";
|
||||
var image = await dallE.GenerateImageAsync(imageDescription, 1024, 1024);
|
||||
|
||||
Console.WriteLine(imageDescription);
|
||||
Console.WriteLine("Image URL: " + image);
|
||||
WriteLine(imageDescription);
|
||||
WriteLine("Image URL: " + image);
|
||||
|
||||
/* Output:
|
||||
|
||||
@@ -124,7 +125,7 @@ public static class Example18_DallE
|
||||
|
||||
*/
|
||||
|
||||
Console.WriteLine("======== Chat with images ========");
|
||||
WriteLine("======== Chat with images ========");
|
||||
|
||||
var chatGPT = kernel.GetRequiredService<IChatCompletionService>();
|
||||
var chatHistory = new ChatHistory(
|
||||
@@ -135,23 +136,23 @@ public static class Example18_DallE
|
||||
|
||||
var msg = "Hi, I'm from Tokyo, where are you from?";
|
||||
chatHistory.AddUserMessage(msg);
|
||||
Console.WriteLine("User: " + msg);
|
||||
WriteLine("User: " + msg);
|
||||
|
||||
var reply = await chatGPT.GetChatMessageContentAsync(chatHistory);
|
||||
chatHistory.Add(reply);
|
||||
image = await dallE.GenerateImageAsync(reply.Content!, 1024, 1024);
|
||||
Console.WriteLine("Bot: " + image);
|
||||
Console.WriteLine("Img description: " + reply);
|
||||
WriteLine("Bot: " + image);
|
||||
WriteLine("Img description: " + reply);
|
||||
|
||||
msg = "Oh, wow. Not sure where that is, could you provide more details?";
|
||||
chatHistory.AddUserMessage(msg);
|
||||
Console.WriteLine("User: " + msg);
|
||||
WriteLine("User: " + msg);
|
||||
|
||||
reply = await chatGPT.GetChatMessageContentAsync(chatHistory);
|
||||
chatHistory.Add(reply);
|
||||
image = await dallE.GenerateImageAsync(reply.Content!, 1024, 1024);
|
||||
Console.WriteLine("Bot: " + image);
|
||||
Console.WriteLine("Img description: " + reply);
|
||||
WriteLine("Bot: " + image);
|
||||
WriteLine("Img description: " + reply);
|
||||
|
||||
/* Output:
|
||||
|
||||
@@ -165,4 +166,8 @@ public static class Example18_DallE
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
public Example18_DallE(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,23 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
// The following example shows how to use Semantic Kernel with HuggingFace API.
|
||||
public static class Example20_HuggingFace
|
||||
public class Example20_HuggingFace : BaseTest
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
{
|
||||
await RunInferenceApiExampleAsync();
|
||||
await RunLlamaExampleAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This example uses HuggingFace Inference API to access hosted models.
|
||||
/// More information here: <see href="https://huggingface.co/inference-api"/>
|
||||
/// </summary>
|
||||
private static async Task RunInferenceApiExampleAsync()
|
||||
[Fact]
|
||||
public async Task RunInferenceApiExampleAsync()
|
||||
{
|
||||
Console.WriteLine("\n======== HuggingFace Inference API example ========\n");
|
||||
WriteLine("\n======== HuggingFace Inference API example ========\n");
|
||||
|
||||
Kernel kernel = Kernel.CreateBuilder()
|
||||
.AddHuggingFaceTextGeneration(
|
||||
@@ -31,7 +29,7 @@ public static class Example20_HuggingFace
|
||||
|
||||
var result = await kernel.InvokeAsync(questionAnswerFunction, new() { ["input"] = "What is New York?" });
|
||||
|
||||
Console.WriteLine(result.GetValue<string>());
|
||||
WriteLine(result.GetValue<string>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -45,20 +43,21 @@ public static class Example20_HuggingFace
|
||||
/// Note: Your Hugging Face account email address MUST match the email you provide on the Meta website, or your request will not be approved.
|
||||
/// </remarks>
|
||||
/// </summary>
|
||||
private static async Task RunLlamaExampleAsync()
|
||||
[Fact(Skip = "Requires local model or Huggingface Pro subscription")]
|
||||
public async Task RunLlamaExampleAsync()
|
||||
{
|
||||
Console.WriteLine("\n======== HuggingFace Llama 2 example ========\n");
|
||||
WriteLine("\n======== HuggingFace Llama 2 example ========\n");
|
||||
|
||||
// HuggingFace Llama 2 model: https://huggingface.co/meta-llama/Llama-2-7b-hf
|
||||
const string Model = "meta-llama/Llama-2-7b-hf";
|
||||
|
||||
// HuggingFace local HTTP server endpoint
|
||||
const string Endpoint = "http://localhost:5000/completions";
|
||||
// const string Endpoint = "http://localhost:5000/completions";
|
||||
|
||||
Kernel kernel = Kernel.CreateBuilder()
|
||||
.AddHuggingFaceTextGeneration(
|
||||
model: Model,
|
||||
endpoint: Endpoint,
|
||||
//endpoint: Endpoint,
|
||||
apiKey: TestConfiguration.HuggingFace.ApiKey)
|
||||
.Build();
|
||||
|
||||
@@ -66,6 +65,10 @@ public static class Example20_HuggingFace
|
||||
|
||||
var result = await kernel.InvokeAsync(questionAnswerFunction, new() { ["input"] = "What is New York?" });
|
||||
|
||||
Console.WriteLine(result.GetValue<string>());
|
||||
WriteLine(result.GetValue<string>());
|
||||
}
|
||||
|
||||
public Example20_HuggingFace(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,22 +5,18 @@ using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Plugins.OpenApi;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
public static class Example21_OpenAIPlugins
|
||||
namespace Examples;
|
||||
|
||||
public class Example21_OpenAIPlugins : BaseTest
|
||||
{
|
||||
public static Task RunAsync()
|
||||
{
|
||||
// Uncomment after filling the template below
|
||||
// await RunOpenAIPluginAsync();
|
||||
|
||||
// --------------- Example using Klarna's OpenAI plugin ------------------------
|
||||
return CallKlarnaAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generic template on how to call OpenAI plugins
|
||||
/// </summary>
|
||||
public static async Task RunOpenAIPluginAsync()
|
||||
[Fact(Skip = "Run it only after filling the template below")]
|
||||
public async Task RunOpenAIPluginAsync()
|
||||
{
|
||||
Kernel kernel = new();
|
||||
|
||||
@@ -38,10 +34,11 @@ public static class Example21_OpenAIPlugins
|
||||
|
||||
var result = functionResult.GetValue<RestApiOperationResponse>();
|
||||
|
||||
Console.WriteLine("Function execution result: {0}", result?.Content?.ToString());
|
||||
WriteLine($"Function execution result: {result?.Content}");
|
||||
}
|
||||
|
||||
public static async Task CallKlarnaAsync()
|
||||
[Fact]
|
||||
public async Task CallKlarnaAsync()
|
||||
{
|
||||
Kernel kernel = new();
|
||||
|
||||
@@ -58,6 +55,10 @@ public static class Example21_OpenAIPlugins
|
||||
|
||||
var result = functionResult.GetValue<RestApiOperationResponse>();
|
||||
|
||||
Console.WriteLine("Function execution result: {0}", result?.Content?.ToString());
|
||||
WriteLine($"Function execution result: {result?.Content}");
|
||||
}
|
||||
|
||||
public Example21_OpenAIPlugins(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,12 @@ using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Plugins.OpenApi;
|
||||
using Resources;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
public static class Example22_OpenAIPlugin_AzureKeyVault
|
||||
namespace Examples;
|
||||
|
||||
public class Example22_OpenAIPlugin_AzureKeyVault : BaseTest
|
||||
{
|
||||
private const string SecretName = "Foo";
|
||||
private const string SecretValue = "Bar";
|
||||
@@ -38,7 +42,8 @@ public static class Example22_OpenAIPlugin_AzureKeyVault
|
||||
///
|
||||
/// 5. Replace your tenant ID with the "TENANT_ID" placeholder in dotnet/samples/KernelSyntaxExamples/Resources/22-ai-plugin.json
|
||||
/// </summary>
|
||||
public static async Task RunAsync()
|
||||
[Fact(Skip = "Setup credentials")]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
var authenticationProvider = new OpenAIAuthenticationProvider(
|
||||
new Dictionary<string, Dictionary<string, string>>()
|
||||
@@ -78,7 +83,7 @@ public static class Example22_OpenAIPlugin_AzureKeyVault
|
||||
await GetSecretFromAzureKeyVaultWithRetryAsync(kernel, plugin);
|
||||
}
|
||||
|
||||
public static async Task AddSecretToAzureKeyVaultAsync(Kernel kernel, KernelPlugin plugin)
|
||||
private async Task AddSecretToAzureKeyVaultAsync(Kernel kernel, KernelPlugin plugin)
|
||||
{
|
||||
// Add arguments for required parameters, arguments for optional ones can be skipped.
|
||||
var arguments = new KernelArguments
|
||||
@@ -97,7 +102,7 @@ public static class Example22_OpenAIPlugin_AzureKeyVault
|
||||
Console.WriteLine("SetSecret function result: {0}", result?.Content?.ToString());
|
||||
}
|
||||
|
||||
public static async Task GetSecretFromAzureKeyVaultWithRetryAsync(Kernel kernel, KernelPlugin plugin)
|
||||
private static async Task GetSecretFromAzureKeyVaultWithRetryAsync(Kernel kernel, KernelPlugin plugin)
|
||||
{
|
||||
// Add arguments for required parameters, arguments for optional ones can be skipped.
|
||||
var arguments = new KernelArguments();
|
||||
@@ -111,6 +116,10 @@ public static class Example22_OpenAIPlugin_AzureKeyVault
|
||||
|
||||
Console.WriteLine("GetSecret function result: {0}", result?.Content?.ToString());
|
||||
}
|
||||
|
||||
public Example22_OpenAIPlugin_AzureKeyVault(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#region Utility Classes
|
||||
|
||||
@@ -12,8 +12,12 @@ using System.Threading.Tasks;
|
||||
using Microsoft.Identity.Client;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Plugins.OpenApi;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
public static class Example24_OpenApiPlugin_Jira
|
||||
namespace Examples;
|
||||
|
||||
public class Example24_OpenApiPlugin_Jira : BaseTest
|
||||
{
|
||||
private static readonly JsonSerializerOptions s_jsonOptionsCache = new()
|
||||
{
|
||||
@@ -37,7 +41,8 @@ public static class Example24_OpenApiPlugin_Jira
|
||||
/// instance then select "Manage account".
|
||||
/// 4. Configure the secrets as described by the ReadMe.md in the dotnet/samples/KernelSyntaxExamples folder.
|
||||
/// </summary>
|
||||
public static async Task RunAsync()
|
||||
[Fact(Skip = "Setup credentials")]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
Kernel kernel = new();
|
||||
|
||||
@@ -90,10 +95,10 @@ public static class Example24_OpenApiPlugin_Jira
|
||||
// Run operation via the semantic kernel
|
||||
var result = await kernel.InvokeAsync(jiraFunctions["GetIssue"], arguments);
|
||||
|
||||
Console.WriteLine("\n\n\n");
|
||||
WriteLine("\n\n\n");
|
||||
var formattedContent = JsonSerializer.Serialize(
|
||||
result.GetValue<RestApiOperationResponse>(), s_jsonOptionsCache);
|
||||
Console.WriteLine("GetIssue jiraPlugin response: \n{0}", formattedContent);
|
||||
WriteLine($"GetIssue jiraPlugin response: \n{formattedContent}");
|
||||
|
||||
// AddComment Function
|
||||
arguments["issueKey"] = "TEST-2";
|
||||
@@ -102,10 +107,10 @@ public static class Example24_OpenApiPlugin_Jira
|
||||
// Run operation via the semantic kernel
|
||||
result = await kernel.InvokeAsync(jiraFunctions["AddComment"], arguments);
|
||||
|
||||
Console.WriteLine("\n\n\n");
|
||||
WriteLine("\n\n\n");
|
||||
|
||||
formattedContent = JsonSerializer.Serialize(result.GetValue<RestApiOperationResponse>(), s_jsonOptionsCache);
|
||||
Console.WriteLine("AddComment jiraPlugin response: \n{0}", formattedContent);
|
||||
WriteLine($"AddComment jiraPlugin response: \n{formattedContent}");
|
||||
}
|
||||
|
||||
#region Example of authentication providers
|
||||
@@ -251,4 +256,8 @@ public static class Example24_OpenApiPlugin_Jira
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public Example24_OpenApiPlugin_Jira(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,10 @@ using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel.Memory;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
/// <summary>
|
||||
/// This sample provides a custom implementation of <see cref="IMemoryStore"/> that is read only.
|
||||
@@ -18,26 +22,27 @@ using Microsoft.SemanticKernel.Memory;
|
||||
/// of <see cref="IMemoryStore"/> has a single collection, and thus does not need to be named.
|
||||
/// It also assumes that the JSON formatted data can be deserialized into <see cref="MemoryRecord"/> objects.
|
||||
/// </summary>
|
||||
public static class Example25_ReadOnlyMemoryStore
|
||||
public class Example25_ReadOnlyMemoryStore : BaseTest
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
var store = new ReadOnlyMemoryStore(s_jsonVectorEntries);
|
||||
|
||||
var embedding = new ReadOnlyMemory<float>(new float[] { 22, 4, 6 });
|
||||
|
||||
Console.WriteLine("Reading data from custom read-only memory store");
|
||||
WriteLine("Reading data from custom read-only memory store");
|
||||
var memoryRecord = await store.GetAsync("collection", "key3");
|
||||
if (memoryRecord != null)
|
||||
{
|
||||
Console.WriteLine("ID = {0}, Embedding = {1}", memoryRecord.Metadata.Id, string.Join(", ", MemoryMarshal.ToEnumerable(memoryRecord.Embedding)));
|
||||
WriteLine($"ID = {memoryRecord.Metadata.Id}, Embedding = {string.Join(", ", MemoryMarshal.ToEnumerable(memoryRecord.Embedding))}");
|
||||
}
|
||||
|
||||
Console.WriteLine("Getting most similar vector to {0}", string.Join(", ", MemoryMarshal.ToEnumerable(embedding)));
|
||||
WriteLine($"Getting most similar vector to {string.Join(", ", MemoryMarshal.ToEnumerable(embedding))}");
|
||||
var result = await store.GetNearestMatchAsync("collection", embedding, 0.0);
|
||||
if (result.HasValue)
|
||||
{
|
||||
Console.WriteLine("Embedding = {0}, Similarity = {1}", string.Join(", ", MemoryMarshal.ToEnumerable(result.Value.Item1.Embedding)), result.Value.Item2);
|
||||
WriteLine($"ID = {string.Join(", ", MemoryMarshal.ToEnumerable(result.Value.Item1.Embedding))}, Embedding = {result.Value.Item2}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,4 +241,8 @@ public static class Example25_ReadOnlyMemoryStore
|
||||
""timestamp"": null
|
||||
}
|
||||
]";
|
||||
|
||||
public Example25_ReadOnlyMemoryStore(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Azure.Identity;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
/// <summary>
|
||||
/// This example shows how to connect your app to Azure OpenAI using
|
||||
@@ -18,11 +21,12 @@ using Microsoft.SemanticKernel.ChatCompletion;
|
||||
/// -Shared tokens
|
||||
/// -etc.
|
||||
/// </summary>
|
||||
public static class Example26_AADAuth
|
||||
public class Example26_AADAuth : BaseTest
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
[Fact(Skip = "Setup credentials")]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
Console.WriteLine("======== SK with AAD Auth ========");
|
||||
WriteLine("======== SK with AAD Auth ========");
|
||||
|
||||
// Optional: choose which authentication to support
|
||||
var authOptions = new DefaultAzureCredentialOptions
|
||||
@@ -55,8 +59,12 @@ public static class Example26_AADAuth
|
||||
|
||||
// Bot reply
|
||||
var reply = await chatGPT.GetChatMessageContentAsync(chatHistory);
|
||||
Console.WriteLine(reply);
|
||||
WriteLine(reply);
|
||||
|
||||
/* Output: Why did the hourglass go to the doctor? Because it was feeling a little run down! */
|
||||
}
|
||||
|
||||
public Example26_AADAuth(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
/// <summary>
|
||||
/// This example shows how to use GPT3.5 Chat model for prompts and prompt functions.
|
||||
/// </summary>
|
||||
public static class Example27_PromptFunctionsUsingChatGPT
|
||||
public class Example27_PromptFunctionsUsingChatGPT : BaseTest
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
Console.WriteLine("======== Using Chat GPT model for text generation ========");
|
||||
WriteLine("======== Using Chat GPT model for text generation ========");
|
||||
|
||||
Kernel kernel = Kernel.CreateBuilder()
|
||||
.AddAzureOpenAIChatCompletion(
|
||||
@@ -25,7 +29,7 @@ public static class Example27_PromptFunctionsUsingChatGPT
|
||||
"List the two planets closest to '{{$input}}', excluding moons, using bullet points.");
|
||||
|
||||
var result = await func.InvokeAsync(kernel, new() { ["input"] = "Jupiter" });
|
||||
Console.WriteLine(result.GetValue<string>());
|
||||
WriteLine(result.GetValue<string>());
|
||||
|
||||
/*
|
||||
Output:
|
||||
@@ -33,4 +37,8 @@ public static class Example27_PromptFunctionsUsingChatGPT
|
||||
- Uranus
|
||||
*/
|
||||
}
|
||||
|
||||
public Example27_PromptFunctionsUsingChatGPT(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,10 @@ using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using Microsoft.SemanticKernel.Plugins.Core;
|
||||
using Resources;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
/// <summary>
|
||||
/// Scenario:
|
||||
@@ -31,11 +35,12 @@ using Resources;
|
||||
/// Out of scope and not in the example: if needed, one could go further and use a semantic
|
||||
/// function (with extra cost) asking AI to generate the text to send to the Chat model.
|
||||
/// </summary>
|
||||
public static class Example30_ChatWithPrompts
|
||||
public class Example30_ChatWithPrompts : BaseTest
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
Console.WriteLine("======== Chat with prompts ========");
|
||||
WriteLine("======== Chat with prompts ========");
|
||||
|
||||
/* Load 3 files:
|
||||
* - 30-system-prompt.txt: the system prompt, used to initialize the chat session.
|
||||
@@ -76,12 +81,12 @@ public static class Example30_ChatWithPrompts
|
||||
// Render the system prompt. This string is used to configure the chat.
|
||||
// This contains the context, ie a piece of a wikipedia page selected by the user.
|
||||
string systemMessage = await promptTemplateFactory.Create(new PromptTemplateConfig(systemPromptTemplate)).RenderAsync(kernel, arguments);
|
||||
Console.WriteLine($"------------------------------------\n{systemMessage}");
|
||||
WriteLine($"------------------------------------\n{systemMessage}");
|
||||
|
||||
// Render the user prompt. This string is the query sent by the user
|
||||
// This contains the user request, ie "extract locations as a bullet point list"
|
||||
string userMessage = await promptTemplateFactory.Create(new PromptTemplateConfig(userPromptTemplate)).RenderAsync(kernel, arguments);
|
||||
Console.WriteLine($"------------------------------------\n{userMessage}");
|
||||
WriteLine($"------------------------------------\n{userMessage}");
|
||||
|
||||
// Client used to request answers
|
||||
var chatCompletion = kernel.GetRequiredService<IChatCompletionService>();
|
||||
@@ -96,7 +101,7 @@ public static class Example30_ChatWithPrompts
|
||||
|
||||
// Finally, get the response from AI
|
||||
var answer = await chatCompletion.GetChatMessageContentAsync(chatHistory);
|
||||
Console.WriteLine($"------------------------------------\n{answer}");
|
||||
WriteLine($"------------------------------------\n{answer}");
|
||||
|
||||
/*
|
||||
|
||||
@@ -121,4 +126,8 @@ public static class Example30_ChatWithPrompts
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
public Example30_ChatWithPrompts(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Microsoft.SemanticKernel.TextGeneration;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
/**
|
||||
* The following example shows how to use Semantic Kernel with streaming text completion.
|
||||
@@ -15,17 +18,12 @@ using Microsoft.SemanticKernel.TextGeneration;
|
||||
*
|
||||
* Refer to example 33 for streaming chat completion.
|
||||
*/
|
||||
public static class Example32_StreamingCompletion
|
||||
public class Example32_StreamingCompletion : BaseTest
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public Task AzureOpenAITextGenerationStreamAsync()
|
||||
{
|
||||
await AzureOpenAITextGenerationStreamAsync();
|
||||
await OpenAITextGenerationStreamAsync();
|
||||
}
|
||||
|
||||
private static async Task AzureOpenAITextGenerationStreamAsync()
|
||||
{
|
||||
Console.WriteLine("======== Azure OpenAI - Text Completion - Raw Streaming ========");
|
||||
WriteLine("======== Azure OpenAI - Text Completion - Raw Streaming ========");
|
||||
|
||||
var textGeneration = new AzureOpenAITextGenerationService(
|
||||
deploymentName: TestConfiguration.AzureOpenAI.DeploymentName,
|
||||
@@ -33,19 +31,20 @@ public static class Example32_StreamingCompletion
|
||||
apiKey: TestConfiguration.AzureOpenAI.ApiKey,
|
||||
modelId: TestConfiguration.AzureOpenAI.ModelId);
|
||||
|
||||
await TextGenerationStreamAsync(textGeneration);
|
||||
return this.TextGenerationStreamAsync(textGeneration);
|
||||
}
|
||||
|
||||
private static async Task OpenAITextGenerationStreamAsync()
|
||||
[Fact]
|
||||
public Task OpenAITextGenerationStreamAsync()
|
||||
{
|
||||
Console.WriteLine("======== Open AI - Text Completion - Raw Streaming ========");
|
||||
WriteLine("======== Open AI - Text Completion - Raw Streaming ========");
|
||||
|
||||
var textGeneration = new OpenAITextGenerationService("text-davinci-003", TestConfiguration.OpenAI.ApiKey);
|
||||
var textGeneration = new OpenAITextGenerationService("gpt-3.5-turbo-instruct", TestConfiguration.OpenAI.ApiKey);
|
||||
|
||||
await TextGenerationStreamAsync(textGeneration);
|
||||
return this.TextGenerationStreamAsync(textGeneration);
|
||||
}
|
||||
|
||||
private static async Task TextGenerationStreamAsync(ITextGenerationService textGeneration)
|
||||
private async Task TextGenerationStreamAsync(ITextGenerationService textGeneration)
|
||||
{
|
||||
var executionSettings = new OpenAIPromptExecutionSettings()
|
||||
{
|
||||
@@ -58,12 +57,16 @@ public static class Example32_StreamingCompletion
|
||||
|
||||
var prompt = "Write one paragraph why AI is awesome";
|
||||
|
||||
Console.WriteLine("Prompt: " + prompt);
|
||||
WriteLine("Prompt: " + prompt);
|
||||
await foreach (var content in textGeneration.GetStreamingTextContentsAsync(prompt, executionSettings))
|
||||
{
|
||||
Console.Write(content);
|
||||
Write(content);
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
WriteLine();
|
||||
}
|
||||
|
||||
public Example32_StreamingCompletion(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +1,31 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
// The following example shows how to use Semantic Kernel with streaming Chat Completion
|
||||
public static class Example33_StreamingChat
|
||||
public class Example33_StreamingChat : BaseTest
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public Task OpenAIChatStreamSampleAsync()
|
||||
{
|
||||
await AzureOpenAIChatStreamSampleAsync();
|
||||
await OpenAIChatStreamSampleAsync();
|
||||
}
|
||||
|
||||
private static async Task OpenAIChatStreamSampleAsync()
|
||||
{
|
||||
Console.WriteLine("======== Open AI - ChatGPT Streaming ========");
|
||||
WriteLine("======== Open AI - ChatGPT Streaming ========");
|
||||
|
||||
OpenAIChatCompletionService chatCompletionService = new(TestConfiguration.OpenAI.ChatModelId, TestConfiguration.OpenAI.ApiKey);
|
||||
|
||||
await StartStreamingChatAsync(chatCompletionService);
|
||||
return this.StartStreamingChatAsync(chatCompletionService);
|
||||
}
|
||||
|
||||
private static async Task AzureOpenAIChatStreamSampleAsync()
|
||||
[Fact]
|
||||
public Task AzureOpenAIChatStreamSampleAsync()
|
||||
{
|
||||
Console.WriteLine("======== Azure Open AI - ChatGPT Streaming ========");
|
||||
WriteLine("======== Azure Open AI - ChatGPT Streaming ========");
|
||||
|
||||
AzureOpenAIChatCompletionService chatCompletionService = new(
|
||||
deploymentName: TestConfiguration.AzureOpenAI.ChatDeploymentName,
|
||||
@@ -34,13 +33,13 @@ public static class Example33_StreamingChat
|
||||
apiKey: TestConfiguration.AzureOpenAI.ApiKey,
|
||||
modelId: TestConfiguration.AzureOpenAI.ChatModelId);
|
||||
|
||||
await StartStreamingChatAsync(chatCompletionService);
|
||||
return this.StartStreamingChatAsync(chatCompletionService);
|
||||
}
|
||||
|
||||
private static async Task StartStreamingChatAsync(IChatCompletionService chatCompletionService)
|
||||
private async Task StartStreamingChatAsync(IChatCompletionService chatCompletionService)
|
||||
{
|
||||
Console.WriteLine("Chat content:");
|
||||
Console.WriteLine("------------------------");
|
||||
WriteLine("Chat content:");
|
||||
WriteLine("------------------------");
|
||||
|
||||
var chatHistory = new ChatHistory("You are a librarian, expert about books");
|
||||
await MessageOutputAsync(chatHistory);
|
||||
@@ -60,7 +59,7 @@ public static class Example33_StreamingChat
|
||||
await StreamMessageOutputAsync(chatCompletionService, chatHistory, AuthorRole.Assistant);
|
||||
}
|
||||
|
||||
private static async Task StreamMessageOutputAsync(IChatCompletionService chatCompletionService, ChatHistory chatHistory, AuthorRole authorRole)
|
||||
private async Task StreamMessageOutputAsync(IChatCompletionService chatCompletionService, ChatHistory chatHistory, AuthorRole authorRole)
|
||||
{
|
||||
bool roleWritten = false;
|
||||
string fullMessage = string.Empty;
|
||||
@@ -69,31 +68,35 @@ public static class Example33_StreamingChat
|
||||
{
|
||||
if (!roleWritten && chatUpdate.Role.HasValue)
|
||||
{
|
||||
Console.Write($"{chatUpdate.Role.Value}: {chatUpdate.Content}");
|
||||
Write($"{chatUpdate.Role.Value}: {chatUpdate.Content}");
|
||||
roleWritten = true;
|
||||
}
|
||||
|
||||
if (chatUpdate.Content is { Length: > 0 })
|
||||
{
|
||||
fullMessage += chatUpdate.Content;
|
||||
Console.Write(chatUpdate.Content);
|
||||
Write(chatUpdate.Content);
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine("\n------------------------");
|
||||
WriteLine("\n------------------------");
|
||||
chatHistory.AddMessage(authorRole, fullMessage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Outputs the last message of the chat history
|
||||
/// </summary>
|
||||
private static Task MessageOutputAsync(ChatHistory chatHistory)
|
||||
private Task MessageOutputAsync(ChatHistory chatHistory)
|
||||
{
|
||||
var message = chatHistory.Last();
|
||||
|
||||
Console.WriteLine($"{message.Role}: {message.Content}");
|
||||
Console.WriteLine("------------------------");
|
||||
WriteLine($"{message.Role}: {message.Content}");
|
||||
WriteLine("------------------------");
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Example33_StreamingChat(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Plugins.Grpc;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
// This example shows how to use gRPC plugins.
|
||||
public static class Example35_GrpcPlugins
|
||||
public class Example35_GrpcPlugins : BaseTest
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
[Fact(Skip = "Setup crendentials")]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
Kernel kernel = new();
|
||||
|
||||
@@ -25,6 +29,10 @@ public static class Example35_GrpcPlugins
|
||||
// Run
|
||||
var result = await kernel.InvokeAsync(plugin["<operation-name>"], arguments);
|
||||
|
||||
Console.WriteLine("Plugin response: {0}", result.GetValue<string>());
|
||||
WriteLine($"Plugin response: {result.GetValue<string>()}");
|
||||
}
|
||||
|
||||
public Example35_GrpcPlugins(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
// The following example shows how to use Semantic Kernel with streaming Multiple Results Chat Completion.
|
||||
public static class Example36_MultiCompletion
|
||||
public class Example36_MultiCompletion : BaseTest
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public Task AzureOpenAIMultiChatCompletionAsync()
|
||||
{
|
||||
await AzureOpenAIMultiChatCompletionAsync();
|
||||
await OpenAIMultiChatCompletionAsync();
|
||||
}
|
||||
|
||||
private static async Task AzureOpenAIMultiChatCompletionAsync()
|
||||
{
|
||||
Console.WriteLine("======== Azure OpenAI - Multiple Chat Completion ========");
|
||||
WriteLine("======== Azure OpenAI - Multiple Chat Completion ========");
|
||||
|
||||
var chatCompletionService = new AzureOpenAIChatCompletionService(
|
||||
deploymentName: TestConfiguration.AzureOpenAI.ChatDeploymentName,
|
||||
@@ -24,21 +22,22 @@ public static class Example36_MultiCompletion
|
||||
apiKey: TestConfiguration.AzureOpenAI.ApiKey,
|
||||
modelId: TestConfiguration.AzureOpenAI.ChatModelId);
|
||||
|
||||
await ChatCompletionAsync(chatCompletionService);
|
||||
return ChatCompletionAsync(chatCompletionService);
|
||||
}
|
||||
|
||||
private static async Task OpenAIMultiChatCompletionAsync()
|
||||
[Fact]
|
||||
public Task OpenAIMultiChatCompletionAsync()
|
||||
{
|
||||
Console.WriteLine("======== Open AI - Multiple Chat Completion ========");
|
||||
WriteLine("======== Open AI - Multiple Chat Completion ========");
|
||||
|
||||
var chatCompletionService = new OpenAIChatCompletionService(
|
||||
TestConfiguration.OpenAI.ChatModelId,
|
||||
TestConfiguration.OpenAI.ApiKey);
|
||||
|
||||
await ChatCompletionAsync(chatCompletionService);
|
||||
return ChatCompletionAsync(chatCompletionService);
|
||||
}
|
||||
|
||||
private static async Task ChatCompletionAsync(IChatCompletionService chatCompletionService)
|
||||
private async Task ChatCompletionAsync(IChatCompletionService chatCompletionService)
|
||||
{
|
||||
var executionSettings = new OpenAIPromptExecutionSettings()
|
||||
{
|
||||
@@ -55,10 +54,14 @@ public static class Example36_MultiCompletion
|
||||
|
||||
foreach (var chatMessageChoice in await chatCompletionService.GetChatMessageContentsAsync(chatHistory, executionSettings))
|
||||
{
|
||||
Console.Write(chatMessageChoice.Content);
|
||||
Console.WriteLine("\n-------------\n");
|
||||
Write(chatMessageChoice.Content ?? string.Empty);
|
||||
WriteLine("\n-------------\n");
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
WriteLine();
|
||||
}
|
||||
|
||||
public Example36_MultiCompletion(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,14 +6,19 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.SemanticKernel;
|
||||
using RepoUtils;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
// The following examples show how to use SK SDK in applications using DI/IoC containers.
|
||||
public static class Example40_DIContainer
|
||||
public class Example40_DIContainer : BaseTest
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
var collection = new ServiceCollection();
|
||||
collection.AddSingleton<ILoggerFactory>(ConsoleLogger.LoggerFactory);
|
||||
collection.AddSingleton(ConsoleLogger.LoggerFactory);
|
||||
collection.AddOpenAITextGeneration(TestConfiguration.OpenAI.ModelId, TestConfiguration.OpenAI.ApiKey);
|
||||
collection.AddSingleton<Kernel>();
|
||||
|
||||
@@ -56,4 +61,8 @@ public static class Example40_DIContainer
|
||||
this._logger.LogWarning("Result - {0}", result.GetValue<string>());
|
||||
}
|
||||
}
|
||||
|
||||
public Example40_DIContainer(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,32 +2,21 @@
|
||||
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
// These examples show how to use HttpClient and HttpClientFactory within SK SDK.
|
||||
public static class Example41_HttpClientUsage
|
||||
public class Example41_HttpClientUsage : BaseTest
|
||||
{
|
||||
public static Task RunAsync()
|
||||
{
|
||||
//Examples showing how to use HttpClient.
|
||||
UseDefaultHttpClient();
|
||||
|
||||
UseCustomHttpClient();
|
||||
|
||||
//Examples showing how to use HttpClientFactory.
|
||||
UseBasicRegistrationWithHttpClientFactory();
|
||||
|
||||
UseNamedRegistrationWitHttpClientFactory();
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrates the usage of the default HttpClient provided by the SK SDK.
|
||||
/// </summary>
|
||||
private static void UseDefaultHttpClient()
|
||||
[Fact]
|
||||
public void UseDefaultHttpClient()
|
||||
{
|
||||
var kernel = Kernel.CreateBuilder()
|
||||
.AddOpenAIChatCompletion(
|
||||
@@ -39,7 +28,8 @@ public static class Example41_HttpClientUsage
|
||||
/// <summary>
|
||||
/// Demonstrates the usage of a custom HttpClient.
|
||||
/// </summary>
|
||||
private static void UseCustomHttpClient()
|
||||
[Fact]
|
||||
public void UseCustomHttpClient()
|
||||
{
|
||||
using var httpClient = new HttpClient();
|
||||
|
||||
@@ -55,7 +45,8 @@ public static class Example41_HttpClientUsage
|
||||
/// <summary>
|
||||
/// Demonstrates the "basic usage" approach for HttpClientFactory.
|
||||
/// </summary>
|
||||
private static void UseBasicRegistrationWithHttpClientFactory()
|
||||
[Fact]
|
||||
public void UseBasicRegistrationWithHttpClientFactory()
|
||||
{
|
||||
//More details - https://learn.microsoft.com/en-us/dotnet/core/extensions/httpclient-factory#basic-usage
|
||||
var serviceCollection = new ServiceCollection();
|
||||
@@ -77,7 +68,8 @@ public static class Example41_HttpClientUsage
|
||||
/// <summary>
|
||||
/// Demonstrates the "named clients" approach for HttpClientFactory.
|
||||
/// </summary>
|
||||
private static void UseNamedRegistrationWitHttpClientFactory()
|
||||
[Fact]
|
||||
public void UseNamedRegistrationWitHttpClientFactory()
|
||||
{
|
||||
// More details https://learn.microsoft.com/en-us/dotnet/core/extensions/httpclient-factory#named-clients
|
||||
|
||||
@@ -102,4 +94,8 @@ public static class Example41_HttpClientUsage
|
||||
.Build();
|
||||
});
|
||||
}
|
||||
|
||||
public Example41_HttpClientUsage(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,51 +5,62 @@
|
||||
// You can access the builder using Kernel.CreateBuilder().
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Plugins.Core;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
public static class Example42_KernelBuilder
|
||||
namespace Examples;
|
||||
|
||||
public class Example42_KernelBuilder : BaseTest
|
||||
{
|
||||
public static Task RunAsync()
|
||||
[Fact]
|
||||
public void BuildKernelWithAzureChatCompletion()
|
||||
{
|
||||
string azureOpenAIKey = TestConfiguration.AzureOpenAI.ApiKey;
|
||||
string azureOpenAIEndpoint = TestConfiguration.AzureOpenAI.Endpoint;
|
||||
string azureOpenAIChatDeploymentName = TestConfiguration.AzureOpenAI.ChatDeploymentName;
|
||||
string azureOpenAIChatModelId = TestConfiguration.AzureOpenAI.ChatModelId;
|
||||
|
||||
// KernelBuilder provides a simple way to configure a Kernel. This constructs a kernel
|
||||
// with logging and an Azure OpenAI chat completion service configured.
|
||||
Kernel kernel1 = Kernel.CreateBuilder()
|
||||
.AddAzureOpenAIChatCompletion(
|
||||
deploymentName: azureOpenAIChatDeploymentName,
|
||||
endpoint: azureOpenAIEndpoint,
|
||||
apiKey: azureOpenAIKey,
|
||||
modelId: azureOpenAIChatModelId)
|
||||
deploymentName: TestConfiguration.AzureOpenAI.ChatDeploymentName,
|
||||
endpoint: TestConfiguration.AzureOpenAI.Endpoint,
|
||||
apiKey: TestConfiguration.AzureOpenAI.ApiKey,
|
||||
modelId: TestConfiguration.AzureOpenAI.ChatModelId)
|
||||
.Build();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildKernelUsingServiceCollection()
|
||||
{
|
||||
// For greater flexibility and to incorporate arbitrary services, KernelBuilder.Services
|
||||
// provides direct access to an underlying IServiceCollection.
|
||||
IKernelBuilder builder = Kernel.CreateBuilder();
|
||||
builder.Services.AddLogging(c => c.AddConsole().SetMinimumLevel(LogLevel.Information))
|
||||
.AddHttpClient()
|
||||
.AddAzureOpenAIChatCompletion(
|
||||
deploymentName: azureOpenAIChatDeploymentName,
|
||||
endpoint: azureOpenAIEndpoint,
|
||||
apiKey: azureOpenAIKey,
|
||||
modelId: azureOpenAIChatModelId);
|
||||
.AddHttpClient()
|
||||
.AddAzureOpenAIChatCompletion(
|
||||
deploymentName: TestConfiguration.AzureOpenAI.ChatDeploymentName,
|
||||
endpoint: TestConfiguration.AzureOpenAI.Endpoint,
|
||||
apiKey: TestConfiguration.AzureOpenAI.ApiKey,
|
||||
modelId: TestConfiguration.AzureOpenAI.ChatModelId);
|
||||
Kernel kernel2 = builder.Build();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildKernelWithPlugins()
|
||||
{
|
||||
// Plugins may also be configured via the corresponding Plugins property.
|
||||
builder = Kernel.CreateBuilder();
|
||||
var builder = Kernel.CreateBuilder();
|
||||
builder.Plugins.AddFromType<HttpPlugin>();
|
||||
Kernel kernel3 = builder.Build();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildKernelUsingServiceProvider()
|
||||
{
|
||||
// Every call to KernelBuilder.Build creates a new Kernel instance, with a new service provider
|
||||
// and a new plugin collection.
|
||||
builder = Kernel.CreateBuilder();
|
||||
var builder = Kernel.CreateBuilder();
|
||||
Debug.Assert(!ReferenceEquals(builder.Build(), builder.Build()));
|
||||
|
||||
// KernelBuilder provides a convenient API for creating Kernel instances. However, it is just a
|
||||
@@ -59,32 +70,38 @@ public static class Example42_KernelBuilder
|
||||
services.AddLogging(c => c.AddConsole().SetMinimumLevel(LogLevel.Information));
|
||||
services.AddHttpClient();
|
||||
services.AddAzureOpenAIChatCompletion(
|
||||
deploymentName: azureOpenAIChatDeploymentName,
|
||||
endpoint: azureOpenAIEndpoint,
|
||||
apiKey: azureOpenAIKey,
|
||||
modelId: azureOpenAIChatModelId);
|
||||
deploymentName: TestConfiguration.AzureOpenAI.ChatDeploymentName,
|
||||
endpoint: TestConfiguration.AzureOpenAI.Endpoint,
|
||||
apiKey: TestConfiguration.AzureOpenAI.ApiKey,
|
||||
modelId: TestConfiguration.AzureOpenAI.ChatModelId);
|
||||
Kernel kernel4 = new(services.BuildServiceProvider());
|
||||
|
||||
// Kernels can also be constructed and resolved via such a dependency injection container.
|
||||
services.AddTransient<Kernel>();
|
||||
Kernel kernel5 = services.BuildServiceProvider().GetRequiredService<Kernel>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildKernelUsingServiceCollectionExtension()
|
||||
{
|
||||
// In fact, the AddKernel method exists to simplify this, registering a singleton KernelPluginCollection
|
||||
// that can be populated automatically with all IKernelPlugins registered in the collection, and a
|
||||
// transient Kernel that can then automatically be constructed from the service provider and resulting
|
||||
// plugins collection.
|
||||
services = new ServiceCollection();
|
||||
var services = new ServiceCollection();
|
||||
services.AddLogging(c => c.AddConsole().SetMinimumLevel(LogLevel.Information));
|
||||
services.AddHttpClient();
|
||||
services.AddKernel().AddAzureOpenAIChatCompletion(
|
||||
deploymentName: azureOpenAIChatDeploymentName,
|
||||
endpoint: azureOpenAIEndpoint,
|
||||
apiKey: azureOpenAIKey,
|
||||
modelId: azureOpenAIChatModelId);
|
||||
deploymentName: TestConfiguration.AzureOpenAI.ChatDeploymentName,
|
||||
endpoint: TestConfiguration.AzureOpenAI.Endpoint,
|
||||
apiKey: TestConfiguration.AzureOpenAI.ApiKey,
|
||||
modelId: TestConfiguration.AzureOpenAI.ChatModelId);
|
||||
services.AddSingleton<KernelPlugin>(sp => KernelPluginFactory.CreateFromType<TimePlugin>(serviceProvider: sp));
|
||||
services.AddSingleton<KernelPlugin>(sp => KernelPluginFactory.CreateFromType<HttpPlugin>(serviceProvider: sp));
|
||||
Kernel kernel6 = services.BuildServiceProvider().GetRequiredService<Kernel>();
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
public Example42_KernelBuilder(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel;
|
||||
using RepoUtils;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
public static class Example43_GetModelResult
|
||||
namespace Examples;
|
||||
|
||||
public class Example43_GetModelResult : BaseTest
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task GetTokenUsageMetadataAsync()
|
||||
{
|
||||
Console.WriteLine("======== Inline Function Definition + Invocation ========");
|
||||
WriteLine("======== Inline Function Definition + Invocation ========");
|
||||
|
||||
// Create kernel
|
||||
Kernel kernel = Kernel.CreateBuilder()
|
||||
@@ -26,8 +30,12 @@ public static class Example43_GetModelResult
|
||||
FunctionResult result = await kernel.InvokeAsync(myFunction, new() { ["input"] = "travel" });
|
||||
|
||||
// Display results
|
||||
Console.WriteLine(result.GetValue<string>());
|
||||
Console.WriteLine(result.Metadata?["Usage"]?.AsJson());
|
||||
Console.WriteLine();
|
||||
WriteLine(result.GetValue<string>());
|
||||
WriteLine(result.Metadata?["Usage"]?.AsJson());
|
||||
WriteLine();
|
||||
}
|
||||
|
||||
public Example43_GetModelResult(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
// The following example shows how to use Semantic Kernel with Multiple Results Text Completion as streaming
|
||||
public static class Example44_MultiChatCompletion
|
||||
public class Example44_MultiChatCompletion : BaseTest
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public Task AzureOpenAIMultiChatCompletionAsync()
|
||||
{
|
||||
await AzureOpenAIMultiChatCompletionAsync();
|
||||
await OpenAIMultiChatCompletionAsync();
|
||||
}
|
||||
|
||||
private static async Task AzureOpenAIMultiChatCompletionAsync()
|
||||
{
|
||||
Console.WriteLine("======== Azure OpenAI - Multiple Chat Completion ========");
|
||||
WriteLine("======== Azure OpenAI - Multiple Chat Completion ========");
|
||||
|
||||
AzureOpenAIChatCompletionService chatCompletionService = new(
|
||||
deploymentName: TestConfiguration.AzureOpenAI.ChatDeploymentName,
|
||||
@@ -25,19 +23,20 @@ public static class Example44_MultiChatCompletion
|
||||
apiKey: TestConfiguration.AzureOpenAI.ApiKey,
|
||||
modelId: TestConfiguration.AzureOpenAI.ChatModelId);
|
||||
|
||||
await RunChatAsync(chatCompletionService);
|
||||
return RunChatAsync(chatCompletionService);
|
||||
}
|
||||
|
||||
private static async Task OpenAIMultiChatCompletionAsync()
|
||||
[Fact]
|
||||
public Task OpenAIMultiChatCompletionAsync()
|
||||
{
|
||||
Console.WriteLine("======== Open AI - Multiple Chat Completion ========");
|
||||
WriteLine("======== Open AI - Multiple Chat Completion ========");
|
||||
|
||||
OpenAIChatCompletionService chatCompletionService = new(modelId: TestConfiguration.OpenAI.ChatModelId, TestConfiguration.OpenAI.ApiKey);
|
||||
|
||||
await RunChatAsync(chatCompletionService);
|
||||
return RunChatAsync(chatCompletionService);
|
||||
}
|
||||
|
||||
private static async Task RunChatAsync(IChatCompletionService chatCompletionService)
|
||||
private async Task RunChatAsync(IChatCompletionService chatCompletionService)
|
||||
{
|
||||
var chatHistory = new ChatHistory("You are a librarian, expert about books");
|
||||
|
||||
@@ -61,19 +60,23 @@ public static class Example44_MultiChatCompletion
|
||||
await MessageOutputAsync(chatHistory);
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
WriteLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Outputs the last message of the chat history
|
||||
/// </summary>
|
||||
private static Task MessageOutputAsync(ChatHistory chatHistory)
|
||||
private Task MessageOutputAsync(ChatHistory chatHistory)
|
||||
{
|
||||
var message = chatHistory.Last();
|
||||
|
||||
Console.WriteLine($"{message.Role}: {message.Content}");
|
||||
Console.WriteLine("------------------------");
|
||||
WriteLine($"{message.Role}: {message.Content}");
|
||||
WriteLine("------------------------");
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Example44_MultiChatCompletion(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,21 +6,18 @@ using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
// The following example shows how to use Semantic Kernel with multiple streaming chat completion results.
|
||||
public static class Example45_MultiStreamingChatCompletion
|
||||
public class Example45_MultiStreamingChatCompletion : BaseTest
|
||||
{
|
||||
// First procress multiple Azure OpenAI chat completions
|
||||
// and then multiple plain OpenAI chat completions.
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public Task AzureOpenAIMultiStreamingChatCompletionAsync()
|
||||
{
|
||||
await AzureOpenAIMultiStreamingChatCompletionAsync();
|
||||
await OpenAIMultiStreamingChatCompletionAsync();
|
||||
}
|
||||
|
||||
private static async Task AzureOpenAIMultiStreamingChatCompletionAsync()
|
||||
{
|
||||
Console.WriteLine("======== Azure OpenAI - Multiple Chat Completions - Raw Streaming ========");
|
||||
WriteLine("======== Azure OpenAI - Multiple Chat Completions - Raw Streaming ========");
|
||||
|
||||
AzureOpenAIChatCompletionService chatCompletionService = new(
|
||||
deploymentName: TestConfiguration.AzureOpenAI.ChatDeploymentName,
|
||||
@@ -28,18 +25,19 @@ public static class Example45_MultiStreamingChatCompletion
|
||||
apiKey: TestConfiguration.AzureOpenAI.ApiKey,
|
||||
modelId: TestConfiguration.AzureOpenAI.ChatModelId);
|
||||
|
||||
await StreamingChatCompletionAsync(chatCompletionService, 3);
|
||||
return StreamingChatCompletionAsync(chatCompletionService, 3);
|
||||
}
|
||||
|
||||
private static async Task OpenAIMultiStreamingChatCompletionAsync()
|
||||
[Fact]
|
||||
public Task OpenAIMultiStreamingChatCompletionAsync()
|
||||
{
|
||||
Console.WriteLine("======== OpenAI - Multiple Chat Completions - Raw Streaming ========");
|
||||
WriteLine("======== OpenAI - Multiple Chat Completions - Raw Streaming ========");
|
||||
|
||||
OpenAIChatCompletionService chatCompletionService = new(
|
||||
modelId: TestConfiguration.OpenAI.ChatModelId,
|
||||
apiKey: TestConfiguration.OpenAI.ApiKey);
|
||||
|
||||
await StreamingChatCompletionAsync(chatCompletionService, 3);
|
||||
return StreamingChatCompletionAsync(chatCompletionService, 3);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -47,7 +45,7 @@ public static class Example45_MultiStreamingChatCompletion
|
||||
/// </summary>
|
||||
/// <param name="chatCompletionService">Chat completion service to use</param>
|
||||
/// <param name="numResultsPerPrompt">Number of results to get for each chat completion request</param>
|
||||
private static async Task StreamingChatCompletionAsync(IChatCompletionService chatCompletionService,
|
||||
private async Task StreamingChatCompletionAsync(IChatCompletionService chatCompletionService,
|
||||
int numResultsPerPrompt)
|
||||
{
|
||||
var executionSettings = new OpenAIPromptExecutionSettings()
|
||||
@@ -62,24 +60,25 @@ public static class Example45_MultiStreamingChatCompletion
|
||||
|
||||
var consoleLinesPerResult = 10;
|
||||
|
||||
ClearDisplayByAddingEmptyLines();
|
||||
// Uncomment this if you want to use a console app to display the results
|
||||
// ClearDisplayByAddingEmptyLines();
|
||||
|
||||
var prompt = "Hi, I'm looking for 5 random title names for sci-fi books";
|
||||
|
||||
await ProcessStreamAsyncEnumerableAsync(chatCompletionService, prompt, executionSettings, consoleLinesPerResult);
|
||||
|
||||
Console.WriteLine();
|
||||
WriteLine();
|
||||
|
||||
// Set cursor position to after displayed results
|
||||
Console.SetCursorPosition(0, executionSettings.ResultsPerPrompt * consoleLinesPerResult);
|
||||
// Console.SetCursorPosition(0, executionSettings.ResultsPerPrompt * consoleLinesPerResult);
|
||||
|
||||
Console.WriteLine();
|
||||
WriteLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does the actual streaming and display of the chat completion.
|
||||
/// </summary>
|
||||
private static async Task ProcessStreamAsyncEnumerableAsync(IChatCompletionService chatCompletionService, string prompt,
|
||||
private async Task ProcessStreamAsyncEnumerableAsync(IChatCompletionService chatCompletionService, string prompt,
|
||||
OpenAIPromptExecutionSettings executionSettings, int consoleLinesPerResult)
|
||||
{
|
||||
var messagesPerChoice = new Dictionary<int, string>();
|
||||
@@ -90,12 +89,13 @@ public static class Example45_MultiStreamingChatCompletion
|
||||
{
|
||||
// Set cursor position to the beginning of where this choice (i.e. this result of
|
||||
// a single multi-result request) is to be displayed.
|
||||
Console.SetCursorPosition(0, chatUpdate.ChoiceIndex * consoleLinesPerResult + 1);
|
||||
// Console.SetCursorPosition(0, chatUpdate.ChoiceIndex * consoleLinesPerResult + 1);
|
||||
|
||||
// The first time around, start choice text with role information
|
||||
if (!messagesPerChoice.ContainsKey(chatUpdate.ChoiceIndex))
|
||||
{
|
||||
messagesPerChoice[chatUpdate.ChoiceIndex] = $"Role: {chatUpdate.Role ?? new AuthorRole()}\n";
|
||||
Write($"Choice index: {chatUpdate.ChoiceIndex}, Role: {chatUpdate.Role ?? new AuthorRole()}");
|
||||
}
|
||||
|
||||
// Add latest completion bit, if any
|
||||
@@ -105,18 +105,30 @@ public static class Example45_MultiStreamingChatCompletion
|
||||
}
|
||||
|
||||
// Overwrite what is currently in the console area for the updated choice
|
||||
Console.Write(messagesPerChoice[chatUpdate.ChoiceIndex]);
|
||||
// Console.Write(messagesPerChoice[chatUpdate.ChoiceIndex]);
|
||||
Write($"Choice index: {chatUpdate.ChoiceIndex}, Content: {chatUpdate.Content}");
|
||||
}
|
||||
|
||||
// Display the aggregated results
|
||||
foreach (string message in messagesPerChoice.Values)
|
||||
{
|
||||
WriteLine("-------------------");
|
||||
WriteLine(message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add enough new lines to clear the console window.
|
||||
/// </summary>
|
||||
private static void ClearDisplayByAddingEmptyLines()
|
||||
private void ClearDisplayByAddingEmptyLines()
|
||||
{
|
||||
for (int i = 0; i < Console.WindowHeight - 2; i++)
|
||||
{
|
||||
Console.WriteLine();
|
||||
WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
public Example45_MultiStreamingChatCompletion(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,118 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Planning.Handlebars;
|
||||
using Microsoft.SemanticKernel.Plugins.Core;
|
||||
using RepoUtils;
|
||||
using xRetry;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
internal static class Example48_GroundednessChecks
|
||||
namespace Examples;
|
||||
|
||||
public class Example48_GroundednessChecks : BaseTest
|
||||
{
|
||||
[RetryFact(typeof(HttpOperationException))]
|
||||
public async Task GroundednessCheckingAsync()
|
||||
{
|
||||
WriteLine("\n======== Groundedness Checks ========");
|
||||
var kernel = Kernel.CreateBuilder()
|
||||
.AddAzureOpenAIChatCompletion(
|
||||
deploymentName: TestConfiguration.AzureOpenAI.ChatDeploymentName,
|
||||
endpoint: TestConfiguration.AzureOpenAI.Endpoint,
|
||||
apiKey: TestConfiguration.AzureOpenAI.ApiKey,
|
||||
modelId: TestConfiguration.AzureOpenAI.ChatModelId)
|
||||
.Build();
|
||||
|
||||
string folder = RepoFiles.SamplePluginsPath();
|
||||
var summarizePlugin = kernel.ImportPluginFromPromptDirectory(Path.Combine(folder, "SummarizePlugin"));
|
||||
var groundingPlugin = kernel.ImportPluginFromPromptDirectory(Path.Combine(folder, "GroundingPlugin"));
|
||||
|
||||
var create_summary = summarizePlugin["Summarize"];
|
||||
var entityExtraction = groundingPlugin["ExtractEntities"];
|
||||
var reference_check = groundingPlugin["ReferenceCheckEntities"];
|
||||
var entity_excision = groundingPlugin["ExciseEntities"];
|
||||
|
||||
var summaryText = @"
|
||||
My father, a respected resident of Milan, was a close friend of a merchant named Beaufort who, after a series of
|
||||
misfortunes, moved to Zurich in poverty. My father was upset by his friend's troubles and sought him out,
|
||||
finding him in a mean street. Beaufort had saved a small sum of money, but it was not enough to support him and
|
||||
his daughter, Mary. Mary procured work to eek out a living, but after ten months her father died, leaving
|
||||
her a beggar. My father came to her aid and two years later they married.
|
||||
";
|
||||
|
||||
KernelArguments variables = new()
|
||||
{
|
||||
["input"] = summaryText,
|
||||
["topic"] = "people and places",
|
||||
["example_entities"] = "John, Jane, mother, brother, Paris, Rome"
|
||||
};
|
||||
|
||||
var extractionResult = (await kernel.InvokeAsync(entityExtraction, variables)).ToString();
|
||||
|
||||
WriteLine("======== Extract Entities ========");
|
||||
WriteLine(extractionResult);
|
||||
|
||||
variables["input"] = extractionResult;
|
||||
variables["reference_context"] = GroundingText;
|
||||
|
||||
var groundingResult = (await kernel.InvokeAsync(reference_check, variables)).ToString();
|
||||
|
||||
WriteLine("\n======== Reference Check ========");
|
||||
WriteLine(groundingResult);
|
||||
|
||||
variables["input"] = summaryText;
|
||||
variables["ungrounded_entities"] = groundingResult;
|
||||
var excisionResult = await kernel.InvokeAsync(entity_excision, variables);
|
||||
|
||||
WriteLine("\n======== Excise Entities ========");
|
||||
WriteLine(excisionResult.GetValue<string>());
|
||||
}
|
||||
|
||||
[Fact(Skip = "Unreliable - Needs attention")]
|
||||
public async Task PlanningWithGroundednessAsync()
|
||||
{
|
||||
var targetTopic = "people and places";
|
||||
var samples = "John, Jane, mother, brother, Paris, Rome";
|
||||
var ask = @$"Make a summary of the following text. Then make a list of entities
|
||||
related to {targetTopic} (such as {samples}) which are present in the summary.
|
||||
Take this list of entities, and from it make another list of those which are not
|
||||
grounded in the original input text. Finally, rewrite your summary to remove the entities
|
||||
which are not grounded in the original.
|
||||
|
||||
Text:\n{GroundingText};
|
||||
";
|
||||
|
||||
WriteLine("\n======== Planning - Groundedness Checks ========");
|
||||
|
||||
var kernel = Kernel.CreateBuilder()
|
||||
.AddAzureOpenAIChatCompletion(
|
||||
deploymentName: TestConfiguration.AzureOpenAI.ChatDeploymentName,
|
||||
endpoint: TestConfiguration.AzureOpenAI.Endpoint,
|
||||
apiKey: TestConfiguration.AzureOpenAI.ApiKey,
|
||||
modelId: TestConfiguration.AzureOpenAI.ChatModelId)
|
||||
.Build();
|
||||
|
||||
string folder = RepoFiles.SamplePluginsPath();
|
||||
kernel.ImportPluginFromPromptDirectory(Path.Combine(folder, "SummarizePlugin"));
|
||||
kernel.ImportPluginFromPromptDirectory(Path.Combine(folder, "GroundingPlugin"));
|
||||
|
||||
kernel.ImportPluginFromType<TextPlugin>();
|
||||
|
||||
var planner = new HandlebarsPlanner();
|
||||
var plan = await planner.CreatePlanAsync(kernel, ask);
|
||||
|
||||
WriteLine($"======== Goal: ========\n{ask}");
|
||||
WriteLine($"======== Plan ========\n{plan}");
|
||||
|
||||
var result = await plan.InvokeAsync(kernel);
|
||||
|
||||
WriteLine("======== Result ========");
|
||||
WriteLine(result);
|
||||
}
|
||||
|
||||
private const string GroundingText = @"""I am by birth a Genevese, and my family is one of the most distinguished of that republic.
|
||||
My ancestors had been for many years counsellors and syndics, and my father had filled several public situations
|
||||
with honour and reputation.He was respected by all who knew him for his integrity and indefatigable attention
|
||||
@@ -47,107 +150,8 @@ the chamber. He came like a protecting spirit to the poor girl, who committed he
|
||||
interment of his friend he conducted her to Geneva and placed her under the protection of a relation.Two years
|
||||
after this event Caroline became his wife.""";
|
||||
|
||||
public static async Task RunAsync()
|
||||
public Example48_GroundednessChecks(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
await GroundednessCheckingAsync();
|
||||
await PlanningWithGroundednessAsync();
|
||||
}
|
||||
|
||||
public static async Task GroundednessCheckingAsync()
|
||||
{
|
||||
Console.WriteLine("\n======== Groundedness Checks ========");
|
||||
var kernel = Kernel.CreateBuilder()
|
||||
.AddAzureOpenAIChatCompletion(
|
||||
deploymentName: TestConfiguration.AzureOpenAI.ChatDeploymentName,
|
||||
endpoint: TestConfiguration.AzureOpenAI.Endpoint,
|
||||
apiKey: TestConfiguration.AzureOpenAI.ApiKey,
|
||||
modelId: TestConfiguration.AzureOpenAI.ChatModelId)
|
||||
.Build();
|
||||
|
||||
string folder = RepoFiles.SamplePluginsPath();
|
||||
var summarizePlugin = kernel.ImportPluginFromPromptDirectory(Path.Combine(folder, "SummarizePlugin"));
|
||||
var groundingPlugin = kernel.ImportPluginFromPromptDirectory(Path.Combine(folder, "GroundingPlugin"));
|
||||
|
||||
var create_summary = summarizePlugin["Summarize"];
|
||||
var entityExtraction = groundingPlugin["ExtractEntities"];
|
||||
var reference_check = groundingPlugin["ReferenceCheckEntities"];
|
||||
var entity_excision = groundingPlugin["ExciseEntities"];
|
||||
|
||||
var summaryText = @"
|
||||
My father, a respected resident of Milan, was a close friend of a merchant named Beaufort who, after a series of
|
||||
misfortunes, moved to Zurich in poverty. My father was upset by his friend's troubles and sought him out,
|
||||
finding him in a mean street. Beaufort had saved a small sum of money, but it was not enough to support him and
|
||||
his daughter, Mary. Mary procured work to eek out a living, but after ten months her father died, leaving
|
||||
her a beggar. My father came to her aid and two years later they married.
|
||||
";
|
||||
|
||||
KernelArguments variables = new()
|
||||
{
|
||||
["input"] = summaryText,
|
||||
["topic"] = "people and places",
|
||||
["example_entities"] = "John, Jane, mother, brother, Paris, Rome"
|
||||
};
|
||||
|
||||
var extractionResult = (await kernel.InvokeAsync(entityExtraction, variables)).ToString();
|
||||
|
||||
Console.WriteLine("======== Extract Entities ========");
|
||||
Console.WriteLine(extractionResult);
|
||||
|
||||
variables["input"] = extractionResult;
|
||||
variables["reference_context"] = GroundingText;
|
||||
|
||||
var groundingResult = (await kernel.InvokeAsync(reference_check, variables)).ToString();
|
||||
|
||||
Console.WriteLine("\n======== Reference Check ========");
|
||||
Console.WriteLine(groundingResult);
|
||||
|
||||
variables["input"] = summaryText;
|
||||
variables["ungrounded_entities"] = groundingResult;
|
||||
var excisionResult = await kernel.InvokeAsync(entity_excision, variables);
|
||||
|
||||
Console.WriteLine("\n======== Excise Entities ========");
|
||||
Console.WriteLine(excisionResult.GetValue<string>());
|
||||
}
|
||||
|
||||
public static async Task PlanningWithGroundednessAsync()
|
||||
{
|
||||
var targetTopic = "people and places";
|
||||
var samples = "John, Jane, mother, brother, Paris, Rome";
|
||||
var ask = @$"Make a summary of the following text. Then make a list of entities
|
||||
related to {targetTopic} (such as {samples}) which are present in the summary.
|
||||
Take this list of entities, and from it make another list of those which are not
|
||||
grounded in the original input text. Finally, rewrite your summary to remove the entities
|
||||
which are not grounded in the original.
|
||||
|
||||
Text:\n{GroundingText};
|
||||
";
|
||||
|
||||
Console.WriteLine("\n======== Planning - Groundedness Checks ========");
|
||||
|
||||
var kernel = Kernel.CreateBuilder()
|
||||
.AddAzureOpenAIChatCompletion(
|
||||
deploymentName: TestConfiguration.AzureOpenAI.ChatDeploymentName,
|
||||
endpoint: TestConfiguration.AzureOpenAI.Endpoint,
|
||||
apiKey: TestConfiguration.AzureOpenAI.ApiKey,
|
||||
modelId: TestConfiguration.AzureOpenAI.ChatModelId)
|
||||
.Build();
|
||||
|
||||
string folder = RepoFiles.SamplePluginsPath();
|
||||
kernel.ImportPluginFromPromptDirectory(Path.Combine(folder, "SummarizePlugin"));
|
||||
kernel.ImportPluginFromPromptDirectory(Path.Combine(folder, "GroundingPlugin"));
|
||||
|
||||
kernel.ImportPluginFromType<TextPlugin>();
|
||||
|
||||
var planner = new HandlebarsPlanner();
|
||||
var plan = await planner.CreatePlanAsync(kernel, ask);
|
||||
|
||||
Console.WriteLine($"======== Goal: ========\n{ask}");
|
||||
Console.WriteLine($"======== Plan ========\n{plan}");
|
||||
|
||||
var result = await plan.InvokeAsync(kernel);
|
||||
|
||||
Console.WriteLine("======== Result ========");
|
||||
Console.WriteLine(result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
/**
|
||||
* Logit_bias is an optional parameter that modifies the likelihood of specified tokens appearing in a Completion.
|
||||
* When using the Token Selection Biases parameter, the bias is added to the logits generated by the model prior to sampling.
|
||||
*/
|
||||
public static class Example49_LogitBias
|
||||
public class Example49_LogitBias : BaseTest
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
OpenAIChatCompletionService chatCompletionService = new(TestConfiguration.OpenAI.ChatModelId, TestConfiguration.OpenAI.ApiKey);
|
||||
|
||||
@@ -23,14 +27,15 @@ public static class Example49_LogitBias
|
||||
// "novel literature reading author library story chapter paperback hardcover ebook publishing fiction nonfiction manuscript textbook bestseller bookstore reading list bookworm"
|
||||
var keys = new[] { 3919, 626, 17201, 1300, 25782, 9800, 32016, 13571, 43582, 20189, 1891, 10424, 9631, 16497, 12984, 20020, 24046, 13159, 805, 15817, 5239, 2070, 13466, 32932, 8095, 1351, 25323 };
|
||||
|
||||
var settings = new OpenAIPromptExecutionSettings();
|
||||
var settings = new OpenAIPromptExecutionSettings
|
||||
{
|
||||
// This will make the model try its best to avoid any of the above related words.
|
||||
//-100 to potentially ban all the tokens from the list.
|
||||
TokenSelectionBiases = keys.ToDictionary(key => key, key => -100)
|
||||
};
|
||||
|
||||
// This will make the model try its best to avoid any of the above related words.
|
||||
//-100 to potentially ban all the tokens from the list.
|
||||
settings.TokenSelectionBiases = keys.ToDictionary(key => key, key => -100);
|
||||
|
||||
Console.WriteLine("Chat content:");
|
||||
Console.WriteLine("------------------------");
|
||||
WriteLine("Chat content:");
|
||||
WriteLine("------------------------");
|
||||
|
||||
var chatHistory = new ChatHistory("You are a librarian expert");
|
||||
|
||||
@@ -66,13 +71,17 @@ public static class Example49_LogitBias
|
||||
/// <summary>
|
||||
/// Outputs the last message of the chat history
|
||||
/// </summary>
|
||||
private static Task MessageOutputAsync(ChatHistory chatHistory)
|
||||
private Task MessageOutputAsync(ChatHistory chatHistory)
|
||||
{
|
||||
var message = chatHistory.Last();
|
||||
|
||||
Console.WriteLine($"{message.Role}: {message.Content}");
|
||||
Console.WriteLine("------------------------");
|
||||
WriteLine($"{message.Role}: {message.Content}");
|
||||
WriteLine("------------------------");
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Example49_LogitBias(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Azure.AI.OpenAI;
|
||||
using Azure.Core;
|
||||
using Azure.Core.Pipeline;
|
||||
using Azure.Identity;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.SemanticKernel;
|
||||
using RepoUtils;
|
||||
|
||||
public static class Example52_ApimAuth
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
{
|
||||
// Azure API Management details
|
||||
// For more information see 'Protect your Azure OpenAI API keys with Azure API Management' here: https://learn.microsoft.com/en-us/semantic-kernel/deploy/
|
||||
var apimUri = new Uri(Env.Var("Apim__Endpoint"));
|
||||
var subscriptionKey = Env.Var("Apim__SubscriptionKey");
|
||||
|
||||
// Use interactive browser login
|
||||
string[] scopes = new string[] { "https://cognitiveservices.azure.com/.default" };
|
||||
var credential = new InteractiveBrowserCredential();
|
||||
var requestContext = new TokenRequestContext(scopes);
|
||||
var accessToken = await credential.GetTokenAsync(requestContext);
|
||||
|
||||
// Create HttpClient and include subscription key as a default header
|
||||
var httpClient = new HttpClient();
|
||||
httpClient.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", subscriptionKey);
|
||||
|
||||
// Configure OpenAIClient to use
|
||||
// - Custom HttpClient with subscription key header
|
||||
// - Diagnostics to log error response headers from APIM to aid problem determination
|
||||
// - Authentication using BearerTokenCredential retrieved via interactive browser login
|
||||
var clientOptions = new OpenAIClientOptions
|
||||
{
|
||||
Transport = new HttpClientTransport(httpClient),
|
||||
Diagnostics =
|
||||
{
|
||||
LoggedHeaderNames = { "ErrorSource", "ErrorReason", "ErrorMessage", "ErrorScope", "ErrorSection", "ErrorStatusCode" },
|
||||
}
|
||||
};
|
||||
var openAIClient = new OpenAIClient(apimUri, new BearerTokenCredential(accessToken), clientOptions);
|
||||
|
||||
IKernelBuilder builder = Kernel.CreateBuilder();
|
||||
builder.Services.AddLogging(c => c.SetMinimumLevel(LogLevel.Warning).AddConsole());
|
||||
builder.AddAzureOpenAIChatCompletion(
|
||||
deploymentName: TestConfiguration.AzureOpenAI.ChatDeploymentName,
|
||||
openAIClient: openAIClient);
|
||||
Kernel kernel = builder.Build();
|
||||
|
||||
// Load semantic plugin defined with prompt templates
|
||||
string folder = RepoFiles.SamplePluginsPath();
|
||||
|
||||
kernel.ImportPluginFromPromptDirectory(Path.Combine(folder, "FunPlugin"));
|
||||
|
||||
// Run
|
||||
var result = await kernel.InvokeAsync(
|
||||
kernel.Plugins["FunPlugin"]["Excuses"],
|
||||
new() { ["input"] = "I have no homework" }
|
||||
);
|
||||
Console.WriteLine(result.GetValue<string>());
|
||||
|
||||
httpClient.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public class BearerTokenCredential : TokenCredential
|
||||
{
|
||||
private readonly AccessToken _accessToken;
|
||||
|
||||
// Constructor that takes a Bearer token string and its expiration date
|
||||
public BearerTokenCredential(AccessToken accessToken)
|
||||
{
|
||||
this._accessToken = accessToken;
|
||||
}
|
||||
|
||||
public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken)
|
||||
{
|
||||
return this._accessToken;
|
||||
}
|
||||
|
||||
public override ValueTask<AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)
|
||||
{
|
||||
return new ValueTask<AccessToken>(this._accessToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Azure;
|
||||
using Azure.AI.OpenAI;
|
||||
using Azure.Core.Pipeline;
|
||||
using Microsoft.SemanticKernel;
|
||||
using RepoUtils;
|
||||
|
||||
public static class Example52_CustomOpenAIClient
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
{
|
||||
Console.WriteLine("======== Using a custom OpenAI client ========");
|
||||
|
||||
string endpoint = TestConfiguration.AzureOpenAI.Endpoint;
|
||||
string deploymentName = TestConfiguration.AzureOpenAI.ChatDeploymentName;
|
||||
string apiKey = TestConfiguration.AzureOpenAI.ApiKey;
|
||||
|
||||
if (endpoint is null || deploymentName is null || apiKey is null)
|
||||
{
|
||||
Console.WriteLine("Azure OpenAI credentials not found. Skipping example.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create an HttpClient and include your custom header(s)
|
||||
var httpClient = new HttpClient();
|
||||
httpClient.DefaultRequestHeaders.Add("x-my-custom-header", "My custom value");
|
||||
|
||||
// Configure OpenAIClient to use the customized HttpClient
|
||||
var clientOptions = new OpenAIClientOptions
|
||||
{
|
||||
Transport = new HttpClientTransport(httpClient),
|
||||
};
|
||||
var openAIClient = new OpenAIClient(new Uri(endpoint), new AzureKeyCredential(apiKey), clientOptions);
|
||||
|
||||
IKernelBuilder builder = Kernel.CreateBuilder();
|
||||
builder.AddAzureOpenAIChatCompletion(deploymentName, openAIClient);
|
||||
Kernel kernel = builder.Build();
|
||||
|
||||
// Load semantic plugin defined with prompt templates
|
||||
string folder = RepoFiles.SamplePluginsPath();
|
||||
|
||||
kernel.ImportPluginFromPromptDirectory(Path.Combine(folder, "FunPlugin"));
|
||||
|
||||
// Run
|
||||
var result = await kernel.InvokeAsync(
|
||||
kernel.Plugins["FunPlugin"]["Excuses"],
|
||||
new() { ["input"] = "I have no homework" }
|
||||
);
|
||||
Console.WriteLine(result.GetValue<string>());
|
||||
|
||||
httpClient.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,10 @@ using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using xRetry;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
/// <summary>
|
||||
/// This example demonstrates how to use Azure OpenAI Chat Completion with data.
|
||||
@@ -24,17 +28,12 @@ using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
/// <para> dotnet user-secrets set "AzureAISearch:ApiKey" "{Key from your Search service resource}"</para>
|
||||
/// <para> dotnet user-secrets set "AzureAISearch:IndexName" "..."</para>
|
||||
/// </value>
|
||||
public static class Example54_AzureChatCompletionWithData
|
||||
public class Example54_AzureChatCompletionWithData : BaseTest
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
[RetryFact(typeof(HttpOperationException))]
|
||||
public async Task ExampleWithChatCompletionAsync()
|
||||
{
|
||||
await ExampleWithChatCompletionAsync();
|
||||
await ExampleWithKernelAsync();
|
||||
}
|
||||
|
||||
private static async Task ExampleWithChatCompletionAsync()
|
||||
{
|
||||
Console.WriteLine("=== Example with Chat Completion ===");
|
||||
WriteLine("=== Example with Chat Completion ===");
|
||||
|
||||
var chatCompletion = new AzureOpenAIChatCompletionWithDataService(GetCompletionWithDataConfig());
|
||||
var chatHistory = new ChatHistory();
|
||||
@@ -52,9 +51,9 @@ public static class Example54_AzureChatCompletionWithData
|
||||
// Output
|
||||
// Ask: How did Emily and David meet?
|
||||
// Response: Emily and David, both passionate scientists, met during a research expedition to Antarctica.
|
||||
Console.WriteLine($"Ask: {ask}");
|
||||
Console.WriteLine($"Response: {response}");
|
||||
Console.WriteLine();
|
||||
WriteLine($"Ask: {ask}");
|
||||
WriteLine($"Response: {response}");
|
||||
WriteLine();
|
||||
|
||||
// Chat history maintenance
|
||||
if (!string.IsNullOrEmpty(toolResponse))
|
||||
@@ -69,20 +68,21 @@ public static class Example54_AzureChatCompletionWithData
|
||||
chatHistory.AddUserMessage(ask);
|
||||
|
||||
// Chat Completion Streaming example
|
||||
Console.WriteLine($"Ask: {ask}");
|
||||
Console.WriteLine("Response: ");
|
||||
WriteLine($"Ask: {ask}");
|
||||
WriteLine("Response: ");
|
||||
|
||||
await foreach (var word in chatCompletion.GetStreamingChatMessageContentsAsync(chatHistory))
|
||||
{
|
||||
Console.Write(word);
|
||||
Write(word);
|
||||
}
|
||||
|
||||
Console.WriteLine(Environment.NewLine);
|
||||
WriteLine(Environment.NewLine);
|
||||
}
|
||||
|
||||
private static async Task ExampleWithKernelAsync()
|
||||
[RetryFact(typeof(HttpOperationException))]
|
||||
public async Task ExampleWithKernelAsync()
|
||||
{
|
||||
Console.WriteLine("=== Example with Kernel ===");
|
||||
WriteLine("=== Example with Kernel ===");
|
||||
|
||||
var ask = "How did Emily and David meet?";
|
||||
|
||||
@@ -100,9 +100,9 @@ public static class Example54_AzureChatCompletionWithData
|
||||
// Output
|
||||
// Ask: How did Emily and David meet?
|
||||
// Response: Emily and David, both passionate scientists, met during a research expedition to Antarctica.
|
||||
Console.WriteLine($"Ask: {ask}");
|
||||
Console.WriteLine($"Response: {response.GetValue<string>()}");
|
||||
Console.WriteLine();
|
||||
WriteLine($"Ask: {ask}");
|
||||
WriteLine($"Response: {response.GetValue<string>()}");
|
||||
WriteLine();
|
||||
|
||||
// Second question based on uploaded content.
|
||||
ask = "What are Emily and David studying?";
|
||||
@@ -112,9 +112,9 @@ public static class Example54_AzureChatCompletionWithData
|
||||
// Ask: What are Emily and David studying?
|
||||
// Response: They are passionate scientists who study glaciology,
|
||||
// a branch of geology that deals with the study of ice and its effects.
|
||||
Console.WriteLine($"Ask: {ask}");
|
||||
Console.WriteLine($"Response: {response.GetValue<string>()}");
|
||||
Console.WriteLine();
|
||||
WriteLine($"Ask: {ask}");
|
||||
WriteLine($"Response: {response.GetValue<string>()}");
|
||||
WriteLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -132,4 +132,8 @@ public static class Example54_AzureChatCompletionWithData
|
||||
DataSourceIndex = TestConfiguration.AzureAISearch.IndexName
|
||||
};
|
||||
}
|
||||
|
||||
public Example54_AzureChatCompletionWithData(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,49 +4,23 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.DeepDev;
|
||||
using Microsoft.ML.Tokenizers;
|
||||
using Microsoft.SemanticKernel.Text;
|
||||
using Resources;
|
||||
using SharpToken;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
using static Microsoft.SemanticKernel.Text.TextChunker;
|
||||
|
||||
public static class Example55_TextChunker
|
||||
namespace Examples;
|
||||
|
||||
public class Example55_TextChunker : BaseTest
|
||||
{
|
||||
private const string Text = @"The city of Venice, located in the northeastern part of Italy,
|
||||
is renowned for its unique geographical features. Built on more than 100 small islands in a lagoon in the
|
||||
Adriatic Sea, it has no roads, just canals including the Grand Canal thoroughfare lined with Renaissance and
|
||||
Gothic palaces. The central square, Piazza San Marco, contains St. Mark's Basilica, which is tiled with Byzantine
|
||||
mosaics, and the Campanile bell tower offering views of the city's red roofs.
|
||||
|
||||
The Amazon Rainforest, also known as Amazonia, is a moist broadleaf tropical rainforest in the Amazon biome that
|
||||
covers most of the Amazon basin of South America. This basin encompasses 7 million square kilometers, of which
|
||||
5.5 million square kilometers are covered by the rainforest. This region includes territory belonging to nine nations
|
||||
and 3.4 million square kilometers of uncontacted tribes. The Amazon represents over half of the planet's remaining
|
||||
rainforests and comprises the largest and most biodiverse tract of tropical rainforest in the world.
|
||||
|
||||
The Great Barrier Reef is the world's largest coral reef system composed of over 2,900 individual reefs and 900 islands
|
||||
stretching for over 2,300 kilometers over an area of approximately 344,400 square kilometers. The reef is located in the
|
||||
Coral Sea, off the coast of Queensland, Australia. The Great Barrier Reef can be seen from outer space and is the world's
|
||||
biggest single structure made by living organisms. This reef structure is composed of and built by billions of tiny organisms,
|
||||
known as coral polyps.";
|
||||
|
||||
public static Task RunAsync()
|
||||
[Fact]
|
||||
public void RunExample()
|
||||
{
|
||||
RunExample();
|
||||
RunExampleForTokenCounterType(TokenCounterType.SharpToken);
|
||||
RunExampleForTokenCounterType(TokenCounterType.MicrosoftML);
|
||||
RunExampleForTokenCounterType(TokenCounterType.MicrosoftMLRoberta);
|
||||
RunExampleForTokenCounterType(TokenCounterType.DeepDev);
|
||||
RunExampleWithHeader();
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private static void RunExample()
|
||||
{
|
||||
Console.WriteLine("=== Text chunking ===");
|
||||
WriteLine("=== Text chunking ===");
|
||||
|
||||
var lines = TextChunker.SplitPlainTextLines(Text, 40);
|
||||
var paragraphs = TextChunker.SplitPlainTextParagraphs(lines, 120);
|
||||
@@ -54,9 +28,14 @@ known as coral polyps.";
|
||||
WriteParagraphsToConsole(paragraphs);
|
||||
}
|
||||
|
||||
private static void RunExampleForTokenCounterType(TokenCounterType counterType)
|
||||
[Theory]
|
||||
[InlineData(TokenCounterType.SharpToken)]
|
||||
[InlineData(TokenCounterType.MicrosoftML)]
|
||||
[InlineData(TokenCounterType.MicrosoftMLRoberta)]
|
||||
[InlineData(TokenCounterType.DeepDev)]
|
||||
public void RunExampleForTokenCounterType(TokenCounterType counterType)
|
||||
{
|
||||
Console.WriteLine($"=== Text chunking with a custom({counterType}) token counter ===");
|
||||
WriteLine($"=== Text chunking with a custom({counterType}) token counter ===");
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var tokenCounter = s_tokenCounterFactory(counterType);
|
||||
@@ -65,13 +44,14 @@ known as coral polyps.";
|
||||
var paragraphs = TextChunker.SplitPlainTextParagraphs(lines, 120, tokenCounter: tokenCounter);
|
||||
|
||||
sw.Stop();
|
||||
Console.WriteLine($"Elapsed time: {sw.ElapsedMilliseconds} ms");
|
||||
WriteLine($"Elapsed time: {sw.ElapsedMilliseconds} ms");
|
||||
WriteParagraphsToConsole(paragraphs);
|
||||
}
|
||||
|
||||
private static void RunExampleWithHeader()
|
||||
[Fact]
|
||||
public void RunExampleWithHeader()
|
||||
{
|
||||
Console.WriteLine("=== Text chunking with chunk header ===");
|
||||
WriteLine("=== Text chunking with chunk header ===");
|
||||
|
||||
var lines = TextChunker.SplitPlainTextLines(Text, 40);
|
||||
var paragraphs = TextChunker.SplitPlainTextParagraphs(lines, 150, chunkHeader: "DOCUMENT NAME: test.txt\n\n");
|
||||
@@ -79,20 +59,20 @@ known as coral polyps.";
|
||||
WriteParagraphsToConsole(paragraphs);
|
||||
}
|
||||
|
||||
private static void WriteParagraphsToConsole(List<string> paragraphs)
|
||||
private void WriteParagraphsToConsole(List<string> paragraphs)
|
||||
{
|
||||
for (var i = 0; i < paragraphs.Count; i++)
|
||||
{
|
||||
Console.WriteLine(paragraphs[i]);
|
||||
WriteLine(paragraphs[i]);
|
||||
|
||||
if (i < paragraphs.Count - 1)
|
||||
{
|
||||
Console.WriteLine("------------------------");
|
||||
WriteLine("------------------------");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private enum TokenCounterType
|
||||
public enum TokenCounterType
|
||||
{
|
||||
SharpToken,
|
||||
MicrosoftML,
|
||||
@@ -175,4 +155,26 @@ known as coral polyps.";
|
||||
TokenCounterType.MicrosoftMLRoberta => (string input) => MicrosoftMLRobertaTokenCounter(input),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(counterType), counterType, null),
|
||||
};
|
||||
|
||||
private const string Text = @"The city of Venice, located in the northeastern part of Italy,
|
||||
is renowned for its unique geographical features. Built on more than 100 small islands in a lagoon in the
|
||||
Adriatic Sea, it has no roads, just canals including the Grand Canal thoroughfare lined with Renaissance and
|
||||
Gothic palaces. The central square, Piazza San Marco, contains St. Mark's Basilica, which is tiled with Byzantine
|
||||
mosaics, and the Campanile bell tower offering views of the city's red roofs.
|
||||
|
||||
The Amazon Rainforest, also known as Amazonia, is a moist broadleaf tropical rainforest in the Amazon biome that
|
||||
covers most of the Amazon basin of South America. This basin encompasses 7 million square kilometers, of which
|
||||
5.5 million square kilometers are covered by the rainforest. This region includes territory belonging to nine nations
|
||||
and 3.4 million square kilometers of uncontacted tribes. The Amazon represents over half of the planet's remaining
|
||||
rainforests and comprises the largest and most biodiverse tract of tropical rainforest in the world.
|
||||
|
||||
The Great Barrier Reef is the world's largest coral reef system composed of over 2,900 individual reefs and 900 islands
|
||||
stretching for over 2,300 kilometers over an area of approximately 344,400 square kilometers. The reef is located in the
|
||||
Coral Sea, off the coast of Queensland, Australia. The Great Barrier Reef can be seen from outer space and is the world's
|
||||
biggest single structure made by living organisms. This reef structure is composed of and built by billions of tiny organisms,
|
||||
known as coral polyps.";
|
||||
|
||||
public Example55_TextChunker(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
+17
-9
@@ -1,22 +1,26 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Microsoft.SemanticKernel.Plugins.Core;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
public static class Example56_TemplateMethodFunctionsWithMultipleArguments
|
||||
namespace Examples;
|
||||
|
||||
public class Example56_TemplateMethodFunctionsWithMultipleArguments : BaseTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Show how to invoke a Method Function written in C# with multiple arguments
|
||||
/// from a Prompt Function written in natural language
|
||||
/// </summary>
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
Console.WriteLine("======== TemplateMethodFunctionsWithMultipleArguments ========");
|
||||
WriteLine("======== TemplateMethodFunctionsWithMultipleArguments ========");
|
||||
|
||||
string serviceId = TestConfiguration.AzureOpenAI.ServiceId;
|
||||
string apiKey = TestConfiguration.AzureOpenAI.ApiKey;
|
||||
@@ -26,7 +30,7 @@ public static class Example56_TemplateMethodFunctionsWithMultipleArguments
|
||||
|
||||
if (apiKey == null || deploymentName == null || modelId == null || endpoint == null)
|
||||
{
|
||||
Console.WriteLine("AzureOpenAI modelId, endpoint, apiKey, or deploymentName not found. Skipping example.");
|
||||
WriteLine("AzureOpenAI modelId, endpoint, apiKey, or deploymentName not found. Skipping example.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -53,19 +57,19 @@ public static class Example56_TemplateMethodFunctionsWithMultipleArguments
|
||||
";
|
||||
|
||||
// This allows to see the prompt before it's sent to OpenAI
|
||||
Console.WriteLine("--- Rendered Prompt");
|
||||
WriteLine("--- Rendered Prompt");
|
||||
var promptTemplateFactory = new KernelPromptTemplateFactory();
|
||||
var promptTemplate = promptTemplateFactory.Create(new PromptTemplateConfig(FunctionDefinition));
|
||||
var renderedPrompt = await promptTemplate.RenderAsync(kernel, arguments);
|
||||
Console.WriteLine(renderedPrompt);
|
||||
WriteLine(renderedPrompt);
|
||||
|
||||
// Run the prompt / prompt function
|
||||
var haiku = kernel.CreateFunctionFromPrompt(FunctionDefinition, new OpenAIPromptExecutionSettings() { MaxTokens = 100 });
|
||||
|
||||
// Show the result
|
||||
Console.WriteLine("--- Prompt Function result");
|
||||
WriteLine("--- Prompt Function result");
|
||||
var result = await kernel.InvokeAsync(haiku, arguments);
|
||||
Console.WriteLine(result.GetValue<string>());
|
||||
WriteLine(result.GetValue<string>());
|
||||
|
||||
/* OUTPUT:
|
||||
|
||||
@@ -79,4 +83,8 @@ Wizarding world he explores,
|
||||
Harry Potter's tale.
|
||||
*/
|
||||
}
|
||||
|
||||
public Example56_TemplateMethodFunctionsWithMultipleArguments(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,55 +1,32 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using RepoUtils;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
public static class Example57_KernelHooks
|
||||
namespace Examples;
|
||||
|
||||
public class Example57_KernelHooks : BaseTest
|
||||
{
|
||||
private static string? s_openAIModelId;
|
||||
private static string? s_openAIApiKey;
|
||||
|
||||
public static async Task RunAsync()
|
||||
{
|
||||
Console.WriteLine("\n======== Using Function Execution Handlers ========\n");
|
||||
|
||||
s_openAIModelId = TestConfiguration.OpenAI.ChatModelId;
|
||||
s_openAIApiKey = TestConfiguration.OpenAI.ApiKey;
|
||||
|
||||
if (s_openAIModelId == null || s_openAIApiKey == null)
|
||||
{
|
||||
Console.WriteLine("OpenAI credentials not found. Skipping example.");
|
||||
return;
|
||||
}
|
||||
|
||||
await GetUsageAsync();
|
||||
|
||||
await GetRenderedPromptAsync();
|
||||
|
||||
await ChangingResultAsync();
|
||||
|
||||
await BeforeInvokeCancellationAsync();
|
||||
|
||||
await AfterInvokeCancellationAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrate using kernel invocation-hooks to monitor usage:
|
||||
/// <see cref="Kernel.FunctionInvoking"/>
|
||||
/// <see cref="Kernel.FunctionInvoked"/>
|
||||
/// </summary>
|
||||
private static async Task GetUsageAsync()
|
||||
[Fact]
|
||||
public async Task GetUsageAsync()
|
||||
{
|
||||
Console.WriteLine("\n======== Get Usage Data ========\n");
|
||||
WriteLine("\n======== Get Usage Data ========\n");
|
||||
|
||||
// Create kernel instance
|
||||
Kernel kernel = Kernel.CreateBuilder()
|
||||
.AddOpenAIChatCompletion(
|
||||
modelId: s_openAIModelId!,
|
||||
apiKey: s_openAIApiKey!)
|
||||
modelId: _openAIModelId!,
|
||||
apiKey: _openAIApiKey!)
|
||||
.Build();
|
||||
|
||||
// Initialize prompt
|
||||
@@ -63,18 +40,18 @@ public static class Example57_KernelHooks
|
||||
// Define hooks
|
||||
void MyPreHandler(object? sender, FunctionInvokingEventArgs e)
|
||||
{
|
||||
Console.WriteLine($"{e.Function.Name} : Pre Execution Handler - Triggered");
|
||||
WriteLine($"{e.Function.Name} : Pre Execution Handler - Triggered");
|
||||
}
|
||||
|
||||
void MyRemovedPreExecutionHandler(object? sender, FunctionInvokingEventArgs e)
|
||||
{
|
||||
Console.WriteLine($"{e.Function.Name} : Pre Execution Handler - Should not trigger");
|
||||
WriteLine($"{e.Function.Name} : Pre Execution Handler - Should not trigger");
|
||||
e.Cancel = true;
|
||||
}
|
||||
|
||||
void MyPostExecutionHandler(object? sender, FunctionInvokedEventArgs e)
|
||||
{
|
||||
Console.WriteLine($"{e.Function.Name} : Post Execution Handler - Usage: {e.Result.Metadata?["Usage"]?.AsJson()}");
|
||||
WriteLine($"{e.Function.Name} : Post Execution Handler - Usage: {e.Result.Metadata?["Usage"]?.AsJson()}");
|
||||
}
|
||||
|
||||
kernel.FunctionInvoking += MyPreHandler;
|
||||
@@ -88,7 +65,7 @@ public static class Example57_KernelHooks
|
||||
// Invoke prompt to trigger execution hooks.
|
||||
const string Input = "I missed the F1 final race";
|
||||
var result = await kernel.InvokeAsync(excuseFunction, new() { ["input"] = Input });
|
||||
Console.WriteLine($"Function Result: {result}");
|
||||
WriteLine($"Function Result: {result}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -96,15 +73,16 @@ public static class Example57_KernelHooks
|
||||
/// <see cref="Kernel.PromptRendering"/>
|
||||
/// <see cref="Kernel.PromptRendered"/>
|
||||
/// </summary>
|
||||
private static async Task GetRenderedPromptAsync()
|
||||
[Fact]
|
||||
public async Task GetRenderedPromptAsync()
|
||||
{
|
||||
Console.WriteLine("\n======== Get Rendered Prompt ========\n");
|
||||
WriteLine("\n======== Get Rendered Prompt ========\n");
|
||||
|
||||
// Create kernel instance
|
||||
Kernel kernel = Kernel.CreateBuilder()
|
||||
.AddOpenAIChatCompletion(
|
||||
modelId: s_openAIModelId!,
|
||||
apiKey: s_openAIApiKey!)
|
||||
modelId: _openAIModelId!,
|
||||
apiKey: _openAIApiKey!)
|
||||
.Build();
|
||||
|
||||
// Initialize prompt
|
||||
@@ -118,16 +96,16 @@ public static class Example57_KernelHooks
|
||||
// Define hooks
|
||||
void MyRenderingHandler(object? sender, PromptRenderingEventArgs e)
|
||||
{
|
||||
Console.WriteLine($"{e.Function.Name} : Prompt Rendering Handler - Triggered");
|
||||
WriteLine($"{e.Function.Name} : Prompt Rendering Handler - Triggered");
|
||||
e.Arguments["style"] = "Seinfeld";
|
||||
}
|
||||
|
||||
void MyRenderedHandler(object? sender, PromptRenderedEventArgs e)
|
||||
{
|
||||
Console.WriteLine($"{e.Function.Name} : Prompt Rendered Handler - Triggered");
|
||||
WriteLine($"{e.Function.Name} : Prompt Rendered Handler - Triggered");
|
||||
e.RenderedPrompt += " USE SHORT, CLEAR, COMPLETE SENTENCES.";
|
||||
|
||||
Console.WriteLine(e.RenderedPrompt);
|
||||
WriteLine(e.RenderedPrompt);
|
||||
}
|
||||
|
||||
kernel.PromptRendering += MyRenderingHandler;
|
||||
@@ -136,22 +114,23 @@ public static class Example57_KernelHooks
|
||||
// Invoke prompt to trigger prompt rendering hooks.
|
||||
const string Input = "I missed the F1 final race";
|
||||
var result = await kernel.InvokeAsync(excuseFunction, new() { ["input"] = Input });
|
||||
Console.WriteLine($"Function Result: {result.GetValue<string>()}");
|
||||
WriteLine($"Function Result: {result.GetValue<string>()}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrate using kernel invocation-hooks to post process result:
|
||||
/// <see cref="Kernel.FunctionInvoked"/>
|
||||
/// </summary>
|
||||
private static async Task ChangingResultAsync()
|
||||
[Fact]
|
||||
public async Task ChangingResultAsync()
|
||||
{
|
||||
Console.WriteLine("\n======== Changing/Filtering Function Result ========\n");
|
||||
WriteLine("\n======== Changing/Filtering Function Result ========\n");
|
||||
|
||||
// Create kernel instance
|
||||
Kernel kernel = Kernel.CreateBuilder()
|
||||
.AddOpenAIChatCompletion(
|
||||
modelId: s_openAIModelId!,
|
||||
apiKey: s_openAIApiKey!)
|
||||
modelId: _openAIModelId!,
|
||||
apiKey: _openAIApiKey!)
|
||||
.Build();
|
||||
|
||||
// Initialize function
|
||||
@@ -178,7 +157,7 @@ public static class Example57_KernelHooks
|
||||
// Invoke prompt to trigger execution hooks.
|
||||
var result = await kernel.InvokeAsync(writerFunction);
|
||||
|
||||
Console.WriteLine($"Function Result: {result.GetValue<string>()}");
|
||||
WriteLine($"Function Result: {result.GetValue<string>()}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -186,15 +165,16 @@ public static class Example57_KernelHooks
|
||||
/// <see cref="Kernel.FunctionInvoking"/>
|
||||
/// <see cref="Kernel.FunctionInvoked"/>
|
||||
/// </summary>
|
||||
private static async Task BeforeInvokeCancellationAsync()
|
||||
[Fact]
|
||||
public async Task BeforeInvokeCancellationAsync()
|
||||
{
|
||||
Console.WriteLine("\n======== Cancelling Pipeline Execution - Invoking event ========\n");
|
||||
WriteLine("\n======== Cancelling Pipeline Execution - Invoking event ========\n");
|
||||
|
||||
// Create kernel instance
|
||||
Kernel kernel = Kernel.CreateBuilder()
|
||||
.AddOpenAIChatCompletion(
|
||||
modelId: s_openAIModelId!,
|
||||
apiKey: s_openAIApiKey!)
|
||||
modelId: _openAIModelId!,
|
||||
apiKey: _openAIApiKey!)
|
||||
.Build();
|
||||
|
||||
// Initialize prompt
|
||||
@@ -208,7 +188,7 @@ public static class Example57_KernelHooks
|
||||
// Adding new inline handler to cancel/prevent function execution
|
||||
kernel.FunctionInvoking += (object? sender, FunctionInvokingEventArgs e) =>
|
||||
{
|
||||
Console.WriteLine($"{e.Function.Name} : FunctionInvoking - Cancelling before execution");
|
||||
WriteLine($"{e.Function.Name} : FunctionInvoking - Cancelling before execution");
|
||||
e.Cancel = true;
|
||||
};
|
||||
|
||||
@@ -220,8 +200,16 @@ public static class Example57_KernelHooks
|
||||
};
|
||||
|
||||
// Invoke prompt to trigger execution hooks.
|
||||
var result = await kernel.InvokeAsync(writerFunction);
|
||||
Console.WriteLine($"Function Invocation Times: {functionInvokedCount}");
|
||||
try
|
||||
{
|
||||
var result = await kernel.InvokeAsync(writerFunction);
|
||||
}
|
||||
catch (KernelFunctionCanceledException fcex)
|
||||
{
|
||||
WriteLine(fcex.Message);
|
||||
}
|
||||
|
||||
WriteLine($"Function Invocation Times: {functionInvokedCount}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -229,15 +217,16 @@ public static class Example57_KernelHooks
|
||||
/// <see cref="Kernel.FunctionInvoking"/>
|
||||
/// <see cref="Kernel.FunctionInvoked"/>
|
||||
/// </summary>
|
||||
private static async Task AfterInvokeCancellationAsync()
|
||||
[Fact]
|
||||
public async Task AfterInvokeCancellationAsync()
|
||||
{
|
||||
Console.WriteLine("\n======== Cancelling Pipeline Execution - Invoked event ========\n");
|
||||
WriteLine("\n======== Cancelling Pipeline Execution - Invoked event ========\n");
|
||||
|
||||
// Create kernel instance
|
||||
Kernel kernel = Kernel.CreateBuilder()
|
||||
.AddOpenAIChatCompletion(
|
||||
modelId: s_openAIModelId!,
|
||||
apiKey: s_openAIApiKey!)
|
||||
modelId: _openAIModelId!,
|
||||
apiKey: _openAIApiKey!)
|
||||
.Build();
|
||||
|
||||
// Initialize prompts
|
||||
@@ -261,8 +250,31 @@ public static class Example57_KernelHooks
|
||||
};
|
||||
|
||||
// Invoke prompt to trigger execution hooks.
|
||||
var result = await kernel.InvokeAsync(secondFunction);
|
||||
Console.WriteLine($"Function Invoked Times: {functionInvokedCount}");
|
||||
Console.WriteLine($"Function Invoking Times: {functionInvokingCount}");
|
||||
try
|
||||
{
|
||||
var result = await kernel.InvokeAsync(secondFunction);
|
||||
}
|
||||
catch (KernelFunctionCanceledException fcex)
|
||||
{
|
||||
WriteLine(fcex.Message);
|
||||
}
|
||||
|
||||
WriteLine($"Function Invoked Times: {functionInvokedCount}");
|
||||
WriteLine($"Function Invoking Times: {functionInvokingCount}");
|
||||
}
|
||||
|
||||
private readonly string? _openAIModelId;
|
||||
private readonly string? _openAIApiKey;
|
||||
|
||||
public Example57_KernelHooks(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
this._openAIModelId = TestConfiguration.OpenAI.ChatModelId;
|
||||
this._openAIApiKey = TestConfiguration.OpenAI.ApiKey;
|
||||
|
||||
if (this._openAIModelId == null || this._openAIApiKey == null)
|
||||
{
|
||||
WriteLine("OpenAI credentials not found. Skipping example.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,11 @@ using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
public static class Example58_ConfigureExecutionSettings
|
||||
namespace Examples;
|
||||
|
||||
public class Example58_ConfigureExecutionSettings : BaseTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Show how to configure model execution settings
|
||||
@@ -94,4 +97,8 @@ Hello! As an AI language model, I can help you with a variety of tasks, includin
|
||||
4. Providing explanations and
|
||||
*/
|
||||
}
|
||||
|
||||
public Example58_ConfigureExecutionSettings(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Azure.AI.OpenAI;
|
||||
@@ -12,11 +11,16 @@ using Microsoft.Extensions.Logging;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
// This example shows how to use OpenAI's tool calling capability via the chat completions interface.
|
||||
public static class Example59_OpenAIFunctionCalling
|
||||
public class Example59_OpenAIFunctionCalling : BaseTest
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
// Create kernel.
|
||||
IKernelBuilder builder = Kernel.CreateBuilder();
|
||||
@@ -46,24 +50,24 @@ public static class Example59_OpenAIFunctionCalling
|
||||
}, "Get_Weather_For_City", "Gets the current weather for the specified city"),
|
||||
});
|
||||
|
||||
Console.WriteLine("======== Example 1: Use automated function calling with a non-streaming prompt ========");
|
||||
WriteLine("======== Example 1: Use automated function calling with a non-streaming prompt ========");
|
||||
{
|
||||
OpenAIPromptExecutionSettings settings = new() { ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions };
|
||||
Console.WriteLine(await kernel.InvokePromptAsync("Given the current time of day and weather, what is the likely color of the sky in Boston?", new(settings)));
|
||||
Console.WriteLine();
|
||||
WriteLine(await kernel.InvokePromptAsync("Given the current time of day and weather, what is the likely color of the sky in Boston?", new(settings)));
|
||||
WriteLine();
|
||||
}
|
||||
|
||||
Console.WriteLine("======== Example 2: Use automated function calling with a streaming prompt ========");
|
||||
WriteLine("======== Example 2: Use automated function calling with a streaming prompt ========");
|
||||
{
|
||||
OpenAIPromptExecutionSettings settings = new() { ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions };
|
||||
await foreach (var update in kernel.InvokePromptStreamingAsync("Given the current time of day and weather, what is the likely color of the sky in Boston?", new(settings)))
|
||||
{
|
||||
Console.Write(update);
|
||||
Write(update);
|
||||
}
|
||||
Console.WriteLine();
|
||||
WriteLine();
|
||||
}
|
||||
|
||||
Console.WriteLine("======== Example 3: Use manual function calling with a non-streaming prompt ========");
|
||||
WriteLine("======== Example 3: Use manual function calling with a non-streaming prompt ========");
|
||||
{
|
||||
var chat = kernel.GetRequiredService<IChatCompletionService>();
|
||||
var chatHistory = new ChatHistory();
|
||||
@@ -76,7 +80,7 @@ public static class Example59_OpenAIFunctionCalling
|
||||
|
||||
if (result.Content is not null)
|
||||
{
|
||||
Console.Write(result.Content);
|
||||
Write(result.Content);
|
||||
}
|
||||
|
||||
List<ChatCompletionsFunctionToolCall> toolCalls = result.ToolCalls.OfType<ChatCompletionsFunctionToolCall>().ToList();
|
||||
@@ -99,9 +103,10 @@ public static class Example59_OpenAIFunctionCalling
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
WriteLine();
|
||||
}
|
||||
|
||||
/* Uncomment this to try in a console chat loop.
|
||||
Console.WriteLine("======== Example 4: Use automated function calling with a streaming chat ========");
|
||||
{
|
||||
OpenAIPromptExecutionSettings settings = new() { ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions };
|
||||
@@ -130,6 +135,10 @@ public static class Example59_OpenAIFunctionCalling
|
||||
chatHistory.AddAssistantMessage(sb.ToString());
|
||||
Console.WriteLine();
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
public Example59_OpenAIFunctionCalling(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,23 +6,23 @@ using System.Globalization;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
// This example shows different ways how to define and execute method functions using custom and primitive types.
|
||||
public static class Example60_AdvancedMethodFunctions
|
||||
public class Example60_AdvancedMethodFunctions : BaseTest
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
{
|
||||
await MethodFunctionsChainingAsync();
|
||||
}
|
||||
|
||||
#region Method Functions Chaining
|
||||
|
||||
/// <summary>
|
||||
/// This example executes Function1, which in turn executes Function2.
|
||||
/// </summary>
|
||||
private static async Task MethodFunctionsChainingAsync()
|
||||
[Fact]
|
||||
public async Task MethodFunctionsChainingAsync()
|
||||
{
|
||||
Console.WriteLine("Running Method Function Chaining example...");
|
||||
WriteLine("Running Method Function Chaining example...");
|
||||
|
||||
var kernel = new Kernel();
|
||||
|
||||
@@ -30,8 +30,8 @@ public static class Example60_AdvancedMethodFunctions
|
||||
|
||||
var customType = await kernel.InvokeAsync<MyCustomType>(functions["Function1"]);
|
||||
|
||||
Console.WriteLine($"CustomType.Number: {customType!.Number}"); // 2
|
||||
Console.WriteLine($"CustomType.Text: {customType.Text}"); // From Function1 + From Function2
|
||||
WriteLine($"CustomType.Number: {customType!.Number}"); // 2
|
||||
WriteLine($"CustomType.Text: {customType.Text}"); // From Function1 + From Function2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -39,7 +39,7 @@ public static class Example60_AdvancedMethodFunctions
|
||||
/// </summary>
|
||||
private sealed class FunctionsChainingPlugin
|
||||
{
|
||||
public const string PluginName = nameof(FunctionsChainingPlugin);
|
||||
private const string PluginName = nameof(FunctionsChainingPlugin);
|
||||
|
||||
[KernelFunction]
|
||||
public async Task<MyCustomType> Function1Async(Kernel kernel)
|
||||
@@ -115,4 +115,8 @@ public static class Example60_AdvancedMethodFunctions
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public Example60_AdvancedMethodFunctions(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,60 +1,42 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel;
|
||||
using xRetry;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
public static class Example61_MultipleLLMs
|
||||
namespace Examples;
|
||||
|
||||
public class Example61_MultipleLLMs : BaseTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Show how to run a prompt function and specify a specific service to use.
|
||||
/// </summary>
|
||||
public static async Task RunAsync()
|
||||
[RetryFact(typeof(HttpOperationException))]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
Console.WriteLine("======== Example61_MultipleLLMs ========");
|
||||
|
||||
string azureApiKey = TestConfiguration.AzureOpenAI.ApiKey;
|
||||
string azureDeploymentName = TestConfiguration.AzureOpenAI.ChatDeploymentName;
|
||||
string azureModelId = TestConfiguration.AzureOpenAI.ChatModelId;
|
||||
string azureEndpoint = TestConfiguration.AzureOpenAI.Endpoint;
|
||||
|
||||
if (azureApiKey == null || azureDeploymentName == null || azureModelId == null || azureEndpoint == null)
|
||||
{
|
||||
Console.WriteLine("AzureOpenAI endpoint, apiKey, deploymentName or modelId not found. Skipping example.");
|
||||
return;
|
||||
}
|
||||
|
||||
string openAIModelId = TestConfiguration.OpenAI.ChatModelId;
|
||||
string openAIApiKey = TestConfiguration.OpenAI.ApiKey;
|
||||
|
||||
if (openAIModelId == null || openAIApiKey == null)
|
||||
{
|
||||
Console.WriteLine("OpenAI credentials not found. Skipping example.");
|
||||
return;
|
||||
}
|
||||
|
||||
Kernel kernel = Kernel.CreateBuilder()
|
||||
.AddAzureOpenAIChatCompletion(
|
||||
deploymentName: azureDeploymentName,
|
||||
endpoint: azureEndpoint,
|
||||
apiKey: azureApiKey,
|
||||
deploymentName: TestConfiguration.AzureOpenAI.ChatDeploymentName,
|
||||
endpoint: TestConfiguration.AzureOpenAI.Endpoint,
|
||||
apiKey: TestConfiguration.AzureOpenAI.ApiKey,
|
||||
serviceId: "AzureOpenAIChat",
|
||||
modelId: azureModelId)
|
||||
modelId: TestConfiguration.AzureOpenAI.ChatModelId)
|
||||
.AddOpenAIChatCompletion(
|
||||
modelId: openAIModelId,
|
||||
apiKey: openAIApiKey,
|
||||
modelId: TestConfiguration.OpenAI.ChatModelId,
|
||||
apiKey: TestConfiguration.OpenAI.ApiKey,
|
||||
serviceId: "OpenAIChat")
|
||||
.Build();
|
||||
|
||||
await RunByServiceIdAsync(kernel, "AzureOpenAIChat");
|
||||
await RunByModelIdAsync(kernel, openAIModelId);
|
||||
await RunByFirstModelIdAsync(kernel, "gpt-4-1106-preview", azureModelId, openAIModelId);
|
||||
await RunByModelIdAsync(kernel, TestConfiguration.OpenAI.ChatModelId);
|
||||
await RunByFirstModelIdAsync(kernel, "gpt-4-1106-preview", TestConfiguration.AzureOpenAI.ChatModelId, TestConfiguration.OpenAI.ChatModelId);
|
||||
}
|
||||
|
||||
public static async Task RunByServiceIdAsync(Kernel kernel, string serviceId)
|
||||
private async Task RunByServiceIdAsync(Kernel kernel, string serviceId)
|
||||
{
|
||||
Console.WriteLine($"======== Service Id: {serviceId} ========");
|
||||
WriteLine($"======== Service Id: {serviceId} ========");
|
||||
|
||||
var prompt = "Hello AI, what can you do for me?";
|
||||
|
||||
@@ -64,12 +46,12 @@ public static class Example61_MultipleLLMs
|
||||
{ serviceId, new PromptExecutionSettings() }
|
||||
};
|
||||
var result = await kernel.InvokePromptAsync(prompt, arguments);
|
||||
Console.WriteLine(result.GetValue<string>());
|
||||
WriteLine(result.GetValue<string>());
|
||||
}
|
||||
|
||||
public static async Task RunByModelIdAsync(Kernel kernel, string modelId)
|
||||
private async Task RunByModelIdAsync(Kernel kernel, string modelId)
|
||||
{
|
||||
Console.WriteLine($"======== Model Id: {modelId} ========");
|
||||
WriteLine($"======== Model Id: {modelId} ========");
|
||||
|
||||
var prompt = "Hello AI, what can you do for me?";
|
||||
|
||||
@@ -79,12 +61,12 @@ public static class Example61_MultipleLLMs
|
||||
{
|
||||
ModelId = modelId
|
||||
}));
|
||||
Console.WriteLine(result.GetValue<string>());
|
||||
WriteLine(result.GetValue<string>());
|
||||
}
|
||||
|
||||
public static async Task RunByFirstModelIdAsync(Kernel kernel, params string[] modelIds)
|
||||
private async Task RunByFirstModelIdAsync(Kernel kernel, params string[] modelIds)
|
||||
{
|
||||
Console.WriteLine($"======== Model Ids: {string.Join(", ", modelIds)} ========");
|
||||
WriteLine($"======== Model Ids: {string.Join(", ", modelIds)} ========");
|
||||
|
||||
var prompt = "Hello AI, what can you do for me?";
|
||||
|
||||
@@ -98,6 +80,10 @@ public static class Example61_MultipleLLMs
|
||||
var function = kernel.CreateFunctionFromPrompt(promptConfig);
|
||||
|
||||
var result = await kernel.InvokeAsync(function);
|
||||
Console.WriteLine(result.GetValue<string>());
|
||||
WriteLine(result.GetValue<string>());
|
||||
}
|
||||
|
||||
public Example61_MultipleLLMs(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,55 +7,40 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Microsoft.SemanticKernel.Services;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
public static class Example62_CustomAIServiceSelector
|
||||
namespace Examples;
|
||||
|
||||
public class Example62_CustomAIServiceSelector : BaseTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Show how to use a custom AI service selector to select a specific model
|
||||
/// </summary>
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
Console.WriteLine("======== Example62_CustomAIServiceSelector ========");
|
||||
|
||||
string azureApiKey = TestConfiguration.AzureOpenAI.ApiKey;
|
||||
string azureDeploymentName = TestConfiguration.AzureOpenAI.ChatDeploymentName;
|
||||
string azureModelId = TestConfiguration.AzureOpenAI.ChatModelId;
|
||||
string azureEndpoint = TestConfiguration.AzureOpenAI.Endpoint;
|
||||
|
||||
if (azureApiKey == null || azureDeploymentName == null || azureModelId == null || azureEndpoint == null)
|
||||
{
|
||||
Console.WriteLine("AzureOpenAI endpoint, apiKey, deploymentName or modelId not found. Skipping example.");
|
||||
return;
|
||||
}
|
||||
|
||||
string openAIModelId = TestConfiguration.OpenAI.ChatModelId;
|
||||
string openAIApiKey = TestConfiguration.OpenAI.ApiKey;
|
||||
|
||||
if (openAIModelId == null || openAIApiKey == null)
|
||||
{
|
||||
Console.WriteLine("OpenAI credentials not found. Skipping example.");
|
||||
return;
|
||||
}
|
||||
WriteLine("======== Example62_CustomAIServiceSelector ========");
|
||||
|
||||
// Build a kernel with multiple chat completion services
|
||||
var builder = Kernel.CreateBuilder()
|
||||
.AddAzureOpenAIChatCompletion(
|
||||
deploymentName: azureDeploymentName,
|
||||
endpoint: azureEndpoint,
|
||||
apiKey: azureApiKey,
|
||||
deploymentName: TestConfiguration.AzureOpenAI.ChatDeploymentName,
|
||||
endpoint: TestConfiguration.AzureOpenAI.Endpoint,
|
||||
apiKey: TestConfiguration.AzureOpenAI.ApiKey,
|
||||
serviceId: "AzureOpenAIChat",
|
||||
modelId: azureModelId)
|
||||
modelId: TestConfiguration.AzureOpenAI.ChatModelId)
|
||||
.AddOpenAIChatCompletion(
|
||||
modelId: openAIModelId,
|
||||
apiKey: openAIApiKey,
|
||||
modelId: TestConfiguration.OpenAI.ChatModelId,
|
||||
apiKey: TestConfiguration.OpenAI.ApiKey,
|
||||
serviceId: "OpenAIChat");
|
||||
builder.Services.AddSingleton<IAIServiceSelector>(new GptAIServiceSelector()); // Use the custom AI service selector to select the GPT model
|
||||
builder.Services.AddSingleton<IAIServiceSelector>(new GptAIServiceSelector(this.Output)); // Use the custom AI service selector to select the GPT model
|
||||
Kernel kernel = builder.Build();
|
||||
|
||||
// This invocation is done with the model selected by the custom selector
|
||||
var prompt = "Hello AI, what can you do for me?";
|
||||
var result = await kernel.InvokePromptAsync(prompt);
|
||||
Console.WriteLine(result.GetValue<string>());
|
||||
WriteLine(result.GetValue<string>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -66,6 +51,13 @@ public static class Example62_CustomAIServiceSelector
|
||||
/// </summary>
|
||||
private sealed class GptAIServiceSelector : IAIServiceSelector
|
||||
{
|
||||
private readonly ITestOutputHelper _output;
|
||||
|
||||
public GptAIServiceSelector(ITestOutputHelper output)
|
||||
{
|
||||
this._output = output;
|
||||
}
|
||||
|
||||
public bool TrySelectAIService<T>(
|
||||
Kernel kernel, KernelFunction function, KernelArguments arguments,
|
||||
[NotNullWhen(true)] out T? service, out PromptExecutionSettings? serviceSettings) where T : class, IAIService
|
||||
@@ -77,7 +69,7 @@ public static class Example62_CustomAIServiceSelector
|
||||
var endpoint = serviceToCheck.GetEndpoint();
|
||||
if (!string.IsNullOrEmpty(serviceModelId) && serviceModelId.StartsWith("gpt", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Console.WriteLine($"Selected model: {serviceModelId} {endpoint}");
|
||||
this._output.WriteLine($"Selected model: {serviceModelId} {endpoint}");
|
||||
service = serviceToCheck;
|
||||
serviceSettings = new OpenAIPromptExecutionSettings();
|
||||
return true;
|
||||
@@ -89,4 +81,8 @@ public static class Example62_CustomAIServiceSelector
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public Example62_CustomAIServiceSelector(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
// This example shows how to use chat completion standardized prompts.
|
||||
public static class Example63_ChatCompletionPrompts
|
||||
public class Example63_ChatCompletionPrompts : BaseTest
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
const string ChatPrompt = @"
|
||||
<message role=""user"">What is Seattle?</message>
|
||||
@@ -23,17 +27,21 @@ public static class Example63_ChatCompletionPrompts
|
||||
var chatSemanticFunction = kernel.CreateFunctionFromPrompt(ChatPrompt);
|
||||
var chatPromptResult = await kernel.InvokeAsync(chatSemanticFunction);
|
||||
|
||||
Console.WriteLine("Chat Prompt:");
|
||||
Console.WriteLine(ChatPrompt);
|
||||
Console.WriteLine("Chat Prompt Result:");
|
||||
Console.WriteLine(chatPromptResult);
|
||||
WriteLine("Chat Prompt:");
|
||||
WriteLine(ChatPrompt);
|
||||
WriteLine("Chat Prompt Result:");
|
||||
WriteLine(chatPromptResult);
|
||||
|
||||
Console.WriteLine("Chat Prompt Streaming Result:");
|
||||
WriteLine("Chat Prompt Streaming Result:");
|
||||
string completeMessage = string.Empty;
|
||||
await foreach (var message in kernel.InvokeStreamingAsync<string>(chatSemanticFunction))
|
||||
{
|
||||
Console.Write(message);
|
||||
completeMessage += message;
|
||||
Write(message);
|
||||
}
|
||||
Console.WriteLine();
|
||||
|
||||
WriteLine("---------- Streamed Content ----------");
|
||||
WriteLine(completeMessage);
|
||||
|
||||
/*
|
||||
Chat Prompt:
|
||||
@@ -51,4 +59,8 @@ public static class Example63_ChatCompletionPrompts
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public Example63_ChatCompletionPrompts(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,54 +1,46 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.PromptTemplates.Handlebars;
|
||||
using xRetry;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
// This example shows how to use multiple prompt template formats.
|
||||
public static class Example64_MultiplePromptTemplates
|
||||
public class Example64_MultiplePromptTemplates : BaseTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Show how to combine multiple prompt template factories.
|
||||
/// </summary>
|
||||
public static async Task RunAsync()
|
||||
[RetryTheory(typeof(HttpOperationException))]
|
||||
[InlineData("semantic-kernel", "Hello AI, my name is {{$name}}. What is the origin of my name?")]
|
||||
[InlineData("handlebars", "Hello AI, my name is {{name}}. What is the origin of my name?")]
|
||||
public Task RunAsync(string templateFormat, string prompt)
|
||||
{
|
||||
Console.WriteLine("======== Example64_MultiplePromptTemplates ========");
|
||||
|
||||
string apiKey = TestConfiguration.AzureOpenAI.ApiKey;
|
||||
string chatDeploymentName = TestConfiguration.AzureOpenAI.ChatDeploymentName;
|
||||
string chatModelId = TestConfiguration.AzureOpenAI.ChatModelId;
|
||||
string endpoint = TestConfiguration.AzureOpenAI.Endpoint;
|
||||
|
||||
if (apiKey == null || chatDeploymentName == null || endpoint == null || chatModelId == null)
|
||||
{
|
||||
Console.WriteLine("Azure endpoint, apiKey, deploymentName or modelId not found. Skipping example.");
|
||||
return;
|
||||
}
|
||||
WriteLine("======== Example64_MultiplePromptTemplates ========");
|
||||
|
||||
Kernel kernel = Kernel.CreateBuilder()
|
||||
.AddAzureOpenAIChatCompletion(
|
||||
deploymentName: chatDeploymentName,
|
||||
endpoint: endpoint,
|
||||
deploymentName: TestConfiguration.AzureOpenAI.ChatDeploymentName,
|
||||
endpoint: TestConfiguration.AzureOpenAI.Endpoint,
|
||||
serviceId: "AzureOpenAIChat",
|
||||
apiKey: apiKey,
|
||||
modelId: chatModelId)
|
||||
apiKey: TestConfiguration.AzureOpenAI.ApiKey,
|
||||
modelId: TestConfiguration.AzureOpenAI.ChatModelId)
|
||||
.Build();
|
||||
|
||||
var promptTemplateFactory = new AggregatorPromptTemplateFactory(
|
||||
new KernelPromptTemplateFactory(),
|
||||
new HandlebarsPromptTemplateFactory());
|
||||
|
||||
var skPrompt = "Hello AI, my name is {{$name}}. What is the origin of my name?";
|
||||
var handlebarsPrompt = "Hello AI, my name is {{name}}. What is the origin of my name?";
|
||||
|
||||
await RunPromptAsync(kernel, skPrompt, "semantic-kernel", promptTemplateFactory);
|
||||
await RunPromptAsync(kernel, handlebarsPrompt, "handlebars", promptTemplateFactory);
|
||||
return RunPromptAsync(kernel, prompt, templateFormat, promptTemplateFactory);
|
||||
}
|
||||
|
||||
public static async Task RunPromptAsync(Kernel kernel, string prompt, string templateFormat, IPromptTemplateFactory promptTemplateFactory)
|
||||
private async Task RunPromptAsync(Kernel kernel, string prompt, string templateFormat, IPromptTemplateFactory promptTemplateFactory)
|
||||
{
|
||||
Console.WriteLine($"======== {templateFormat} : {prompt} ========");
|
||||
WriteLine($"======== {templateFormat} : {prompt} ========");
|
||||
|
||||
var function = kernel.CreateFunctionFromPrompt(
|
||||
promptConfig: new PromptTemplateConfig()
|
||||
@@ -66,6 +58,10 @@ public static class Example64_MultiplePromptTemplates
|
||||
};
|
||||
|
||||
var result = await kernel.InvokeAsync(function, arguments);
|
||||
Console.WriteLine(result.GetValue<string>());
|
||||
WriteLine(result.GetValue<string>());
|
||||
}
|
||||
|
||||
public Example64_MultiplePromptTemplates(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,40 +8,24 @@ using Microsoft.SemanticKernel.Planning.Handlebars;
|
||||
using Microsoft.SemanticKernel.Plugins.OpenApi;
|
||||
using Plugins.DictionaryPlugin;
|
||||
using RepoUtils;
|
||||
using xRetry;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
// This example shows how to use the Handlebars sequential planner.
|
||||
public static class Example65_HandlebarsPlanner
|
||||
public class Example65_HandlebarsPlanner : BaseTest
|
||||
{
|
||||
private static int s_sampleIndex;
|
||||
|
||||
private const string CourseraPluginName = "CourseraPlugin";
|
||||
|
||||
/// <summary>
|
||||
/// Show how to create a plan with Handlebars and execute it.
|
||||
/// </summary>
|
||||
public static async Task RunAsync()
|
||||
private void WriteSampleHeading(string name)
|
||||
{
|
||||
s_sampleIndex = 1;
|
||||
|
||||
// Plugin with primitive types as inputs and outputs
|
||||
await RunDictionaryWithBasicTypesSampleAsync();
|
||||
await RunPoetrySampleAsync();
|
||||
await RunBookSampleAsync();
|
||||
await PlanNotPossibleSampleAsync();
|
||||
|
||||
// Plugin with Complex Types as inputs and outputs
|
||||
await RunLocalDictionaryWithComplexTypesSampleAsync();
|
||||
|
||||
// OpenAPI plugin
|
||||
await RunCourseraSampleAsync(shouldPrintPrompt: true);
|
||||
WriteLine($"======== [Handlebars Planner] Sample {s_sampleIndex++} - Create and Execute Plan with: {name} ========");
|
||||
}
|
||||
|
||||
private static void WriteSampleHeadingToConsole(string name)
|
||||
{
|
||||
Console.WriteLine($"======== [Handlebars Planner] Sample {s_sampleIndex++} - Create and Execute Plan with: {name} ========");
|
||||
}
|
||||
|
||||
private static async Task RunSampleAsync(string goal, bool shouldPrintPrompt = false, params string[] pluginDirectoryNames)
|
||||
private async Task RunSampleAsync(string goal, bool shouldPrintPrompt = false, params string[] pluginDirectoryNames)
|
||||
{
|
||||
string apiKey = TestConfiguration.AzureOpenAI.ApiKey;
|
||||
string chatDeploymentName = TestConfiguration.AzureOpenAI.ChatDeploymentName;
|
||||
@@ -50,7 +34,7 @@ public static class Example65_HandlebarsPlanner
|
||||
|
||||
if (apiKey == null || chatDeploymentName == null || chatModelId == null || endpoint == null)
|
||||
{
|
||||
Console.WriteLine("Azure endpoint, apiKey, deploymentName, or modelId not found. Skipping example.");
|
||||
WriteLine("Azure endpoint, apiKey, deploymentName, or modelId not found. Skipping example.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -101,7 +85,7 @@ public static class Example65_HandlebarsPlanner
|
||||
AllowLoops = allowLoopsInPlan
|
||||
});
|
||||
|
||||
Console.WriteLine($"Goal: {goal}");
|
||||
WriteLine($"Goal: {goal}");
|
||||
|
||||
// Create the plan
|
||||
var plan = await planner.CreatePlanAsync(kernel, goal);
|
||||
@@ -109,19 +93,21 @@ public static class Example65_HandlebarsPlanner
|
||||
// Print the prompt template
|
||||
if (shouldPrintPrompt && plan.Prompt is not null)
|
||||
{
|
||||
Console.WriteLine($"\nPrompt template:\n{plan.Prompt}");
|
||||
WriteLine($"\nPrompt template:\n{plan.Prompt}");
|
||||
}
|
||||
|
||||
Console.WriteLine($"\nOriginal plan:\n{plan}");
|
||||
WriteLine($"\nOriginal plan:\n{plan}");
|
||||
|
||||
// Execute the plan
|
||||
var result = await plan.InvokeAsync(kernel);
|
||||
Console.WriteLine($"\nResult:\n{result}\n");
|
||||
WriteLine($"\nResult:\n{result}\n");
|
||||
}
|
||||
|
||||
private static async Task PlanNotPossibleSampleAsync(bool shouldPrintPrompt = false)
|
||||
[RetryTheory(typeof(HttpOperationException))]
|
||||
[InlineData(false)]
|
||||
public async Task PlanNotPossibleSampleAsync(bool shouldPrintPrompt = false)
|
||||
{
|
||||
WriteSampleHeadingToConsole("Plan Not Possible");
|
||||
WriteSampleHeading("Plan Not Possible");
|
||||
|
||||
try
|
||||
{
|
||||
@@ -142,20 +128,25 @@ public static class Example65_HandlebarsPlanner
|
||||
Therefore, I cannot create a Handlebars template to achieve the specified goal with the available helpers.
|
||||
Additional helpers may be required.
|
||||
*/
|
||||
Console.WriteLine($"\n{ex.Message}\n");
|
||||
WriteLine($"\n{ex.Message}\n");
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task RunCourseraSampleAsync(bool shouldPrintPrompt = false)
|
||||
[RetryTheory(typeof(HttpOperationException))]
|
||||
[InlineData(true)]
|
||||
|
||||
public Task RunCourseraSampleAsync(bool shouldPrintPrompt = false)
|
||||
{
|
||||
WriteSampleHeadingToConsole("Coursera OpenAPI Plugin");
|
||||
await RunSampleAsync("Show me courses about Artificial Intelligence.", shouldPrintPrompt, CourseraPluginName);
|
||||
this.WriteSampleHeading("Coursera OpenAPI Plugin");
|
||||
return RunSampleAsync("Show me courses about Artificial Intelligence.", shouldPrintPrompt, CourseraPluginName);
|
||||
}
|
||||
|
||||
private static async Task RunDictionaryWithBasicTypesSampleAsync(bool shouldPrintPrompt = false)
|
||||
[RetryTheory(typeof(HttpOperationException))]
|
||||
[InlineData(false)]
|
||||
public Task RunDictionaryWithBasicTypesSampleAsync(bool shouldPrintPrompt = false)
|
||||
{
|
||||
WriteSampleHeadingToConsole("Basic Types using Local Dictionary Plugin");
|
||||
await RunSampleAsync("Get a random word and its definition.", shouldPrintPrompt, StringParamsDictionaryPlugin.PluginName);
|
||||
this.WriteSampleHeading("Basic Types using Local Dictionary Plugin");
|
||||
return RunSampleAsync("Get a random word and its definition.", shouldPrintPrompt, StringParamsDictionaryPlugin.PluginName);
|
||||
/*
|
||||
Original plan:
|
||||
{{!-- Step 1: Get a random word --}}
|
||||
@@ -172,10 +163,12 @@ public static class Example65_HandlebarsPlanner
|
||||
*/
|
||||
}
|
||||
|
||||
private static async Task RunLocalDictionaryWithComplexTypesSampleAsync(bool shouldPrintPrompt = false)
|
||||
[RetryTheory(typeof(HttpOperationException))]
|
||||
[InlineData(true)]
|
||||
public Task RunLocalDictionaryWithComplexTypesSampleAsync(bool shouldPrintPrompt = false)
|
||||
{
|
||||
WriteSampleHeadingToConsole("Complex Types using Local Dictionary Plugin");
|
||||
await RunSampleAsync("Teach me two random words and their definition.", shouldPrintPrompt, ComplexParamsDictionaryPlugin.PluginName);
|
||||
this.WriteSampleHeading("Complex Types using Local Dictionary Plugin");
|
||||
return RunSampleAsync("Teach me two random words and their definition.", shouldPrintPrompt, ComplexParamsDictionaryPlugin.PluginName);
|
||||
/*
|
||||
Original Plan:
|
||||
{{!-- Step 1: Get two random dictionary entries --}}
|
||||
@@ -206,10 +199,12 @@ public static class Example65_HandlebarsPlanner
|
||||
*/
|
||||
}
|
||||
|
||||
private static async Task RunPoetrySampleAsync(bool shouldPrintPrompt = false)
|
||||
[RetryTheory(typeof(HttpOperationException))]
|
||||
[InlineData(false)]
|
||||
public Task RunPoetrySampleAsync(bool shouldPrintPrompt = false)
|
||||
{
|
||||
WriteSampleHeadingToConsole("Multiple Plugins");
|
||||
await RunSampleAsync("Write a poem about John Doe, then translate it into Italian.", shouldPrintPrompt, "SummarizePlugin", "WriterPlugin");
|
||||
this.WriteSampleHeading("Multiple Plugins");
|
||||
return RunSampleAsync("Write a poem about John Doe, then translate it into Italian.", shouldPrintPrompt, "SummarizePlugin", "WriterPlugin");
|
||||
/*
|
||||
Original plan:
|
||||
{{!-- Step 1: Initialize the scenario for the poem --}}
|
||||
@@ -233,10 +228,12 @@ public static class Example65_HandlebarsPlanner
|
||||
*/
|
||||
}
|
||||
|
||||
private static async Task RunBookSampleAsync(bool shouldPrintPrompt = false)
|
||||
[RetryTheory(typeof(HttpOperationException))]
|
||||
[InlineData(false)]
|
||||
public Task RunBookSampleAsync(bool shouldPrintPrompt = false)
|
||||
{
|
||||
WriteSampleHeadingToConsole("Loops and Conditionals");
|
||||
await RunSampleAsync("Create a book with 3 chapters about a group of kids in a club called 'The Thinking Caps.'", shouldPrintPrompt, "WriterPlugin", "MiscPlugin");
|
||||
this.WriteSampleHeading("Loops and Conditionals");
|
||||
return RunSampleAsync("Create a book with 3 chapters about a group of kids in a club called 'The Thinking Caps.'", shouldPrintPrompt, "WriterPlugin", "MiscPlugin");
|
||||
/*
|
||||
Original plan:
|
||||
{{!-- Step 1: Initialize the book title and chapter count --}}
|
||||
@@ -260,4 +257,8 @@ public static class Example65_HandlebarsPlanner
|
||||
{{/each}}
|
||||
*/
|
||||
}
|
||||
|
||||
public Example65_HandlebarsPlanner(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Planning;
|
||||
using Microsoft.SemanticKernel.Plugins.Core;
|
||||
using Plugins;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
public static class Example66_FunctionCallingStepwisePlanner
|
||||
namespace Examples;
|
||||
|
||||
public class Example66_FunctionCallingStepwisePlanner : BaseTest
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
string[] questions = new string[]
|
||||
{
|
||||
string[] questions = {
|
||||
"What is the current hour number, plus 5?",
|
||||
"What is 387 minus 22? Email the solution to John and Mary.",
|
||||
"Write a limerick, translate it to Spanish, and send it to Jane",
|
||||
@@ -30,7 +33,7 @@ public static class Example66_FunctionCallingStepwisePlanner
|
||||
foreach (var question in questions)
|
||||
{
|
||||
FunctionCallingStepwisePlannerResult result = await planner.ExecuteAsync(kernel, question);
|
||||
Console.WriteLine($"Q: {question}\nA: {result.FinalAnswer}");
|
||||
WriteLine($"Q: {question}\nA: {result.FinalAnswer}");
|
||||
|
||||
// You can uncomment the line below to see the planner's process for completing the request.
|
||||
// Console.WriteLine($"Chat history:\n{System.Text.Json.JsonSerializer.Serialize(result.ChatHistory)}");
|
||||
@@ -44,11 +47,9 @@ public static class Example66_FunctionCallingStepwisePlanner
|
||||
private static Kernel InitializeKernel()
|
||||
{
|
||||
Kernel kernel = Kernel.CreateBuilder()
|
||||
.AddAzureOpenAIChatCompletion(
|
||||
deploymentName: TestConfiguration.AzureOpenAI.ChatDeploymentName,
|
||||
endpoint: TestConfiguration.AzureOpenAI.Endpoint,
|
||||
apiKey: TestConfiguration.AzureOpenAI.ApiKey,
|
||||
modelId: TestConfiguration.AzureOpenAI.ChatModelId)
|
||||
.AddOpenAIChatCompletion(
|
||||
apiKey: TestConfiguration.OpenAI.ApiKey,
|
||||
modelId: "gpt-3.5-turbo-1106")
|
||||
.Build();
|
||||
|
||||
kernel.ImportPluginFromType<EmailPlugin>();
|
||||
@@ -57,4 +58,8 @@ public static class Example66_FunctionCallingStepwisePlanner
|
||||
|
||||
return kernel;
|
||||
}
|
||||
|
||||
public Example66_FunctionCallingStepwisePlanner(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
// This example shows how to use multiple prompt template formats.
|
||||
public static class Example67_KernelStreaming
|
||||
public class Example67_KernelStreaming : BaseTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Show how to combine multiple prompt template factories.
|
||||
/// </summary>
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
string apiKey = TestConfiguration.AzureOpenAI.ApiKey;
|
||||
string chatDeploymentName = TestConfiguration.AzureOpenAI.ChatDeploymentName;
|
||||
@@ -20,7 +24,7 @@ public static class Example67_KernelStreaming
|
||||
|
||||
if (apiKey == null || chatDeploymentName == null || chatModelId == null || endpoint == null)
|
||||
{
|
||||
Console.WriteLine("Azure endpoint, apiKey, deploymentName or modelId not found. Skipping example.");
|
||||
WriteLine("Azure endpoint, apiKey, deploymentName or modelId not found. Skipping example.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -37,22 +41,32 @@ public static class Example67_KernelStreaming
|
||||
|
||||
var roleDisplayed = false;
|
||||
|
||||
Console.WriteLine("\n=== Prompt Function - Streaming ===\n");
|
||||
WriteLine("\n=== Prompt Function - Streaming ===\n");
|
||||
|
||||
string fullContent = string.Empty;
|
||||
// Streaming can be of any type depending on the underlying service the function is using.
|
||||
await foreach (var update in kernel.InvokeStreamingAsync<OpenAIStreamingChatMessageContent>(funnyParagraphFunction))
|
||||
{
|
||||
// You will be always able to know the type of the update by checking the Type property.
|
||||
if (!roleDisplayed && update.Role.HasValue)
|
||||
{
|
||||
Console.WriteLine($"Role: {update.Role}");
|
||||
WriteLine($"Role: {update.Role}");
|
||||
fullContent += $"Role: {update.Role}\n";
|
||||
roleDisplayed = true;
|
||||
}
|
||||
|
||||
if (update.Content is { Length: > 0 })
|
||||
{
|
||||
Console.Write(update.Content);
|
||||
fullContent += update.Content;
|
||||
Write(update.Content);
|
||||
}
|
||||
}
|
||||
|
||||
WriteLine("\n------ Streamed Content ------\n");
|
||||
WriteLine(fullContent);
|
||||
}
|
||||
|
||||
public Example67_KernelStreaming(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,16 @@ using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
// This example shows how to use GPT Vision model with different content types (text and image).
|
||||
public static class Example68_GPTVision
|
||||
public class Example68_GPTVision : BaseTest
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
const string ImageUri = "https://upload.wikimedia.org/wikipedia/commons/d/d5/Half-timbered_mansion%2C_Zirkel%2C_East_view.jpg";
|
||||
|
||||
@@ -28,8 +33,10 @@ public static class Example68_GPTVision
|
||||
|
||||
var reply = await chatCompletionService.GetChatMessageContentAsync(chatHistory);
|
||||
|
||||
Console.WriteLine(reply.Content);
|
||||
WriteLine(reply.Content);
|
||||
}
|
||||
|
||||
Console.ReadKey();
|
||||
public Example68_GPTVision(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,14 +5,19 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
// This example shows how to create a mutable <see cref="KernelPlugin"/>.
|
||||
public static class Example69_MutableKernelPlugin
|
||||
public class Example69_MutableKernelPlugin : BaseTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Show how to create a mutable <see cref="KernelPlugin"/>.
|
||||
/// </summary>
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
var plugin = new MutableKernelPlugin("Plugin");
|
||||
plugin.AddFunction(KernelFunctionFactory.CreateFromMethod(() => "Plugin.Function", "Function"));
|
||||
@@ -22,7 +27,7 @@ public static class Example69_MutableKernelPlugin
|
||||
|
||||
var result = await kernel.InvokeAsync(kernel.Plugins["Plugin"]["Function"]);
|
||||
|
||||
Console.WriteLine($"Result: {result}");
|
||||
WriteLine($"Result: {result}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -73,4 +78,8 @@ public static class Example69_MutableKernelPlugin
|
||||
/// <inheritdoc/>
|
||||
public override IEnumerator<KernelFunction> GetEnumerator() => this._functions.Values.GetEnumerator();
|
||||
}
|
||||
|
||||
public Example69_MutableKernelPlugin(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,12 +7,16 @@ using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Experimental.Agents;
|
||||
using Plugins;
|
||||
using Resources;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
/// <summary>
|
||||
/// Showcase Open AI Agent integration with semantic kernel:
|
||||
/// https://platform.openai.com/docs/api-reference/agents
|
||||
/// </summary>
|
||||
public static class Example70_Agent
|
||||
public class Example70_Agent : BaseTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Specific model is required that supports agents and function calling.
|
||||
@@ -20,42 +24,17 @@ public static class Example70_Agent
|
||||
/// </summary>
|
||||
private const string OpenAIFunctionEnabledModel = "gpt-3.5-turbo-1106";
|
||||
|
||||
/// <summary>
|
||||
/// Show how to define an use a single agent using multiple patterns.
|
||||
/// </summary>
|
||||
public static async Task RunAsync()
|
||||
{
|
||||
Console.WriteLine("======== Example70_Agent ========");
|
||||
|
||||
if (TestConfiguration.OpenAI.ApiKey == null)
|
||||
{
|
||||
Console.WriteLine("OpenAI apiKey not found. Skipping example.");
|
||||
return;
|
||||
}
|
||||
|
||||
// "Hello agent"
|
||||
await RunSimpleChatAsync();
|
||||
|
||||
// Run agent with "method" tool/function
|
||||
await RunWithMethodFunctionsAsync();
|
||||
|
||||
// Run agent with "prompt" tool/function
|
||||
await RunWithPromptFunctionsAsync();
|
||||
|
||||
// Run agent as function
|
||||
await RunAsFunctionAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Chat using the "Parrot" agent.
|
||||
/// Tools/functions: None
|
||||
/// </summary>
|
||||
private static async Task RunSimpleChatAsync()
|
||||
[Fact]
|
||||
public Task RunSimpleChatAsync()
|
||||
{
|
||||
Console.WriteLine("======== Run:SimpleChat ========");
|
||||
WriteLine("======== Run:SimpleChat ========");
|
||||
|
||||
// Call the common chat-loop
|
||||
await ChatAsync(
|
||||
return ChatAsync(
|
||||
"Agents.ParrotAgent.yaml", // Defined under ./Resources/Agents
|
||||
plugin: null, // No plugin
|
||||
arguments: new KernelArguments { { "count", 3 } },
|
||||
@@ -68,14 +47,15 @@ public static class Example70_Agent
|
||||
/// Chat using the "Tool" agent and a method function.
|
||||
/// Tools/functions: MenuPlugin
|
||||
/// </summary>
|
||||
private static async Task RunWithMethodFunctionsAsync()
|
||||
[Fact]
|
||||
public Task RunWithMethodFunctionsAsync()
|
||||
{
|
||||
Console.WriteLine("======== Run:WithMethodFunctions ========");
|
||||
WriteLine("======== Run:WithMethodFunctions ========");
|
||||
|
||||
KernelPlugin plugin = KernelPluginFactory.CreateFromType<MenuPlugin>();
|
||||
|
||||
// Call the common chat-loop
|
||||
await ChatAsync(
|
||||
return ChatAsync(
|
||||
"Agents.ToolAgent.yaml", // Defined under ./Resources/Agents
|
||||
plugin,
|
||||
arguments: null,
|
||||
@@ -89,9 +69,10 @@ public static class Example70_Agent
|
||||
/// Chat using the "Tool" agent and a prompt function.
|
||||
/// Tools/functions: spellChecker prompt function
|
||||
/// </summary>
|
||||
private static async Task RunWithPromptFunctionsAsync()
|
||||
[Fact]
|
||||
public Task RunWithPromptFunctionsAsync()
|
||||
{
|
||||
Console.WriteLine("======== WithPromptFunctions ========");
|
||||
WriteLine("======== WithPromptFunctions ========");
|
||||
|
||||
// Create a prompt function.
|
||||
var function = KernelFunctionFactory.CreateFromPrompt(
|
||||
@@ -102,7 +83,7 @@ public static class Example70_Agent
|
||||
var plugin = KernelPluginFactory.CreateFromFunctions("spelling", "Spelling functions", new[] { function });
|
||||
|
||||
// Call the common chat-loop
|
||||
await ChatAsync(
|
||||
return ChatAsync(
|
||||
"Agents.ToolAgent.yaml", // Defined under ./Resources/Agents
|
||||
plugin,
|
||||
arguments: null,
|
||||
@@ -115,9 +96,10 @@ public static class Example70_Agent
|
||||
/// <summary>
|
||||
/// Invoke agent just like any other <see cref="KernelFunction"/>.
|
||||
/// </summary>
|
||||
private static async Task RunAsFunctionAsync()
|
||||
[Fact]
|
||||
public async Task RunAsFunctionAsync()
|
||||
{
|
||||
Console.WriteLine("======== Run:AsFunction ========");
|
||||
WriteLine("======== Run:AsFunction ========");
|
||||
|
||||
// Create parrot agent, same as the other cases.
|
||||
var agent =
|
||||
@@ -132,7 +114,7 @@ public static class Example70_Agent
|
||||
var response = await agent.AsPlugin().InvokeAsync("Practice makes perfect.", new KernelArguments { { "count", 2 } });
|
||||
|
||||
// Display result.
|
||||
Console.WriteLine(response ?? $"No response from agent: {agent.Id}");
|
||||
WriteLine(response ?? $"No response from agent: {agent.Id}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -149,7 +131,7 @@ public static class Example70_Agent
|
||||
/// 4. Create a chat-thread
|
||||
/// 5. Process the provided "messages" on the chat-thread
|
||||
/// </summary>
|
||||
private static async Task ChatAsync(
|
||||
private async Task ChatAsync(
|
||||
string resourcePath,
|
||||
KernelPlugin? plugin = null,
|
||||
KernelArguments? arguments = null,
|
||||
@@ -191,4 +173,8 @@ public static class Example70_Agent
|
||||
agent.DeleteAsync());
|
||||
}
|
||||
}
|
||||
|
||||
public Example70_Agent(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
@@ -8,11 +7,15 @@ using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Experimental.Agents;
|
||||
using Plugins;
|
||||
using Resources;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
/// <summary>
|
||||
/// Showcase complex Open AI Agent interactions using semantic kernel.
|
||||
/// </summary>
|
||||
public static class Example71_AgentDelegation
|
||||
public class Example71_AgentDelegation : BaseTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Specific model is required that supports agents and function calling.
|
||||
@@ -26,13 +29,14 @@ public static class Example71_AgentDelegation
|
||||
/// <summary>
|
||||
/// Show how to combine coordinate multiple agents.
|
||||
/// </summary>
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
Console.WriteLine("======== Example71_AgentDelegation ========");
|
||||
WriteLine("======== Example71_AgentDelegation ========");
|
||||
|
||||
if (TestConfiguration.OpenAI.ApiKey == null)
|
||||
{
|
||||
Console.WriteLine("OpenAI apiKey not found. Skipping example.");
|
||||
WriteLine("OpenAI apiKey not found. Skipping example.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -78,8 +82,8 @@ public static class Example71_AgentDelegation
|
||||
{
|
||||
await foreach (var message in response)
|
||||
{
|
||||
Console.WriteLine($"[{message.Id}]");
|
||||
Console.WriteLine($"# {message.Role}: {message.Content}");
|
||||
WriteLine($"[{message.Id}]");
|
||||
WriteLine($"# {message.Role}: {message.Content}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -98,4 +102,8 @@ public static class Example71_AgentDelegation
|
||||
|
||||
return agent;
|
||||
}
|
||||
|
||||
public Example71_AgentDelegation(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,15 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel.Experimental.Agents;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
/// <summary>
|
||||
/// Showcase complex Open AI Agent collaboration using semantic kernel.
|
||||
/// </summary>
|
||||
public static class Example72_AgentCollaboration
|
||||
public class Example72_AgentCollaboration : BaseTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Specific model is required that supports agents and function calling.
|
||||
@@ -21,36 +24,14 @@ public static class Example72_AgentCollaboration
|
||||
// Track agents for clean-up
|
||||
private static readonly List<IAgent> s_agents = new();
|
||||
|
||||
/// <summary>
|
||||
/// Show how to combine and coordinate multiple agents.
|
||||
/// </summary>
|
||||
public static async Task RunAsync()
|
||||
{
|
||||
Console.WriteLine("======== Example72_AgentCollaboration ========");
|
||||
|
||||
if (TestConfiguration.OpenAI.ApiKey == null)
|
||||
{
|
||||
Console.WriteLine("OpenAI apiKey not found. Skipping example.");
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: Either of these examples produce a conversation
|
||||
// whose duration may vary depending on the collaboration dynamics.
|
||||
// It is sometimes possible that agreement is never achieved.
|
||||
|
||||
// Explicit collaboration
|
||||
await RunCollaborationAsync();
|
||||
|
||||
// Coordinate collaboration as plugin agents (equivalent to previous case - shared thread)
|
||||
await RunAsPluginsAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show how two agents are able to collaborate as agents on a single thread.
|
||||
/// </summary>
|
||||
private static async Task RunCollaborationAsync()
|
||||
[Fact(Skip = "This test take more than 5 minutes to execute")]
|
||||
public async Task RunCollaborationAsync()
|
||||
{
|
||||
Console.WriteLine("======== Run:Collaboration ========");
|
||||
WriteLine("======== Example72_AgentCollaboration ========");
|
||||
WriteLine("======== Run:Collaboration ========");
|
||||
IAgentThread? thread = null;
|
||||
try
|
||||
{
|
||||
@@ -99,9 +80,11 @@ public static class Example72_AgentCollaboration
|
||||
/// While this may achieve an equivalent result to <see cref="RunCollaborationAsync"/>,
|
||||
/// it is not using shared thread state for agent interaction.
|
||||
/// </remarks>
|
||||
private static async Task RunAsPluginsAsync()
|
||||
[Fact(Skip = "This test take more than 2 minutes to execute")]
|
||||
public async Task RunAsPluginsAsync()
|
||||
{
|
||||
Console.WriteLine("======== Run:AsPlugins ========");
|
||||
WriteLine("======== Example72_AgentCollaboration ========");
|
||||
WriteLine("======== Run:AsPlugins ========");
|
||||
try
|
||||
{
|
||||
// Create copy-writer agent to generate ideas
|
||||
@@ -123,7 +106,7 @@ public static class Example72_AgentCollaboration
|
||||
var response = await coordinator.AsPlugin().InvokeAsync("concept: maps made out of egg cartons.");
|
||||
|
||||
// Display final result
|
||||
Console.WriteLine(response);
|
||||
WriteLine(response);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -132,7 +115,7 @@ public static class Example72_AgentCollaboration
|
||||
}
|
||||
}
|
||||
|
||||
private async static Task<IAgent> CreateCopyWriterAsync(IAgent? agent = null)
|
||||
private static async Task<IAgent> CreateCopyWriterAsync(IAgent? agent = null)
|
||||
{
|
||||
return
|
||||
Track(
|
||||
@@ -157,7 +140,7 @@ public static class Example72_AgentCollaboration
|
||||
.BuildAsync());
|
||||
}
|
||||
|
||||
private static void DisplayMessages(IEnumerable<IChatMessage> messages, IAgent? agent = null)
|
||||
private void DisplayMessages(IEnumerable<IChatMessage> messages, IAgent? agent = null)
|
||||
{
|
||||
foreach (var message in messages)
|
||||
{
|
||||
@@ -165,16 +148,16 @@ public static class Example72_AgentCollaboration
|
||||
}
|
||||
}
|
||||
|
||||
private static void DisplayMessage(IChatMessage message, IAgent? agent = null)
|
||||
private void DisplayMessage(IChatMessage message, IAgent? agent = null)
|
||||
{
|
||||
Console.WriteLine($"[{message.Id}]");
|
||||
WriteLine($"[{message.Id}]");
|
||||
if (agent != null)
|
||||
{
|
||||
Console.WriteLine($"# {message.Role}: ({agent.Name}) {message.Content}");
|
||||
WriteLine($"# {message.Role}: ({agent.Name}) {message.Content}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"# {message.Role}: {message.Content}");
|
||||
WriteLine($"# {message.Role}: {message.Content}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,4 +167,8 @@ public static class Example72_AgentCollaboration
|
||||
|
||||
return agent;
|
||||
}
|
||||
|
||||
public Example72_AgentCollaboration(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel.Experimental.Agents;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
/// <summary>
|
||||
/// Showcase hiearchical Open AI Agent interactions using semantic kernel.
|
||||
/// </summary>
|
||||
public static class Example73_AgentAuthoring
|
||||
public class Example73_AgentAuthoring : BaseTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Specific model is required that supports agents and parallel function calling.
|
||||
@@ -21,28 +23,10 @@ public static class Example73_AgentAuthoring
|
||||
// Track agents for clean-up
|
||||
private static readonly List<IAgent> s_agents = new();
|
||||
|
||||
/// <summary>
|
||||
/// Show how to combine coordinate multiple agents.
|
||||
/// </summary>
|
||||
public static async Task RunAsync()
|
||||
{
|
||||
Console.WriteLine("======== Example73_AgentAuthoring ========");
|
||||
|
||||
if (TestConfiguration.OpenAI.ApiKey == null)
|
||||
{
|
||||
Console.WriteLine("OpenAI apiKey not found. Skipping example.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Run demo by invoking agent directly
|
||||
await RunAgentAsync();
|
||||
|
||||
// Run demo by invoking agent as a plugin
|
||||
await RunAsPluginAsync();
|
||||
}
|
||||
|
||||
private static async Task RunAgentAsync()
|
||||
[Fact(Skip = "This test take more than 2 minutes to execute")]
|
||||
public async Task RunAgentAsync()
|
||||
{
|
||||
WriteLine("======== Example73_AgentAuthoring ========");
|
||||
try
|
||||
{
|
||||
// Initialize the agent with tools
|
||||
@@ -51,8 +35,8 @@ public static class Example73_AgentAuthoring
|
||||
// "Stream" messages as they become available
|
||||
await foreach (IChatMessage message in articleGenerator.InvokeAsync("Thai food is the best in the world"))
|
||||
{
|
||||
Console.WriteLine($"[{message.Id}]");
|
||||
Console.WriteLine($"# {message.Role}: {message.Content}");
|
||||
WriteLine($"[{message.Id}]");
|
||||
WriteLine($"# {message.Role}: {message.Content}");
|
||||
}
|
||||
}
|
||||
finally
|
||||
@@ -61,8 +45,10 @@ public static class Example73_AgentAuthoring
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task RunAsPluginAsync()
|
||||
[Fact(Skip = "This test take more than 2 minutes to execute")]
|
||||
public async Task RunAsPluginAsync()
|
||||
{
|
||||
WriteLine("======== Example73_AgentAuthoring ========");
|
||||
try
|
||||
{
|
||||
// Initialize the agent with tools
|
||||
@@ -72,7 +58,7 @@ public static class Example73_AgentAuthoring
|
||||
string response = await articleGenerator.AsPlugin().InvokeAsync("Thai food is the best in the world");
|
||||
|
||||
// Display final result
|
||||
Console.WriteLine(response);
|
||||
WriteLine(response);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -113,7 +99,7 @@ public static class Example73_AgentAuthoring
|
||||
.BuildAsync());
|
||||
}
|
||||
|
||||
private async static Task<IAgent> CreateResearchGeneratorAsync()
|
||||
private static async Task<IAgent> CreateResearchGeneratorAsync()
|
||||
{
|
||||
// Initialize agent so that it may be automatically deleted.
|
||||
return
|
||||
@@ -132,4 +118,8 @@ public static class Example73_AgentAuthoring
|
||||
|
||||
return agent;
|
||||
}
|
||||
|
||||
public Example73_AgentAuthoring(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,13 +17,13 @@ using Microsoft.SemanticKernel.Memory;
|
||||
using Microsoft.SemanticKernel.Plugins.Core;
|
||||
using Microsoft.SemanticKernel.Plugins.Web;
|
||||
using Microsoft.SemanticKernel.Plugins.Web.Bing;
|
||||
using NCalcPlugins;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
/**
|
||||
* This example shows how to use FlowOrchestrator to execute a given flow with interaction with client.
|
||||
*/
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public static class Example74_FlowOrchestrator
|
||||
namespace Examples;
|
||||
|
||||
// This example shows how to use FlowOrchestrator to execute a given flow with interaction with client.
|
||||
public class Example74_FlowOrchestrator : BaseTest
|
||||
{
|
||||
private static readonly Flow s_flow = FlowSerializer.DeserializeFromYaml(@"
|
||||
name: FlowOrchestrator_Example_Flow
|
||||
@@ -56,11 +56,9 @@ provides:
|
||||
- email
|
||||
");
|
||||
|
||||
public static Task RunAsync()
|
||||
[Fact(Skip = "Can take more than 1 minute")]
|
||||
public Task RunAsync()
|
||||
{
|
||||
// Load assemblies for external plugins
|
||||
Console.WriteLine("Loading {0}", typeof(SimpleCalculatorPlugin).AssemblyQualifiedName);
|
||||
|
||||
return RunExampleAsync();
|
||||
//return RunInteractiveAsync();
|
||||
}
|
||||
@@ -331,6 +329,10 @@ Do not expose the regex in your response.
|
||||
public string? Content { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
public Example74_FlowOrchestrator(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************************************
|
||||
|
||||
@@ -1,17 +1,22 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Examples;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace GettingStarted;
|
||||
|
||||
// This example shows how to create and use a <see cref="Kernel"/>.
|
||||
public static class Step1_Create_Kernel
|
||||
public class Step1_Create_Kernel : BaseTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Show how to create a <see cref="Kernel"/> and use it to execute prompts.
|
||||
/// </summary>
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
// Create a kernel with OpenAI chat completion
|
||||
Kernel kernel = Kernel.CreateBuilder()
|
||||
@@ -21,23 +26,30 @@ public static class Step1_Create_Kernel
|
||||
.Build();
|
||||
|
||||
// Example 1. Invoke the kernel with a prompt and display the result
|
||||
Console.WriteLine(await kernel.InvokePromptAsync("What color is the sky?"));
|
||||
Console.WriteLine();
|
||||
WriteLine(await kernel.InvokePromptAsync("What color is the sky?"));
|
||||
WriteLine();
|
||||
|
||||
// Example 2. Invoke the kernel with a templated prompt and display the result
|
||||
KernelArguments arguments = new() { { "topic", "sea" } };
|
||||
Console.WriteLine(await kernel.InvokePromptAsync("What color is the {{$topic}}?", arguments));
|
||||
Console.WriteLine();
|
||||
WriteLine(await kernel.InvokePromptAsync("What color is the {{$topic}}?", arguments));
|
||||
WriteLine();
|
||||
|
||||
// Example 3. Invoke the kernel with a templated prompt and stream the results to the display
|
||||
|
||||
await foreach (var update in kernel.InvokePromptStreamingAsync("What color is the {{$topic}}? Provide a detailed explanation.", arguments))
|
||||
{
|
||||
Console.Write(update);
|
||||
Write(update);
|
||||
// Console.Write(update);
|
||||
}
|
||||
Console.WriteLine();
|
||||
|
||||
WriteLine(string.Empty);
|
||||
|
||||
// Example 4. Invoke the kernel with a templated prompt and execution settings
|
||||
arguments = new(new OpenAIPromptExecutionSettings { MaxTokens = 500, Temperature = 0.5 }) { { "topic", "dogs" } };
|
||||
Console.WriteLine(await kernel.InvokePromptAsync("Tell me a story about {{$topic}}", arguments));
|
||||
WriteLine(await kernel.InvokePromptAsync("Tell me a story about {{$topic}}", arguments));
|
||||
}
|
||||
|
||||
public Step1_Create_Kernel(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,16 +3,22 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
using Examples;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace GettingStarted;
|
||||
|
||||
// This example shows how to load a <see cref="KernelPlugin"/> instances.
|
||||
public static class Step2_Add_Plugins
|
||||
public class Step2_Add_Plugins : BaseTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Shows different ways to load a <see cref="KernelPlugin"/> instances.
|
||||
/// </summary>
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
// Create a kernel with OpenAI chat completion
|
||||
IKernelBuilder kernelBuilder = Kernel.CreateBuilder();
|
||||
@@ -23,14 +29,14 @@ public static class Step2_Add_Plugins
|
||||
Kernel kernel = kernelBuilder.Build();
|
||||
|
||||
// Example 1. Invoke the kernel with a prompt that asks the AI for inromation it cannot provide and may hallucinate
|
||||
Console.WriteLine(await kernel.InvokePromptAsync("How many days until Christmas?"));
|
||||
WriteLine(await kernel.InvokePromptAsync("How many days until Christmas?"));
|
||||
|
||||
// Example 2. Invoke the kernel with a templated prompt that invokes a plugin and display the result
|
||||
Console.WriteLine(await kernel.InvokePromptAsync("The current time is {{TimeInformation.GetCurrentUtcTime}}. How many days until Christmas?"));
|
||||
WriteLine(await kernel.InvokePromptAsync("The current time is {{TimeInformation.GetCurrentUtcTime}}. How many days until Christmas?"));
|
||||
|
||||
// Example 3. Invoke the kernel with a prompt and allow the AI to automatically invoke functions
|
||||
OpenAIPromptExecutionSettings settings = new() { ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions };
|
||||
Console.WriteLine(await kernel.InvokePromptAsync("How many days until Christmas? Explain your thinking.", new(settings)));
|
||||
WriteLine(await kernel.InvokePromptAsync("How many days until Christmas? Explain your thinking.", new(settings)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -42,4 +48,8 @@ public static class Step2_Add_Plugins
|
||||
[Description("Retrieves the current time in UTC.")]
|
||||
public string GetCurrentUtcTime() => DateTime.UtcNow.ToString("R");
|
||||
}
|
||||
|
||||
public Step2_Add_Plugins(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Examples;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.PromptTemplates.Handlebars;
|
||||
using Resources;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace GettingStarted;
|
||||
|
||||
// This example shows how to create a prompt <see cref="KernelFunction"/> from a YAML resource.
|
||||
public static class Step3_Yaml_Prompt
|
||||
public class Step3_Yaml_Prompt : BaseTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Show how to create a prompt <see cref="KernelFunction"/> from a YAML resource.
|
||||
/// </summary>
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
// Create a kernel with OpenAI chat completion
|
||||
Kernel kernel = Kernel.CreateBuilder()
|
||||
@@ -26,7 +31,7 @@ public static class Step3_Yaml_Prompt
|
||||
var function = kernel.CreateFunctionFromPromptYaml(generateStoryYaml);
|
||||
|
||||
// Invoke the prompt function and display the result
|
||||
Console.WriteLine(await kernel.InvokeAsync(function, arguments: new()
|
||||
WriteLine(await kernel.InvokeAsync(function, arguments: new()
|
||||
{
|
||||
{ "topic", "Dog" },
|
||||
{ "length", "3" },
|
||||
@@ -37,10 +42,14 @@ public static class Step3_Yaml_Prompt
|
||||
function = kernel.CreateFunctionFromPromptYaml(generateStoryHandlebarsYaml, new HandlebarsPromptTemplateFactory());
|
||||
|
||||
// Invoke the prompt function and display the result
|
||||
Console.WriteLine(await kernel.InvokeAsync(function, arguments: new()
|
||||
WriteLine(await kernel.InvokeAsync(function, arguments: new()
|
||||
{
|
||||
{ "topic", "Cat" },
|
||||
{ "length", "3" },
|
||||
}));
|
||||
}
|
||||
|
||||
public Step3_Yaml_Prompt(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,18 +3,24 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
using Examples;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.SemanticKernel;
|
||||
using RepoUtils;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace GettingStarted;
|
||||
|
||||
// This example shows how to using Dependency Injection with the Semantic Kernel
|
||||
public static class Step4_Dependency_Injection
|
||||
public class Step4_Dependency_Injection : BaseTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Show how to create a <see cref="Kernel"/> that participates in Dependency Injection.
|
||||
/// </summary>
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
// If an application follows DI guidelines, the following line is unnecessary because DI will inject an instance of the KernelClient class to a class that references it.
|
||||
// DI container guidelines - https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection-guidelines#recommendations
|
||||
@@ -25,7 +31,7 @@ public static class Step4_Dependency_Injection
|
||||
KernelArguments arguments = new() { { "topic", "earth when viewed from space" } };
|
||||
await foreach (var update in kernel.InvokePromptStreamingAsync("What color is the {{$topic}}? Provide a detailed explanation.", arguments))
|
||||
{
|
||||
Console.Write(update);
|
||||
Write(update);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +41,7 @@ public static class Step4_Dependency_Injection
|
||||
private static ServiceProvider BuildServiceProvider()
|
||||
{
|
||||
var collection = new ServiceCollection();
|
||||
collection.AddSingleton<ILoggerFactory>(ConsoleLogger.LoggerFactory);
|
||||
collection.AddSingleton(ConsoleLogger.LoggerFactory);
|
||||
|
||||
var kernelBuilder = collection.AddKernel();
|
||||
kernelBuilder.Services.AddOpenAITextGeneration(TestConfiguration.OpenAI.ModelId, TestConfiguration.OpenAI.ApiKey);
|
||||
@@ -65,4 +71,8 @@ public static class Step4_Dependency_Injection
|
||||
return utcNow;
|
||||
}
|
||||
}
|
||||
|
||||
public Step4_Dependency_Injection(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Examples;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
public static class Step5_Chat_Prompt
|
||||
namespace GettingStarted;
|
||||
|
||||
public class Step5_Chat_Prompt : BaseTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Show how to construct a chat prompt and invoke it.
|
||||
/// </summary>
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
// Create a kernel with OpenAI chat completion
|
||||
Kernel kernel = Kernel.CreateBuilder()
|
||||
@@ -23,6 +28,11 @@ public static class Step5_Chat_Prompt
|
||||
<message role=""user"">What is Seattle?</message>
|
||||
<message role=""system"">Respond with JSON.</message>
|
||||
";
|
||||
Console.WriteLine(await kernel.InvokePromptAsync(chatPrompt));
|
||||
|
||||
WriteLine(await kernel.InvokePromptAsync(chatPrompt));
|
||||
}
|
||||
|
||||
public Step5_Chat_Prompt(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Examples;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace GettingStarted;
|
||||
|
||||
// This example shows how to use rendering event hooks to ensure that prompts are rendered in a responsible manner.
|
||||
public static class Step6_Responsible_AI
|
||||
public class Step6_Responsible_AI : BaseTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Show how to use rendering event hooks to ensure that prompts are rendered in a responsible manner.
|
||||
/// </summary>
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
// Create a kernel with OpenAI chat completion
|
||||
Kernel kernel = Kernel.CreateBuilder()
|
||||
@@ -33,7 +38,7 @@ public static class Step6_Responsible_AI
|
||||
{
|
||||
e.RenderedPrompt += " NO SEXISM, RACISM OR OTHER BIAS/BIGOTRY";
|
||||
|
||||
Console.WriteLine(e.RenderedPrompt);
|
||||
WriteLine(e.RenderedPrompt);
|
||||
}
|
||||
|
||||
// Add the handlers to the kernel
|
||||
@@ -41,6 +46,10 @@ public static class Step6_Responsible_AI
|
||||
kernel.PromptRendered += MyRenderedHandler;
|
||||
|
||||
KernelArguments arguments = new() { { "card_number", "4444 3333 2222 1111" } };
|
||||
Console.WriteLine(await kernel.InvokePromptAsync("Tell me some useful information about this credit card number {{$card_number}}?", arguments));
|
||||
WriteLine(await kernel.InvokePromptAsync("Tell me some useful information about this credit card number {{$card_number}}?", arguments));
|
||||
}
|
||||
|
||||
public Step6_Responsible_AI(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,16 +3,22 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
using Examples;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using RepoUtils;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
public static class Step7_Observability
|
||||
namespace GettingStarted;
|
||||
|
||||
public class Step7_Observability : BaseTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Shows different ways observe the execution of a <see cref="KernelPlugin"/> instances.
|
||||
/// </summary>
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
// Create a kernel with OpenAI chat completion
|
||||
IKernelBuilder kernelBuilder = Kernel.CreateBuilder();
|
||||
@@ -25,13 +31,13 @@ public static class Step7_Observability
|
||||
// Handler which is called before a function is invoked
|
||||
void MyInvokingHandler(object? sender, FunctionInvokingEventArgs e)
|
||||
{
|
||||
Console.WriteLine($"Invoking {e.Function.Name}");
|
||||
WriteLine($"Invoking {e.Function.Name}");
|
||||
}
|
||||
|
||||
// Handler which is called after a prompt is rendered
|
||||
void MyRenderedHandler(object? sender, PromptRenderedEventArgs e)
|
||||
{
|
||||
Console.WriteLine($"Prompt sent to model: {e.RenderedPrompt}");
|
||||
WriteLine($"Prompt sent to model: {e.RenderedPrompt}");
|
||||
}
|
||||
|
||||
// Handler which is called after a function is invoked
|
||||
@@ -39,7 +45,7 @@ public static class Step7_Observability
|
||||
{
|
||||
if (e.Result.Metadata is not null && e.Result.Metadata.ContainsKey("Usage"))
|
||||
{
|
||||
Console.WriteLine($"Token usage: {e.Result.Metadata?["Usage"]?.AsJson()}");
|
||||
WriteLine($"Token usage: {e.Result.Metadata?["Usage"]?.AsJson()}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +56,7 @@ public static class Step7_Observability
|
||||
|
||||
// Invoke the kernel with a prompt and allow the AI to automatically invoke functions
|
||||
OpenAIPromptExecutionSettings settings = new() { ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions };
|
||||
Console.WriteLine(await kernel.InvokePromptAsync("How many days until Christmas? Explain your thinking.", new(settings)));
|
||||
WriteLine(await kernel.InvokePromptAsync("How many days until Christmas? Explain your thinking.", new(settings)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -62,4 +68,8 @@ public static class Step7_Observability
|
||||
[Description("Retrieves the current time in UTC.")]
|
||||
public string GetCurrentUtcTime() => DateTime.UtcNow.ToString("R");
|
||||
}
|
||||
|
||||
public Step7_Observability(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,17 +6,23 @@ using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Examples;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
public static class Step8_Pipelining
|
||||
namespace GettingStarted;
|
||||
|
||||
public class Step8_Pipelining : BaseTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides an example of combining multiple functions into a single function that invokes
|
||||
/// them in a sequence, passing the output from one as input to the next.
|
||||
/// </summary>
|
||||
public static async Task RunAsync()
|
||||
[Fact]
|
||||
public async Task RunAsync()
|
||||
{
|
||||
IKernelBuilder builder = Kernel.CreateBuilder();
|
||||
builder.AddOpenAIChatCompletion(
|
||||
@@ -25,7 +31,7 @@ public static class Step8_Pipelining
|
||||
builder.Services.AddLogging(c => c.AddConsole().SetMinimumLevel(LogLevel.Trace));
|
||||
Kernel kernel = builder.Build();
|
||||
|
||||
Console.WriteLine("================ PIPELINE ================");
|
||||
WriteLine("================ PIPELINE ================");
|
||||
{
|
||||
// Create a pipeline of functions that will parse a string into an int, multiply it by a double, truncate it to an int, and then humanize it.
|
||||
KernelFunction parseInt32 = KernelFunctionFactory.CreateFromMethod((string s) => double.Parse(s, CultureInfo.InvariantCulture), "parseInt32");
|
||||
@@ -47,10 +53,10 @@ public static class Step8_Pipelining
|
||||
// - The parseInt32 function will be invoked, read "123.456" from the arguments, and parse it into (double)123.456.
|
||||
// - The multiplyByN function will be invoked, with i=123.456 and n=78.90, and return (double)9740.6784.
|
||||
// - The truncate function will be invoked, with d=9740.6784, and return (int)9740, which will be the final result.
|
||||
Console.WriteLine(await pipeline.InvokeAsync(kernel, args));
|
||||
WriteLine(await pipeline.InvokeAsync(kernel, args));
|
||||
}
|
||||
|
||||
Console.WriteLine("================ GRAPH ================");
|
||||
WriteLine("================ GRAPH ================");
|
||||
{
|
||||
KernelFunction rand = KernelFunctionFactory.CreateFromMethod(() => Random.Shared.Next(), "GetRandomInt32");
|
||||
KernelFunction mult = KernelFunctionFactory.CreateFromMethod((int i, int j) => i * j, "Multiply");
|
||||
@@ -65,9 +71,13 @@ public static class Step8_Pipelining
|
||||
(mult, "")
|
||||
}, "graph");
|
||||
|
||||
Console.WriteLine(await graph.InvokeAsync(kernel));
|
||||
WriteLine(await graph.InvokeAsync(kernel));
|
||||
}
|
||||
}
|
||||
|
||||
public Step8_Pipelining(ITestOutputHelper output) : base(output)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public static class KernelFunctionCombinators
|
||||
|
||||
@@ -3,19 +3,17 @@
|
||||
<UserSecretsId>5ee045b0-aea3-4f08-8d31-32d1a6f8fed0</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<AssemblyName>KernelSyntaxExamples</AssemblyName>
|
||||
<RootNamespace></RootNamespace>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<RollForward>LatestMajor</RollForward>
|
||||
<OutputType>Exe</OutputType>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
<IsPackable>false</IsPackable>
|
||||
<!-- Suppress: "Declare types in namespaces", "Require ConfigureAwait", "Experimental" -->
|
||||
<NoWarn>CA1050,CA1707,CA2007,VSTHRD111,CS1591,RCS1110,CA5394,SKEXP0001,SKEXP0002,SKEXP0003,SKEXP0004,SKEXP0010,SKEXP0011,,SKEXP0012,SKEXP0020,SKEXP0021,SKEXP0022,SKEXP0023,SKEXP0024,SKEXP0025,SKEXP0026,SKEXP0027,SKEXP0028,SKEXP0029,SKEXP0030,SKEXP0031,SKEXP0032,SKEXP0040,SKEXP0041,SKEXP0042,SKEXP0050,SKEXP0051,SKEXP0052,SKEXP0053,SKEXP0054,SKEXP0055,SKEXP0060,SKEXP0061,SKEXP0101,SKEXP0102</NoWarn>
|
||||
<NoWarn>CS8618,IDE0009,CA1051,CA1050,CA1707,CA2007,VSTHRD111,CS1591,RCS1110,CA5394,SKEXP0001,SKEXP0002,SKEXP0003,SKEXP0004,SKEXP0010,SKEXP0011,,SKEXP0012,SKEXP0020,SKEXP0021,SKEXP0022,SKEXP0023,SKEXP0024,SKEXP0025,SKEXP0026,SKEXP0027,SKEXP0028,SKEXP0029,SKEXP0030,SKEXP0031,SKEXP0032,SKEXP0040,SKEXP0041,SKEXP0042,SKEXP0050,SKEXP0051,SKEXP0052,SKEXP0053,SKEXP0054,SKEXP0055,SKEXP0060,SKEXP0061,SKEXP0101,SKEXP0102</NoWarn>
|
||||
<OutputType>Library</OutputType>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Remove="Example12_SequentialPlanner.cs" />
|
||||
<Compile Remove="Example28_ActionPlanner.cs" />
|
||||
<Compile Remove="Example31_CustomPlanner.cs" />
|
||||
<Compile Remove="Example51_StepwisePlanner.cs" />
|
||||
<Compile Remove="RepoUtils\PlanExtensions.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -24,6 +22,13 @@
|
||||
<None Remove="Resources\travelinfo.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" />
|
||||
<PackageReference Include="xRetry" />
|
||||
<PackageReference Include="xunit" />
|
||||
<PackageReference Include="xunit.runner.visualstudio">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Azure.Identity" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" />
|
||||
@@ -36,7 +41,6 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
|
||||
<PackageReference Include="Polly" />
|
||||
<PackageReference Include="SharpToken" />
|
||||
<PackageReference Include="Microsoft.ML.Tokenizers" />
|
||||
<PackageReference Include="Microsoft.DeepDev.TokenizerLib" />
|
||||
@@ -69,7 +73,6 @@
|
||||
<ProjectReference Include="..\..\src\Connectors\Connectors.Memory.Qdrant\Connectors.Memory.Qdrant.csproj" />
|
||||
<ProjectReference Include="..\..\src\Plugins\Plugins.Web\Plugins.Web.csproj" />
|
||||
<ProjectReference Include="..\..\src\SemanticKernel.Core\SemanticKernel.Core.csproj" />
|
||||
<ProjectReference Include="..\NCalcPlugins\NCalcPlugins.csproj" />
|
||||
<PackageReference Include="System.Text.Json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Reliability;
|
||||
using RepoUtils;
|
||||
|
||||
public static class Program
|
||||
{
|
||||
/// <summary>
|
||||
/// We recommend using the Debug properties to set the filter as a command line argument.
|
||||
/// If you don't want to use it, set the filter here.
|
||||
/// Examples:
|
||||
/// DefaultFilter = "18" => run only example 18 (also "180" if there is such test)
|
||||
/// DefaultFilter = "chat" => run all examples with a name that contains "chat"
|
||||
/// </summary>
|
||||
public const string? DefaultFilter = "";
|
||||
|
||||
public static async Task Main(string[] args)
|
||||
{
|
||||
// Load configuration from environment variables or user secrets.
|
||||
LoadUserSecrets();
|
||||
|
||||
// Execution canceled if the user presses Ctrl+C.
|
||||
using CancellationTokenSource cancellationTokenSource = new();
|
||||
CancellationToken cancelToken = cancellationTokenSource.ConsoleCancellationToken();
|
||||
|
||||
// Check if args[0] is provided
|
||||
string? filter = args.Length > 0 ? args[0] : DefaultFilter;
|
||||
|
||||
// Run examples based on the filter
|
||||
await RunExamplesAsync(filter, cancelToken);
|
||||
}
|
||||
|
||||
private static async Task RunExamplesAsync(string? filter, CancellationToken cancellationToken)
|
||||
{
|
||||
var examples = (Assembly.GetExecutingAssembly().GetTypes())
|
||||
.Select(type => type.Name).ToList();
|
||||
|
||||
// Filter and run examples
|
||||
foreach (var example in examples)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filter) || example.Contains(filter, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
try
|
||||
{
|
||||
var method = Assembly.GetExecutingAssembly().GetType(example)?.GetMethod("RunAsync");
|
||||
if (method == null)
|
||||
{
|
||||
// Skip if the type does not have a RunAsync method
|
||||
continue;
|
||||
}
|
||||
|
||||
Console.WriteLine($"Running {example}...");
|
||||
|
||||
bool hasCancellationToken = method.GetParameters().Any(param => param.ParameterType == typeof(CancellationToken));
|
||||
|
||||
var taskParameters = hasCancellationToken ? new object[] { cancellationToken } : null;
|
||||
if (method.Invoke(null, taskParameters) is Task t)
|
||||
{
|
||||
await t.SafeWaitAsync(cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
method.Invoke(null, null);
|
||||
}
|
||||
}
|
||||
catch (ConfigurationNotFoundException ex)
|
||||
{
|
||||
Console.WriteLine($"{ex.Message}. Skipping example {example}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void LoadUserSecrets()
|
||||
{
|
||||
IConfigurationRoot configRoot = new ConfigurationBuilder()
|
||||
.AddJsonFile("appsettings.Development.json", true)
|
||||
.AddEnvironmentVariables()
|
||||
.AddUserSecrets<Env>()
|
||||
.Build();
|
||||
TestConfiguration.Initialize(configRoot);
|
||||
}
|
||||
|
||||
private static CancellationToken ConsoleCancellationToken(this CancellationTokenSource tokenSource)
|
||||
{
|
||||
Console.CancelKeyPress += (s, e) =>
|
||||
{
|
||||
Console.WriteLine("Canceling...");
|
||||
tokenSource.Cancel();
|
||||
e.Cancel = true;
|
||||
};
|
||||
|
||||
return tokenSource.Token;
|
||||
}
|
||||
|
||||
private static async Task SafeWaitAsync(this Task task,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
await task.WaitAsync(cancellationToken);
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("== DONE ==");
|
||||
}
|
||||
catch (ConfigurationNotFoundException ex)
|
||||
{
|
||||
Console.WriteLine($"{ex.Message}. Skipping example.");
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
}
|
||||
@@ -103,9 +103,6 @@ dotnet user-secrets set "Google:SearchEngineId" "..."
|
||||
|
||||
dotnet user-secrets set "Github:PAT" "github_pat_..."
|
||||
|
||||
dotnet user-secrets set "Apim:Endpoint" "https://apim...azure-api.net/"
|
||||
dotnet user-secrets set "Apim:SubscriptionKey" "..."
|
||||
|
||||
dotnet user-secrets set "Postgres:ConnectionString" "..."
|
||||
dotnet user-secrets set "Redis:Configuration" "..."
|
||||
dotnet user-secrets set "Kusto:ConnectionString" "..."
|
||||
@@ -173,10 +170,6 @@ Google__SearchEngineId
|
||||
# Github
|
||||
Github__PAT
|
||||
|
||||
# Azure API Management (APIM)
|
||||
Apim__Endpoint
|
||||
Apim__SubscriptionKey
|
||||
|
||||
# Other
|
||||
Postgres__ConnectionString
|
||||
Redis__Configuration
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Examples;
|
||||
|
||||
public static class TextOutputHelperExtensions
|
||||
{
|
||||
public static void WriteLine(this ITestOutputHelper testOutputHelper, object target)
|
||||
{
|
||||
testOutputHelper.WriteLine(target.ToString());
|
||||
}
|
||||
|
||||
public static void WriteLine(this ITestOutputHelper testOutputHelper)
|
||||
{
|
||||
testOutputHelper.WriteLine(string.Empty);
|
||||
}
|
||||
|
||||
public static void Write(this ITestOutputHelper testOutputHelper)
|
||||
{
|
||||
testOutputHelper.WriteLine(string.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Current interface ITestOutputHelper does not have a Write method. This extension method adds it to make it analogous to Console.Write when used in Console apps.
|
||||
/// </summary>
|
||||
/// <param name="testOutputHelper">TestOutputHelper</param>
|
||||
/// <param name="target">Target object to write</param>
|
||||
public static void Write(this ITestOutputHelper testOutputHelper, object target)
|
||||
{
|
||||
testOutputHelper.WriteLine(target.ToString());
|
||||
}
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel;
|
||||
using NCalc;
|
||||
|
||||
namespace NCalcPlugins;
|
||||
|
||||
/// <summary>
|
||||
/// Plugin that enables the comprehension of mathematical problems presented in English / natural-language text, followed by the execution of the necessary calculations to solve those problems.
|
||||
/// </summary>
|
||||
public class LanguageCalculatorPlugin
|
||||
{
|
||||
private readonly KernelFunction _mathTranslator;
|
||||
private const string MathTranslatorPrompt =
|
||||
@"Translate a math problem into a expression that can be executed using .net NCalc library. Use the output of running this code to answer the question.
|
||||
Available functions: Abs, Acos, Asin, Atan, Ceiling, Cos, Exp, Floor, IEEERemainder, Log, Log10, Max, Min, Pow, Round, Sign, Sin, Sqrt, Tan, and Truncate. in and if are also supported.
|
||||
|
||||
Question: $((Question with math problem.))
|
||||
expression:``` $((single line mathematical expression that solves the problem))```
|
||||
|
||||
[Examples]
|
||||
Question: What is 37593 * 67?
|
||||
expression:```37593 * 67```
|
||||
|
||||
Question: what is 3 to the 2nd power?
|
||||
expression:```Pow(3, 2)```
|
||||
|
||||
Question: what is sine of 0 radians?
|
||||
expression:```Sin(0)```
|
||||
|
||||
Question: what is sine of 45 degrees?
|
||||
expression:```Sin(45 * Pi /180 )```
|
||||
|
||||
Question: how many radians is 45 degrees?
|
||||
expression:``` 45 * Pi / 180 ```
|
||||
|
||||
Question: what is the square root of 81?
|
||||
expression:```Sqrt(81)```
|
||||
|
||||
Question: what is the angle whose sine is the number 1?
|
||||
expression:```Asin(1)```
|
||||
|
||||
[End of Examples]
|
||||
|
||||
Question: {{ $input }}
|
||||
";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LanguageCalculatorPlugin"/> class.
|
||||
/// </summary>
|
||||
public LanguageCalculatorPlugin()
|
||||
{
|
||||
this._mathTranslator = KernelFunctionFactory.CreateFromPrompt(
|
||||
MathTranslatorPrompt,
|
||||
functionName: "TranslateMathProblem",
|
||||
description: "Used by 'Calculator' function.",
|
||||
executionSettings: new PromptExecutionSettings()
|
||||
{
|
||||
ExtensionData = new Dictionary<string, object>()
|
||||
{
|
||||
{ "MaxTokens", 256 },
|
||||
{ "Temperature", 0.0 },
|
||||
{ "TopP", 1 },
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the result of a non-trivial math expression.
|
||||
/// </summary>
|
||||
/// <param name="input">A valid mathematical expression that could be executed by a calculator capable of more advanced math functions like sine/cosine/floor.</param>
|
||||
/// <param name="kernel">The <see cref="Kernel"/> containing services, plugins, and other state for use throughout the operation.</param>
|
||||
/// <returns>A <see cref="Task{TResult}"/> representing the result of the asynchronous operation.</returns>
|
||||
[KernelFunction("Calculator"), Description("Useful for getting the result of a non-trivial math expression.")]
|
||||
public async Task<string> CalculateAsync(
|
||||
[Description("A valid mathematical expression that could be executed by a calculator capable of more advanced math functions like sin/cosine/floor.")]
|
||||
string input,
|
||||
Kernel kernel)
|
||||
{
|
||||
string answer;
|
||||
|
||||
try
|
||||
{
|
||||
var result = await kernel.InvokeAsync(this._mathTranslator, new() { ["input"] = input }).ConfigureAwait(false);
|
||||
answer = result?.GetValue<string>() ?? string.Empty;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException($"Error in calculator for input {input} {ex.Message}", ex);
|
||||
}
|
||||
|
||||
string pattern = @"```\s*(.*?)\s*```";
|
||||
|
||||
Match match = Regex.Match(answer, pattern, RegexOptions.Singleline);
|
||||
if (match.Success)
|
||||
{
|
||||
var result = EvaluateMathExpression(match);
|
||||
return result;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Input value [{input}] could not be understood, received following {answer}");
|
||||
}
|
||||
|
||||
private static string EvaluateMathExpression(Match match)
|
||||
{
|
||||
var textExpressions = match.Groups[1].Value;
|
||||
var expr = new Expression(textExpressions, EvaluateOptions.IgnoreCase);
|
||||
expr.EvaluateParameter += (string name, ParameterArgs args) =>
|
||||
{
|
||||
args.Result = name.ToLower(System.Globalization.CultureInfo.CurrentCulture) switch
|
||||
{
|
||||
"pi" => Math.PI,
|
||||
"e" => Math.E,
|
||||
_ => args.Result
|
||||
};
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
if (expr.HasErrors())
|
||||
{
|
||||
return "Error:" + expr.Error + " could not evaluate " + textExpressions;
|
||||
}
|
||||
|
||||
var result = expr.Evaluate();
|
||||
return "Answer:" + result.ToString();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new InvalidOperationException("could not evaluate " + textExpressions, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<LangVersion>10</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\SemanticKernel.Core\SemanticKernel.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CoreCLR-NCalc" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,36 +0,0 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.SemanticKernel;
|
||||
|
||||
namespace NCalcPlugins;
|
||||
|
||||
/// <summary>
|
||||
/// Simple calculator plugin that evaluates a mathematical expression.
|
||||
/// </summary>
|
||||
public class SimpleCalculatorPlugin
|
||||
{
|
||||
private readonly KernelFunction _mathTranslator;
|
||||
|
||||
private static readonly string[] s_stopSequences = new[] { "Problem:", "Solution:" };
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SimpleCalculatorPlugin"/> class.
|
||||
/// </summary>
|
||||
public SimpleCalculatorPlugin()
|
||||
{
|
||||
this._mathTranslator = KernelFunctionFactory.CreateFromPrompt(
|
||||
"Task: Give the final solution for the problem. Be as concise as possible.\nProblem:4+4\nSolution:8\nProblem:{{$input}}\nSolution:\n",
|
||||
functionName: "Calculator",
|
||||
description: "Evaluate a mathematical expression. Input is a valid mathematical expression that could be executed by a simple calculator i.e. add, subtract, multiply and divide. Cannot use variables.",
|
||||
executionSettings: new PromptExecutionSettings()
|
||||
{
|
||||
ExtensionData = new Dictionary<string, object>()
|
||||
{
|
||||
{ "MaxTokens", 256 },
|
||||
{ "Temperature", 0.0 },
|
||||
{ "StopSequences", s_stopSequences },
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,6 @@
|
||||
<ProjectReference Include="..\..\src\SemanticKernel.Core\SemanticKernel.Core.csproj" />
|
||||
<ProjectReference Include="..\..\src\Plugins\Plugins.Core\Plugins.Core.csproj" />
|
||||
<ProjectReference Include="..\..\src\Plugins\Plugins.Web\Plugins.Web.csproj" />
|
||||
<ProjectReference Include="..\NCalcPlugins\NCalcPlugins.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Azure;
|
||||
using Azure.AI.OpenAI;
|
||||
using Azure.Core;
|
||||
@@ -98,16 +97,4 @@ internal sealed class AzureOpenAIClientCore : ClientCore
|
||||
|
||||
this.AddAttribute(DeploymentNameKey, deploymentName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logs Azure OpenAI action details.
|
||||
/// </summary>
|
||||
/// <param name="callerMemberName">Caller member name. Populated automatically by runtime.</param>
|
||||
internal void LogActionDetails([CallerMemberName] string? callerMemberName = default)
|
||||
{
|
||||
if (this.Logger.IsEnabled(LogLevel.Information))
|
||||
{
|
||||
this.Logger.LogInformation("Action: {Action}. Azure OpenAI Deployment Name: {DeploymentName}.", callerMemberName, this.DeploymentOrModelName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -30,7 +30,8 @@ public sealed class AzureOpenAIWithDataChatMessageContent : ChatMessageContent
|
||||
: base(default, string.Empty, modelId, chatChoice, System.Text.Encoding.UTF8, CreateMetadataDictionary(metadata))
|
||||
{
|
||||
// An assistant message content must be present, otherwise the chat is not valid.
|
||||
var chatMessage = chatChoice.Messages.First(m => string.Equals(m.Role, AuthorRole.Assistant.Label, StringComparison.OrdinalIgnoreCase));
|
||||
var chatMessage = chatChoice.Messages.FirstOrDefault(m => string.Equals(m.Role, AuthorRole.Assistant.Label, StringComparison.OrdinalIgnoreCase)) ??
|
||||
throw new ArgumentException("Chat is not valid. Chat message does not contain any messages with 'assistant' role.");
|
||||
|
||||
this.Content = chatMessage.Content;
|
||||
this.Role = new AuthorRole(chatMessage.Role);
|
||||
|
||||
@@ -33,13 +33,13 @@ public static class OpenAIMemoryBuilderExtensions
|
||||
string? modelId = null,
|
||||
HttpClient? httpClient = null)
|
||||
{
|
||||
return builder.WithTextEmbeddingGeneration((loggerFactory, httpClient) =>
|
||||
return builder.WithTextEmbeddingGeneration((loggerFactory, builderHttpClient) =>
|
||||
new AzureOpenAITextEmbeddingGenerationService(
|
||||
deploymentName,
|
||||
endpoint,
|
||||
apiKey,
|
||||
modelId,
|
||||
HttpClientProvider.GetHttpClient(httpClient),
|
||||
HttpClientProvider.GetHttpClient(httpClient ?? builderHttpClient),
|
||||
loggerFactory));
|
||||
}
|
||||
|
||||
@@ -63,13 +63,13 @@ public static class OpenAIMemoryBuilderExtensions
|
||||
string? modelId = null,
|
||||
HttpClient? httpClient = null)
|
||||
{
|
||||
return builder.WithTextEmbeddingGeneration((loggerFactory, httpClient) =>
|
||||
return builder.WithTextEmbeddingGeneration((loggerFactory, builderHttpClient) =>
|
||||
new AzureOpenAITextEmbeddingGenerationService(
|
||||
deploymentName,
|
||||
endpoint,
|
||||
credential,
|
||||
modelId,
|
||||
HttpClientProvider.GetHttpClient(httpClient),
|
||||
HttpClientProvider.GetHttpClient(httpClient ?? builderHttpClient),
|
||||
loggerFactory));
|
||||
}
|
||||
|
||||
@@ -91,12 +91,12 @@ public static class OpenAIMemoryBuilderExtensions
|
||||
string? orgId = null,
|
||||
HttpClient? httpClient = null)
|
||||
{
|
||||
return builder.WithTextEmbeddingGeneration((loggerFactory, httpClient) =>
|
||||
return builder.WithTextEmbeddingGeneration((loggerFactory, builderHttpClient) =>
|
||||
new OpenAITextEmbeddingGenerationService(
|
||||
modelId,
|
||||
apiKey,
|
||||
orgId,
|
||||
HttpClientProvider.GetHttpClient(httpClient),
|
||||
HttpClientProvider.GetHttpClient(httpClient ?? builderHttpClient),
|
||||
loggerFactory));
|
||||
}
|
||||
}
|
||||
|
||||
-1
@@ -93,7 +93,6 @@ public sealed class AzureOpenAITextEmbeddingGenerationService : ITextEmbeddingGe
|
||||
Kernel? kernel = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
this._core.LogActionDetails();
|
||||
return this._core.GetEmbeddingsAsync(data, kernel, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Net.Http;
|
||||
using System.Text.Json;
|
||||
@@ -87,10 +86,7 @@ public sealed class OpenAITextToImageService : ITextToImageService
|
||||
string format, Func<TextToImageResponse.Image, string> extractResponse,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
Debug.Assert(width == height);
|
||||
Debug.Assert(width is 256 or 512 or 1024);
|
||||
Debug.Assert(format is "url" or "b64_json");
|
||||
Debug.Assert(extractResponse is not null);
|
||||
Verify.NotNull(extractResponse);
|
||||
|
||||
var requestBody = JsonSerializer.Serialize(new TextToImageRequest
|
||||
{
|
||||
|
||||
@@ -27,14 +27,17 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.Numerics.Tensors" />
|
||||
<PackageReference Include="System.Text.Json" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="$(RepoRoot)/dotnet/src/InternalUtilities/test/AssertExtensions.cs"
|
||||
Link="%(RecursiveDir)%(Filename)%(Extension)" />
|
||||
<Compile Include="$(RepoRoot)/dotnet/src/InternalUtilities/test/AssertExtensions.cs" Link="%(RecursiveDir)%(Filename)%(Extension)" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -55,16 +58,10 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="HuggingFace\TestData\completion_test_response.json">
|
||||
<None Update="HuggingFace\TestData\*">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="HuggingFace\TestData\embeddings_test_response.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="OpenAI\TestData\image_result_test_response.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="OpenAI\TestData\image_generation_test_response.json">
|
||||
<None Update="OpenAI\TestData\*">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SemanticKernel.Connectors.UnitTests;
|
||||
|
||||
internal sealed class MultipleHttpMessageHandlerStub : DelegatingHandler
|
||||
{
|
||||
private int _callIteration = 0;
|
||||
|
||||
public List<HttpRequestHeaders?> RequestHeaders { get; private set; }
|
||||
|
||||
public List<HttpContentHeaders?> ContentHeaders { get; private set; }
|
||||
|
||||
public List<byte[]?> RequestContents { get; private set; }
|
||||
|
||||
public List<Uri?> RequestUris { get; private set; }
|
||||
|
||||
public List<HttpMethod?> Methods { get; private set; }
|
||||
|
||||
public List<HttpResponseMessage> ResponsesToReturn { get; set; }
|
||||
|
||||
public MultipleHttpMessageHandlerStub()
|
||||
{
|
||||
this.RequestHeaders = [];
|
||||
this.ContentHeaders = [];
|
||||
this.RequestContents = [];
|
||||
this.RequestUris = [];
|
||||
this.Methods = [];
|
||||
this.ResponsesToReturn = [];
|
||||
}
|
||||
|
||||
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
this._callIteration++;
|
||||
|
||||
this.Methods.Add(request.Method);
|
||||
this.RequestUris.Add(request.RequestUri);
|
||||
this.RequestHeaders.Add(request.Headers);
|
||||
this.ContentHeaders.Add(request.Content?.Headers);
|
||||
|
||||
var content = request.Content == null ? null : await request.Content.ReadAsByteArrayAsync(cancellationToken);
|
||||
|
||||
this.RequestContents.Add(content);
|
||||
|
||||
return await Task.FromResult(this.ResponsesToReturn[this._callIteration - 1]);
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Xunit;
|
||||
|
||||
namespace SemanticKernel.Connectors.UnitTests.OpenAI.AzureSdk;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for <see cref="AzureOpenAIWithDataChatMessageContent"/> class.
|
||||
/// </summary>
|
||||
public sealed class AzureOpenAIWithDataChatMessageContentTests
|
||||
{
|
||||
[Fact]
|
||||
public void ConstructorThrowsExceptionWhenAssistantMessageIsNotProvided()
|
||||
{
|
||||
// Arrange
|
||||
var choice = new ChatWithDataChoice();
|
||||
|
||||
// Act & Assert
|
||||
var exception = Assert.Throws<ArgumentException>(() => new AzureOpenAIWithDataChatMessageContent(choice, "model-id"));
|
||||
|
||||
Assert.Contains("Chat is not valid", exception.Message, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConstructorReturnsInstanceWithNullToolContent()
|
||||
{
|
||||
// Arrange
|
||||
var choice = new ChatWithDataChoice { Messages = [new() { Content = "Assistant content", Role = "assistant" }] };
|
||||
|
||||
// Act
|
||||
var content = new AzureOpenAIWithDataChatMessageContent(choice, "model-id");
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Assistant content", content.Content);
|
||||
Assert.Equal(AuthorRole.Assistant, content.Role);
|
||||
|
||||
Assert.Null(content.ToolContent);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void ConstructorReturnsInstanceWithNonNullToolContent(bool includeMetadata)
|
||||
{
|
||||
// Arrange
|
||||
var choice = new ChatWithDataChoice
|
||||
{
|
||||
Messages = [
|
||||
new() { Content = "Assistant content", Role = "assistant" },
|
||||
new() { Content = "Tool content", Role = "tool" }]
|
||||
};
|
||||
|
||||
// Act
|
||||
var content = includeMetadata ?
|
||||
new AzureOpenAIWithDataChatMessageContent(choice, "model-id", new Dictionary<string, object?>()) :
|
||||
new AzureOpenAIWithDataChatMessageContent(choice, "model-id");
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Assistant content", content.Content);
|
||||
Assert.Equal("Tool content", content.ToolContent);
|
||||
Assert.Equal(AuthorRole.Assistant, content.Role);
|
||||
|
||||
Assert.NotNull(content.Metadata);
|
||||
Assert.Equal("Tool content", content.Metadata["ToolContent"]);
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Xunit;
|
||||
|
||||
namespace SemanticKernel.Connectors.UnitTests.OpenAI.AzureSdk;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for <see cref="AzureOpenAIWithDataStreamingChatMessageContent"/> class.
|
||||
/// </summary>
|
||||
public sealed class AzureOpenAIWithDataStreamingChatMessageContentTests
|
||||
{
|
||||
[Theory]
|
||||
[MemberData(nameof(ValidChoices))]
|
||||
public void ConstructorWithValidChoiceSetsNonEmptyContent(object choice, string expectedContent)
|
||||
{
|
||||
// Arrange
|
||||
var streamingChoice = choice as ChatWithDataStreamingChoice;
|
||||
|
||||
// Act
|
||||
var content = new AzureOpenAIWithDataStreamingChatMessageContent(streamingChoice!, 0, "model-id");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedContent, content.Content);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(InvalidChoices))]
|
||||
public void ConstructorWithInvalidChoiceSetsNullContent(object choice)
|
||||
{
|
||||
// Arrange
|
||||
var streamingChoice = choice as ChatWithDataStreamingChoice;
|
||||
|
||||
// Act
|
||||
var content = new AzureOpenAIWithDataStreamingChatMessageContent(streamingChoice!, 0, "model-id");
|
||||
|
||||
// Assert
|
||||
Assert.Null(content.Content);
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> ValidChoices
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new object[] { new ChatWithDataStreamingChoice { Messages = [new() { Delta = new() { Content = "Content 1" } }] }, "Content 1" };
|
||||
yield return new object[] { new ChatWithDataStreamingChoice { Messages = [new() { Delta = new() { Content = "Content 2", Role = "Assistant" } }] }, "Content 2" };
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> InvalidChoices
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new object[] { new ChatWithDataStreamingChoice { Messages = [new() { EndTurn = true }] } };
|
||||
yield return new object[] { new ChatWithDataStreamingChoice { Messages = [new() { Delta = new() { Content = "Content", Role = "tool" } }] } };
|
||||
}
|
||||
}
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Azure.AI.OpenAI;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Xunit;
|
||||
|
||||
namespace SemanticKernel.Connectors.UnitTests.OpenAI.AzureSdk;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for <see cref="OpenAIChatMessageContent"/> class.
|
||||
/// </summary>
|
||||
public sealed class OpenAIChatMessageContentTests
|
||||
{
|
||||
[Fact]
|
||||
public void ConstructorsWorkCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
List<ChatCompletionsToolCall> toolCalls = [new FakeChatCompletionsToolCall("id")];
|
||||
|
||||
// Act
|
||||
var content1 = new OpenAIChatMessageContent(new ChatRole("user"), "content1", "model-id1", toolCalls);
|
||||
var content2 = new OpenAIChatMessageContent(AuthorRole.User, "content2", "model-id2", toolCalls);
|
||||
|
||||
// Assert
|
||||
this.AssertChatMessageContent(AuthorRole.User, "content1", "model-id1", toolCalls, content1);
|
||||
this.AssertChatMessageContent(AuthorRole.User, "content2", "model-id2", toolCalls, content2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetOpenAIFunctionToolCallsReturnsCorrectList()
|
||||
{
|
||||
// Arrange
|
||||
List<ChatCompletionsToolCall> toolCalls = [
|
||||
new ChatCompletionsFunctionToolCall("id1", "name", string.Empty),
|
||||
new ChatCompletionsFunctionToolCall("id2", "name", string.Empty),
|
||||
new FakeChatCompletionsToolCall("id3"),
|
||||
new FakeChatCompletionsToolCall("id4")];
|
||||
|
||||
var content1 = new OpenAIChatMessageContent(AuthorRole.User, "content", "model-id", toolCalls);
|
||||
var content2 = new OpenAIChatMessageContent(AuthorRole.User, "content", "model-id", []);
|
||||
|
||||
// Act
|
||||
var actualToolCalls1 = content1.GetOpenAIFunctionToolCalls();
|
||||
var actualToolCalls2 = content2.GetOpenAIFunctionToolCalls();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, actualToolCalls1.Count);
|
||||
Assert.Equal("id1", actualToolCalls1[0].Id);
|
||||
Assert.Equal("id2", actualToolCalls1[1].Id);
|
||||
|
||||
Assert.Empty(actualToolCalls2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MetadataIsInitializedCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var metadata = new Dictionary<string, object?> { { "key", "value" } };
|
||||
List<ChatCompletionsToolCall> toolCalls = [
|
||||
new ChatCompletionsFunctionToolCall("id1", "name", string.Empty),
|
||||
new ChatCompletionsFunctionToolCall("id2", "name", string.Empty),
|
||||
new FakeChatCompletionsToolCall("id3"),
|
||||
new FakeChatCompletionsToolCall("id4")];
|
||||
|
||||
// Act
|
||||
var content1 = new OpenAIChatMessageContent(AuthorRole.User, "content1", "model-id1", [], metadata);
|
||||
var content2 = new OpenAIChatMessageContent(AuthorRole.User, "content2", "model-id2", toolCalls, metadata);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(content1.Metadata);
|
||||
Assert.Single(content1.Metadata);
|
||||
|
||||
Assert.NotNull(content2.Metadata);
|
||||
Assert.Equal(2, content2.Metadata.Count);
|
||||
Assert.Equal("value", content2.Metadata["key"]);
|
||||
|
||||
Assert.IsType<List<ChatCompletionsFunctionToolCall>>(content2.Metadata["ChatResponseMessage.FunctionToolCalls"]);
|
||||
|
||||
var actualToolCalls = content2.Metadata["ChatResponseMessage.FunctionToolCalls"] as List<ChatCompletionsFunctionToolCall>;
|
||||
Assert.NotNull(actualToolCalls);
|
||||
|
||||
Assert.Equal(2, actualToolCalls.Count);
|
||||
Assert.Equal("id1", actualToolCalls[0].Id);
|
||||
Assert.Equal("id2", actualToolCalls[1].Id);
|
||||
}
|
||||
|
||||
private void AssertChatMessageContent(
|
||||
AuthorRole expectedRole,
|
||||
string expectedContent,
|
||||
string expectedModelId,
|
||||
IReadOnlyList<ChatCompletionsToolCall> expectedToolCalls,
|
||||
OpenAIChatMessageContent actualContent)
|
||||
{
|
||||
Assert.Equal(expectedRole, actualContent.Role);
|
||||
Assert.Equal(expectedContent, actualContent.Content);
|
||||
Assert.Equal(expectedModelId, actualContent.ModelId);
|
||||
Assert.Same(expectedToolCalls, actualContent.ToolCalls);
|
||||
}
|
||||
|
||||
private sealed class FakeChatCompletionsToolCall(string id) : ChatCompletionsToolCall(id)
|
||||
{ }
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Azure.AI.OpenAI;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Xunit;
|
||||
|
||||
namespace SemanticKernel.Connectors.UnitTests.OpenAI.AzureSdk;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for <see cref="OpenAIFunctionToolCall"/> class.
|
||||
/// </summary>
|
||||
public sealed class OpenAIFunctionToolCallTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("MyFunction", "MyFunction")]
|
||||
[InlineData("MyPlugin_MyFunction", "MyPlugin_MyFunction")]
|
||||
public void FullyQualifiedNameReturnsValidName(string toolCallName, string expectedName)
|
||||
{
|
||||
// Arrange
|
||||
var toolCall = new ChatCompletionsFunctionToolCall("id", toolCallName, string.Empty);
|
||||
var openAIFunctionToolCall = new OpenAIFunctionToolCall(toolCall);
|
||||
|
||||
// Act & Assert
|
||||
Assert.Equal(expectedName, openAIFunctionToolCall.FullyQualifiedName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToStringReturnsCorrectValue()
|
||||
{
|
||||
// Arrange
|
||||
var toolCall = new ChatCompletionsFunctionToolCall("id", "MyPlugin_MyFunction", "{\n \"location\": \"San Diego\",\n \"max_price\": 300\n}");
|
||||
var openAIFunctionToolCall = new OpenAIFunctionToolCall(toolCall);
|
||||
|
||||
// Act & Assert
|
||||
Assert.Equal("MyPlugin_MyFunction(location:San Diego, max_price:300)", openAIFunctionToolCall.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConvertToolCallUpdatesWithEmptyIndexesReturnsEmptyToolCalls()
|
||||
{
|
||||
// Arrange
|
||||
var toolCallIdsByIndex = new Dictionary<int, string>();
|
||||
var functionNamesByIndex = new Dictionary<int, string>();
|
||||
var functionArgumentBuildersByIndex = new Dictionary<int, StringBuilder>();
|
||||
|
||||
// Act
|
||||
var toolCalls = OpenAIFunctionToolCall.ConvertToolCallUpdatesToChatCompletionsFunctionToolCalls(
|
||||
ref toolCallIdsByIndex,
|
||||
ref functionNamesByIndex,
|
||||
ref functionArgumentBuildersByIndex);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(toolCalls);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConvertToolCallUpdatesWithNotEmptyIndexesReturnsNotEmptyToolCalls()
|
||||
{
|
||||
// Arrange
|
||||
var toolCallIdsByIndex = new Dictionary<int, string> { { 3, "test-id" } };
|
||||
var functionNamesByIndex = new Dictionary<int, string> { { 3, "test-function" } };
|
||||
var functionArgumentBuildersByIndex = new Dictionary<int, StringBuilder> { { 3, new("test-argument") } };
|
||||
|
||||
// Act
|
||||
var toolCalls = OpenAIFunctionToolCall.ConvertToolCallUpdatesToChatCompletionsFunctionToolCalls(
|
||||
ref toolCallIdsByIndex,
|
||||
ref functionNamesByIndex,
|
||||
ref functionArgumentBuildersByIndex);
|
||||
|
||||
// Assert
|
||||
Assert.Single(toolCalls);
|
||||
|
||||
var toolCall = toolCalls[0];
|
||||
|
||||
Assert.Equal("test-id", toolCall.Id);
|
||||
Assert.Equal("test-function", toolCall.Name);
|
||||
Assert.Equal("test-argument", toolCall.Arguments);
|
||||
}
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Azure.AI.OpenAI;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Xunit;
|
||||
|
||||
namespace SemanticKernel.Connectors.UnitTests.OpenAI.AzureSdk;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for <see cref="OpenAIPluginCollectionExtensions"/> class.
|
||||
/// </summary>
|
||||
public sealed class OpenAIPluginCollectionExtensionsTests
|
||||
{
|
||||
[Fact]
|
||||
public void TryGetFunctionAndArgumentsWithNonExistingFunctionReturnsFalse()
|
||||
{
|
||||
// Arrange
|
||||
var plugin = KernelPluginFactory.CreateFromFunctions("MyPlugin", []);
|
||||
var plugins = new KernelPluginCollection([plugin]);
|
||||
|
||||
var toolCall = new ChatCompletionsFunctionToolCall("id", "MyPlugin_MyFunction", string.Empty);
|
||||
|
||||
// Act
|
||||
var result = plugins.TryGetFunctionAndArguments(toolCall, out var actualFunction, out var actualArguments);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
Assert.Null(actualFunction);
|
||||
Assert.Null(actualArguments);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryGetFunctionAndArgumentsWithoutArgumentsReturnsTrue()
|
||||
{
|
||||
// Arrange
|
||||
var function = KernelFunctionFactory.CreateFromMethod(() => "Result", "MyFunction");
|
||||
var plugin = KernelPluginFactory.CreateFromFunctions("MyPlugin", [function]);
|
||||
|
||||
var plugins = new KernelPluginCollection([plugin]);
|
||||
var toolCall = new ChatCompletionsFunctionToolCall("id", "MyPlugin_MyFunction", string.Empty);
|
||||
|
||||
// Act
|
||||
var result = plugins.TryGetFunctionAndArguments(toolCall, out var actualFunction, out var actualArguments);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
Assert.Same(function, actualFunction);
|
||||
Assert.Null(actualArguments);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryGetFunctionAndArgumentsWithArgumentsReturnsTrue()
|
||||
{
|
||||
// Arrange
|
||||
var function = KernelFunctionFactory.CreateFromMethod(() => "Result", "MyFunction");
|
||||
var plugin = KernelPluginFactory.CreateFromFunctions("MyPlugin", [function]);
|
||||
|
||||
var plugins = new KernelPluginCollection([plugin]);
|
||||
var toolCall = new ChatCompletionsFunctionToolCall("id", "MyPlugin_MyFunction", "{\n \"location\": \"San Diego\",\n \"max_price\": 300\n,\n \"null_argument\": null\n}");
|
||||
|
||||
// Act
|
||||
var result = plugins.TryGetFunctionAndArguments(toolCall, out var actualFunction, out var actualArguments);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
Assert.Same(function, actualFunction);
|
||||
|
||||
Assert.NotNull(actualArguments);
|
||||
Assert.Equal("San Diego", actualArguments["location"]);
|
||||
Assert.Equal("300", actualArguments["max_price"]);
|
||||
Assert.Null(actualArguments["null_argument"]);
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Text;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Xunit;
|
||||
|
||||
namespace SemanticKernel.Connectors.UnitTests.OpenAI.AzureSdk;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for <see cref="OpenAIStreamingTextContent"/> class.
|
||||
/// </summary>
|
||||
public sealed class OpenAIStreamingTextContentTests
|
||||
{
|
||||
[Fact]
|
||||
public void ToByteArrayWorksCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var expectedBytes = Encoding.UTF8.GetBytes("content");
|
||||
var content = new OpenAIStreamingTextContent("content", 0, "model-id");
|
||||
|
||||
// Act
|
||||
var actualBytes = content.ToByteArray();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedBytes, actualBytes);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, "")]
|
||||
[InlineData("content", "content")]
|
||||
public void ToStringWorksCorrectly(string? content, string expectedString)
|
||||
{
|
||||
// Arrange
|
||||
var textContent = new OpenAIStreamingTextContent(content!, 0, "model-id");
|
||||
|
||||
// Act
|
||||
var actualString = textContent.ToString();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedString, actualString);
|
||||
}
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using Azure;
|
||||
using Azure.Core;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Xunit;
|
||||
|
||||
namespace SemanticKernel.Connectors.UnitTests.OpenAI.AzureSdk;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for <see cref="RequestFailedExceptionExtensions"/> class.
|
||||
/// </summary>
|
||||
public sealed class RequestFailedExceptionExtensionsTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(0, null)]
|
||||
[InlineData(500, HttpStatusCode.InternalServerError)]
|
||||
public void ToHttpOperationExceptionWithStatusReturnsValidException(int responseStatus, HttpStatusCode? httpStatusCode)
|
||||
{
|
||||
// Arrange
|
||||
var exception = new RequestFailedException(responseStatus, "Error Message");
|
||||
|
||||
// Act
|
||||
var actualException = exception.ToHttpOperationException();
|
||||
|
||||
// Assert
|
||||
Assert.IsType<HttpOperationException>(actualException);
|
||||
Assert.Equal(httpStatusCode, actualException.StatusCode);
|
||||
Assert.Equal("Error Message", actualException.Message);
|
||||
Assert.Same(exception, actualException.InnerException);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToHttpOperationExceptionWithContentReturnsValidException()
|
||||
{
|
||||
// Arrange
|
||||
using var response = new FakeResponse("Response Content", 500);
|
||||
var exception = new RequestFailedException(response);
|
||||
|
||||
// Act
|
||||
var actualException = exception.ToHttpOperationException();
|
||||
|
||||
// Assert
|
||||
Assert.IsType<HttpOperationException>(actualException);
|
||||
Assert.Equal(HttpStatusCode.InternalServerError, actualException.StatusCode);
|
||||
Assert.Equal("Response Content", actualException.ResponseContent);
|
||||
Assert.Same(exception, actualException.InnerException);
|
||||
}
|
||||
|
||||
#region private
|
||||
|
||||
private sealed class FakeResponse(string responseContent, int status) : Response
|
||||
{
|
||||
private readonly string _responseContent = responseContent;
|
||||
private readonly int _status = status;
|
||||
private readonly IEnumerable<HttpHeader> _headers = new List<HttpHeader>();
|
||||
|
||||
public override BinaryData Content => BinaryData.FromString(this._responseContent);
|
||||
public override int Status => this._status;
|
||||
public override string ReasonPhrase => "Reason Phrase";
|
||||
public override Stream? ContentStream { get => null; set => throw new NotImplementedException(); }
|
||||
public override string ClientRequestId { get => "Client Request Id"; set => throw new NotImplementedException(); }
|
||||
|
||||
public override void Dispose() { }
|
||||
protected override bool ContainsHeader(string name) => throw new NotImplementedException();
|
||||
protected override IEnumerable<HttpHeader> EnumerateHeaders() => this._headers;
|
||||
#pragma warning disable CS8765 // Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes).
|
||||
protected override bool TryGetHeader(string name, out string? value) => throw new NotImplementedException();
|
||||
protected override bool TryGetHeaderValues(string name, out IEnumerable<string>? values) => throw new NotImplementedException();
|
||||
#pragma warning restore CS8765 // Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes).
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
+583
@@ -0,0 +1,583 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Azure.AI.OpenAI;
|
||||
using Azure.Core;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace SemanticKernel.Connectors.UnitTests.OpenAI.ChatCompletion;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for <see cref="AzureOpenAIChatCompletionService"/>
|
||||
/// </summary>
|
||||
public sealed class AzureOpenAIChatCompletionServiceTests : IDisposable
|
||||
{
|
||||
private readonly MultipleHttpMessageHandlerStub _messageHandlerStub;
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly Mock<ILoggerFactory> _mockLoggerFactory;
|
||||
|
||||
public AzureOpenAIChatCompletionServiceTests()
|
||||
{
|
||||
this._messageHandlerStub = new MultipleHttpMessageHandlerStub();
|
||||
this._httpClient = new HttpClient(this._messageHandlerStub, false);
|
||||
this._mockLoggerFactory = new Mock<ILoggerFactory>();
|
||||
|
||||
var mockLogger = new Mock<ILogger>();
|
||||
|
||||
mockLogger.Setup(l => l.IsEnabled(It.IsAny<LogLevel>())).Returns(true);
|
||||
|
||||
this._mockLoggerFactory.Setup(l => l.CreateLogger(It.IsAny<string>())).Returns(mockLogger.Object);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void ConstructorWithApiKeyWorksCorrectly(bool includeLoggerFactory)
|
||||
{
|
||||
// Arrange & Act
|
||||
var service = includeLoggerFactory ?
|
||||
new AzureOpenAIChatCompletionService("deployment", "https://endpoint", "api-key", "model-id", loggerFactory: this._mockLoggerFactory.Object) :
|
||||
new AzureOpenAIChatCompletionService("deployment", "https://endpoint", "api-key", "model-id");
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(service);
|
||||
Assert.Equal("model-id", service.Attributes["ModelId"]);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void ConstructorWithTokenCredentialWorksCorrectly(bool includeLoggerFactory)
|
||||
{
|
||||
// Arrange & Act
|
||||
var credentials = DelegatedTokenCredential.Create((_, _) => new AccessToken());
|
||||
var service = includeLoggerFactory ?
|
||||
new AzureOpenAIChatCompletionService("deployment", "https://endpoint", credentials, "model-id", loggerFactory: this._mockLoggerFactory.Object) :
|
||||
new AzureOpenAIChatCompletionService("deployment", "https://endpoint", credentials, "model-id");
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(service);
|
||||
Assert.Equal("model-id", service.Attributes["ModelId"]);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void ConstructorWithOpenAIClientWorksCorrectly(bool includeLoggerFactory)
|
||||
{
|
||||
// Arrange & Act
|
||||
var client = new OpenAIClient("key");
|
||||
var service = includeLoggerFactory ?
|
||||
new AzureOpenAIChatCompletionService("deployment", client, "model-id", loggerFactory: this._mockLoggerFactory.Object) :
|
||||
new AzureOpenAIChatCompletionService("deployment", client, "model-id");
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(service);
|
||||
Assert.Equal("model-id", service.Attributes["ModelId"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetTextContentsWorksCorrectlyAsync()
|
||||
{
|
||||
// Arrange
|
||||
var service = new AzureOpenAIChatCompletionService("deployment", "https://endpoint", "api-key", "model-id", this._httpClient);
|
||||
this._messageHandlerStub.ResponsesToReturn.Add(new HttpResponseMessage(HttpStatusCode.OK)
|
||||
{
|
||||
Content = new StringContent(OpenAITestHelper.GetTestResponse("chat_completion_test_response.json"))
|
||||
});
|
||||
|
||||
// Act
|
||||
var result = await service.GetTextContentsAsync("Prompt");
|
||||
|
||||
// Assert
|
||||
Assert.True(result.Count > 0);
|
||||
Assert.Equal("Test chat response", result[0].Text);
|
||||
|
||||
var usage = result[0].Metadata?["Usage"] as CompletionsUsage;
|
||||
|
||||
Assert.NotNull(usage);
|
||||
Assert.Equal(55, usage.PromptTokens);
|
||||
Assert.Equal(100, usage.CompletionTokens);
|
||||
Assert.Equal(155, usage.TotalTokens);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetChatMessageContentsWithEmptyChoicesThrowsExceptionAsync()
|
||||
{
|
||||
// Arrange
|
||||
var service = new AzureOpenAIChatCompletionService("deployment", "https://endpoint", "api-key", "model-id", this._httpClient);
|
||||
this._messageHandlerStub.ResponsesToReturn.Add(new HttpResponseMessage(HttpStatusCode.OK)
|
||||
{
|
||||
Content = new StringContent("{\"id\":\"response-id\",\"object\":\"chat.completion\",\"created\":1704208954,\"model\":\"gpt-4\",\"choices\":[],\"usage\":{\"prompt_tokens\":55,\"completion_tokens\":100,\"total_tokens\":155},\"system_fingerprint\":null}")
|
||||
});
|
||||
|
||||
// Act & Assert
|
||||
var exception = await Assert.ThrowsAsync<KernelException>(() => service.GetChatMessageContentsAsync([]));
|
||||
|
||||
Assert.Equal("Chat completions not found", exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0)]
|
||||
[InlineData(129)]
|
||||
public async Task GetChatMessageContentsWithInvalidResultsPerPromptValueThrowsExceptionAsync(int resultsPerPrompt)
|
||||
{
|
||||
// Arrange
|
||||
var service = new AzureOpenAIChatCompletionService("deployment", "https://endpoint", "api-key", "model-id", this._httpClient);
|
||||
var settings = new OpenAIPromptExecutionSettings { ResultsPerPrompt = resultsPerPrompt };
|
||||
|
||||
// Act & Assert
|
||||
var exception = await Assert.ThrowsAsync<ArgumentOutOfRangeException>(() => service.GetChatMessageContentsAsync([], settings));
|
||||
|
||||
Assert.Contains("The value must be in range between", exception.Message, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetChatMessageContentsHandlesSettingsCorrectlyAsync()
|
||||
{
|
||||
// Arrange
|
||||
var service = new AzureOpenAIChatCompletionService("deployment", "https://endpoint", "api-key", "model-id", this._httpClient);
|
||||
var settings = new OpenAIPromptExecutionSettings()
|
||||
{
|
||||
MaxTokens = 123,
|
||||
Temperature = 0.6,
|
||||
TopP = 0.5,
|
||||
FrequencyPenalty = 1.6,
|
||||
PresencePenalty = 1.2,
|
||||
ResultsPerPrompt = 5,
|
||||
Seed = 567,
|
||||
TokenSelectionBiases = new Dictionary<int, int> { { 2, 3 } },
|
||||
StopSequences = ["stop_sequence"]
|
||||
};
|
||||
|
||||
var chatHistory = new ChatHistory();
|
||||
chatHistory.AddUserMessage("User Message");
|
||||
chatHistory.AddSystemMessage("System Message");
|
||||
chatHistory.AddAssistantMessage("Assistant Message");
|
||||
|
||||
this._messageHandlerStub.ResponsesToReturn.Add(new HttpResponseMessage(HttpStatusCode.OK)
|
||||
{
|
||||
Content = new StringContent(OpenAITestHelper.GetTestResponse("chat_completion_test_response.json"))
|
||||
});
|
||||
|
||||
// Act
|
||||
var result = await service.GetChatMessageContentsAsync(chatHistory, settings);
|
||||
|
||||
// Assert
|
||||
var requestContent = this._messageHandlerStub.RequestContents[0];
|
||||
|
||||
Assert.NotNull(requestContent);
|
||||
|
||||
var content = JsonSerializer.Deserialize<JsonElement>(Encoding.UTF8.GetString(requestContent));
|
||||
|
||||
var messages = content.GetProperty("messages");
|
||||
|
||||
var userMessage = messages[0];
|
||||
var systemMessage = messages[1];
|
||||
var assistantMessage = messages[2];
|
||||
|
||||
Assert.Equal("user", userMessage.GetProperty("role").GetString());
|
||||
Assert.Equal("User Message", userMessage.GetProperty("content").GetString());
|
||||
|
||||
Assert.Equal("system", systemMessage.GetProperty("role").GetString());
|
||||
Assert.Equal("System Message", systemMessage.GetProperty("content").GetString());
|
||||
|
||||
Assert.Equal("assistant", assistantMessage.GetProperty("role").GetString());
|
||||
Assert.Equal("Assistant Message", assistantMessage.GetProperty("content").GetString());
|
||||
|
||||
Assert.Equal(123, content.GetProperty("max_tokens").GetInt32());
|
||||
Assert.Equal(0.6, content.GetProperty("temperature").GetDouble());
|
||||
Assert.Equal(0.5, content.GetProperty("top_p").GetDouble());
|
||||
Assert.Equal(1.6, content.GetProperty("frequency_penalty").GetDouble());
|
||||
Assert.Equal(1.2, content.GetProperty("presence_penalty").GetDouble());
|
||||
Assert.Equal(5, content.GetProperty("n").GetInt32());
|
||||
Assert.Equal(567, content.GetProperty("seed").GetInt32());
|
||||
Assert.Equal(3, content.GetProperty("logit_bias").GetProperty("2").GetInt32());
|
||||
Assert.Equal("stop_sequence", content.GetProperty("stop")[0].GetString());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(ResponseFormats))]
|
||||
public async Task GetChatMessageContentsHandlesResponseFormatCorrectlyAsync(object responseFormat, string? expectedResponseType)
|
||||
{
|
||||
// Arrange
|
||||
var service = new AzureOpenAIChatCompletionService("deployment", "https://endpoint", "api-key", "model-id", this._httpClient);
|
||||
var settings = new OpenAIPromptExecutionSettings
|
||||
{
|
||||
ResponseFormat = responseFormat
|
||||
};
|
||||
|
||||
this._messageHandlerStub.ResponsesToReturn.Add(new HttpResponseMessage(HttpStatusCode.OK)
|
||||
{
|
||||
Content = new StringContent(OpenAITestHelper.GetTestResponse("chat_completion_test_response.json"))
|
||||
});
|
||||
|
||||
// Act
|
||||
var result = await service.GetChatMessageContentsAsync([], settings);
|
||||
|
||||
// Assert
|
||||
var requestContent = this._messageHandlerStub.RequestContents[0];
|
||||
|
||||
Assert.NotNull(requestContent);
|
||||
|
||||
var content = JsonSerializer.Deserialize<JsonElement>(Encoding.UTF8.GetString(requestContent));
|
||||
|
||||
Assert.Equal(expectedResponseType, content.GetProperty("response_format").GetProperty("type").GetString());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(ToolCallBehaviors))]
|
||||
public async Task GetChatMessageContentsWorksCorrectlyAsync(ToolCallBehavior behavior)
|
||||
{
|
||||
// Arrange
|
||||
var kernel = Kernel.CreateBuilder().Build();
|
||||
var service = new AzureOpenAIChatCompletionService("deployment", "https://endpoint", "api-key", "model-id", this._httpClient);
|
||||
var settings = new OpenAIPromptExecutionSettings() { ToolCallBehavior = behavior };
|
||||
|
||||
this._messageHandlerStub.ResponsesToReturn.Add(new HttpResponseMessage(HttpStatusCode.OK)
|
||||
{
|
||||
Content = new StringContent(OpenAITestHelper.GetTestResponse("chat_completion_test_response.json"))
|
||||
});
|
||||
|
||||
// Act
|
||||
var result = await service.GetChatMessageContentsAsync([], settings, kernel);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.Count > 0);
|
||||
Assert.Equal("Test chat response", result[0].Content);
|
||||
|
||||
var usage = result[0].Metadata?["Usage"] as CompletionsUsage;
|
||||
|
||||
Assert.NotNull(usage);
|
||||
Assert.Equal(55, usage.PromptTokens);
|
||||
Assert.Equal(100, usage.CompletionTokens);
|
||||
Assert.Equal(155, usage.TotalTokens);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetChatMessageContentsWithFunctionCallAsync()
|
||||
{
|
||||
// Arrange
|
||||
int functionCallCount = 0;
|
||||
|
||||
var kernel = Kernel.CreateBuilder().Build();
|
||||
var function1 = KernelFunctionFactory.CreateFromMethod((string location) =>
|
||||
{
|
||||
functionCallCount++;
|
||||
return "Some weather";
|
||||
}, "GetCurrentWeather");
|
||||
|
||||
var function2 = KernelFunctionFactory.CreateFromMethod((string argument) =>
|
||||
{
|
||||
functionCallCount++;
|
||||
throw new ArgumentException("Some exception");
|
||||
}, "FunctionWithException");
|
||||
|
||||
kernel.Plugins.Add(KernelPluginFactory.CreateFromFunctions("MyPlugin", [function1, function2]));
|
||||
|
||||
var service = new AzureOpenAIChatCompletionService("deployment", "https://endpoint", "api-key", "model-id", this._httpClient, this._mockLoggerFactory.Object);
|
||||
var settings = new OpenAIPromptExecutionSettings() { ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions };
|
||||
|
||||
using var response1 = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(OpenAITestHelper.GetTestResponse("chat_completion_multiple_function_calls_test_response.json")) };
|
||||
using var response2 = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(OpenAITestHelper.GetTestResponse("chat_completion_test_response.json")) };
|
||||
|
||||
this._messageHandlerStub.ResponsesToReturn = [response1, response2];
|
||||
|
||||
// Act
|
||||
var result = await service.GetChatMessageContentsAsync([], settings, kernel);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.Count > 0);
|
||||
Assert.Equal("Test chat response", result[0].Content);
|
||||
|
||||
Assert.Equal(2, functionCallCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetChatMessageContentsWithFunctionCallMaximumAutoInvokeAttemptsAsync()
|
||||
{
|
||||
// Arrange
|
||||
const int DefaultMaximumAutoInvokeAttempts = 5;
|
||||
const int AutoInvokeResponsesCount = 6;
|
||||
|
||||
int functionCallCount = 0;
|
||||
|
||||
var kernel = Kernel.CreateBuilder().Build();
|
||||
var function = KernelFunctionFactory.CreateFromMethod((string location) =>
|
||||
{
|
||||
functionCallCount++;
|
||||
return "Some weather";
|
||||
}, "GetCurrentWeather");
|
||||
|
||||
kernel.Plugins.Add(KernelPluginFactory.CreateFromFunctions("MyPlugin", [function]));
|
||||
|
||||
var service = new AzureOpenAIChatCompletionService("deployment", "https://endpoint", "api-key", "model-id", this._httpClient, this._mockLoggerFactory.Object);
|
||||
var settings = new OpenAIPromptExecutionSettings() { ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions };
|
||||
|
||||
var responses = new List<HttpResponseMessage>();
|
||||
|
||||
for (var i = 0; i < AutoInvokeResponsesCount; i++)
|
||||
{
|
||||
responses.Add(new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(OpenAITestHelper.GetTestResponse("chat_completion_single_function_call_test_response.json")) });
|
||||
}
|
||||
|
||||
this._messageHandlerStub.ResponsesToReturn = responses;
|
||||
|
||||
// Act
|
||||
var result = await service.GetChatMessageContentsAsync([], settings, kernel);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(DefaultMaximumAutoInvokeAttempts, functionCallCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetChatMessageContentsWithRequiredFunctionCallAsync()
|
||||
{
|
||||
// Arrange
|
||||
int functionCallCount = 0;
|
||||
|
||||
var kernel = Kernel.CreateBuilder().Build();
|
||||
var function = KernelFunctionFactory.CreateFromMethod((string location) =>
|
||||
{
|
||||
functionCallCount++;
|
||||
return "Some weather";
|
||||
}, "GetCurrentWeather");
|
||||
|
||||
var plugin = KernelPluginFactory.CreateFromFunctions("MyPlugin", [function]);
|
||||
var openAIFunction = plugin.GetFunctionsMetadata().First().ToOpenAIFunction();
|
||||
|
||||
kernel.Plugins.Add(plugin);
|
||||
|
||||
var service = new AzureOpenAIChatCompletionService("deployment", "https://endpoint", "api-key", "model-id", this._httpClient, this._mockLoggerFactory.Object);
|
||||
var settings = new OpenAIPromptExecutionSettings() { ToolCallBehavior = ToolCallBehavior.RequireFunction(openAIFunction, autoInvoke: true) };
|
||||
|
||||
using var response1 = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(OpenAITestHelper.GetTestResponse("chat_completion_single_function_call_test_response.json")) };
|
||||
using var response2 = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(OpenAITestHelper.GetTestResponse("chat_completion_test_response.json")) };
|
||||
|
||||
this._messageHandlerStub.ResponsesToReturn = [response1, response2];
|
||||
|
||||
// Act
|
||||
var result = await service.GetChatMessageContentsAsync([], settings, kernel);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1, functionCallCount);
|
||||
|
||||
var requestContents = this._messageHandlerStub.RequestContents;
|
||||
|
||||
Assert.Equal(2, requestContents.Count);
|
||||
|
||||
requestContents.ForEach(Assert.NotNull);
|
||||
|
||||
var firstContent = Encoding.UTF8.GetString(requestContents[0]!);
|
||||
var secondContent = Encoding.UTF8.GetString(requestContents[1]!);
|
||||
|
||||
var firstContentJson = JsonSerializer.Deserialize<JsonElement>(firstContent);
|
||||
var secondContentJson = JsonSerializer.Deserialize<JsonElement>(secondContent);
|
||||
|
||||
Assert.Equal(1, firstContentJson.GetProperty("tools").GetArrayLength());
|
||||
Assert.Equal("MyPlugin_GetCurrentWeather", firstContentJson.GetProperty("tool_choice").GetProperty("function").GetProperty("name").GetString());
|
||||
|
||||
Assert.Equal("none", secondContentJson.GetProperty("tool_choice").GetString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetStreamingTextContentsWorksCorrectlyAsync()
|
||||
{
|
||||
// Arrange
|
||||
var service = new AzureOpenAIChatCompletionService("deployment", "https://endpoint", "api-key", "model-id", this._httpClient);
|
||||
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(OpenAITestHelper.GetTestResponse("chat_completion_streaming_test_response.txt")));
|
||||
|
||||
this._messageHandlerStub.ResponsesToReturn.Add(new HttpResponseMessage(HttpStatusCode.OK)
|
||||
{
|
||||
Content = new StreamContent(stream)
|
||||
});
|
||||
|
||||
// Act & Assert
|
||||
await foreach (var chunk in service.GetStreamingTextContentsAsync("Prompt"))
|
||||
{
|
||||
Assert.Equal("Test chat streaming response", chunk.Text);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetStreamingChatMessageContentsWorksCorrectlyAsync()
|
||||
{
|
||||
// Arrange
|
||||
var service = new AzureOpenAIChatCompletionService("deployment", "https://endpoint", "api-key", "model-id", this._httpClient);
|
||||
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(OpenAITestHelper.GetTestResponse("chat_completion_streaming_test_response.txt")));
|
||||
|
||||
this._messageHandlerStub.ResponsesToReturn.Add(new HttpResponseMessage(HttpStatusCode.OK)
|
||||
{
|
||||
Content = new StreamContent(stream)
|
||||
});
|
||||
|
||||
// Act & Assert
|
||||
await foreach (var chunk in service.GetStreamingChatMessageContentsAsync([]))
|
||||
{
|
||||
Assert.Equal("Test chat streaming response", chunk.Content);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetStreamingChatMessageContentsWithFunctionCallAsync()
|
||||
{
|
||||
// Arrange
|
||||
int functionCallCount = 0;
|
||||
|
||||
var kernel = Kernel.CreateBuilder().Build();
|
||||
var function1 = KernelFunctionFactory.CreateFromMethod((string location) =>
|
||||
{
|
||||
functionCallCount++;
|
||||
return "Some weather";
|
||||
}, "GetCurrentWeather");
|
||||
|
||||
var function2 = KernelFunctionFactory.CreateFromMethod((string argument) =>
|
||||
{
|
||||
functionCallCount++;
|
||||
throw new ArgumentException("Some exception");
|
||||
}, "FunctionWithException");
|
||||
|
||||
kernel.Plugins.Add(KernelPluginFactory.CreateFromFunctions("MyPlugin", [function1, function2]));
|
||||
|
||||
var service = new AzureOpenAIChatCompletionService("deployment", "https://endpoint", "api-key", "model-id", this._httpClient, this._mockLoggerFactory.Object);
|
||||
var settings = new OpenAIPromptExecutionSettings() { ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions };
|
||||
|
||||
using var response1 = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(OpenAITestHelper.GetTestResponse("chat_completion_streaming_multiple_function_calls_test_response.txt")) };
|
||||
using var response2 = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(OpenAITestHelper.GetTestResponse("chat_completion_streaming_test_response.txt")) };
|
||||
|
||||
this._messageHandlerStub.ResponsesToReturn = [response1, response2];
|
||||
|
||||
// Act & Assert
|
||||
await foreach (var chunk in service.GetStreamingChatMessageContentsAsync([], settings, kernel))
|
||||
{
|
||||
Assert.Equal("Test chat streaming response", chunk.Content);
|
||||
}
|
||||
|
||||
Assert.Equal(2, functionCallCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetStreamingChatMessageContentsWithFunctionCallMaximumAutoInvokeAttemptsAsync()
|
||||
{
|
||||
// Arrange
|
||||
const int DefaultMaximumAutoInvokeAttempts = 5;
|
||||
const int AutoInvokeResponsesCount = 6;
|
||||
|
||||
int functionCallCount = 0;
|
||||
|
||||
var kernel = Kernel.CreateBuilder().Build();
|
||||
var function = KernelFunctionFactory.CreateFromMethod((string location) =>
|
||||
{
|
||||
functionCallCount++;
|
||||
return "Some weather";
|
||||
}, "GetCurrentWeather");
|
||||
|
||||
kernel.Plugins.Add(KernelPluginFactory.CreateFromFunctions("MyPlugin", [function]));
|
||||
|
||||
var service = new AzureOpenAIChatCompletionService("deployment", "https://endpoint", "api-key", "model-id", this._httpClient, this._mockLoggerFactory.Object);
|
||||
var settings = new OpenAIPromptExecutionSettings() { ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions };
|
||||
|
||||
var responses = new List<HttpResponseMessage>();
|
||||
|
||||
for (var i = 0; i < AutoInvokeResponsesCount; i++)
|
||||
{
|
||||
responses.Add(new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(OpenAITestHelper.GetTestResponse("chat_completion_streaming_single_function_call_test_response.txt")) });
|
||||
}
|
||||
|
||||
this._messageHandlerStub.ResponsesToReturn = responses;
|
||||
|
||||
// Act & Assert
|
||||
await foreach (var chunk in service.GetStreamingChatMessageContentsAsync([], settings, kernel))
|
||||
{
|
||||
Assert.Equal("Test chat streaming response", chunk.Content);
|
||||
}
|
||||
|
||||
Assert.Equal(DefaultMaximumAutoInvokeAttempts, functionCallCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetStreamingChatMessageContentsWithRequiredFunctionCallAsync()
|
||||
{
|
||||
// Arrange
|
||||
int functionCallCount = 0;
|
||||
|
||||
var kernel = Kernel.CreateBuilder().Build();
|
||||
var function = KernelFunctionFactory.CreateFromMethod((string location) =>
|
||||
{
|
||||
functionCallCount++;
|
||||
return "Some weather";
|
||||
}, "GetCurrentWeather");
|
||||
|
||||
var plugin = KernelPluginFactory.CreateFromFunctions("MyPlugin", [function]);
|
||||
var openAIFunction = plugin.GetFunctionsMetadata().First().ToOpenAIFunction();
|
||||
|
||||
kernel.Plugins.Add(plugin);
|
||||
|
||||
var service = new AzureOpenAIChatCompletionService("deployment", "https://endpoint", "api-key", "model-id", this._httpClient, this._mockLoggerFactory.Object);
|
||||
var settings = new OpenAIPromptExecutionSettings() { ToolCallBehavior = ToolCallBehavior.RequireFunction(openAIFunction, autoInvoke: true) };
|
||||
|
||||
using var response1 = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(OpenAITestHelper.GetTestResponse("chat_completion_streaming_single_function_call_test_response.txt")) };
|
||||
using var response2 = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(OpenAITestHelper.GetTestResponse("chat_completion_streaming_test_response.txt")) };
|
||||
|
||||
this._messageHandlerStub.ResponsesToReturn = [response1, response2];
|
||||
|
||||
// Act & Assert
|
||||
await foreach (var chunk in service.GetStreamingChatMessageContentsAsync([], settings, kernel))
|
||||
{
|
||||
Assert.Equal("Test chat streaming response", chunk.Content);
|
||||
}
|
||||
|
||||
Assert.Equal(1, functionCallCount);
|
||||
|
||||
var requestContents = this._messageHandlerStub.RequestContents;
|
||||
|
||||
Assert.Equal(2, requestContents.Count);
|
||||
|
||||
requestContents.ForEach(Assert.NotNull);
|
||||
|
||||
var firstContent = Encoding.UTF8.GetString(requestContents[0]!);
|
||||
var secondContent = Encoding.UTF8.GetString(requestContents[1]!);
|
||||
|
||||
var firstContentJson = JsonSerializer.Deserialize<JsonElement>(firstContent);
|
||||
var secondContentJson = JsonSerializer.Deserialize<JsonElement>(secondContent);
|
||||
|
||||
Assert.Equal(1, firstContentJson.GetProperty("tools").GetArrayLength());
|
||||
Assert.Equal("MyPlugin_GetCurrentWeather", firstContentJson.GetProperty("tool_choice").GetProperty("function").GetProperty("name").GetString());
|
||||
|
||||
Assert.Equal("none", secondContentJson.GetProperty("tool_choice").GetString());
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this._httpClient.Dispose();
|
||||
this._messageHandlerStub.Dispose();
|
||||
}
|
||||
|
||||
public static TheoryData<ToolCallBehavior> ToolCallBehaviors => new()
|
||||
{
|
||||
ToolCallBehavior.EnableKernelFunctions,
|
||||
ToolCallBehavior.AutoInvokeKernelFunctions
|
||||
};
|
||||
|
||||
public static TheoryData<object, string?> ResponseFormats => new()
|
||||
{
|
||||
{ new FakeChatCompletionsResponseFormat(), null },
|
||||
{ "json_object", "json_object" },
|
||||
{ "text", "text" }
|
||||
};
|
||||
|
||||
private sealed class FakeChatCompletionsResponseFormat : ChatCompletionsResponseFormat { }
|
||||
}
|
||||
+78
-2
@@ -3,14 +3,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Azure.AI.OpenAI;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Microsoft.SemanticKernel.TextGeneration;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace SemanticKernel.Connectors.UnitTests.OpenAI.ChatCompletion;
|
||||
@@ -18,17 +23,19 @@ namespace SemanticKernel.Connectors.UnitTests.OpenAI.ChatCompletion;
|
||||
/// <summary>
|
||||
/// Unit tests for <see cref="OpenAIChatCompletionService"/>
|
||||
/// </summary>
|
||||
public sealed class OpenAIChatCompletionTests : IDisposable
|
||||
public sealed class OpenAIChatCompletionServiceTests : IDisposable
|
||||
{
|
||||
private readonly HttpMessageHandlerStub _messageHandlerStub;
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly OpenAIFunction _timepluginDate, _timepluginNow;
|
||||
private readonly OpenAIPromptExecutionSettings _executionSettings;
|
||||
private readonly Mock<ILoggerFactory> _mockLoggerFactory;
|
||||
|
||||
public OpenAIChatCompletionTests()
|
||||
public OpenAIChatCompletionServiceTests()
|
||||
{
|
||||
this._messageHandlerStub = new HttpMessageHandlerStub();
|
||||
this._httpClient = new HttpClient(this._messageHandlerStub, false);
|
||||
this._mockLoggerFactory = new Mock<ILoggerFactory>();
|
||||
|
||||
IList<KernelFunctionMetadata> functions = KernelPluginFactory.CreateFromFunctions("TimePlugin", new[]
|
||||
{
|
||||
@@ -45,6 +52,37 @@ public sealed class OpenAIChatCompletionTests : IDisposable
|
||||
};
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void ConstructorWithApiKeyWorksCorrectly(bool includeLoggerFactory)
|
||||
{
|
||||
// Arrange & Act
|
||||
var service = includeLoggerFactory ?
|
||||
new OpenAIChatCompletionService("model-id", "api-key", "organization", loggerFactory: this._mockLoggerFactory.Object) :
|
||||
new OpenAIChatCompletionService("model-id", "api-key", "organization");
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(service);
|
||||
Assert.Equal("model-id", service.Attributes["ModelId"]);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void ConstructorWithOpenAIClientWorksCorrectly(bool includeLoggerFactory)
|
||||
{
|
||||
// Arrange & Act
|
||||
var client = new OpenAIClient("key");
|
||||
var service = includeLoggerFactory ?
|
||||
new OpenAIChatCompletionService("model-id", client, loggerFactory: this._mockLoggerFactory.Object) :
|
||||
new OpenAIChatCompletionService("model-id", client);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(service);
|
||||
Assert.Equal("model-id", service.Attributes["ModelId"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ItCreatesCorrectFunctionToolCallsWhenUsingAutoAsync()
|
||||
{
|
||||
@@ -163,6 +201,44 @@ public sealed class OpenAIChatCompletionTests : IDisposable
|
||||
Assert.Equal("gpt-3.5-turbo", textContent.ModelId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetStreamingTextContentsWorksCorrectlyAsync()
|
||||
{
|
||||
// Arrange
|
||||
var service = new OpenAIChatCompletionService("model-id", "api-key", "organization", this._httpClient);
|
||||
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(OpenAITestHelper.GetTestResponse("chat_completion_streaming_test_response.txt")));
|
||||
|
||||
this._messageHandlerStub.ResponseToReturn = new HttpResponseMessage(HttpStatusCode.OK)
|
||||
{
|
||||
Content = new StreamContent(stream)
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
await foreach (var chunk in service.GetStreamingTextContentsAsync("Prompt"))
|
||||
{
|
||||
Assert.Equal("Test chat streaming response", chunk.Text);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetStreamingChatMessageContentsWorksCorrectlyAsync()
|
||||
{
|
||||
// Arrange
|
||||
var service = new OpenAIChatCompletionService("model-id", "api-key", "organization", this._httpClient);
|
||||
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(OpenAITestHelper.GetTestResponse("chat_completion_streaming_test_response.txt")));
|
||||
|
||||
this._messageHandlerStub.ResponseToReturn = new HttpResponseMessage(HttpStatusCode.OK)
|
||||
{
|
||||
Content = new StreamContent(stream)
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
await foreach (var chunk in service.GetStreamingChatMessageContentsAsync([]))
|
||||
{
|
||||
Assert.Equal("Test chat streaming response", chunk.Content);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ItAddsSystemMessageAsync()
|
||||
{
|
||||
+113
-5
@@ -1,11 +1,14 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel.ChatCompletion;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace SemanticKernel.Connectors.UnitTests.OpenAI.ChatCompletionWithData;
|
||||
@@ -19,6 +22,7 @@ public sealed class AzureOpenAIChatCompletionWithDataTests : IDisposable
|
||||
|
||||
private readonly HttpMessageHandlerStub _messageHandlerStub;
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly Mock<ILoggerFactory> _mockLoggerFactory;
|
||||
|
||||
public AzureOpenAIChatCompletionWithDataTests()
|
||||
{
|
||||
@@ -26,6 +30,22 @@ public sealed class AzureOpenAIChatCompletionWithDataTests : IDisposable
|
||||
|
||||
this._messageHandlerStub = new HttpMessageHandlerStub();
|
||||
this._httpClient = new HttpClient(this._messageHandlerStub, false);
|
||||
this._mockLoggerFactory = new Mock<ILoggerFactory>();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void ConstructorWorksCorrectly(bool includeLoggerFactory)
|
||||
{
|
||||
// Arrange & Act
|
||||
var service = includeLoggerFactory ?
|
||||
new AzureOpenAIChatCompletionWithDataService(this._config, this._httpClient, this._mockLoggerFactory.Object) :
|
||||
new AzureOpenAIChatCompletionWithDataService(this._config, this._httpClient);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(service);
|
||||
Assert.Equal("fake-completion-model-id", service.Attributes["ModelId"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -33,10 +53,10 @@ public sealed class AzureOpenAIChatCompletionWithDataTests : IDisposable
|
||||
{
|
||||
// Arrange
|
||||
const string ExpectedUri = "https://fake-completion-endpoint/openai/deployments/fake-completion-model-id/extensions/chat/completions?api-version=fake-api-version";
|
||||
var chatCompletion = new AzureOpenAIChatCompletionWithDataService(this._config, this._httpClient);
|
||||
var service = new AzureOpenAIChatCompletionWithDataService(this._config, this._httpClient);
|
||||
|
||||
// Act
|
||||
await chatCompletion.GetChatMessageContentsAsync(new ChatHistory());
|
||||
await service.GetChatMessageContentsAsync([]);
|
||||
|
||||
// Assert
|
||||
var actualUri = this._messageHandlerStub.RequestUri?.AbsoluteUri;
|
||||
@@ -58,10 +78,10 @@ public sealed class AzureOpenAIChatCompletionWithDataTests : IDisposable
|
||||
var config = this.GetConfig();
|
||||
config.CompletionApiVersion = string.Empty;
|
||||
|
||||
var chatCompletion = new AzureOpenAIChatCompletionWithDataService(config, this._httpClient);
|
||||
var service = new AzureOpenAIChatCompletionWithDataService(config, this._httpClient);
|
||||
|
||||
// Act
|
||||
await chatCompletion.GetChatMessageContentsAsync(new ChatHistory());
|
||||
await service.GetChatMessageContentsAsync([]);
|
||||
|
||||
// Assert
|
||||
var actualUri = this._messageHandlerStub.RequestUri?.AbsoluteUri;
|
||||
@@ -69,6 +89,94 @@ public sealed class AzureOpenAIChatCompletionWithDataTests : IDisposable
|
||||
Assert.Contains("2023-06-01-preview", actualUri, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetChatMessageContentsWorksCorrectlyAsync()
|
||||
{
|
||||
// Arrange
|
||||
var service = new AzureOpenAIChatCompletionWithDataService(this._config, this._httpClient);
|
||||
this._messageHandlerStub.ResponseToReturn = new HttpResponseMessage(HttpStatusCode.OK)
|
||||
{
|
||||
Content = new StringContent(OpenAITestHelper.GetTestResponse("chat_completion_with_data_test_response.json"))
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await service.GetChatMessageContentsAsync([]);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.Count > 0);
|
||||
Assert.Equal("Test chat with data response", result[0].Content);
|
||||
|
||||
var usage = result[0].Metadata?["Usage"] as ChatWithDataUsage;
|
||||
|
||||
Assert.NotNull(usage);
|
||||
Assert.Equal(55, usage.PromptTokens);
|
||||
Assert.Equal(100, usage.CompletionTokens);
|
||||
Assert.Equal(155, usage.TotalTokens);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetStreamingChatMessageContentsWorksCorrectlyAsync()
|
||||
{
|
||||
// Arrange
|
||||
var service = new AzureOpenAIChatCompletionWithDataService(this._config, this._httpClient);
|
||||
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(OpenAITestHelper.GetTestResponse("chat_completion_with_data_streaming_test_response.txt")));
|
||||
|
||||
this._messageHandlerStub.ResponseToReturn = new HttpResponseMessage(HttpStatusCode.OK)
|
||||
{
|
||||
Content = new StreamContent(stream)
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
await foreach (var chunk in service.GetStreamingChatMessageContentsAsync([]))
|
||||
{
|
||||
Assert.Equal("Test chat with data streaming response", chunk.Content);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetTextContentsWorksCorrectlyAsync()
|
||||
{
|
||||
// Arrange
|
||||
var service = new AzureOpenAIChatCompletionWithDataService(this._config, this._httpClient);
|
||||
this._messageHandlerStub.ResponseToReturn = new HttpResponseMessage(HttpStatusCode.OK)
|
||||
{
|
||||
Content = new StringContent(OpenAITestHelper.GetTestResponse("chat_completion_with_data_test_response.json"))
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await service.GetTextContentsAsync("Prompt");
|
||||
|
||||
// Assert
|
||||
Assert.True(result.Count > 0);
|
||||
Assert.Equal("Test chat with data response", result[0].Text);
|
||||
|
||||
var usage = result[0].Metadata?["Usage"] as ChatWithDataUsage;
|
||||
|
||||
Assert.NotNull(usage);
|
||||
Assert.Equal(55, usage.PromptTokens);
|
||||
Assert.Equal(100, usage.CompletionTokens);
|
||||
Assert.Equal(155, usage.TotalTokens);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetStreamingTextContentsWorksCorrectlyAsync()
|
||||
{
|
||||
// Arrange
|
||||
var service = new AzureOpenAIChatCompletionWithDataService(this._config, this._httpClient);
|
||||
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(OpenAITestHelper.GetTestResponse("chat_completion_with_data_streaming_test_response.txt")));
|
||||
|
||||
this._messageHandlerStub.ResponseToReturn = new HttpResponseMessage(HttpStatusCode.OK)
|
||||
{
|
||||
Content = new StreamContent(stream)
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
await foreach (var chunk in service.GetStreamingTextContentsAsync("Prompt"))
|
||||
{
|
||||
Assert.Equal("Test chat with data streaming response", chunk.Text);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this._httpClient.Dispose();
|
||||
|
||||
+45
@@ -13,6 +13,38 @@ namespace SemanticKernel.Connectors.UnitTests.OpenAI.FunctionCalling;
|
||||
|
||||
public sealed class OpenAIFunctionTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(null, null, "", "")]
|
||||
[InlineData("name", "description", "name", "description")]
|
||||
public void ItInitializesOpenAIFunctionParameterCorrectly(string? name, string? description, string expectedName, string expectedDescription)
|
||||
{
|
||||
// Arrange & Act
|
||||
var schema = KernelJsonSchema.Parse("{\"type\": \"object\" }");
|
||||
var functionParameter = new OpenAIFunctionParameter(name, description, true, typeof(string), schema);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedName, functionParameter.Name);
|
||||
Assert.Equal(expectedDescription, functionParameter.Description);
|
||||
Assert.True(functionParameter.IsRequired);
|
||||
Assert.Equal(typeof(string), functionParameter.ParameterType);
|
||||
Assert.Same(schema, functionParameter.Schema);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, "")]
|
||||
[InlineData("description", "description")]
|
||||
public void ItInitializesOpenAIFunctionReturnParameterCorrectly(string? description, string expectedDescription)
|
||||
{
|
||||
// Arrange & Act
|
||||
var schema = KernelJsonSchema.Parse("{\"type\": \"object\" }");
|
||||
var functionParameter = new OpenAIFunctionReturnParameter(description, typeof(string), schema);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedDescription, functionParameter.Description);
|
||||
Assert.Equal(typeof(string), functionParameter.ParameterType);
|
||||
Assert.Same(schema, functionParameter.Schema);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItCanConvertToFunctionDefinitionWithNoPluginName()
|
||||
{
|
||||
@@ -27,6 +59,19 @@ public sealed class OpenAIFunctionTests
|
||||
Assert.Equal(sut.Description, result.Description);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItCanConvertToFunctionDefinitionWithNullParameters()
|
||||
{
|
||||
// Arrange
|
||||
OpenAIFunction sut = new("plugin", "function", "description", null, null);
|
||||
|
||||
// Act
|
||||
var result = sut.ToFunctionDefinition();
|
||||
|
||||
// Assert
|
||||
Assert.Equal("{\"type\":\"object\",\"required\":[],\"properties\":{}}", result.Parameters.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItCanConvertToFunctionDefinitionWithPluginName()
|
||||
{
|
||||
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Azure.Core;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Microsoft.SemanticKernel.Memory;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace SemanticKernel.Connectors.UnitTests.OpenAI;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for <see cref="OpenAIMemoryBuilderExtensions"/> class.
|
||||
/// </summary>
|
||||
public sealed class OpenAIMemoryBuilderExtensionsTests
|
||||
{
|
||||
private readonly Mock<IMemoryStore> _mockMemoryStore = new();
|
||||
|
||||
[Fact]
|
||||
public void AzureOpenAITextEmbeddingGenerationWithApiKeyWorksCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new MemoryBuilder();
|
||||
|
||||
// Act
|
||||
var memory = builder
|
||||
.WithAzureOpenAITextEmbeddingGeneration("deployment-name", "https://endpoint", "api-key", "model-id")
|
||||
.WithMemoryStore(this._mockMemoryStore.Object)
|
||||
.Build();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(memory);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AzureOpenAITextEmbeddingGenerationWithTokenCredentialWorksCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new MemoryBuilder();
|
||||
var credentials = DelegatedTokenCredential.Create((_, _) => new AccessToken());
|
||||
|
||||
// Act
|
||||
var memory = builder
|
||||
.WithAzureOpenAITextEmbeddingGeneration("deployment-name", "https://endpoint", credentials, "model-id")
|
||||
.WithMemoryStore(this._mockMemoryStore.Object)
|
||||
.Build();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(memory);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OpenAITextEmbeddingGenerationWithApiKeyWorksCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new MemoryBuilder();
|
||||
|
||||
// Act
|
||||
var memory = builder
|
||||
.WithOpenAITextEmbeddingGeneration("model-id", "api-key", "organization-id")
|
||||
.WithMemoryStore(this._mockMemoryStore.Object)
|
||||
.Build();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(memory);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user