mirror of
https://github.com/microsoft/semantic-kernel.git
synced 2026-10-12 02:19:06 +00:00
Feature serviceregistry (#993)
### Motivation, Context and Description This PR introduces several changes aimed to simplify the kernel and enhancing its extensibility for AI services management. The changes include the following: 1. Kernel simplification and extensibility: The code responsible for AI services management, such as registration and resolution, has been moved out of the Kernel and KernelConfig classes into a new class called AIServiceProvider. This restructuring promotes the principle of Single Responsibility, ensuring that each class has a clear and focused purpose. 2. Hosting apps customization: With the introduction of the AIServiceProvider, hosting applications now have the flexibility to provide their own implementation of the provider if needed. This promotes extensibility, allowing the hosting apps to tailor the AI service management according to their specific requirements. 3. AI services registration improvements: A new method called WithAiService has been added, which enables the registration of any new AI service that is not currently supported. 4. Improved kernel builder interface: The Add* methods for AI services registration have been moved from the KernelConfig class to the KernelBuilder. This change aligns the interface with other KernelBilder methods, such as WithLogger and WithMemory, creating a more cohesive and intuitive kernel builder interface. --------- Co-authored-by: Shawn Callegari <[email protected]> Co-authored-by: Lee Miller <[email protected]>
This commit is contained in:
co-authored by
Shawn Callegari
Lee Miller
parent
c0ab238f58
commit
af03e00a79
@@ -3,7 +3,6 @@
|
||||
<!-- using Central Package Management feature -->
|
||||
<!-- https://learn.microsoft.com/en-us/nuget/consume-packages/Central-Package-Management -->
|
||||
<Sdk Name="Microsoft.Build.CentralPackageVersions" Version="2.1.3" />
|
||||
|
||||
<!-- Only run 'dotnet format' on dev machines, Release builds. Skip on GitHub Actions -->
|
||||
<!-- as this runs in its own Actions job. -->
|
||||
<Target Name="DotnetFormatOnBuild" BeforeTargets="Build"
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ namespace Microsoft.SemanticKernel.Connectors.AI.HuggingFace.TextEmbedding;
|
||||
/// <summary>
|
||||
/// HuggingFace embedding generation service.
|
||||
/// </summary>
|
||||
public sealed class HuggingFaceTextEmbeddingGeneration : IEmbeddingGeneration<string, float>, IDisposable
|
||||
public sealed class HuggingFaceTextEmbeddingGeneration : ITextEmbeddingGeneration, IDisposable
|
||||
{
|
||||
private const string HttpUserAgent = "Microsoft Semantic Kernel";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- THIS PROPERTY GROUP MUST COME FIRST -->
|
||||
@@ -20,7 +20,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\SemanticKernel.Abstractions\SemanticKernel.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\..\SemanticKernel\SemanticKernel.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using Azure.Core;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -34,6 +35,7 @@ public static class KernelConfigOpenAIExtensions
|
||||
/// <param name="httpClient">Custom <see cref="HttpClient"/> for HTTP requests.</param>
|
||||
/// <param name="logger">Application logger</param>
|
||||
/// <returns>Self instance</returns>
|
||||
[Obsolete("This method is deprecated and will be removed in one of the next SK SDK versions. Please use the corresponding extension method in the KernelBuilder class instead.")]
|
||||
public static KernelConfig AddAzureTextCompletionService(this KernelConfig config,
|
||||
string deploymentName,
|
||||
string endpoint,
|
||||
@@ -66,6 +68,7 @@ public static class KernelConfigOpenAIExtensions
|
||||
/// <param name="httpClient">Custom <see cref="HttpClient"/> for HTTP requests.</param>
|
||||
/// <param name="logger">Application logger</param>
|
||||
/// <returns>Self instance</returns>
|
||||
[Obsolete("This method is deprecated and will be removed in one of the next SK SDK versions. Please use the corresponding extension method in the KernelBuilder class instead.")]
|
||||
public static KernelConfig AddAzureTextCompletionService(this KernelConfig config,
|
||||
string deploymentName,
|
||||
string endpoint,
|
||||
@@ -98,6 +101,7 @@ public static class KernelConfigOpenAIExtensions
|
||||
/// <param name="httpClient">Custom <see cref="HttpClient"/> for HTTP requests.</param>
|
||||
/// <param name="logger">Application logger</param>
|
||||
/// <returns>Self instance</returns>
|
||||
[Obsolete("This method is deprecated and will be removed in one of the next SK SDK versions. Please use the corresponding extension method in the KernelBuilder class instead.")]
|
||||
public static KernelConfig AddOpenAITextCompletionService(this KernelConfig config,
|
||||
string modelId,
|
||||
string apiKey,
|
||||
@@ -134,6 +138,7 @@ public static class KernelConfigOpenAIExtensions
|
||||
/// <param name="httpClient">Custom <see cref="HttpClient"/> for HTTP requests.</param>
|
||||
/// <param name="logger">Application logger</param>
|
||||
/// <returns>Self instance</returns>
|
||||
[Obsolete("This method is deprecated and will be removed in one of the next SK SDK versions. Please use the corresponding extension method in the KernelBuilder class instead.")]
|
||||
public static KernelConfig AddAzureTextEmbeddingGenerationService(this KernelConfig config,
|
||||
string deploymentName,
|
||||
string endpoint,
|
||||
@@ -166,6 +171,7 @@ public static class KernelConfigOpenAIExtensions
|
||||
/// <param name="httpClient">Custom <see cref="HttpClient"/> for HTTP requests.</param>
|
||||
/// <param name="logger">Application logger</param>
|
||||
/// <returns>Self instance</returns>
|
||||
[Obsolete("This method is deprecated and will be removed in one of the next SK SDK versions. Please use the corresponding extension method in the KernelBuilder class instead.")]
|
||||
public static KernelConfig AddAzureTextEmbeddingGenerationService(this KernelConfig config,
|
||||
string deploymentName,
|
||||
string endpoint,
|
||||
@@ -198,6 +204,7 @@ public static class KernelConfigOpenAIExtensions
|
||||
/// <param name="httpClient">Custom <see cref="HttpClient"/> for HTTP requests.</param>
|
||||
/// <param name="logger">Application logger</param>
|
||||
/// <returns>Self instance</returns>
|
||||
[Obsolete("This method is deprecated and will be removed in one of the next SK SDK versions. Please use the corresponding extension method in the KernelBuilder class instead.")]
|
||||
public static KernelConfig AddOpenAITextEmbeddingGenerationService(this KernelConfig config,
|
||||
string modelId,
|
||||
string apiKey,
|
||||
@@ -235,6 +242,7 @@ public static class KernelConfigOpenAIExtensions
|
||||
/// <param name="httpClient">Custom <see cref="HttpClient"/> for HTTP requests.</param>
|
||||
/// <param name="logger">Application logger</param>
|
||||
/// <returns>Self instance</returns>
|
||||
[Obsolete("This method is deprecated and will be removed in one of the next SK SDK versions. Please use the corresponding extension method in the KernelBuilder class instead.")]
|
||||
public static KernelConfig AddAzureChatCompletionService(this KernelConfig config,
|
||||
string deploymentName,
|
||||
string endpoint,
|
||||
@@ -278,6 +286,7 @@ public static class KernelConfigOpenAIExtensions
|
||||
/// <param name="httpClient">Custom <see cref="HttpClient"/> for HTTP requests.</param>
|
||||
/// <param name="logger">Application logger</param>
|
||||
/// <returns>Self instance</returns>
|
||||
[Obsolete("This method is deprecated and will be removed in one of the next SK SDK versions. Please use the corresponding extension method in the KernelBuilder class instead.")]
|
||||
public static KernelConfig AddAzureChatCompletionService(this KernelConfig config,
|
||||
string deploymentName,
|
||||
string endpoint,
|
||||
@@ -325,6 +334,7 @@ public static class KernelConfigOpenAIExtensions
|
||||
/// <param name="httpClient">Custom <see cref="HttpClient"/> for HTTP requests.</param>
|
||||
/// <param name="logger">Application logger</param>
|
||||
/// <returns>Self instance</returns>
|
||||
[Obsolete("This method is deprecated and will be removed in one of the next SK SDK versions. Please use the corresponding extension method in the KernelBuilder class instead.")]
|
||||
public static KernelConfig AddOpenAIChatCompletionService(this KernelConfig config,
|
||||
string modelId,
|
||||
string apiKey,
|
||||
@@ -373,6 +383,7 @@ public static class KernelConfigOpenAIExtensions
|
||||
/// <param name="httpClient">Custom <see cref="HttpClient"/> for HTTP requests.</param>
|
||||
/// <param name="logger">Application logger</param>
|
||||
/// <returns>Self instance</returns>
|
||||
[Obsolete("This method is deprecated and will be removed in one of the next SK SDK versions. Please use the corresponding extension method in the KernelBuilder class instead.")]
|
||||
public static KernelConfig AddOpenAIImageGenerationService(this KernelConfig config,
|
||||
string apiKey,
|
||||
string? orgId = null,
|
||||
|
||||
@@ -0,0 +1,380 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Net.Http;
|
||||
using Azure.Core;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.SemanticKernel.AI.ChatCompletion;
|
||||
using Microsoft.SemanticKernel.AI.Embeddings;
|
||||
using Microsoft.SemanticKernel.AI.TextCompletion;
|
||||
using Microsoft.SemanticKernel.Connectors.AI.OpenAI.ChatCompletion;
|
||||
using Microsoft.SemanticKernel.Connectors.AI.OpenAI.ImageGeneration;
|
||||
using Microsoft.SemanticKernel.Connectors.AI.OpenAI.TextCompletion;
|
||||
using Microsoft.SemanticKernel.Connectors.AI.OpenAI.TextEmbedding;
|
||||
using Microsoft.SemanticKernel.Reliability;
|
||||
|
||||
#pragma warning disable IDE0130
|
||||
// ReSharper disable once CheckNamespace - Using NS of KernelConfig
|
||||
namespace Microsoft.SemanticKernel;
|
||||
#pragma warning restore IDE0130
|
||||
|
||||
public static class OpenAIKernelBuilderExtensions
|
||||
{
|
||||
#region Text Completion
|
||||
|
||||
/// <summary>
|
||||
/// Adds an Azure OpenAI text completion service to the list.
|
||||
/// See https://learn.microsoft.com/azure/cognitive-services/openai for service details.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="KernelBuilder"/> instance</param>
|
||||
/// <param name="deploymentName">Azure OpenAI deployment name, see https://learn.microsoft.com/azure/cognitive-services/openai/how-to/create-resource</param>
|
||||
/// <param name="endpoint">Azure OpenAI deployment URL, see https://learn.microsoft.com/azure/cognitive-services/openai/quickstart</param>
|
||||
/// <param name="apiKey">Azure OpenAI API key, see https://learn.microsoft.com/azure/cognitive-services/openai/quickstart</param>
|
||||
/// <param name="serviceId">A local identifier for the given AI service</param>
|
||||
/// <param name="setAsDefault">Whether the service should be the default for its type.</param>
|
||||
/// <param name="httpClient">Custom <see cref="HttpClient"/> for HTTP requests.</param>
|
||||
/// <returns>Self instance</returns>
|
||||
public static KernelBuilder WithAzureTextCompletionService(this KernelBuilder builder,
|
||||
string deploymentName,
|
||||
string endpoint,
|
||||
string apiKey,
|
||||
string? serviceId = null,
|
||||
bool setAsDefault = false,
|
||||
HttpClient? httpClient = null)
|
||||
{
|
||||
builder.WithAIService<ITextCompletion>(serviceId, (parameters) =>
|
||||
new AzureTextCompletion(
|
||||
deploymentName,
|
||||
endpoint,
|
||||
apiKey,
|
||||
httpClient ?? parameters.Config.HttpHandlerFactory.CreateHttpClient(parameters.Logger),
|
||||
parameters.Logger),
|
||||
setAsDefault);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an Azure OpenAI text completion service to the list.
|
||||
/// See https://learn.microsoft.com/azure/cognitive-services/openai for service details.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="KernelBuilder"/> instance</param>
|
||||
/// <param name="deploymentName">Azure OpenAI deployment name, see https://learn.microsoft.com/azure/cognitive-services/openai/how-to/create-resource</param>
|
||||
/// <param name="endpoint">Azure OpenAI deployment URL, see https://learn.microsoft.com/azure/cognitive-services/openai/quickstart</param>
|
||||
/// <param name="credentials">Token credentials, e.g. DefaultAzureCredential, ManagedIdentityCredential, EnvironmentCredential, etc.</param>
|
||||
/// <param name="serviceId">A local identifier for the given AI service</param>
|
||||
/// <param name="setAsDefault">Whether the service should be the default for its type.</param>
|
||||
/// <param name="httpClient">Custom <see cref="HttpClient"/> for HTTP requests.</param>
|
||||
/// <returns>Self instance</returns>
|
||||
public static KernelBuilder WithAzureTextCompletionService(this KernelBuilder builder,
|
||||
string deploymentName,
|
||||
string endpoint,
|
||||
TokenCredential credentials,
|
||||
string? serviceId = null,
|
||||
bool setAsDefault = false,
|
||||
HttpClient? httpClient = null)
|
||||
{
|
||||
builder.WithAIService<ITextCompletion>(serviceId, (parameters) =>
|
||||
new AzureTextCompletion(
|
||||
deploymentName,
|
||||
endpoint,
|
||||
credentials,
|
||||
httpClient ?? parameters.Config.HttpHandlerFactory.CreateHttpClient(parameters.Logger),
|
||||
parameters.Logger),
|
||||
setAsDefault);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the OpenAI text completion service to the list.
|
||||
/// See https://platform.openai.com/docs for service details.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="KernelBuilder"/> instance</param>
|
||||
/// <param name="modelId">OpenAI model name, see https://platform.openai.com/docs/models</param>
|
||||
/// <param name="apiKey">OpenAI API key, see https://platform.openai.com/account/api-keys</param>
|
||||
/// <param name="orgId">OpenAI organization id. This is usually optional unless your account belongs to multiple organizations.</param>
|
||||
/// <param name="serviceId">A local identifier for the given AI service</param>
|
||||
/// <param name="setAsDefault">Whether the service should be the default for its type.</param>
|
||||
/// <param name="httpClient">Custom <see cref="HttpClient"/> for HTTP requests.</param>
|
||||
/// <returns>Self instance</returns>
|
||||
public static KernelBuilder WithOpenAITextCompletionService(this KernelBuilder builder,
|
||||
string modelId,
|
||||
string apiKey,
|
||||
string? orgId = null,
|
||||
string? serviceId = null,
|
||||
bool setAsDefault = false,
|
||||
HttpClient? httpClient = null)
|
||||
{
|
||||
builder.WithAIService<ITextCompletion>(serviceId, (parameters) =>
|
||||
new OpenAITextCompletion(
|
||||
modelId,
|
||||
apiKey,
|
||||
orgId,
|
||||
httpClient ?? parameters.Config.HttpHandlerFactory.CreateHttpClient(parameters.Logger),
|
||||
parameters.Logger),
|
||||
setAsDefault);
|
||||
return builder;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Text Embedding
|
||||
|
||||
/// <summary>
|
||||
/// Adds an Azure OpenAI text embeddings service to the list.
|
||||
/// See https://learn.microsoft.com/azure/cognitive-services/openai for service details.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="KernelBuilder"/> instance</param>
|
||||
/// <param name="deploymentName">Azure OpenAI deployment name, see https://learn.microsoft.com/azure/cognitive-services/openai/how-to/create-resource</param>
|
||||
/// <param name="endpoint">Azure OpenAI deployment URL, see https://learn.microsoft.com/azure/cognitive-services/openai/quickstart</param>
|
||||
/// <param name="apiKey">Azure OpenAI API key, see https://learn.microsoft.com/azure/cognitive-services/openai/quickstart</param>
|
||||
/// <param name="serviceId">A local identifier for the given AI service</param>
|
||||
/// <param name="setAsDefault">Whether the service should be the default for its type.</param>
|
||||
/// <param name="httpClient">Custom <see cref="HttpClient"/> for HTTP requests.</param>
|
||||
/// <returns>Self instance</returns>
|
||||
public static KernelBuilder WithAzureTextEmbeddingGenerationService(this KernelBuilder builder,
|
||||
string deploymentName,
|
||||
string endpoint,
|
||||
string apiKey,
|
||||
string? serviceId = null,
|
||||
bool setAsDefault = false,
|
||||
HttpClient? httpClient = null)
|
||||
{
|
||||
builder.WithAIService<ITextEmbeddingGeneration>(serviceId, (parameters) =>
|
||||
new AzureTextEmbeddingGeneration(
|
||||
deploymentName,
|
||||
endpoint,
|
||||
apiKey,
|
||||
httpClient ?? parameters.Config.HttpHandlerFactory.CreateHttpClient(parameters.Logger),
|
||||
parameters.Logger),
|
||||
setAsDefault);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an Azure OpenAI text embeddings service to the list.
|
||||
/// See https://learn.microsoft.com/azure/cognitive-services/openai for service details.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="KernelBuilder"/> instance</param>
|
||||
/// <param name="deploymentName">Azure OpenAI deployment name, see https://learn.microsoft.com/azure/cognitive-services/openai/how-to/create-resource</param>
|
||||
/// <param name="endpoint">Azure OpenAI deployment URL, see https://learn.microsoft.com/azure/cognitive-services/openai/quickstart</param>
|
||||
/// <param name="credential">Token credentials, e.g. DefaultAzureCredential, ManagedIdentityCredential, EnvironmentCredential, etc.</param>
|
||||
/// <param name="serviceId">A local identifier for the given AI service</param>
|
||||
/// <param name="setAsDefault">Whether the service should be the default for its type.</param>
|
||||
/// <param name="httpClient">Custom <see cref="HttpClient"/> for HTTP requests.</param>
|
||||
/// <returns>Self instance</returns>
|
||||
public static KernelBuilder WithAzureTextEmbeddingGenerationService(this KernelBuilder builder,
|
||||
string deploymentName,
|
||||
string endpoint,
|
||||
TokenCredential credential,
|
||||
string? serviceId = null,
|
||||
bool setAsDefault = false,
|
||||
HttpClient? httpClient = null)
|
||||
{
|
||||
builder.WithAIService<ITextEmbeddingGeneration>(serviceId, (parameters) =>
|
||||
new AzureTextEmbeddingGeneration(
|
||||
deploymentName,
|
||||
endpoint,
|
||||
credential,
|
||||
httpClient ?? parameters.Config.HttpHandlerFactory.CreateHttpClient(parameters.Logger),
|
||||
parameters.Logger),
|
||||
setAsDefault);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the OpenAI text embeddings service to the list.
|
||||
/// See https://platform.openai.com/docs for service details.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="KernelBuilder"/> instance</param>
|
||||
/// <param name="modelId">OpenAI model name, see https://platform.openai.com/docs/models</param>
|
||||
/// <param name="apiKey">OpenAI API key, see https://platform.openai.com/account/api-keys</param>
|
||||
/// <param name="orgId">OpenAI organization id. This is usually optional unless your account belongs to multiple organizations.</param>
|
||||
/// <param name="serviceId">A local identifier for the given AI service</param>
|
||||
/// <param name="setAsDefault">Whether the service should be the default for its type.</param>
|
||||
/// <param name="httpClient">Custom <see cref="HttpClient"/> for HTTP requests.</param>
|
||||
/// <returns>Self instance</returns>
|
||||
public static KernelBuilder WithOpenAITextEmbeddingGenerationService(this KernelBuilder builder,
|
||||
string modelId,
|
||||
string apiKey,
|
||||
string? orgId = null,
|
||||
string? serviceId = null,
|
||||
bool setAsDefault = false,
|
||||
HttpClient? httpClient = null)
|
||||
{
|
||||
builder.WithAIService<ITextEmbeddingGeneration>(serviceId, (parameters) =>
|
||||
new OpenAITextEmbeddingGeneration(
|
||||
modelId,
|
||||
apiKey,
|
||||
orgId,
|
||||
httpClient ?? parameters.Config.HttpHandlerFactory.CreateHttpClient(parameters.Logger),
|
||||
parameters.Logger),
|
||||
setAsDefault);
|
||||
return builder;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Chat Completion
|
||||
|
||||
/// <summary>
|
||||
/// Adds the Azure OpenAI ChatGPT completion service to the list.
|
||||
/// See https://platform.openai.com/docs for service details.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="KernelBuilder"/> instance</param>
|
||||
/// <param name="deploymentName">Azure OpenAI deployment name, see https://learn.microsoft.com/azure/cognitive-services/openai/how-to/create-resource</param>
|
||||
/// <param name="endpoint">Azure OpenAI deployment URL, see https://learn.microsoft.com/azure/cognitive-services/openai/quickstart</param>
|
||||
/// <param name="apiKey">Azure OpenAI API key, see https://learn.microsoft.com/azure/cognitive-services/openai/quickstart</param>
|
||||
/// <param name="alsoAsTextCompletion">Whether to use the service also for text completion, if supported</param>
|
||||
/// <param name="serviceId">A local identifier for the given AI service</param>
|
||||
/// <param name="setAsDefault">Whether the service should be the default for its type.</param>
|
||||
/// <param name="httpClient">Custom <see cref="HttpClient"/> for HTTP requests.</param>
|
||||
/// <returns>Self instance</returns>
|
||||
public static KernelBuilder WithAzureChatCompletionService(this KernelBuilder builder,
|
||||
string deploymentName,
|
||||
string endpoint,
|
||||
string apiKey,
|
||||
bool alsoAsTextCompletion = true,
|
||||
string? serviceId = null,
|
||||
bool setAsDefault = false,
|
||||
HttpClient? httpClient = null)
|
||||
{
|
||||
AzureChatCompletion Factory((ILogger Logger, KernelConfig Config) parameters) => new(
|
||||
deploymentName,
|
||||
endpoint,
|
||||
apiKey,
|
||||
httpClient ?? parameters.Config.HttpHandlerFactory.CreateHttpClient(parameters.Logger),
|
||||
parameters.Logger);
|
||||
|
||||
builder.WithAIService<IChatCompletion>(serviceId, Factory, setAsDefault);
|
||||
|
||||
// If the class implements the text completion interface, allow to use it also for semantic functions
|
||||
if (alsoAsTextCompletion && typeof(ITextCompletion).IsAssignableFrom(typeof(AzureChatCompletion)))
|
||||
{
|
||||
builder.WithAIService<ITextCompletion>(serviceId, Factory, setAsDefault);
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the Azure OpenAI ChatGPT completion service to the list.
|
||||
/// See https://platform.openai.com/docs for service details.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="KernelBuilder"/> instance</param>
|
||||
/// <param name="deploymentName">Azure OpenAI deployment name, see https://learn.microsoft.com/azure/cognitive-services/openai/how-to/create-resource</param>
|
||||
/// <param name="endpoint">Azure OpenAI deployment URL, see https://learn.microsoft.com/azure/cognitive-services/openai/quickstart</param>
|
||||
/// <param name="credentials">Token credentials, e.g. DefaultAzureCredential, ManagedIdentityCredential, EnvironmentCredential, etc.</param>
|
||||
/// <param name="alsoAsTextCompletion">Whether to use the service also for text completion, if supported</param>
|
||||
/// <param name="serviceId">A local identifier for the given AI service</param>
|
||||
/// <param name="setAsDefault">Whether the service should be the default for its type.</param>
|
||||
/// <param name="httpClient">Custom <see cref="HttpClient"/> for HTTP requests.</param>
|
||||
/// <returns>Self instance</returns>
|
||||
public static KernelBuilder WithAzureChatCompletionService(this KernelBuilder builder,
|
||||
string deploymentName,
|
||||
string endpoint,
|
||||
TokenCredential credentials,
|
||||
bool alsoAsTextCompletion = true,
|
||||
string? serviceId = null,
|
||||
bool setAsDefault = false,
|
||||
HttpClient? httpClient = null)
|
||||
{
|
||||
AzureChatCompletion Factory((ILogger Logger, KernelConfig Config) parameters) => new(
|
||||
deploymentName,
|
||||
endpoint,
|
||||
credentials,
|
||||
httpClient ?? parameters.Config.HttpHandlerFactory.CreateHttpClient(parameters.Logger),
|
||||
parameters.Logger);
|
||||
|
||||
builder.WithAIService<IChatCompletion>(serviceId, Factory, setAsDefault);
|
||||
|
||||
// If the class implements the text completion interface, allow to use it also for semantic functions
|
||||
if (alsoAsTextCompletion && typeof(ITextCompletion).IsAssignableFrom(typeof(AzureChatCompletion)))
|
||||
{
|
||||
builder.WithAIService<ITextCompletion>(serviceId, Factory, setAsDefault);
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the OpenAI ChatGPT completion service to the list.
|
||||
/// See https://platform.openai.com/docs for service details.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="KernelBuilder"/> instance</param>
|
||||
/// <param name="modelId">OpenAI model name, see https://platform.openai.com/docs/models</param>
|
||||
/// <param name="apiKey">OpenAI API key, see https://platform.openai.com/account/api-keys</param>
|
||||
/// <param name="orgId">OpenAI organization id. This is usually optional unless your account belongs to multiple organizations.</param>
|
||||
/// <param name="serviceId">A local identifier for the given AI service</param>
|
||||
/// <param name="alsoAsTextCompletion">Whether to use the service also for text completion, if supported</param>
|
||||
/// <param name="setAsDefault">Whether the service should be the default for its type.</param>
|
||||
/// <param name="httpClient">Custom <see cref="HttpClient"/> for HTTP requests.</param>
|
||||
/// <returns>Self instance</returns>
|
||||
public static KernelBuilder WithOpenAIChatCompletionService(this KernelBuilder builder,
|
||||
string modelId,
|
||||
string apiKey,
|
||||
string? orgId = null,
|
||||
string? serviceId = null,
|
||||
bool alsoAsTextCompletion = true,
|
||||
bool setAsDefault = false,
|
||||
HttpClient? httpClient = null)
|
||||
{
|
||||
OpenAIChatCompletion Factory((ILogger Logger, KernelConfig Config) parameters) => new(
|
||||
modelId,
|
||||
apiKey,
|
||||
orgId,
|
||||
httpClient ?? parameters.Config.HttpHandlerFactory.CreateHttpClient(parameters.Logger),
|
||||
parameters.Logger);
|
||||
|
||||
builder.WithAIService<IChatCompletion>(serviceId, Factory, setAsDefault);
|
||||
|
||||
// If the class implements the text completion interface, allow to use it also for semantic functions
|
||||
if (alsoAsTextCompletion && typeof(ITextCompletion).IsAssignableFrom(typeof(OpenAIChatCompletion)))
|
||||
{
|
||||
builder.WithAIService<ITextCompletion>(serviceId, Factory, setAsDefault);
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
private static HttpClient CreateHttpClient(this IDelegatingHandlerFactory handlerFactory, ILogger? logger)
|
||||
{
|
||||
var retryHandler = handlerFactory.Create(logger);
|
||||
retryHandler.InnerHandler = new HttpClientHandler { CheckCertificateRevocationList = true };
|
||||
return new HttpClient(retryHandler);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Images
|
||||
|
||||
/// <summary>
|
||||
/// Add the OpenAI DallE image generation service to the list
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="KernelBuilder"/> instance</param>
|
||||
/// <param name="apiKey">OpenAI API key, see https://platform.openai.com/account/api-keys</param>
|
||||
/// <param name="orgId">OpenAI organization id. This is usually optional unless your account belongs to multiple organizations.</param>
|
||||
/// <param name="serviceId">A local identifier for the given AI service</param>
|
||||
/// <param name="setAsDefault">Whether the service should be the default for its type.</param>
|
||||
/// <param name="httpClient">Custom <see cref="HttpClient"/> for HTTP requests.</param>
|
||||
/// <returns>Self instance</returns>
|
||||
public static KernelBuilder WithOpenAIImageGenerationService(this KernelBuilder builder,
|
||||
string apiKey,
|
||||
string? orgId = null,
|
||||
string? serviceId = null,
|
||||
bool setAsDefault = false,
|
||||
HttpClient? httpClient = null)
|
||||
{
|
||||
builder.WithAIService(serviceId, ((ILogger Logger, KernelConfig Config) parameters) =>
|
||||
new OpenAIImageGeneration(
|
||||
apiKey,
|
||||
orgId,
|
||||
httpClient ?? parameters.Config.HttpHandlerFactory.CreateHttpClient(parameters.Logger),
|
||||
parameters.Logger),
|
||||
setAsDefault);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
+1
-1
@@ -14,7 +14,7 @@ namespace Microsoft.SemanticKernel.Connectors.AI.OpenAI.TextEmbedding;
|
||||
/// <summary>
|
||||
/// Azure OpenAI text embedding service.
|
||||
/// </summary>
|
||||
public sealed class AzureTextEmbeddingGeneration : AzureOpenAIClientBase, IEmbeddingGeneration<string, float>
|
||||
public sealed class AzureTextEmbeddingGeneration : AzureOpenAIClientBase, ITextEmbeddingGeneration
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new AzureTextCompletion client instance using API Key auth
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ namespace Microsoft.SemanticKernel.Connectors.AI.OpenAI.TextEmbedding;
|
||||
/// <summary>
|
||||
/// OpenAI text embedding service.
|
||||
/// </summary>
|
||||
public sealed class OpenAITextEmbeddingGeneration : OpenAIClientBase, IEmbeddingGeneration<string, float>
|
||||
public sealed class OpenAITextEmbeddingGeneration : OpenAIClientBase, ITextEmbeddingGeneration
|
||||
{
|
||||
/// <summary>
|
||||
/// Create an instance of the OpenAI text embedding connector
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.AI.Embeddings;
|
||||
using Microsoft.SemanticKernel.AI.TextCompletion;
|
||||
using Microsoft.SemanticKernel.Connectors.AI.OpenAI.TextCompletion;
|
||||
using Xunit;
|
||||
|
||||
namespace SemanticKernel.Connectors.UnitTests.OpenAI;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests of <see cref="OpenAIKernelBuilderExtensions"/>.
|
||||
/// </summary>
|
||||
public class AIServicesOpenAIExtensionsTests
|
||||
{
|
||||
[Fact]
|
||||
public void ItSucceedsWhenAddingDifferentServiceTypeWithSameId()
|
||||
{
|
||||
KernelBuilder targetBuilder = Kernel.Builder;
|
||||
targetBuilder.WithAzureTextCompletionService("depl", "https://url", "key", "azure");
|
||||
targetBuilder.WithAzureTextEmbeddingGenerationService("depl2", "https://url", "key", "azure");
|
||||
|
||||
IKernel targetKernel = targetBuilder.Build();
|
||||
Assert.NotNull(targetKernel.GetService<ITextCompletion>("azure"));
|
||||
Assert.NotNull(targetKernel.GetService<ITextEmbeddingGeneration>("azure"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItTellsIfAServiceIsAvailable()
|
||||
{
|
||||
KernelBuilder targetBuilder = Kernel.Builder;
|
||||
targetBuilder.WithAzureTextCompletionService("depl", "https://url", "key", serviceId: "azure");
|
||||
targetBuilder.WithOpenAITextCompletionService("model", "apikey", serviceId: "oai");
|
||||
targetBuilder.WithAzureTextEmbeddingGenerationService("depl2", "https://url2", "key", serviceId: "azure");
|
||||
targetBuilder.WithOpenAITextEmbeddingGenerationService("model2", "apikey2", serviceId: "oai2");
|
||||
|
||||
// Assert
|
||||
IKernel targetKernel = targetBuilder.Build();
|
||||
Assert.NotNull(targetKernel.GetService<ITextCompletion>("azure"));
|
||||
Assert.NotNull(targetKernel.GetService<ITextCompletion>("oai"));
|
||||
Assert.NotNull(targetKernel.GetService<ITextEmbeddingGeneration>("azure"));
|
||||
Assert.NotNull(targetKernel.GetService<ITextCompletion>("oai"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItCanOverwriteServices()
|
||||
{
|
||||
// Arrange
|
||||
KernelBuilder targetBuilder = Kernel.Builder;
|
||||
|
||||
// Act - Assert no exception occurs
|
||||
targetBuilder.WithAzureTextCompletionService("dep", "https://localhost", "key", serviceId: "one");
|
||||
targetBuilder.WithAzureTextCompletionService("dep", "https://localhost", "key", serviceId: "one");
|
||||
|
||||
targetBuilder.WithOpenAITextCompletionService("model", "key", serviceId: "one");
|
||||
targetBuilder.WithOpenAITextCompletionService("model", "key", serviceId: "one");
|
||||
|
||||
targetBuilder.WithAzureTextEmbeddingGenerationService("dep", "https://localhost", "key", serviceId: "one");
|
||||
targetBuilder.WithAzureTextEmbeddingGenerationService("dep", "https://localhost", "key", serviceId: "one");
|
||||
|
||||
targetBuilder.WithOpenAITextEmbeddingGenerationService("model", "key", serviceId: "one");
|
||||
targetBuilder.WithOpenAITextEmbeddingGenerationService("model", "key", serviceId: "one");
|
||||
|
||||
targetBuilder.WithAzureChatCompletionService("dep", "https://localhost", "key", serviceId: "one");
|
||||
targetBuilder.WithAzureChatCompletionService("dep", "https://localhost", "key", serviceId: "one");
|
||||
|
||||
targetBuilder.WithOpenAIChatCompletionService("model", "key", serviceId: "one");
|
||||
targetBuilder.WithOpenAIChatCompletionService("model", "key", serviceId: "one");
|
||||
|
||||
targetBuilder.WithOpenAIImageGenerationService("model", "key", serviceId: "one");
|
||||
targetBuilder.WithOpenAIImageGenerationService("model", "key", serviceId: "one");
|
||||
|
||||
targetBuilder.WithDefaultAIService(new OpenAITextCompletion("model", "key"));
|
||||
targetBuilder.WithDefaultAIService(new OpenAITextCompletion("model", "key"));
|
||||
|
||||
targetBuilder.WithDefaultAIService((_) => new OpenAITextCompletion("model", "key"));
|
||||
targetBuilder.WithDefaultAIService((_) => new OpenAITextCompletion("model", "key"));
|
||||
|
||||
targetBuilder.WithAIService<ITextCompletion>("one", new OpenAITextCompletion("model", "key"));
|
||||
targetBuilder.WithAIService<ITextCompletion>("one", new OpenAITextCompletion("model", "key"));
|
||||
|
||||
targetBuilder.WithAIService<ITextCompletion>("one", (_) => new OpenAITextCompletion("model", "key"));
|
||||
targetBuilder.WithAIService<ITextCompletion>("one", (_) => new OpenAITextCompletion("model", "key"));
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ namespace SemanticKernel.Connectors.UnitTests.OpenAI;
|
||||
/// <summary>
|
||||
/// Unit tests of <see cref="KernelConfigOpenAIExtensions"/>.
|
||||
/// </summary>
|
||||
[System.Obsolete("All the methods of this class are deprecated and it will be removed in one of the next SK SDK versions.")]
|
||||
public class KernelConfigOpenAIExtensionsTests
|
||||
{
|
||||
[Fact]
|
||||
|
||||
@@ -36,9 +36,6 @@ public sealed class OpenAICompletionTests : IDisposable
|
||||
.AddEnvironmentVariables()
|
||||
.AddUserSecrets<OpenAICompletionTests>()
|
||||
.Build();
|
||||
|
||||
this._serviceConfiguration.Add(AIServiceType.OpenAI, this.ConfigureOpenAI);
|
||||
this._serviceConfiguration.Add(AIServiceType.AzureOpenAI, this.ConfigureAzureOpenAI);
|
||||
}
|
||||
|
||||
[Theory(Skip = "OpenAI will often throttle requests. This test is for manual verification.")]
|
||||
@@ -46,9 +43,17 @@ public sealed class OpenAICompletionTests : IDisposable
|
||||
public async Task OpenAITestAsync(string prompt, string expectedAnswerContains)
|
||||
{
|
||||
// Arrange
|
||||
IKernel target = Kernel.Builder.WithLogger(this._logger).Build();
|
||||
var openAIConfiguration = this._configuration.GetSection("OpenAI").Get<OpenAIConfiguration>();
|
||||
Assert.NotNull(openAIConfiguration);
|
||||
|
||||
this.ConfigureOpenAI(target);
|
||||
IKernel target = Kernel.Builder
|
||||
.WithLogger(this._logger)
|
||||
.WithOpenAITextCompletionService(
|
||||
serviceId: openAIConfiguration.ServiceId,
|
||||
modelId: openAIConfiguration.ModelId,
|
||||
apiKey: openAIConfiguration.ApiKey,
|
||||
setAsDefault: true)
|
||||
.Build();
|
||||
|
||||
IDictionary<string, ISKFunction> skill = TestHelpers.GetSkills(target, "ChatSkill");
|
||||
|
||||
@@ -64,9 +69,11 @@ public sealed class OpenAICompletionTests : IDisposable
|
||||
public async Task OpenAIChatAsTextTestAsync(string prompt, string expectedAnswerContains)
|
||||
{
|
||||
// Arrange
|
||||
IKernel target = Kernel.Builder.WithLogger(this._logger).Build();
|
||||
KernelBuilder builder = Kernel.Builder.WithLogger(this._logger);
|
||||
|
||||
this.ConfigureChatOpenAI(target);
|
||||
this.ConfigureChatOpenAI(builder);
|
||||
|
||||
IKernel target = builder.Build();
|
||||
|
||||
IDictionary<string, ISKFunction> skill = TestHelpers.GetSkills(target, "ChatSkill");
|
||||
|
||||
@@ -81,8 +88,10 @@ public sealed class OpenAICompletionTests : IDisposable
|
||||
public async Task CanUseOpenAiChatForTextCompletionAsync()
|
||||
{
|
||||
// Note: we use OpenAi Chat Completion and GPT 3.5 Turbo
|
||||
IKernel target = Kernel.Builder.WithLogger(this._logger).Build();
|
||||
this.ConfigureChatOpenAI(target);
|
||||
KernelBuilder builder = Kernel.Builder.WithLogger(this._logger);
|
||||
this.ConfigureChatOpenAI(builder);
|
||||
|
||||
IKernel target = builder.Build();
|
||||
|
||||
var func = target.CreateSemanticFunction(
|
||||
"List the two planets after '{{$input}}', excluding moons, using bullet points.");
|
||||
@@ -101,17 +110,23 @@ public sealed class OpenAICompletionTests : IDisposable
|
||||
public async Task AzureOpenAITestAsync(bool useChatModel, string prompt, string expectedAnswerContains)
|
||||
{
|
||||
// Arrange
|
||||
IKernel target = Kernel.Builder.WithLogger(this._logger).Build();
|
||||
|
||||
var azureOpenAIConfiguration = this._configuration.GetSection("AzureOpenAI").Get<AzureOpenAIConfiguration>();
|
||||
Assert.NotNull(azureOpenAIConfiguration);
|
||||
|
||||
var builder = Kernel.Builder.WithLogger(this._logger);
|
||||
|
||||
if (useChatModel)
|
||||
{
|
||||
this.ConfigureAzureOpenAIChatAsText(target);
|
||||
this.ConfigureAzureOpenAIChatAsText(builder);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.ConfigureAzureOpenAI(target);
|
||||
this.ConfigureAzureOpenAI(builder);
|
||||
}
|
||||
|
||||
IKernel target = builder.Build();
|
||||
|
||||
IDictionary<string, ISKFunction> skill = TestHelpers.GetSkills(target, "ChatSkill");
|
||||
|
||||
// Act
|
||||
@@ -132,15 +147,18 @@ public sealed class OpenAICompletionTests : IDisposable
|
||||
// Arrange
|
||||
var retryConfig = new HttpRetryConfig();
|
||||
retryConfig.RetryableStatusCodes.Add(HttpStatusCode.Unauthorized);
|
||||
IKernel target = Kernel.Builder.WithLogger(this._testOutputHelper).Configure(c => c.SetDefaultHttpRetryConfig(retryConfig)).Build();
|
||||
|
||||
OpenAIConfiguration? openAIConfiguration = this._configuration.GetSection("OpenAI").Get<OpenAIConfiguration>();
|
||||
Assert.NotNull(openAIConfiguration);
|
||||
|
||||
// Use an invalid API key to force a 401 Unauthorized response
|
||||
target.Config.AddOpenAITextCompletionService(
|
||||
modelId: openAIConfiguration.ModelId,
|
||||
apiKey: "INVALID_KEY");
|
||||
IKernel target = Kernel.Builder
|
||||
.WithLogger(this._testOutputHelper)
|
||||
.Configure(c => c.SetDefaultHttpRetryConfig(retryConfig))
|
||||
.WithOpenAITextCompletionService(
|
||||
serviceId: openAIConfiguration.ServiceId,
|
||||
modelId: openAIConfiguration.ModelId,
|
||||
apiKey: "INVALID_KEY") // Use an invalid API key to force a 401 Unauthorized response
|
||||
.Build();
|
||||
|
||||
IDictionary<string, ISKFunction> skill = TestHelpers.GetSkills(target, "SummarizeSkill");
|
||||
|
||||
@@ -160,17 +178,21 @@ public sealed class OpenAICompletionTests : IDisposable
|
||||
// Arrange
|
||||
var retryConfig = new HttpRetryConfig();
|
||||
retryConfig.RetryableStatusCodes.Add(HttpStatusCode.Unauthorized);
|
||||
IKernel target = Kernel.Builder.WithLogger(this._testOutputHelper).Configure(c => c.SetDefaultHttpRetryConfig(retryConfig)).Build();
|
||||
KernelBuilder builder = Kernel.Builder
|
||||
.WithLogger(this._testOutputHelper)
|
||||
.Configure(c => c.SetDefaultHttpRetryConfig(retryConfig));
|
||||
|
||||
var azureOpenAIConfiguration = this._configuration.GetSection("AzureOpenAI").Get<AzureOpenAIConfiguration>();
|
||||
Assert.NotNull(azureOpenAIConfiguration);
|
||||
|
||||
// Use an invalid API key to force a 401 Unauthorized response
|
||||
target.Config.AddAzureTextCompletionService(
|
||||
builder.WithAzureTextCompletionService(
|
||||
deploymentName: azureOpenAIConfiguration.DeploymentName,
|
||||
endpoint: azureOpenAIConfiguration.Endpoint,
|
||||
apiKey: "INVALID_KEY");
|
||||
|
||||
IKernel target = builder.Build();
|
||||
|
||||
IDictionary<string, ISKFunction> skill = TestHelpers.GetSkills(target, "SummarizeSkill");
|
||||
|
||||
// Act
|
||||
@@ -184,15 +206,16 @@ public sealed class OpenAICompletionTests : IDisposable
|
||||
public async Task OpenAIHttpInvalidKeyShouldReturnErrorDetailAsync()
|
||||
{
|
||||
// Arrange
|
||||
IKernel target = Kernel.Builder.WithLogger(this._testOutputHelper).Build();
|
||||
|
||||
OpenAIConfiguration? openAIConfiguration = this._configuration.GetSection("OpenAI").Get<OpenAIConfiguration>();
|
||||
Assert.NotNull(openAIConfiguration);
|
||||
|
||||
// Use an invalid API key to force a 401 Unauthorized response
|
||||
target.Config.AddOpenAITextCompletionService(
|
||||
modelId: openAIConfiguration.ModelId,
|
||||
apiKey: "INVALID_KEY");
|
||||
IKernel target = Kernel.Builder
|
||||
.WithOpenAITextCompletionService(
|
||||
modelId: openAIConfiguration.ModelId,
|
||||
apiKey: "INVALID_KEY",
|
||||
serviceId: openAIConfiguration.ServiceId)
|
||||
.Build();
|
||||
|
||||
IDictionary<string, ISKFunction> skill = TestHelpers.GetSkills(target, "SummarizeSkill");
|
||||
|
||||
@@ -210,16 +233,17 @@ public sealed class OpenAICompletionTests : IDisposable
|
||||
public async Task AzureOpenAIHttpInvalidKeyShouldReturnErrorDetailAsync()
|
||||
{
|
||||
// Arrange
|
||||
IKernel target = Kernel.Builder.WithLogger(this._testOutputHelper).Build();
|
||||
|
||||
var azureOpenAIConfiguration = this._configuration.GetSection("AzureOpenAI").Get<AzureOpenAIConfiguration>();
|
||||
|
||||
Assert.NotNull(azureOpenAIConfiguration);
|
||||
|
||||
target.Config.AddAzureTextCompletionService(
|
||||
deploymentName: azureOpenAIConfiguration.DeploymentName,
|
||||
endpoint: azureOpenAIConfiguration.Endpoint,
|
||||
apiKey: "INVALID_KEY");
|
||||
IKernel target = Kernel.Builder
|
||||
.WithLogger(this._testOutputHelper)
|
||||
.WithAzureTextCompletionService(
|
||||
deploymentName: azureOpenAIConfiguration.DeploymentName,
|
||||
endpoint: azureOpenAIConfiguration.Endpoint,
|
||||
apiKey: "INVALID_KEY",
|
||||
serviceId: azureOpenAIConfiguration.ServiceId)
|
||||
.Build();
|
||||
|
||||
IDictionary<string, ISKFunction> skill = TestHelpers.GetSkills(target, "SummarizeSkill");
|
||||
|
||||
@@ -236,17 +260,18 @@ public sealed class OpenAICompletionTests : IDisposable
|
||||
[Fact]
|
||||
public async Task AzureOpenAIHttpExceededMaxTokensShouldReturnErrorDetailAsync()
|
||||
{
|
||||
// Arrange
|
||||
IKernel target = Kernel.Builder.WithLogger(this._testOutputHelper).Build();
|
||||
|
||||
var azureOpenAIConfiguration = this._configuration.GetSection("AzureOpenAI").Get<AzureOpenAIConfiguration>();
|
||||
|
||||
Assert.NotNull(azureOpenAIConfiguration);
|
||||
|
||||
target.Config.AddAzureTextCompletionService(
|
||||
deploymentName: azureOpenAIConfiguration.DeploymentName,
|
||||
endpoint: azureOpenAIConfiguration.Endpoint,
|
||||
apiKey: azureOpenAIConfiguration.ApiKey);
|
||||
// Arrange
|
||||
IKernel target = Kernel.Builder
|
||||
.WithLogger(this._testOutputHelper)
|
||||
.WithAzureTextCompletionService(
|
||||
deploymentName: azureOpenAIConfiguration.DeploymentName,
|
||||
endpoint: azureOpenAIConfiguration.Endpoint,
|
||||
apiKey: azureOpenAIConfiguration.ApiKey,
|
||||
serviceId: azureOpenAIConfiguration.ServiceId)
|
||||
.Build();
|
||||
|
||||
IDictionary<string, ISKFunction> skill = TestHelpers.GetSkills(target, "SummarizeSkill");
|
||||
|
||||
@@ -316,7 +341,7 @@ public sealed class OpenAICompletionTests : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
private void ConfigureOpenAI(IKernel kernel)
|
||||
private void ConfigureOpenAI(KernelBuilder kernelBuilder)
|
||||
{
|
||||
var openAIConfiguration = this._configuration.GetSection("OpenAI").Get<OpenAIConfiguration>();
|
||||
|
||||
@@ -325,15 +350,14 @@ public sealed class OpenAICompletionTests : IDisposable
|
||||
Assert.NotNull(openAIConfiguration.ApiKey);
|
||||
Assert.NotNull(openAIConfiguration.ServiceId);
|
||||
|
||||
kernel.Config.AddOpenAITextCompletionService(
|
||||
kernelBuilder.WithOpenAITextCompletionService(
|
||||
modelId: openAIConfiguration.ModelId,
|
||||
apiKey: openAIConfiguration.ApiKey,
|
||||
serviceId: openAIConfiguration.ServiceId);
|
||||
|
||||
kernel.Config.SetDefaultTextCompletionService(openAIConfiguration.ServiceId);
|
||||
serviceId: openAIConfiguration.ServiceId,
|
||||
setAsDefault: true);
|
||||
}
|
||||
|
||||
private void ConfigureChatOpenAI(IKernel kernel)
|
||||
private void ConfigureChatOpenAI(KernelBuilder kernelBuilder)
|
||||
{
|
||||
var openAIConfiguration = this._configuration.GetSection("OpenAI").Get<OpenAIConfiguration>();
|
||||
|
||||
@@ -342,15 +366,14 @@ public sealed class OpenAICompletionTests : IDisposable
|
||||
Assert.NotNull(openAIConfiguration.ApiKey);
|
||||
Assert.NotNull(openAIConfiguration.ServiceId);
|
||||
|
||||
kernel.Config.AddOpenAIChatCompletionService(
|
||||
kernelBuilder.WithOpenAIChatCompletionService(
|
||||
modelId: openAIConfiguration.ChatModelId,
|
||||
apiKey: openAIConfiguration.ApiKey,
|
||||
serviceId: openAIConfiguration.ServiceId);
|
||||
|
||||
kernel.Config.SetDefaultTextCompletionService(openAIConfiguration.ServiceId);
|
||||
serviceId: openAIConfiguration.ServiceId,
|
||||
setAsDefault: true);
|
||||
}
|
||||
|
||||
private void ConfigureAzureOpenAI(IKernel kernel)
|
||||
private void ConfigureAzureOpenAI(KernelBuilder kernelBuilder)
|
||||
{
|
||||
var azureOpenAIConfiguration = this._configuration.GetSection("AzureOpenAI").Get<AzureOpenAIConfiguration>();
|
||||
|
||||
@@ -360,16 +383,15 @@ public sealed class OpenAICompletionTests : IDisposable
|
||||
Assert.NotNull(azureOpenAIConfiguration.ApiKey);
|
||||
Assert.NotNull(azureOpenAIConfiguration.ServiceId);
|
||||
|
||||
kernel.Config.AddAzureTextCompletionService(
|
||||
kernelBuilder.WithAzureTextCompletionService(
|
||||
deploymentName: azureOpenAIConfiguration.DeploymentName,
|
||||
endpoint: azureOpenAIConfiguration.Endpoint,
|
||||
apiKey: azureOpenAIConfiguration.ApiKey,
|
||||
serviceId: azureOpenAIConfiguration.ServiceId);
|
||||
|
||||
kernel.Config.SetDefaultTextCompletionService(azureOpenAIConfiguration.ServiceId);
|
||||
serviceId: azureOpenAIConfiguration.ServiceId,
|
||||
setAsDefault: true);
|
||||
}
|
||||
|
||||
private void ConfigureAzureOpenAIChatAsText(IKernel kernel)
|
||||
private void ConfigureAzureOpenAIChatAsText(KernelBuilder kernelBuilder)
|
||||
{
|
||||
var azureOpenAIConfiguration = this._configuration.GetSection("AzureOpenAI").Get<AzureOpenAIConfiguration>();
|
||||
|
||||
@@ -379,13 +401,11 @@ public sealed class OpenAICompletionTests : IDisposable
|
||||
Assert.NotNull(azureOpenAIConfiguration.Endpoint);
|
||||
Assert.NotNull(azureOpenAIConfiguration.ServiceId);
|
||||
|
||||
kernel.Config.AddAzureChatCompletionService(
|
||||
kernelBuilder.WithAzureChatCompletionService(
|
||||
deploymentName: azureOpenAIConfiguration.ChatDeploymentName,
|
||||
endpoint: azureOpenAIConfiguration.Endpoint,
|
||||
apiKey: azureOpenAIConfiguration.ApiKey,
|
||||
serviceId: azureOpenAIConfiguration.ServiceId);
|
||||
|
||||
kernel.Config.SetDefaultTextCompletionService(azureOpenAIConfiguration.ServiceId);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -478,37 +478,31 @@ public sealed class PlanTests : IDisposable
|
||||
AzureOpenAIConfiguration? azureOpenAIEmbeddingsConfiguration = this._configuration.GetSection("AzureOpenAIEmbeddings").Get<AzureOpenAIConfiguration>();
|
||||
Assert.NotNull(azureOpenAIEmbeddingsConfiguration);
|
||||
|
||||
var builder = Kernel.Builder
|
||||
.WithLogger(this._logger)
|
||||
.Configure(config =>
|
||||
{
|
||||
if (useChatModel)
|
||||
{
|
||||
config.AddAzureChatCompletionService(
|
||||
var builder = Kernel.Builder.WithLogger(this._logger);
|
||||
|
||||
if (useChatModel)
|
||||
{
|
||||
builder.WithAzureChatCompletionService(
|
||||
deploymentName: azureOpenAIConfiguration.ChatDeploymentName!,
|
||||
endpoint: azureOpenAIConfiguration.Endpoint,
|
||||
apiKey: azureOpenAIConfiguration.ApiKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
config.AddAzureTextCompletionService(
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.WithAzureTextCompletionService(
|
||||
deploymentName: azureOpenAIConfiguration.DeploymentName,
|
||||
endpoint: azureOpenAIConfiguration.Endpoint,
|
||||
apiKey: azureOpenAIConfiguration.ApiKey);
|
||||
}
|
||||
|
||||
if (useEmbeddings)
|
||||
{
|
||||
config.AddAzureTextEmbeddingGenerationService(
|
||||
deploymentName: azureOpenAIEmbeddingsConfiguration.DeploymentName,
|
||||
endpoint: azureOpenAIEmbeddingsConfiguration.Endpoint,
|
||||
apiKey: azureOpenAIEmbeddingsConfiguration.ApiKey);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (useEmbeddings)
|
||||
{
|
||||
builder = builder.WithMemoryStorage(new VolatileMemoryStore());
|
||||
builder
|
||||
.WithAzureTextEmbeddingGenerationService(
|
||||
deploymentName: azureOpenAIEmbeddingsConfiguration.DeploymentName,
|
||||
endpoint: azureOpenAIEmbeddingsConfiguration.Endpoint,
|
||||
apiKey: azureOpenAIEmbeddingsConfiguration.ApiKey)
|
||||
.WithMemoryStorage(new VolatileMemoryStore());
|
||||
}
|
||||
|
||||
var kernel = builder.Build();
|
||||
|
||||
@@ -32,13 +32,12 @@ public class SequentialPlanParserTests
|
||||
Assert.NotNull(azureOpenAIConfiguration);
|
||||
|
||||
IKernel kernel = Kernel.Builder
|
||||
.Configure(config =>
|
||||
{
|
||||
config.AddAzureTextCompletionService(
|
||||
deploymentName: azureOpenAIConfiguration.DeploymentName,
|
||||
endpoint: azureOpenAIConfiguration.Endpoint,
|
||||
apiKey: azureOpenAIConfiguration.ApiKey);
|
||||
})
|
||||
.WithAzureTextCompletionService(
|
||||
deploymentName: azureOpenAIConfiguration.DeploymentName,
|
||||
endpoint: azureOpenAIConfiguration.Endpoint,
|
||||
apiKey: azureOpenAIConfiguration.ApiKey,
|
||||
serviceId: azureOpenAIConfiguration.ServiceId,
|
||||
setAsDefault: true)
|
||||
.Build();
|
||||
kernel.ImportSkill(new EmailSkillFake(), "email");
|
||||
TestHelpers.GetSkills(kernel, "SummarizeSkill", "WriterSkill");
|
||||
|
||||
@@ -109,37 +109,30 @@ public sealed class SequentialPlannerTests : IDisposable
|
||||
AzureOpenAIConfiguration? azureOpenAIEmbeddingsConfiguration = this._configuration.GetSection("AzureOpenAIEmbeddings").Get<AzureOpenAIConfiguration>();
|
||||
Assert.NotNull(azureOpenAIEmbeddingsConfiguration);
|
||||
|
||||
var builder = Kernel.Builder
|
||||
.WithLogger(this._logger)
|
||||
.Configure(config =>
|
||||
{
|
||||
if (useChatModel)
|
||||
{
|
||||
config.AddAzureChatCompletionService(
|
||||
deploymentName: azureOpenAIConfiguration.ChatDeploymentName!,
|
||||
endpoint: azureOpenAIConfiguration.Endpoint,
|
||||
apiKey: azureOpenAIConfiguration.ApiKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
config.AddAzureTextCompletionService(
|
||||
deploymentName: azureOpenAIConfiguration.DeploymentName,
|
||||
endpoint: azureOpenAIConfiguration.Endpoint,
|
||||
apiKey: azureOpenAIConfiguration.ApiKey);
|
||||
}
|
||||
var builder = Kernel.Builder.WithLogger(this._logger);
|
||||
|
||||
if (useEmbeddings)
|
||||
{
|
||||
config.AddAzureTextEmbeddingGenerationService(
|
||||
deploymentName: azureOpenAIEmbeddingsConfiguration.DeploymentName,
|
||||
endpoint: azureOpenAIEmbeddingsConfiguration.Endpoint,
|
||||
apiKey: azureOpenAIEmbeddingsConfiguration.ApiKey);
|
||||
}
|
||||
});
|
||||
if (useChatModel)
|
||||
{
|
||||
builder.WithAzureChatCompletionService(
|
||||
deploymentName: azureOpenAIConfiguration.ChatDeploymentName!,
|
||||
endpoint: azureOpenAIConfiguration.Endpoint,
|
||||
apiKey: azureOpenAIConfiguration.ApiKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.WithAzureTextCompletionService(
|
||||
deploymentName: azureOpenAIConfiguration.DeploymentName,
|
||||
endpoint: azureOpenAIConfiguration.Endpoint,
|
||||
apiKey: azureOpenAIConfiguration.ApiKey);
|
||||
}
|
||||
|
||||
if (useEmbeddings)
|
||||
{
|
||||
builder = builder.WithMemoryStorage(new VolatileMemoryStore());
|
||||
builder.WithAzureTextEmbeddingGenerationService(
|
||||
deploymentName: azureOpenAIEmbeddingsConfiguration.DeploymentName,
|
||||
endpoint: azureOpenAIEmbeddingsConfiguration.Endpoint,
|
||||
apiKey: azureOpenAIEmbeddingsConfiguration.ApiKey)
|
||||
.WithMemoryStorage(new VolatileMemoryStore());
|
||||
}
|
||||
|
||||
var kernel = builder.Build();
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.SemanticKernel.AI.ChatCompletion;
|
||||
using Microsoft.SemanticKernel.Services;
|
||||
|
||||
// Use base namespace for better discoverability and to avoid conflicts with other extensions.
|
||||
#pragma warning disable IDE0130 // Namespace does not match folder structure
|
||||
namespace Microsoft.SemanticKernel;
|
||||
#pragma warning restore IDE0130 // Namespace does not match folder structure
|
||||
|
||||
public static class ChatCompletionServiceExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the <see cref="IChatCompletion"/> matching the given <paramref name="serviceId"/>, or
|
||||
/// the default if <paramref name="serviceId"/> is not provided or not found.
|
||||
/// </summary>
|
||||
/// <param name="services">The service provider.</param>
|
||||
/// <param name="serviceId">Optional identifier of the desired service.</param>
|
||||
/// <returns>The completion service id matching the given id or the default.</returns>
|
||||
/// <exception cref="KernelException">Thrown when no suitable service is found.</exception>
|
||||
public static IChatCompletion GetChatCompletionService(
|
||||
this IAIServiceProvider services,
|
||||
string? serviceId = null) => services.GetService<IChatCompletion>(serviceId)
|
||||
?? throw new KernelException(KernelException.ErrorCodes.ServiceNotFound, "Chat completion service not found");
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if a <see cref="IChatCompletion"/> exist with the specified ID.
|
||||
/// </summary>
|
||||
/// <param name="services">The service provider.</param>
|
||||
/// <param name="serviceId">The service ID to search for. If null, it will look for a default service.</param>
|
||||
/// <returns>True if the service ID is registered, false otherwise.</returns>
|
||||
public static bool HasChatCompletionService(
|
||||
this IAIServiceProvider services,
|
||||
string? serviceId = null)
|
||||
=> services.TryGetService<IChatCompletion>(serviceId, out _);
|
||||
}
|
||||
@@ -3,10 +3,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel.Services;
|
||||
|
||||
namespace Microsoft.SemanticKernel.AI.ChatCompletion;
|
||||
|
||||
public interface IChatCompletion
|
||||
public interface IChatCompletion : IAIService
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a new empty chat instance
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel.Diagnostics;
|
||||
|
||||
namespace Microsoft.SemanticKernel.AI.Embeddings;
|
||||
|
||||
/// <summary>
|
||||
/// Provides a collection of static methods for operating on <see cref="IEmbeddingGeneration{TValue,TEmbedding}"/> objects.
|
||||
/// </summary>
|
||||
public static class EmbeddingGenerationExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates an embedding from the given <paramref name="value"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="TValue">The type from which embeddings will be generated.</typeparam>
|
||||
/// <typeparam name="TEmbedding">The numeric type of the embedding data.</typeparam>
|
||||
/// <param name="generator">The embedding generator.</param>
|
||||
/// <param name="value">A value from which an <see cref="Embedding{TEmbedding}"/> will be generated.</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>A list of <see cref="Embedding{TEmbedding}"/> structs representing the input <paramref name="value"/>.</returns>
|
||||
public static async Task<Embedding<TEmbedding>> GenerateEmbeddingAsync<TValue, TEmbedding>
|
||||
(this IEmbeddingGeneration<TValue, TEmbedding> generator, TValue value, CancellationToken cancellationToken = default)
|
||||
where TEmbedding : unmanaged
|
||||
{
|
||||
Verify.NotNull(generator);
|
||||
return (await generator.GenerateEmbeddingsAsync(new[] { value }, cancellationToken).ConfigureAwait(false)).FirstOrDefault();
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel.Diagnostics;
|
||||
|
||||
namespace Microsoft.SemanticKernel.AI.Embeddings;
|
||||
|
||||
@@ -24,26 +22,3 @@ public interface IEmbeddingGeneration<TValue, TEmbedding>
|
||||
/// <returns>List of embeddings</returns>
|
||||
Task<IList<Embedding<TEmbedding>>> GenerateEmbeddingsAsync(IList<TValue> data, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides a collection of static methods for operating on <see cref="IEmbeddingGeneration{TValue,TEmbedding}"/> objects.
|
||||
/// </summary>
|
||||
public static class EmbeddingGenerationExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates an embedding from the given <paramref name="value"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="TValue">The type from which embeddings will be generated.</typeparam>
|
||||
/// <typeparam name="TEmbedding">The numeric type of the embedding data.</typeparam>
|
||||
/// <param name="generator">The embedding generator.</param>
|
||||
/// <param name="value">A value from which an <see cref="Embedding{TEmbedding}"/> will be generated.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
|
||||
/// <returns>A list of <see cref="Embedding{TEmbedding}"/> structs representing the input <paramref name="value"/>.</returns>
|
||||
public static async Task<Embedding<TEmbedding>> GenerateEmbeddingAsync<TValue, TEmbedding>
|
||||
(this IEmbeddingGeneration<TValue, TEmbedding> generator, TValue value, CancellationToken cancellationToken = default)
|
||||
where TEmbedding : unmanaged
|
||||
{
|
||||
Verify.NotNull(generator);
|
||||
return (await generator.GenerateEmbeddingsAsync(new[] { value }, cancellationToken).ConfigureAwait(false)).FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.SemanticKernel.Services;
|
||||
|
||||
namespace Microsoft.SemanticKernel.AI.Embeddings;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a generator of text embeddings of type <c>float</c>.
|
||||
/// </summary>
|
||||
public interface ITextEmbeddingGeneration : IEmbeddingGeneration<string, float>, IAIService
|
||||
{
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.SemanticKernel.AI.Embeddings;
|
||||
using Microsoft.SemanticKernel.Services;
|
||||
|
||||
// Use base namespace for better discoverability and to avoid conflicts with other extensions.
|
||||
#pragma warning disable IDE0130 // Namespace does not match folder structure
|
||||
namespace Microsoft.SemanticKernel;
|
||||
#pragma warning restore IDE0130 // Namespace does not match folder structure
|
||||
|
||||
public static class TextEmbeddingServiceExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the <see cref="ITextEmbeddingGeneration"/> matching the given <paramref name="serviceId"/>, or the default
|
||||
/// if the <paramref name="serviceId"/> is not provided or not found.
|
||||
/// </summary>
|
||||
/// <param name="services">The service provider.</param>
|
||||
/// <param name="serviceId">Optional identifier of the desired service.</param>
|
||||
/// <returns>The embedding service matching the given id or the default service.</returns>
|
||||
/// <exception cref="KernelException">Thrown when no suitable service is found.</exception>
|
||||
public static ITextEmbeddingGeneration GetTextEmbeddingService(
|
||||
this IAIServiceProvider services,
|
||||
string? serviceId = null)
|
||||
=> services.GetService<ITextEmbeddingGeneration>(serviceId)
|
||||
?? throw new KernelException(KernelException.ErrorCodes.ServiceNotFound, "Text embedding service not available");
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if a <see cref="ITextEmbeddingGeneration"/> exist with the specified ID.
|
||||
/// </summary>
|
||||
/// <param name="services">The service provider.</param>
|
||||
/// <param name="serviceId">The service ID to search for. If null, it will look for a default service.</param>
|
||||
/// <returns>True if the service ID is registered, false otherwise.</returns>
|
||||
public static bool HasTextEmbeddingService(
|
||||
this IAIServiceProvider services,
|
||||
string? serviceId = null)
|
||||
=> services.TryGetService<ITextEmbeddingGeneration>(serviceId, out _);
|
||||
}
|
||||
@@ -2,10 +2,11 @@
|
||||
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel.Services;
|
||||
|
||||
namespace Microsoft.SemanticKernel.AI.ImageGeneration;
|
||||
|
||||
public interface IImageGeneration
|
||||
public interface IImageGeneration : IAIService
|
||||
{
|
||||
/// <summary>
|
||||
/// Generate an image matching the given description
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.SemanticKernel.AI.ImageGeneration;
|
||||
using Microsoft.SemanticKernel.Services;
|
||||
|
||||
// Use base namespace for better discoverability and to avoid conflicts with other extensions.
|
||||
#pragma warning disable IDE0130 // Namespace does not match folder structure
|
||||
namespace Microsoft.SemanticKernel;
|
||||
#pragma warning restore IDE0130 // Namespace does not match folder structure
|
||||
|
||||
public static class ImageGenerationServiceExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the <see cref="IImageGeneration"/> matching the given <paramref name="serviceId"/>, or the default
|
||||
/// if the <paramref name="serviceId"/> is not provided or not found.
|
||||
/// </summary>
|
||||
/// <param name="services">The service provider.</param>
|
||||
/// <param name="serviceId">Optional identifier of the desired service.</param>
|
||||
/// <returns>The <see cref="IImageGeneration"/> id matching the given id or the default.</returns>
|
||||
/// <exception cref="KernelException">Thrown when no suitable service is found.</exception>
|
||||
public static IImageGeneration GetImageGenerationService(
|
||||
this IAIServiceProvider services,
|
||||
string? serviceId = null) => services.GetService<IImageGeneration>(serviceId)
|
||||
?? throw new KernelException(KernelException.ErrorCodes.ServiceNotFound, "Image generation service not found");
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if a <see cref="IImageGeneration"/> exist with the specified ID.
|
||||
/// </summary>
|
||||
/// <param name="services">The service provider.</param>
|
||||
/// <param name="serviceId">The service ID to search for. If null, it will look for a default service.</param>
|
||||
/// <returns>True if the service ID is registered, false otherwise.</returns>
|
||||
public static bool HasImageGenerationService(
|
||||
this IAIServiceProvider services,
|
||||
string? serviceId = null)
|
||||
=> services.TryGetService<IImageGeneration>(serviceId, out _);
|
||||
}
|
||||
@@ -3,13 +3,14 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SemanticKernel.Services;
|
||||
|
||||
namespace Microsoft.SemanticKernel.AI.TextCompletion;
|
||||
|
||||
/// <summary>
|
||||
/// Interface for text completion services
|
||||
/// </summary>
|
||||
public interface ITextCompletion
|
||||
public interface ITextCompletion : IAIService
|
||||
{
|
||||
/// <summary>
|
||||
/// Get completion results for the prompt and settings.
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.SemanticKernel.AI.TextCompletion;
|
||||
using Microsoft.SemanticKernel.Services;
|
||||
|
||||
// Use base namespace for better discoverability and to avoid conflicts with other extensions.
|
||||
#pragma warning disable IDE0130 // Namespace does not match folder structure
|
||||
namespace Microsoft.SemanticKernel;
|
||||
#pragma warning restore IDE0130 // Namespace does not match folder structure
|
||||
|
||||
public static class TextCompletionServiceExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the <see cref="ITextCompletion"/> matching the given <paramref name="serviceId"/>, or the default
|
||||
/// if the <paramref name="serviceId"/> is not provided or not found.
|
||||
/// </summary>
|
||||
/// <param name="services">The service provider.</param>
|
||||
/// <param name="serviceId">Optional identifier of the desired service.</param>
|
||||
/// <returns>The text completion service id matching the given ID or the default.</returns>
|
||||
/// <exception cref="KernelException">Thrown when no suitable service is found.</exception>
|
||||
public static ITextCompletion GetTextCompletionServiceOrDefault(
|
||||
this IAIServiceProvider services,
|
||||
string? serviceId = null) => services.GetService<ITextCompletion>()
|
||||
?? throw new KernelException(KernelException.ErrorCodes.ServiceNotFound, "Text completion service not found");
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if a <see cref="ITextCompletion"/> exist with the specified ID.
|
||||
/// </summary>
|
||||
/// <param name="services">The service provider.</param>
|
||||
/// <param name="serviceId">The service ID to search for. If null, it will look for a default service.</param>
|
||||
/// <returns>True if the service ID is registered, false otherwise.</returns>
|
||||
public static bool HasTextCompletionService(
|
||||
this IAIServiceProvider services,
|
||||
string? serviceId = null)
|
||||
=> services.TryGetService<ITextCompletion>(serviceId, out _);
|
||||
}
|
||||
@@ -7,6 +7,7 @@ using Microsoft.Extensions.Logging;
|
||||
using Microsoft.SemanticKernel.Memory;
|
||||
using Microsoft.SemanticKernel.Orchestration;
|
||||
using Microsoft.SemanticKernel.SemanticFunctions;
|
||||
using Microsoft.SemanticKernel.Services;
|
||||
using Microsoft.SemanticKernel.SkillDefinition;
|
||||
using Microsoft.SemanticKernel.TemplateEngine;
|
||||
|
||||
@@ -171,5 +172,5 @@ public interface IKernel
|
||||
/// <param name="name">Optional name. If the name is not provided, returns the default T available</param>
|
||||
/// <typeparam name="T">Service type</typeparam>
|
||||
/// <returns>Instance of T</returns>
|
||||
T GetService<T>(string? name = null);
|
||||
T GetService<T>(string? name = null) where T : IAIService;
|
||||
}
|
||||
|
||||
@@ -29,21 +29,25 @@ public sealed class KernelConfig
|
||||
/// <summary>
|
||||
/// Text completion service factories
|
||||
/// </summary>
|
||||
[Obsolete("This property is deprecated and will be removed in one of the next SK SDK versions.")]
|
||||
public Dictionary<string, Func<IKernel, ITextCompletion>> TextCompletionServices { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Chat completion service factories
|
||||
/// </summary>
|
||||
[Obsolete("This property is deprecated and will be removed in one of the next SK SDK versions.")]
|
||||
public Dictionary<string, Func<IKernel, IChatCompletion>> ChatCompletionServices { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Text embedding generation service factories
|
||||
/// </summary>
|
||||
[Obsolete("This property is deprecated and will be removed in one of the next SK SDK versions.")]
|
||||
public Dictionary<string, Func<IKernel, IEmbeddingGeneration<string, float>>> TextEmbeddingGenerationServices { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Image generation service factories
|
||||
/// </summary>
|
||||
[Obsolete("This property is deprecated and will be removed in one of the next SK SDK versions.")]
|
||||
public Dictionary<string, Func<IKernel, IImageGeneration>> ImageGenerationServices { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
@@ -58,6 +62,7 @@ public sealed class KernelConfig
|
||||
/// <param name="serviceId">Id used to identify the service</param>
|
||||
/// <returns>Current object instance</returns>
|
||||
/// <exception cref="KernelException">Failure if a service with the same id already exists</exception>
|
||||
[Obsolete("This method is deprecated and will be removed in one of the next SK SDK versions. Please use one of the WithAIService extension methods in the KernelBuilder class instead.")]
|
||||
public KernelConfig AddTextCompletionService(
|
||||
Func<IKernel, ITextCompletion> serviceFactory,
|
||||
string? serviceId = null)
|
||||
@@ -87,6 +92,7 @@ public sealed class KernelConfig
|
||||
/// <param name="serviceId">Id used to identify the service</param>
|
||||
/// <returns>Current object instance</returns>
|
||||
/// <exception cref="KernelException">Failure if a service with the same id already exists</exception>
|
||||
[Obsolete("This method is deprecated and will be removed in one of the next SK SDK versions. Please use one of the WithAIService extension methods in the KernelBuilder class instead.")]
|
||||
public KernelConfig AddChatCompletionService(
|
||||
Func<IKernel, IChatCompletion> serviceFactory,
|
||||
string? serviceId = null)
|
||||
@@ -116,6 +122,7 @@ public sealed class KernelConfig
|
||||
/// <param name="serviceId">Id used to identify the service</param>
|
||||
/// <returns>Current object instance</returns>
|
||||
/// <exception cref="KernelException">Failure if a service with the same id already exists</exception>
|
||||
[Obsolete("This method is deprecated and will be removed in one of the next SK SDK versions. Please use one of the WithAIService extension methods in the KernelBuilder class instead.")]
|
||||
public KernelConfig AddTextEmbeddingGenerationService(
|
||||
Func<IKernel, IEmbeddingGeneration<string, float>> serviceFactory,
|
||||
string? serviceId = null)
|
||||
@@ -145,6 +152,7 @@ public sealed class KernelConfig
|
||||
/// <param name="serviceId">Id used to identify the service</param>
|
||||
/// <returns>Current object instance</returns>
|
||||
/// <exception cref="KernelException">Failure if a service with the same id already exists</exception>
|
||||
[Obsolete("This method is deprecated and will be removed in one of the next SK SDK versions. Please use one of the WithAIService extension methods in the KernelBuilder class instead.")]
|
||||
public KernelConfig AddImageGenerationService(
|
||||
Func<IKernel, IImageGeneration> serviceFactory,
|
||||
string? serviceId = null)
|
||||
@@ -201,6 +209,7 @@ public sealed class KernelConfig
|
||||
/// <param name="serviceId">Identifier of completion service to use.</param>
|
||||
/// <returns>The updated kernel configuration.</returns>
|
||||
/// <exception cref="KernelException">Thrown if the requested service doesn't exist.</exception>
|
||||
[Obsolete("This method is deprecated and will be removed in one of the next SK SDK versions. Please use one of the WithDefaultAIService extension methods in the KernelBuilder class instead.")]
|
||||
public KernelConfig SetDefaultTextCompletionService(string serviceId)
|
||||
{
|
||||
if (!this.TextCompletionServices.ContainsKey(serviceId))
|
||||
@@ -220,6 +229,7 @@ public sealed class KernelConfig
|
||||
/// <param name="serviceId">Identifier of text embedding service to use.</param>
|
||||
/// <returns>The updated kernel configuration.</returns>
|
||||
/// <exception cref="KernelException">Thrown if the requested service doesn't exist.</exception>
|
||||
[Obsolete("This method is deprecated and will be removed in one of the next SK SDK versions. Please use one of the WithDefaultAIService extension methods in the KernelBuilder class instead.")]
|
||||
public KernelConfig SetDefaultTextEmbeddingGenerationService(string serviceId)
|
||||
{
|
||||
if (!this.TextEmbeddingGenerationServices.ContainsKey(serviceId))
|
||||
@@ -241,6 +251,7 @@ public sealed class KernelConfig
|
||||
/// Remove all text completion services.
|
||||
/// </summary>
|
||||
/// <returns>The updated kernel configuration.</returns>
|
||||
[Obsolete("This method is deprecated and will be removed in one of the next SK SDK versions.")]
|
||||
public KernelConfig RemoveAllTextCompletionServices()
|
||||
{
|
||||
this.TextCompletionServices.Clear();
|
||||
@@ -251,6 +262,7 @@ public sealed class KernelConfig
|
||||
/// Remove all chat completion services.
|
||||
/// </summary>
|
||||
/// <returns>The updated kernel configuration.</returns>
|
||||
[Obsolete("This method is deprecated and will be removed in one of the next SK SDK versions.")]
|
||||
public KernelConfig RemoveAllChatCompletionServices()
|
||||
{
|
||||
this.ChatCompletionServices.Clear();
|
||||
@@ -261,6 +273,7 @@ public sealed class KernelConfig
|
||||
/// Remove all text embedding generation services.
|
||||
/// </summary>
|
||||
/// <returns>The updated kernel configuration.</returns>
|
||||
[Obsolete("This method is deprecated and will be removed in one of the next SK SDK versions.")]
|
||||
public KernelConfig RemoveAllTextEmbeddingGenerationServices()
|
||||
{
|
||||
this.TextEmbeddingGenerationServices.Clear();
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Microsoft.SemanticKernel.Services;
|
||||
|
||||
[SuppressMessage("Design", "CA1040:Avoid empty interfaces")]
|
||||
public interface IAIService
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
namespace Microsoft.SemanticKernel.Services;
|
||||
|
||||
public interface IAIServiceProvider : INamedServiceProvider<IAIService>
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
namespace Microsoft.SemanticKernel.Services;
|
||||
|
||||
public interface INamedServiceProvider<TService>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the service of the specified type and name, or null if not found.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the service.</typeparam>
|
||||
/// <param name="name">The name of the service, or null for the default service.</param>
|
||||
/// <returns>The service instance, or null if not found.</returns>
|
||||
T? GetService<T>(string? name = null) where T : TService;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Microsoft.SemanticKernel.Services;
|
||||
internal static class AIServiceProviderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Tries to get the service of the specified type and name, and returns a value indicating whether the operation succeeded.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the service.</typeparam>
|
||||
/// <param name="serviceProvider">The service provider.</param>
|
||||
/// <param name="service">The output parameter to receive the service instance, or null if not found.</param>
|
||||
/// <returns>True if the service was found, false otherwise.</returns>
|
||||
public static bool TryGetService<T>(this IAIServiceProvider serviceProvider,
|
||||
[NotNullWhen(true)] out T? service) where T : IAIService
|
||||
{
|
||||
service = serviceProvider.GetService<T>();
|
||||
return service != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the service of the specified type and name, and returns a value indicating whether the operation succeeded.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the service.</typeparam>
|
||||
/// <param name="serviceProvider">The service provider.</param>
|
||||
/// <param name="name">The name of the service, or null for the default service.</param>
|
||||
/// <param name="service">The output parameter to receive the service instance, or null if not found.</param>
|
||||
/// <returns>True if the service was found, false otherwise.</returns>
|
||||
public static bool TryGetService<T>(this IAIServiceProvider serviceProvider,
|
||||
string? name, [NotNullWhen(true)] out T? service) where T : IAIService
|
||||
{
|
||||
service = serviceProvider.GetService<T>(name);
|
||||
return service != null;
|
||||
}
|
||||
}
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.AI.ChatCompletion;
|
||||
using Microsoft.SemanticKernel.Services;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace SemanticKernel.UnitTests.AI.ChatCompletion;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests of <see cref="ChatCompletionServiceExtensions"/>.
|
||||
/// </summary>
|
||||
public class ChatCompletionServiceExtensionsTests
|
||||
{
|
||||
[Fact]
|
||||
public void ItCanAddChatCompletionServiceInstance()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var serviceId = "test";
|
||||
var instance = Mock.Of<IChatCompletion>();
|
||||
|
||||
// Act
|
||||
services.SetService<IChatCompletion>(serviceId, instance);
|
||||
var provider = services.Build();
|
||||
|
||||
// Assert
|
||||
Assert.True(provider.TryGetService<IChatCompletion>(serviceId, out var instanceRetrieved));
|
||||
Assert.Same(instance, instanceRetrieved);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItCanAddChatCompletionServiceFactory()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var serviceId = "test";
|
||||
var instance = Mock.Of<IChatCompletion>();
|
||||
var factory = new Func<IChatCompletion>(() => instance);
|
||||
|
||||
// Act
|
||||
services.SetService<IChatCompletion>(serviceId, factory);
|
||||
var provider = services.Build();
|
||||
|
||||
// Assert
|
||||
Assert.True(provider.TryGetService<IChatCompletion>(serviceId, out _));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItCanSetDefaultChatCompletionService()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var serviceId1 = "test1";
|
||||
var serviceId2 = "test2";
|
||||
var instance1 = Mock.Of<IChatCompletion>();
|
||||
var instance2 = Mock.Of<IChatCompletion>();
|
||||
services.SetService<IChatCompletion>(serviceId1, instance1);
|
||||
|
||||
// Act
|
||||
services.SetService<IChatCompletion>(serviceId2, instance2, true);
|
||||
var provider = services.Build();
|
||||
|
||||
// Assert
|
||||
Assert.True(provider.TryGetService<IChatCompletion>(out var instanceRetrieved));
|
||||
Assert.Same(instance2, instanceRetrieved);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItReturnsFalseIfNoDefaultChatCompletionServiceIsSet()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var provider = services.Build();
|
||||
|
||||
// Assert
|
||||
Assert.False(provider.TryGetService<IChatCompletion>(out var instanceRetrieved));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItReturnsTrueIfHasChatCompletionServiceWithValidId()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var serviceId = "test";
|
||||
var instance = Mock.Of<IChatCompletion>();
|
||||
services.SetService<IChatCompletion>(serviceId, instance);
|
||||
|
||||
// Act
|
||||
var provider = services.Build();
|
||||
var result = provider.HasChatCompletionService(serviceId);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItReturnsFalseIfHasChatCompletionServiceWithInvalidId()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var serviceId1 = "test1";
|
||||
var serviceId2 = "test2";
|
||||
var instance = Mock.Of<IChatCompletion>();
|
||||
services.SetService<IChatCompletion>(serviceId1, instance);
|
||||
var provider = services.Build();
|
||||
|
||||
// Act
|
||||
var result = provider.HasChatCompletionService(serviceId2);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItReturnsTrueIfHasChatCompletionServiceWithNullIdAndDefaultIsSet()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var serviceId = "test";
|
||||
var instance = Mock.Of<IChatCompletion>();
|
||||
services.SetService<IChatCompletion>(serviceId, instance, setAsDefault: true);
|
||||
var provider = services.Build();
|
||||
|
||||
// Act
|
||||
var result = provider.HasChatCompletionService();
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItReturnsFalseIfHasChatCompletionServiceWithNullIdAndNoDefaultExists()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var provider = services.Build();
|
||||
|
||||
// Act
|
||||
var result = provider.HasChatCompletionService();
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
}
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.AI.Embeddings;
|
||||
using Microsoft.SemanticKernel.Services;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace SemanticKernel.UnitTests.AI.Embeddings;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests of <see cref="TextEmbeddingServiceExtensions"/>.
|
||||
/// </summary>
|
||||
public class TextEmbeddingServiceExtensionsTests
|
||||
{
|
||||
[Fact]
|
||||
public void ItCanAddTextEmbeddingServiceInstance()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var serviceId = "test";
|
||||
var instance = Mock.Of<ITextEmbeddingGeneration>();
|
||||
|
||||
// Act
|
||||
services.SetService<ITextEmbeddingGeneration>(serviceId, instance);
|
||||
var provider = services.Build();
|
||||
|
||||
// Assert
|
||||
Assert.True(provider.TryGetService<ITextEmbeddingGeneration>(serviceId, out var instanceRetrieved));
|
||||
Assert.Same(instance, instanceRetrieved);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItCanAddTextEmbeddingServiceFactory()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var serviceId = "test";
|
||||
var instance = Mock.Of<ITextEmbeddingGeneration>();
|
||||
var factory = new Func<ITextEmbeddingGeneration>(() => instance);
|
||||
|
||||
// Act
|
||||
services.SetService<ITextEmbeddingGeneration>(serviceId, factory);
|
||||
var provider = services.Build();
|
||||
|
||||
// Assert
|
||||
Assert.True(provider.TryGetService<ITextEmbeddingGeneration>(serviceId, out _));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItCanSetDefaultTextEmbeddingService()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var serviceId1 = "test1";
|
||||
var serviceId2 = "test2";
|
||||
var instance1 = Mock.Of<ITextEmbeddingGeneration>();
|
||||
var instance2 = Mock.Of<ITextEmbeddingGeneration>();
|
||||
services.SetService<ITextEmbeddingGeneration>(serviceId1, instance1);
|
||||
|
||||
// Act
|
||||
services.SetService<ITextEmbeddingGeneration>(serviceId2, instance2, setAsDefault: true);
|
||||
var provider = services.Build();
|
||||
|
||||
// Assert
|
||||
Assert.True(provider.TryGetService<ITextEmbeddingGeneration>(out var instanceRetrieved));
|
||||
Assert.Same(instance2, instanceRetrieved);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItReturnsFalseIfNoDefaultTextEmbeddingServiceIsSet()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var provider = services.Build();
|
||||
|
||||
// Assert
|
||||
Assert.False(provider.TryGetService<ITextEmbeddingGeneration>(out var instanceRetrieved));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItReturnsTrueIfHasTextEmbeddingServiceWithValidId()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var serviceId = "test";
|
||||
var instance = Mock.Of<ITextEmbeddingGeneration>();
|
||||
services.SetService<ITextEmbeddingGeneration>(serviceId, instance);
|
||||
var provider = services.Build();
|
||||
|
||||
// Act
|
||||
var result = provider.HasTextEmbeddingService(serviceId);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItReturnsFalseIfHasTextEmbeddingServiceWithInvalidId()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var serviceId1 = "test1";
|
||||
var serviceId2 = "test2";
|
||||
var instance = Mock.Of<ITextEmbeddingGeneration>();
|
||||
services.SetService<ITextEmbeddingGeneration>(serviceId1, instance);
|
||||
var provider = services.Build();
|
||||
|
||||
// Act
|
||||
var result = provider.HasTextEmbeddingService(serviceId2);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItReturnsTrueIfHasTextEmbeddingServiceWithNullIdAndDefaultIsSet()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var serviceId = "test";
|
||||
var instance = Mock.Of<ITextEmbeddingGeneration>();
|
||||
services.SetService<ITextEmbeddingGeneration>(serviceId, instance, setAsDefault: true);
|
||||
var provider = services.Build();
|
||||
|
||||
// Act
|
||||
var result = provider.HasTextEmbeddingService();
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItReturnsFalseIfHasTextEmbeddingServiceWithNullIdAndNoDefaultExists()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var provider = services.Build();
|
||||
|
||||
// Act
|
||||
var result = provider.HasTextEmbeddingService();
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
}
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.AI.ImageGeneration;
|
||||
using Microsoft.SemanticKernel.Services;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace SemanticKernel.UnitTests.AI.ImageGeneration;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests of <see cref="ImageGenerationServiceExtensions"/>.
|
||||
/// </summary>
|
||||
public class ImageGenerationServiceExtensionsTests
|
||||
{
|
||||
[Fact]
|
||||
public void ItCanSetServiceImageGenerationInstance()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var serviceId = "test";
|
||||
var instance = Mock.Of<IImageGeneration>();
|
||||
|
||||
// Act
|
||||
services.SetService<IImageGeneration>(serviceId, instance);
|
||||
var provider = services.Build();
|
||||
|
||||
// Assert
|
||||
Assert.True(provider.TryGetService<IImageGeneration>(serviceId, out var instanceRetrieved));
|
||||
Assert.Same(instance, instanceRetrieved);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItCanSetServiceImageGenerationFactory()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var serviceId = "test";
|
||||
var instance = Mock.Of<IImageGeneration>();
|
||||
var factory = new Func<IImageGeneration>(() => instance);
|
||||
|
||||
// Act
|
||||
services.SetService<IImageGeneration>(serviceId, factory);
|
||||
var provider = services.Build();
|
||||
|
||||
// Assert
|
||||
Assert.True(provider.TryGetService<IImageGeneration>(out var instanceRetrieved));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItCanSetDefaultImageGenerationService()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var serviceId1 = "test1";
|
||||
var serviceId2 = "test2";
|
||||
var instance1 = Mock.Of<IImageGeneration>();
|
||||
var instance2 = Mock.Of<IImageGeneration>();
|
||||
services.SetService<IImageGeneration>(serviceId1, instance1);
|
||||
|
||||
// Act
|
||||
services.SetService<IImageGeneration>(serviceId2, instance2, setAsDefault: true);
|
||||
var provider = services.Build();
|
||||
|
||||
// Assert
|
||||
Assert.True(provider.TryGetService<IImageGeneration>(out var instanceRetrieved));
|
||||
Assert.Same(instance2, instanceRetrieved);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItReturnsFalseIfNoDefaultImageGenerationServiceIsSet()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var provider = services.Build();
|
||||
|
||||
Assert.False(provider.TryGetService<IImageGeneration>(out var instanceRetrieved));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItReturnsTrueIfHasImageGenerationServiceWithValidId()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var serviceId = "test";
|
||||
var instance = Mock.Of<IImageGeneration>();
|
||||
services.SetService<IImageGeneration>(serviceId, instance);
|
||||
var provider = services.Build();
|
||||
|
||||
// Act
|
||||
var result = provider.HasImageGenerationService(serviceId);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItReturnsFalseIfHasImageGenerationServiceWithInvalidId()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var serviceId1 = "test1";
|
||||
var serviceId2 = "test2";
|
||||
var instance = Mock.Of<IImageGeneration>();
|
||||
services.SetService<IImageGeneration>(serviceId1, instance);
|
||||
var provider = services.Build();
|
||||
|
||||
// Act
|
||||
var result = provider.HasImageGenerationService(serviceId2);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItReturnsTrueIfHasImageGenerationServiceWithNullIdAndDefaultIsSet()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var serviceId = "test";
|
||||
var instance = Mock.Of<IImageGeneration>();
|
||||
services.SetService<IImageGeneration>(serviceId, instance, setAsDefault: true);
|
||||
var provider = services.Build();
|
||||
|
||||
// Act
|
||||
var result = provider.HasImageGenerationService();
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItReturnsFalseIfHasImageGenerationServiceWithNullIdAndNoDefaultExists()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var provider = services.Build();
|
||||
|
||||
// Act
|
||||
var result = provider.HasImageGenerationService();
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
}
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.AI.TextCompletion;
|
||||
using Microsoft.SemanticKernel.Services;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace SemanticKernel.UnitTests.AI.TextCompletion;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests of <see cref="TextCompletionServiceExtensions"/>.
|
||||
/// </summary>
|
||||
public class TextCompletionServiceExtensionsTests
|
||||
{
|
||||
[Fact]
|
||||
public void ItCanAddTextCompletionServiceInstance()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var serviceId = "test";
|
||||
var instance = Mock.Of<ITextCompletion>();
|
||||
|
||||
// Act
|
||||
services.SetService<ITextCompletion>(serviceId, instance);
|
||||
var provider = services.Build();
|
||||
|
||||
// Assert
|
||||
Assert.True(provider.TryGetService<ITextCompletion>(serviceId, out var instanceRetrieved));
|
||||
Assert.Same(instance, instanceRetrieved);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItCanAddTextCompletionServiceFactory()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var serviceId = "test";
|
||||
var instance = Mock.Of<ITextCompletion>();
|
||||
var factory = new Func<ITextCompletion>(() => instance);
|
||||
|
||||
// Act
|
||||
services.SetService<ITextCompletion>(serviceId, factory);
|
||||
var provider = services.Build();
|
||||
|
||||
// Assert
|
||||
Assert.True(provider.TryGetService<ITextCompletion>(serviceId, out var _));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItCanSetDefaultTextCompletionService()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var serviceId1 = "test1";
|
||||
var serviceId2 = "test2";
|
||||
var instance1 = Mock.Of<ITextCompletion>();
|
||||
var instance2 = Mock.Of<ITextCompletion>();
|
||||
services.SetService<ITextCompletion>(serviceId1, instance1);
|
||||
|
||||
// Act
|
||||
services.SetService<ITextCompletion>(serviceId2, instance2, setAsDefault: true);
|
||||
var provider = services.Build();
|
||||
|
||||
// Assert
|
||||
Assert.True(provider.TryGetService<ITextCompletion>(out var instanceRetrieved));
|
||||
Assert.Same(instance2, instanceRetrieved);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItReturnsFalseIfNoDefaultTextCompletionServiceIsSet()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var provider = services.Build();
|
||||
|
||||
// Assert
|
||||
Assert.False(provider.TryGetService<ITextCompletion>(out var _));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItReturnsTrueIfHasTextCompletionServiceWithValidId()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var serviceId = "test";
|
||||
var instance = Mock.Of<ITextCompletion>();
|
||||
services.SetService<ITextCompletion>(serviceId, instance);
|
||||
var provider = services.Build();
|
||||
|
||||
// Act
|
||||
var result = provider.HasTextCompletionService(serviceId);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItReturnsFalseIfHasTextCompletionServiceWithInvalidId()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var serviceId1 = "test1";
|
||||
var serviceId2 = "test2";
|
||||
var instance = Mock.Of<ITextCompletion>();
|
||||
services.SetService<ITextCompletion>(serviceId1, instance);
|
||||
var provider = services.Build();
|
||||
|
||||
// Act
|
||||
var result = provider.HasTextCompletionService(serviceId2);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItReturnsTrueIfHasTextCompletionServiceWithNullIdAndDefaultIsSet()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var serviceId = "test";
|
||||
var instance = Mock.Of<ITextCompletion>();
|
||||
services.SetService<ITextCompletion>(serviceId, instance, setAsDefault: true);
|
||||
var provider = services.Build();
|
||||
|
||||
// Act
|
||||
var result = provider.HasTextCompletionService();
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItReturnsFalseIfHasTextCompletionServiceWithNullIdAndNoDefaultExists()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var provider = services.Build();
|
||||
|
||||
// Act
|
||||
var result = provider.HasTextCompletionService();
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ public class FileIOSkillTests
|
||||
public void ItCanBeImported()
|
||||
{
|
||||
// Arrange
|
||||
var kernel = KernelBuilder.Create();
|
||||
var kernel = Kernel.Builder.Build();
|
||||
|
||||
// Act - Assert no exception occurs e.g. due to reflection
|
||||
_ = kernel.ImportSkill(new FileIOSkill(), "fileIO");
|
||||
|
||||
@@ -26,7 +26,7 @@ public class MathSkillTests
|
||||
public void ItCanBeImported()
|
||||
{
|
||||
// Arrange
|
||||
var kernel = KernelBuilder.Create();
|
||||
var kernel = Kernel.Builder.Build();
|
||||
|
||||
// Act - Assert no exception occurs e.g. due to reflection
|
||||
kernel.ImportSkill(new MathSkill(), "math");
|
||||
|
||||
@@ -24,7 +24,7 @@ public class TextSkillTests
|
||||
public void ItCanBeImported()
|
||||
{
|
||||
// Arrange
|
||||
var kernel = KernelBuilder.Create();
|
||||
var kernel = Kernel.Builder.Build();
|
||||
|
||||
// Act - Assert no exception occurs e.g. due to reflection
|
||||
kernel.ImportSkill(new TextSkill(), "text");
|
||||
|
||||
@@ -20,7 +20,7 @@ public class TimeSkillTests
|
||||
public void ItCanBeImported()
|
||||
{
|
||||
// Arrange
|
||||
var kernel = KernelBuilder.Create();
|
||||
var kernel = Kernel.Builder.Build();
|
||||
|
||||
// Act - Assert no exception occurs e.g. due to reflection
|
||||
kernel.ImportSkill(new TimeSkill(), "time");
|
||||
|
||||
@@ -23,7 +23,7 @@ public class WaitSkillTests
|
||||
public void ItCanBeImported()
|
||||
{
|
||||
// Arrange
|
||||
var kernel = KernelBuilder.Create();
|
||||
var kernel = Kernel.Builder.Build();
|
||||
|
||||
// Act - Assert no exception occurs e.g. due to reflection
|
||||
kernel.ImportSkill(new WaitSkill(), "wait");
|
||||
|
||||
@@ -76,6 +76,7 @@ public class KernelConfigTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[System.Obsolete("This method is deprecated and will be removed in one of the next SK SDK versions.")]
|
||||
public void ItFailsWhenSetNonExistentTextCompletionService()
|
||||
{
|
||||
var target = new KernelConfig();
|
||||
@@ -87,6 +88,7 @@ public class KernelConfigTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[System.Obsolete("This method is deprecated and will be removed in one of the next SK SDK versions.")]
|
||||
public void ItFailsWhenSetNonExistentEmbeddingService()
|
||||
{
|
||||
var target = new KernelConfig();
|
||||
|
||||
@@ -4,6 +4,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.AI.TextCompletion;
|
||||
using Microsoft.SemanticKernel.Orchestration;
|
||||
@@ -18,7 +19,8 @@ namespace SemanticKernel.UnitTests;
|
||||
public class KernelTests
|
||||
{
|
||||
[Fact]
|
||||
public void ItProvidesAccessToFunctionsViaSkillCollection()
|
||||
[System.Obsolete("This method is deprecated and will be removed in one of the next SK SDK versions.")]
|
||||
public void ItProvidesAccessToFunctionsViaSkillCollectionObsolete()
|
||||
{
|
||||
// Arrange
|
||||
var kernel = KernelBuilder.Create();
|
||||
@@ -46,7 +48,8 @@ public class KernelTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ItProvidesAccessToFunctionsViaSKContextAsync()
|
||||
[System.Obsolete("This method is deprecated and will be removed in one of the next SK SDK versions.")]
|
||||
public async Task ItProvidesAccessToFunctionsViaSKContextObsoleteAsync()
|
||||
{
|
||||
// Arrange
|
||||
var kernel = KernelBuilder.Create();
|
||||
@@ -69,11 +72,65 @@ public class KernelTests
|
||||
Assert.Equal("Export info.", result["mysk.readskillcollectionasync"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItProvidesAccessToFunctionsViaSkillCollection()
|
||||
{
|
||||
// Arrange
|
||||
var factory = new Mock<Func<ILogger, ITextCompletion>>();
|
||||
var kernel = Kernel.Builder
|
||||
.WithDefaultAIService<ITextCompletion>(factory.Object)
|
||||
.Build();
|
||||
|
||||
var nativeSkill = new MySkill();
|
||||
kernel.CreateSemanticFunction(promptTemplate: "Tell me a joke", functionName: "joker", skillName: "jk", description: "Nice fun");
|
||||
kernel.ImportSkill(nativeSkill, "mySk");
|
||||
|
||||
// Act
|
||||
FunctionsView data = kernel.Skills.GetFunctionsView();
|
||||
|
||||
// Assert - 3 functions, var name is not case sensitive
|
||||
Assert.True(data.IsSemantic("jk", "joker"));
|
||||
Assert.True(data.IsSemantic("JK", "JOKER"));
|
||||
Assert.False(data.IsNative("jk", "joker"));
|
||||
Assert.False(data.IsNative("JK", "JOKER"));
|
||||
Assert.True(data.IsNative("mySk", "sayhello"));
|
||||
Assert.True(data.IsNative("MYSK", "SayHello"));
|
||||
Assert.True(data.IsNative("mySk", "ReadSkillCollectionAsync"));
|
||||
Assert.True(data.IsNative("MYSK", "readskillcollectionasync"));
|
||||
Assert.Single(data.SemanticFunctions["Jk"]);
|
||||
Assert.Equal(3, data.NativeFunctions["mySk"].Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ItProvidesAccessToFunctionsViaSKContextAsync()
|
||||
{
|
||||
// Arrange
|
||||
var factory = new Mock<Func<(ILogger, KernelConfig), ITextCompletion>>();
|
||||
var kernel = Kernel.Builder
|
||||
.WithAIService<ITextCompletion>("x", factory.Object)
|
||||
.Build();
|
||||
|
||||
var nativeSkill = new MySkill();
|
||||
kernel.CreateSemanticFunction("Tell me a joke", functionName: "joker", skillName: "jk", description: "Nice fun");
|
||||
var skill = kernel.ImportSkill(nativeSkill, "mySk");
|
||||
|
||||
// Act
|
||||
SKContext result = await kernel.RunAsync(skill["ReadSkillCollectionAsync"]);
|
||||
|
||||
// Assert - 3 functions, var name is not case sensitive
|
||||
Assert.Equal("Nice fun", result["jk.joker"]);
|
||||
Assert.Equal("Nice fun", result["JK.JOKER"]);
|
||||
Assert.Equal("Just say hello", result["mySk.sayhello"]);
|
||||
Assert.Equal("Just say hello", result["mySk.SayHello"]);
|
||||
Assert.Equal("Export info.", result["mySk.ReadSkillCollectionAsync"]);
|
||||
Assert.Equal("Export info.", result["mysk.readskillcollectionasync"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RunAsyncDoesNotRunWhenCancelledAsync()
|
||||
{
|
||||
// Arrange
|
||||
var kernel = KernelBuilder.Create();
|
||||
var kernel = Kernel.Builder.Build();
|
||||
var nativeSkill = new MySkill();
|
||||
var skill = kernel.ImportSkill(nativeSkill, "mySk");
|
||||
|
||||
@@ -93,7 +150,7 @@ public class KernelTests
|
||||
public async Task RunAsyncRunsWhenNotCancelledAsync()
|
||||
{
|
||||
// Arrange
|
||||
var kernel = KernelBuilder.Create();
|
||||
var kernel = Kernel.Builder.Build();
|
||||
var nativeSkill = new MySkill();
|
||||
kernel.ImportSkill(nativeSkill, "mySk");
|
||||
|
||||
@@ -112,7 +169,7 @@ public class KernelTests
|
||||
public void ItImportsSkillsNotCaseSensitive()
|
||||
{
|
||||
// Act
|
||||
IDictionary<string, ISKFunction> skill = KernelBuilder.Create().ImportSkill(new MySkill(), "test");
|
||||
IDictionary<string, ISKFunction> skill = Kernel.Builder.Build().ImportSkill(new MySkill(), "test");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(3, skill.Count);
|
||||
@@ -125,7 +182,7 @@ public class KernelTests
|
||||
public void ItAllowsToImportSkillsInTheGlobalNamespace()
|
||||
{
|
||||
// Arrange
|
||||
var kernel = KernelBuilder.Create();
|
||||
var kernel = Kernel.Builder.Build();
|
||||
|
||||
// Act
|
||||
IDictionary<string, ISKFunction> skill = kernel.ImportSkill(new MySkill());
|
||||
@@ -140,7 +197,7 @@ public class KernelTests
|
||||
public void ItAllowsToImportTheSameSkillMultipleTimes()
|
||||
{
|
||||
// Arrange
|
||||
var kernel = KernelBuilder.Create();
|
||||
var kernel = Kernel.Builder.Build();
|
||||
|
||||
// Act - Assert no exception occurs
|
||||
kernel.ImportSkill(new MySkill());
|
||||
@@ -148,16 +205,6 @@ public class KernelTests
|
||||
kernel.ImportSkill(new MySkill());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItFailsIfTextCompletionServiceConfigIsNotSet()
|
||||
{
|
||||
// Arrange
|
||||
var kernel = KernelBuilder.Create();
|
||||
|
||||
var exception = Assert.Throws<KernelException>(
|
||||
() => kernel.CreateSemanticFunction(promptTemplate: "Tell me a joke", functionName: "joker", skillName: "jk", description: "Nice fun"));
|
||||
}
|
||||
|
||||
public class MySkill
|
||||
{
|
||||
[SKFunction("Return any value.")]
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Connectors\Connectors.AI.OpenAI\Connectors.AI.OpenAI.csproj" />
|
||||
<ProjectReference Include="..\SemanticKernel.Abstractions\SemanticKernel.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\SemanticKernel\SemanticKernel.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -0,0 +1,219 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.SemanticKernel.Services;
|
||||
using Xunit;
|
||||
|
||||
namespace SemanticKernel.UnitTests.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests of <see cref="AIServiceCollection"/>.
|
||||
/// </summary>
|
||||
public class ServiceRegistryTests
|
||||
{
|
||||
[Fact]
|
||||
public void ItCanSetAndRetrieveServiceInstance()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var service = new TestService();
|
||||
|
||||
// Act
|
||||
services.SetService<IAIService>(service);
|
||||
var provider = services.Build();
|
||||
var result = provider.GetService<IAIService>();
|
||||
|
||||
// Assert
|
||||
Assert.Same(service, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItCanSetAndRetrieveServiceInstanceWithName()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var service1 = new TestService();
|
||||
var service2 = new TestService();
|
||||
|
||||
// Act
|
||||
services.SetService<IAIService>("foo", service1);
|
||||
services.SetService<IAIService>("bar", service2);
|
||||
var provider = services.Build();
|
||||
|
||||
// Assert
|
||||
Assert.Same(service1, provider.GetService<IAIService>("foo"));
|
||||
Assert.Same(service2, provider.GetService<IAIService>("bar"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItCanSetAndRetrieveServiceFactory()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var service = new TestService();
|
||||
|
||||
// Act
|
||||
services.SetService<IAIService>(() => service);
|
||||
var provider = services.Build();
|
||||
|
||||
// Assert
|
||||
Assert.Same(service, provider.GetService<IAIService>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItCanSetAndRetrieveServiceFactoryWithName()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var service1 = new TestService();
|
||||
var service2 = new TestService();
|
||||
|
||||
// Act
|
||||
services.SetService<IAIService>("foo", () => service1);
|
||||
services.SetService<IAIService>("bar", () => service2);
|
||||
var provider = services.Build();
|
||||
|
||||
// Assert
|
||||
Assert.Same(service1, provider.GetService<IAIService>("foo"));
|
||||
Assert.Same(service2, provider.GetService<IAIService>("bar"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItCanSetAndRetrieveServiceFactoryWithServiceProvider()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var service = new TestService();
|
||||
|
||||
// Act
|
||||
services.SetService<IAIService>(() => service);
|
||||
var provider = services.Build();
|
||||
|
||||
// Assert
|
||||
Assert.Same(service, provider.GetService<IAIService>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItCanSetAndRetrieveServiceFactoryWithServiceProviderAndName()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var service1 = new TestService();
|
||||
var service2 = new TestService();
|
||||
|
||||
// Act
|
||||
services.SetService<IAIService>("foo", () => service1);
|
||||
services.SetService<IAIService>("bar", () => service2);
|
||||
var provider = services.Build();
|
||||
|
||||
// Assert
|
||||
Assert.Same(service1, provider.GetService<IAIService>("foo"));
|
||||
Assert.Same(service2, provider.GetService<IAIService>("bar"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItCanSetDefaultService()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var service1 = new TestService();
|
||||
var service2 = new TestService();
|
||||
|
||||
// Act
|
||||
services.SetService<IAIService>("foo", service1);
|
||||
services.SetService<IAIService>("bar", service2, setAsDefault: true);
|
||||
var provider = services.Build();
|
||||
|
||||
// Assert
|
||||
Assert.Same(service2, provider.GetService<IAIService>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItCanSetDefaultServiceFactory()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var service1 = new TestService();
|
||||
var service2 = new TestService();
|
||||
|
||||
// Act
|
||||
services.SetService<IAIService>("foo", () => service1);
|
||||
services.SetService<IAIService>("bar", () => service2, setAsDefault: true);
|
||||
var provider = services.Build();
|
||||
|
||||
// Assert
|
||||
Assert.Same(service2, provider.GetService<IAIService>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItCanSetDefaultServiceFactoryWithServiceProvider()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var service1 = new TestService();
|
||||
var service2 = new TestService();
|
||||
|
||||
// Act
|
||||
services.SetService<IAIService>("foo", () => service1);
|
||||
services.SetService<IAIService>("bar", () => service2, setAsDefault: true);
|
||||
var provider = services.Build();
|
||||
|
||||
// Assert
|
||||
Assert.Same(service2, provider.GetService<IAIService>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItCanTryGetService()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var service = new TestService();
|
||||
services.SetService<IAIService>(service);
|
||||
var provider = services.Build();
|
||||
|
||||
// Act
|
||||
var result = provider.TryGetService(out IAIService? retrieved);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
Assert.Same(service, retrieved);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItCanTryGetServiceWithName()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var service = new TestService();
|
||||
services.SetService<IAIService>("foo", service);
|
||||
var provider = services.Build();
|
||||
|
||||
// Act
|
||||
var result = provider.TryGetService("foo", out IAIService? retrieved);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
Assert.Same(service, retrieved);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ItReturnsFalseIfTryGetServiceWithInvalidName()
|
||||
{
|
||||
// Arrange
|
||||
var services = new AIServiceCollection();
|
||||
var service = new TestService();
|
||||
services.SetService<IAIService>("foo", service);
|
||||
var provider = services.Build();
|
||||
|
||||
// Act
|
||||
var result = provider.TryGetService("bar", out IAIService? retrieved);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
Assert.Null(retrieved);
|
||||
}
|
||||
|
||||
// A test service implementation
|
||||
private sealed class TestService : IAIService
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ using Microsoft.SemanticKernel.Diagnostics;
|
||||
using Microsoft.SemanticKernel.Memory;
|
||||
using Microsoft.SemanticKernel.Orchestration;
|
||||
using Microsoft.SemanticKernel.SemanticFunctions;
|
||||
using Microsoft.SemanticKernel.Services;
|
||||
using Microsoft.SemanticKernel.SkillDefinition;
|
||||
using Microsoft.SemanticKernel.TemplateEngine;
|
||||
|
||||
@@ -58,12 +59,14 @@ public sealed class Kernel : IKernel, IDisposable
|
||||
/// Kernel constructor. See KernelBuilder for an easier and less error prone approach to create kernel instances.
|
||||
/// </summary>
|
||||
/// <param name="skillCollection"></param>
|
||||
/// <param name="aiServiceProvider"></param>
|
||||
/// <param name="promptTemplateEngine"></param>
|
||||
/// <param name="memory"></param>
|
||||
/// <param name="config"></param>
|
||||
/// <param name="log"></param>
|
||||
public Kernel(
|
||||
ISkillCollection skillCollection,
|
||||
IAIServiceProvider aiServiceProvider,
|
||||
IPromptTemplateEngine promptTemplateEngine,
|
||||
ISemanticTextMemory memory,
|
||||
KernelConfig config,
|
||||
@@ -73,6 +76,8 @@ public sealed class Kernel : IKernel, IDisposable
|
||||
this.Config = config;
|
||||
this.PromptTemplateEngine = promptTemplateEngine;
|
||||
this._memory = memory;
|
||||
this._aiServiceProvider = aiServiceProvider;
|
||||
this._promptTemplateEngine = promptTemplateEngine;
|
||||
this._skillCollection = skillCollection;
|
||||
}
|
||||
|
||||
@@ -221,22 +226,26 @@ public sealed class Kernel : IKernel, IDisposable
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public T GetService<T>(string? name = null)
|
||||
public T GetService<T>(string? name = null) where T : IAIService
|
||||
{
|
||||
// TODO: use .NET ServiceCollection (will require a lot of changes)
|
||||
// TODO: support Connectors, IHttpFactory and IDelegatingHandlerFactory
|
||||
var service = this._aiServiceProvider.GetService<T>(name);
|
||||
if (service != null)
|
||||
{
|
||||
return service;
|
||||
}
|
||||
|
||||
if (typeof(T) == typeof(ITextCompletion))
|
||||
{
|
||||
name ??= this.Config.DefaultServiceId;
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
if (!this.Config.TextCompletionServices.TryGetValue(name, out Func<IKernel, ITextCompletion> factory))
|
||||
{
|
||||
throw new KernelException(KernelException.ErrorCodes.ServiceNotFound, $"'{name}' text completion service not available");
|
||||
}
|
||||
|
||||
var service = factory.Invoke(this);
|
||||
return (T)service;
|
||||
var serv = factory.Invoke(this);
|
||||
return (T)serv;
|
||||
}
|
||||
|
||||
if (typeof(T) == typeof(IEmbeddingGeneration<string, float>))
|
||||
@@ -248,8 +257,8 @@ public sealed class Kernel : IKernel, IDisposable
|
||||
throw new KernelException(KernelException.ErrorCodes.ServiceNotFound, $"'{name}' text embedding service not available");
|
||||
}
|
||||
|
||||
var service = factory.Invoke(this);
|
||||
return (T)service;
|
||||
var serv = factory.Invoke(this);
|
||||
return (T)serv;
|
||||
}
|
||||
|
||||
if (typeof(T) == typeof(IChatCompletion))
|
||||
@@ -261,8 +270,8 @@ public sealed class Kernel : IKernel, IDisposable
|
||||
throw new KernelException(KernelException.ErrorCodes.ServiceNotFound, $"'{name}' chat completion service not available");
|
||||
}
|
||||
|
||||
var service = factory.Invoke(this);
|
||||
return (T)service;
|
||||
var serv = factory.Invoke(this);
|
||||
return (T)serv;
|
||||
}
|
||||
|
||||
if (typeof(T) == typeof(IImageGeneration))
|
||||
@@ -274,11 +283,12 @@ public sealed class Kernel : IKernel, IDisposable
|
||||
throw new KernelException(KernelException.ErrorCodes.ServiceNotFound, $"'{name}' image generation service not available");
|
||||
}
|
||||
|
||||
var service = factory.Invoke(this);
|
||||
return (T)service;
|
||||
var serv = factory.Invoke(this);
|
||||
return (T)serv;
|
||||
}
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
|
||||
throw new NotSupportedException("The kernel service collection doesn't support the type " + typeof(T).FullName);
|
||||
throw new KernelException(KernelException.ErrorCodes.ServiceNotFound, $"Service of type {typeof(T)} and name {name ?? "<NONE>"} not registered.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -297,6 +307,8 @@ public sealed class Kernel : IKernel, IDisposable
|
||||
|
||||
private readonly ISkillCollection _skillCollection;
|
||||
private ISemanticTextMemory _memory;
|
||||
private readonly IPromptTemplateEngine _promptTemplateEngine;
|
||||
private readonly IAIServiceProvider _aiServiceProvider;
|
||||
|
||||
private ISKFunction CreateSemanticFunction(
|
||||
string skillName,
|
||||
|
||||
@@ -7,6 +7,7 @@ using Microsoft.SemanticKernel.AI.Embeddings;
|
||||
using Microsoft.SemanticKernel.Diagnostics;
|
||||
using Microsoft.SemanticKernel.Memory;
|
||||
using Microsoft.SemanticKernel.Reliability;
|
||||
using Microsoft.SemanticKernel.Services;
|
||||
using Microsoft.SemanticKernel.SkillDefinition;
|
||||
using Microsoft.SemanticKernel.TemplateEngine;
|
||||
|
||||
@@ -20,9 +21,11 @@ public sealed class KernelBuilder
|
||||
{
|
||||
private KernelConfig _config = new();
|
||||
private ISemanticTextMemory _memory = NullMemory.Instance;
|
||||
private ILogger _log = NullLogger.Instance;
|
||||
private ILogger _logger = NullLogger.Instance;
|
||||
private IMemoryStore? _memoryStorage = null;
|
||||
private IDelegatingHandlerFactory? _httpHandlerFactory = null;
|
||||
private IPromptTemplateEngine? _promptTemplateEngine;
|
||||
private readonly AIServiceCollection _aiServices = new();
|
||||
|
||||
/// <summary>
|
||||
/// Create a new kernel instance
|
||||
@@ -46,11 +49,12 @@ public sealed class KernelBuilder
|
||||
}
|
||||
|
||||
var instance = new Kernel(
|
||||
new SkillCollection(this._log),
|
||||
new PromptTemplateEngine(this._log),
|
||||
new SkillCollection(this._logger),
|
||||
this._aiServices.Build(),
|
||||
this._promptTemplateEngine ?? new PromptTemplateEngine(this._logger),
|
||||
this._memory,
|
||||
this._config,
|
||||
this._log
|
||||
this._logger
|
||||
);
|
||||
|
||||
// TODO: decouple this from 'UseMemory' kernel extension
|
||||
@@ -70,7 +74,7 @@ public sealed class KernelBuilder
|
||||
public KernelBuilder WithLogger(ILogger log)
|
||||
{
|
||||
Verify.NotNull(log);
|
||||
this._log = log;
|
||||
this._logger = log;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -98,6 +102,18 @@ public sealed class KernelBuilder
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add prompt template engine to the kernel to be built.
|
||||
/// </summary>
|
||||
/// <param name="promptTemplateEngine">Prompt template engine to add.</param>
|
||||
/// <returns>Updated kernel builder including the prompt template engine.</returns>
|
||||
public KernelBuilder WithPromptTemplateEngine(IPromptTemplateEngine promptTemplateEngine)
|
||||
{
|
||||
Verify.NotNull(promptTemplateEngine);
|
||||
this._promptTemplateEngine = promptTemplateEngine;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add memory storage and an embedding generator to the kernel to be built.
|
||||
/// </summary>
|
||||
@@ -105,7 +121,7 @@ public sealed class KernelBuilder
|
||||
/// <param name="embeddingGenerator">Embedding generator to add.</param>
|
||||
/// <returns>Updated kernel builder including the memory storage and embedding generator.</returns>
|
||||
public KernelBuilder WithMemoryStorageAndTextEmbeddingGeneration(
|
||||
IMemoryStore storage, IEmbeddingGeneration<string, float> embeddingGenerator)
|
||||
IMemoryStore storage, ITextEmbeddingGeneration embeddingGenerator)
|
||||
{
|
||||
Verify.NotNull(storage);
|
||||
Verify.NotNull(embeddingGenerator);
|
||||
@@ -148,4 +164,54 @@ public sealed class KernelBuilder
|
||||
configure.Invoke(this._config);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a <typeparamref name="TService"/> instance to the services collection
|
||||
/// </summary>
|
||||
/// <param name="instance">The <typeparamref name="TService"/> instance.</param>
|
||||
public KernelBuilder WithDefaultAIService<TService>(TService instance) where TService : IAIService
|
||||
{
|
||||
this._aiServices.SetService<TService>(instance);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a <typeparamref name="TService"/> instance to the services collection
|
||||
/// </summary>
|
||||
/// <param name="serviceId">The service ID</param>
|
||||
/// <param name="instance">The <typeparamref name="TService"/> instance.</param>
|
||||
/// <param name="setAsDefault">Optional: set as the default AI service for type <typeparamref name="TService"/></param>
|
||||
public KernelBuilder WithAIService<TService>(
|
||||
string? serviceId,
|
||||
TService instance,
|
||||
bool setAsDefault = false) where TService : IAIService
|
||||
{
|
||||
this._aiServices.SetService<TService>(serviceId, instance, setAsDefault);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a <typeparamref name="TService"/> factory method to the services collection
|
||||
/// </summary>
|
||||
/// <param name="factory">The factory method that creates the AI service instances of type <typeparamref name="TService"/>.</param>
|
||||
public KernelBuilder WithDefaultAIService<TService>(Func<ILogger, TService> factory) where TService : IAIService
|
||||
{
|
||||
this._aiServices.SetService<TService>(() => factory(this._logger));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a <typeparamref name="TService"/> factory method to the services collection
|
||||
/// </summary>
|
||||
/// <param name="serviceId">The service ID</param>
|
||||
/// <param name="factory">The factory method that creates the AI service instances of type <typeparamref name="TService"/>.</param>
|
||||
/// <param name="setAsDefault">Optional: set as the default AI service for type <typeparamref name="TService"/></param>
|
||||
public KernelBuilder WithAIService<TService>(
|
||||
string? serviceId,
|
||||
Func<(ILogger Logger, KernelConfig Config), TService> factory,
|
||||
bool setAsDefault = false) where TService : IAIService
|
||||
{
|
||||
this._aiServices.SetService<TService>(serviceId, () => factory((this._logger, this._config)), setAsDefault);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ public static class MemoryConfiguration
|
||||
/// <param name="embeddingsServiceId">Kernel service id for embedding generation</param>
|
||||
public static void UseMemory(this IKernel kernel, IMemoryStore storage, string? embeddingsServiceId = null)
|
||||
{
|
||||
var embeddingGenerator = kernel.GetService<IEmbeddingGeneration<string, float>>(embeddingsServiceId);
|
||||
var embeddingGenerator = kernel.GetService<ITextEmbeddingGeneration>(embeddingsServiceId);
|
||||
|
||||
UseMemory(kernel, embeddingGenerator, storage);
|
||||
}
|
||||
@@ -35,7 +35,7 @@ public static class MemoryConfiguration
|
||||
/// <param name="embeddingGenerator">Embedding generator</param>
|
||||
/// <param name="storage">Memory storage</param>
|
||||
[SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope", Justification = "The embeddingGenerator object is disposed by the kernel")]
|
||||
public static void UseMemory(this IKernel kernel, IEmbeddingGeneration<string, float> embeddingGenerator, IMemoryStore storage)
|
||||
public static void UseMemory(this IKernel kernel, ITextEmbeddingGeneration embeddingGenerator, IMemoryStore storage)
|
||||
{
|
||||
Verify.NotNull(storage);
|
||||
Verify.NotNull(embeddingGenerator);
|
||||
|
||||
@@ -15,12 +15,12 @@ namespace Microsoft.SemanticKernel.Memory;
|
||||
/// </summary>
|
||||
public sealed class SemanticTextMemory : ISemanticTextMemory, IDisposable
|
||||
{
|
||||
private readonly IEmbeddingGeneration<string, float> _embeddingGenerator;
|
||||
private readonly ITextEmbeddingGeneration _embeddingGenerator;
|
||||
private readonly IMemoryStore _storage;
|
||||
|
||||
public SemanticTextMemory(
|
||||
IMemoryStore storage,
|
||||
IEmbeddingGeneration<string, float> embeddingGenerator)
|
||||
ITextEmbeddingGeneration embeddingGenerator)
|
||||
{
|
||||
this._embeddingGenerator = embeddingGenerator;
|
||||
this._storage = storage;
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.SemanticKernel.Services;
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1711:Identifiers should not have incorrect suffix")]
|
||||
public class AIServiceCollection
|
||||
{
|
||||
// A constant key for the default service
|
||||
private const string DefaultKey = "__DEFAULT__";
|
||||
|
||||
// A dictionary that maps a service type to a nested dictionary of names and service instances or factories
|
||||
//private readonly Dictionary<Type, Dictionary<string, object>> _services = new();
|
||||
private readonly Dictionary<Type, Dictionary<string, Func<object>>> _services = new();
|
||||
|
||||
// A dictionary that maps a service type to the name of the default service
|
||||
private readonly Dictionary<Type, string> _defaultIds = new();
|
||||
|
||||
/// <summary>
|
||||
/// Registers a singleton service instance with the default name.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the service.</typeparam>
|
||||
/// <param name="service">The service instance.</param>
|
||||
/// <exception cref="ArgumentNullException">The service instance is null.</exception>
|
||||
public void SetService<T>(T service) where T : IAIService
|
||||
=> this.SetService<T>(DefaultKey, service, true);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a singleton service instance with an optional name and default flag.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the service.</typeparam>
|
||||
/// <param name="name">The name of the service, or null for the default service.</param>
|
||||
/// <param name="service">The service instance.</param>
|
||||
/// <param name="setAsDefault">Whether the service should be the default for its type.</param>
|
||||
/// <exception cref="ArgumentNullException">The service instance is null.</exception>
|
||||
/// <exception cref="ArgumentException">The name is empty or whitespace.</exception>
|
||||
public void SetService<T>(string? name, T service, bool setAsDefault = false) where T : IAIService
|
||||
=> this.SetService<T>(name, (() => service), setAsDefault);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a transient service factory with the default name.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the service.</typeparam>
|
||||
/// <param name="factory">The factory function to create the service instance.</param>
|
||||
/// <exception cref="ArgumentNullException">The factory function is null.</exception>
|
||||
public void SetService<T>(Func<T> factory) where T : IAIService
|
||||
=> this.SetService<T>(DefaultKey, factory, true);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a transient service factory with an optional name and default flag.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the service.</typeparam>
|
||||
/// <param name="name">The name of the service, or null for the default service.</param>
|
||||
/// <param name="factory">The factory function to create the service instance.</param>
|
||||
/// <param name="setAsDefault">Whether the service should be the default for its type.</param>
|
||||
/// <exception cref="ArgumentNullException">The factory function is null.</exception>
|
||||
/// <exception cref="ArgumentException">The name is empty or whitespace.</exception>
|
||||
public void SetService<T>(string? name, Func<T> factory, bool setAsDefault = false) where T : IAIService
|
||||
{
|
||||
// Validate the factory function
|
||||
if (factory == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(factory));
|
||||
}
|
||||
|
||||
// Get or create the nested dictionary for the service type
|
||||
var type = typeof(T);
|
||||
if (!this._services.TryGetValue(type, out var namedServices))
|
||||
{
|
||||
namedServices = new();
|
||||
this._services[type] = namedServices;
|
||||
}
|
||||
|
||||
// Set as the default if the name is empty, or the default flag is true,
|
||||
// or there is no default name for the service type.
|
||||
if (name == null || setAsDefault || !this.HasDefault<T>())
|
||||
{
|
||||
// Update the default name for the service type
|
||||
this._defaultIds[type] = name ?? DefaultKey;
|
||||
}
|
||||
|
||||
var objectFactory = factory as Func<object>;
|
||||
|
||||
// Register the factory with the given name
|
||||
namedServices[name ?? DefaultKey] = objectFactory
|
||||
?? throw new InvalidOperationException("Service factory is an invalid format");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds an <see cref="INamedServiceProvider{TService}"/> from the registered services and default names.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IAIServiceProvider Build()
|
||||
{
|
||||
// Create a clone of the services and defaults Dictionaries to prevent further changes
|
||||
// by the services provider.
|
||||
var servicesClone = this._services.ToDictionary(
|
||||
typeCollection => typeCollection.Key,
|
||||
typeCollection => typeCollection.Value.ToDictionary(
|
||||
service => service.Key,
|
||||
service => service.Value));
|
||||
|
||||
var defaultsClone = this._defaultIds.ToDictionary(
|
||||
typeDefault => typeDefault.Key,
|
||||
typeDefault => typeDefault.Value);
|
||||
|
||||
return new AIServiceProvider(servicesClone, defaultsClone);
|
||||
}
|
||||
|
||||
private bool HasDefault<T>() where T : IAIService
|
||||
=> this._defaultIds.TryGetValue(typeof(T), out var defaultName)
|
||||
&& !string.IsNullOrEmpty(defaultName);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.SemanticKernel.Services;
|
||||
public class AIServiceProvider : NamedServiceProvider<IAIService>, IAIServiceProvider
|
||||
{
|
||||
public AIServiceProvider(Dictionary<Type, Dictionary<string, Func<object>>> services, Dictionary<Type, string> defaultIds)
|
||||
: base(services, defaultIds)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.SemanticKernel.Services;
|
||||
public class NamedServiceProvider<TService> : INamedServiceProvider<TService>
|
||||
{
|
||||
// A dictionary that maps a service type to a nested dictionary of names and service instances or factories
|
||||
//private readonly Dictionary<Type, Dictionary<string, object>> _services = new();
|
||||
private readonly Dictionary<Type, Dictionary<string, Func<object>>> _services;
|
||||
|
||||
// A dictionary that maps a service type to the name of the default service
|
||||
private readonly Dictionary<Type, string> _defaultIds;
|
||||
|
||||
public NamedServiceProvider(
|
||||
Dictionary<Type, Dictionary<string, Func<object>>> services,
|
||||
Dictionary<Type, string> defaultIds)
|
||||
{
|
||||
this._services = services;
|
||||
this._defaultIds = defaultIds;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public T? GetService<T>(string? name = null) where T : TService
|
||||
{
|
||||
// Return the service, casting or invoking the factory if needed
|
||||
var factory = this.GetServiceFactory<T>(name);
|
||||
if (factory is Func<T>)
|
||||
{
|
||||
return factory.Invoke();
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
private string? GetDefaultServiceName<T>() where T : TService
|
||||
{
|
||||
// Returns the name of the default service for the given type, or null if none
|
||||
var type = typeof(T);
|
||||
if (this._defaultIds.TryGetValue(type, out var name))
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Func<T>? GetServiceFactory<T>(string? name = null) where T : TService
|
||||
{
|
||||
// Get the nested dictionary for the service type
|
||||
if (this._services.TryGetValue(typeof(T), out var namedServices))
|
||||
{
|
||||
Func<object>? serviceFactory = null;
|
||||
|
||||
// If the name is not specified, try to load the default factory
|
||||
name ??= this.GetDefaultServiceName<T>();
|
||||
if (name != null)
|
||||
{
|
||||
// Check if there is a service registered with the given name
|
||||
namedServices.TryGetValue(name, out serviceFactory);
|
||||
}
|
||||
|
||||
return serviceFactory as Func<T>;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -229,7 +229,7 @@ public sealed class SKFunction : ISKFunction, IDisposable
|
||||
{
|
||||
Verify.NotNull(serviceFactory);
|
||||
this.VerifyIsSemantic();
|
||||
this._aiService = serviceFactory.Invoke();
|
||||
this._aiService = new Lazy<ITextCompletion>(serviceFactory);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ public sealed class SKFunction : ISKFunction, IDisposable
|
||||
private readonly Delegate _function;
|
||||
private readonly ILogger _log;
|
||||
private IReadOnlySkillCollection? _skillCollection;
|
||||
private ITextCompletion? _aiService = null;
|
||||
private Lazy<ITextCompletion>? _aiService = null;
|
||||
private CompleteRequestSettings _aiRequestSettings = new();
|
||||
|
||||
private struct MethodDetails
|
||||
@@ -345,9 +345,15 @@ public sealed class SKFunction : ISKFunction, IDisposable
|
||||
|
||||
private void ReleaseUnmanagedResources()
|
||||
{
|
||||
if (this._aiService is not IDisposable disposable) { return; }
|
||||
if (this._aiService == null || !this._aiService.IsValueCreated)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
disposable.Dispose();
|
||||
if (this._aiService.Value is IDisposable disposable)
|
||||
{
|
||||
disposable.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -374,7 +380,7 @@ public sealed class SKFunction : ISKFunction, IDisposable
|
||||
settings ??= this._aiRequestSettings;
|
||||
|
||||
var callable = (Func<ITextCompletion?, CompleteRequestSettings?, SKContext, Task<SKContext>>)this._function;
|
||||
context.Variables.Update((await callable(this._aiService, settings, context).ConfigureAwait(false)).Variables);
|
||||
context.Variables.Update((await callable(this._aiService?.Value, settings, context).ConfigureAwait(false)).Variables);
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ public class SearchUrlSkillTests
|
||||
public void ItCanBeImported()
|
||||
{
|
||||
// Arrange
|
||||
IKernel kernel = KernelBuilder.Create();
|
||||
IKernel kernel = Kernel.Builder.Build();
|
||||
|
||||
// Act - Assert no exception occurs e.g. due to reflection
|
||||
kernel.ImportSkill(new SearchUrlSkill(), "search");
|
||||
|
||||
@@ -10,8 +10,11 @@
|
||||
using Microsoft.SemanticKernel.AI.TextCompletion;
|
||||
using Microsoft.SemanticKernel.Connectors.AI.OpenAI.TextCompletion;
|
||||
using Microsoft.SemanticKernel.Connectors.AI.OpenAI.TextEmbedding;
|
||||
using Microsoft.SemanticKernel.Services;
|
||||
|
||||
IKernel kernel1 = KernelBuilder.Create();
|
||||
#pragma warning disable CA1852 // Seal internal types
|
||||
IKernel kernel1 = Kernel.Builder.Build();
|
||||
#pragma warning restore CA1852 // Seal internal types
|
||||
|
||||
IKernel kernel2 = Kernel.Builder.Build();
|
||||
|
||||
@@ -49,13 +52,16 @@ var memory = new SemanticTextMemory(memoryStorage, textEmbeddingGenerator);
|
||||
var skills = new SkillCollection();
|
||||
var templateEngine = new PromptTemplateEngine(logger);
|
||||
var config = new KernelConfig();
|
||||
|
||||
var httpHandler = new DefaultHttpRetryHandler(new HttpRetryConfig(), logger);
|
||||
var httpClient = new HttpClient(httpHandler);
|
||||
ITextCompletion Factory(IKernel kernel) => new AzureTextCompletion("deploymentName", "https://...", "apiKey", httpClient, logger);
|
||||
config.AddTextCompletionService(Factory);
|
||||
var aiServices = new AIServiceCollection();
|
||||
ITextCompletion Factory() => new AzureTextCompletion("deploymentName", "https://...", "apiKey", httpClient, logger);
|
||||
aiServices.SetService("foo", Factory);
|
||||
IAIServiceProvider aiServiceProvider = aiServices.Build();
|
||||
|
||||
// Create kernel manually injecting all the dependencies
|
||||
var kernel3 = new Kernel(skills, templateEngine, memory, config, logger);
|
||||
var kernel3 = new Kernel(skills, aiServiceProvider, templateEngine, memory, config, logger);
|
||||
|
||||
// ==========================================================================================================
|
||||
// The kernel builder purpose is to simplify this process, automating how dependencies
|
||||
@@ -65,10 +71,7 @@ var kernel3 = new Kernel(skills, templateEngine, memory, config, logger);
|
||||
var kernel4 = Kernel.Builder
|
||||
.WithLogger(NullLogger.Instance)
|
||||
.WithMemory(memory)
|
||||
.Configure(c =>
|
||||
{
|
||||
c.AddAzureTextCompletionService("deploymentName", "https://...", "apiKey");
|
||||
})
|
||||
.WithAzureTextCompletionService("deploymentName", "https://...", "apiKey")
|
||||
.Build();
|
||||
|
||||
// Example: how to use a custom memory storage and custom embedding generator
|
||||
@@ -81,36 +84,17 @@ var kernel5 = Kernel.Builder
|
||||
var kernel6 = Kernel.Builder
|
||||
.WithLogger(NullLogger.Instance)
|
||||
.WithMemoryStorage(memoryStorage) // Custom memory storage
|
||||
.Configure(c =>
|
||||
{
|
||||
// This will be used when using AI completions
|
||||
c.AddAzureTextCompletionService("completionDeploymentName", "https://...", "apiKey");
|
||||
|
||||
// This will be used when indexing memory records
|
||||
c.AddAzureTextEmbeddingGenerationService("embeddingsDeploymentName", "https://...", "apiKey", serviceId: "myName3");
|
||||
})
|
||||
.WithAzureTextCompletionService("myName1", "completionDeploymentName", "https://...", "apiKey") // This will be used when using AI completions
|
||||
.WithAzureTextEmbeddingGenerationService("myName2", "embeddingsDeploymentName", "https://...", "apiKey") // This will be used when indexing memory records
|
||||
.Build();
|
||||
|
||||
// ==========================================================================================================
|
||||
// The kernel configuration can be defined with the builder, but can also be managed
|
||||
// when the kernel instance is already created.
|
||||
// The AI services are defined with the builder
|
||||
|
||||
var kernel7 = Kernel.Builder
|
||||
.Configure(c =>
|
||||
{
|
||||
c.AddAzureTextCompletionService("completionDeploymentName", "https://...", "apiKey");
|
||||
})
|
||||
.Configure(c =>
|
||||
{
|
||||
c.SetDefaultTextEmbeddingGenerationService("myName3");
|
||||
})
|
||||
.WithAzureTextCompletionService("myName1", "completionDeploymentName", "https://...", "apiKey", true)
|
||||
.Build();
|
||||
|
||||
kernel7.Config
|
||||
.AddAzureTextEmbeddingGenerationService("embeddingsDeploymentName1", "https://...", "apiKey", serviceId: "myName2")
|
||||
.AddAzureTextEmbeddingGenerationService("embeddingsDeploymentName2", "https://...", "apiKey", serviceId: "myName3")
|
||||
.AddOpenAITextCompletionService("text-davinci-003", "sk-...");
|
||||
|
||||
// ==========================================================================================================
|
||||
// When invoking AI, by default the kernel will retry on transient errors, such as throttling and timeouts.
|
||||
// The default behavior can be configured or a custom retry handler can be injected that will apply to all
|
||||
|
||||
@@ -43,53 +43,50 @@ internal static class SemanticKernelFactory
|
||||
|
||||
private static KernelBuilder _ConfigureKernelBuilder(ApiKeyConfig config, KernelBuilder builder, IMemoryStore? memoryStore)
|
||||
{
|
||||
return builder.Configure(c =>
|
||||
switch (config.CompletionConfig.AIService)
|
||||
{
|
||||
switch (config.CompletionConfig.AIService)
|
||||
case AIService.OpenAI:
|
||||
builder.WithOpenAITextCompletionService(
|
||||
config.CompletionConfig.DeploymentOrModelId,
|
||||
config.CompletionConfig.Key,
|
||||
config.CompletionConfig.ServiceId);
|
||||
break;
|
||||
case AIService.AzureOpenAI:
|
||||
builder.WithAzureTextCompletionService(
|
||||
config.CompletionConfig.DeploymentOrModelId,
|
||||
config.CompletionConfig.Endpoint,
|
||||
config.CompletionConfig.Key,
|
||||
serviceId: config.CompletionConfig.ServiceId);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (memoryStore != null && config.EmbeddingConfig.IsValid())
|
||||
{
|
||||
switch (config.EmbeddingConfig.AIService)
|
||||
{
|
||||
case AIService.OpenAI:
|
||||
c.AddOpenAIChatCompletionService(
|
||||
modelId: config.CompletionConfig.DeploymentOrModelId,
|
||||
apiKey: config.CompletionConfig.Key,
|
||||
serviceId: config.CompletionConfig.ServiceId,
|
||||
alsoAsTextCompletion: true);
|
||||
builder.WithOpenAITextEmbeddingGenerationService(
|
||||
config.EmbeddingConfig.DeploymentOrModelId,
|
||||
config.EmbeddingConfig.Key,
|
||||
serviceId: config.EmbeddingConfig.ServiceId);
|
||||
break;
|
||||
case AIService.AzureOpenAI:
|
||||
c.AddAzureChatCompletionService(
|
||||
deploymentName: config.CompletionConfig.DeploymentOrModelId,
|
||||
endpoint: config.CompletionConfig.Endpoint,
|
||||
apiKey: config.CompletionConfig.Key,
|
||||
serviceId: config.CompletionConfig.ServiceId,
|
||||
alsoAsTextCompletion: true);
|
||||
builder.WithAzureTextEmbeddingGenerationService(
|
||||
config.EmbeddingConfig.DeploymentOrModelId,
|
||||
config.EmbeddingConfig.Endpoint,
|
||||
config.EmbeddingConfig.Key,
|
||||
serviceId: config.EmbeddingConfig.ServiceId);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (memoryStore != null && config.EmbeddingConfig.IsValid())
|
||||
{
|
||||
switch (config.EmbeddingConfig.AIService)
|
||||
{
|
||||
case AIService.OpenAI:
|
||||
c.AddOpenAITextEmbeddingGenerationService(
|
||||
config.EmbeddingConfig.DeploymentOrModelId,
|
||||
config.EmbeddingConfig.Key,
|
||||
serviceId: config.EmbeddingConfig.ServiceId);
|
||||
break;
|
||||
case AIService.AzureOpenAI:
|
||||
c.AddAzureTextEmbeddingGenerationService(
|
||||
config.EmbeddingConfig.DeploymentOrModelId,
|
||||
config.EmbeddingConfig.Endpoint,
|
||||
config.EmbeddingConfig.Key,
|
||||
serviceId: config.EmbeddingConfig.ServiceId);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
builder.WithMemoryStorage(memoryStore);
|
||||
}
|
||||
|
||||
builder.WithMemoryStorage(memoryStore);
|
||||
}
|
||||
});
|
||||
return builder;
|
||||
}
|
||||
|
||||
private static IKernel _CompleteKernelSetup(HttpRequestData req, KernelBuilder builder, ILogger logger, IEnumerable<string>? skillsToLoad = null)
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\dotnet\src\Connectors\Connectors.AI.OpenAI\Connectors.AI.OpenAI.csproj" />
|
||||
<ProjectReference Include="..\..\..\dotnet\src\SemanticKernel.Abstractions\SemanticKernel.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\..\..\dotnet\src\Skills\Skills.MsGraph\Skills.MsGraph.csproj" />
|
||||
<ProjectReference Include="..\..\..\dotnet\src\SemanticKernel\SemanticKernel.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -65,6 +65,18 @@ public sealed class Program
|
||||
|
||||
MsGraphConfiguration graphApiConfiguration = candidateGraphApiConfig;
|
||||
|
||||
string? defaultCompletionServiceId = configuration["DefaultCompletionServiceId"];
|
||||
if (string.IsNullOrWhiteSpace(defaultCompletionServiceId))
|
||||
{
|
||||
throw new InvalidOperationException("'DefaultCompletionServiceId' is not set in configuration.");
|
||||
}
|
||||
|
||||
string? currentAssemblyDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
if (string.IsNullOrWhiteSpace(currentAssemblyDirectory))
|
||||
{
|
||||
throw new InvalidOperationException("Unable to determine current assembly directory.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// Initialize the Graph API client with interactive authentication and local caching.
|
||||
@@ -95,22 +107,20 @@ public sealed class Program
|
||||
EmailSkill outlookSkill = new(new OutlookMailConnector(graphServiceClient), loggerFactory.CreateLogger<EmailSkill>());
|
||||
|
||||
// Initialize the Semantic Kernel and and register connections with OpenAI/Azure OpenAI instances.
|
||||
IKernel sk = Kernel.Builder.WithLogger(loggerFactory.CreateLogger<IKernel>()).Build();
|
||||
|
||||
var onedrive = sk.ImportSkill(oneDriveSkill, "onedrive");
|
||||
var todo = sk.ImportSkill(todoSkill, "todo");
|
||||
var outlook = sk.ImportSkill(outlookSkill, "outlook");
|
||||
KernelBuilder builder = Kernel.Builder
|
||||
.WithLogger(loggerFactory.CreateLogger<IKernel>());
|
||||
|
||||
if (configuration.GetSection("AzureOpenAI:ServiceId").Value != null)
|
||||
{
|
||||
AzureOpenAIConfiguration? azureOpenAIConfiguration = configuration.GetSection("AzureOpenAI").Get<AzureOpenAIConfiguration>();
|
||||
if (azureOpenAIConfiguration != null)
|
||||
{
|
||||
sk.Config.AddAzureTextCompletionService(
|
||||
builder.WithAzureTextCompletionService(
|
||||
deploymentName: azureOpenAIConfiguration.DeploymentName,
|
||||
endpoint: azureOpenAIConfiguration.Endpoint,
|
||||
apiKey: azureOpenAIConfiguration.ApiKey,
|
||||
serviceId: azureOpenAIConfiguration.ServiceId);
|
||||
serviceId: azureOpenAIConfiguration.ServiceId,
|
||||
setAsDefault: azureOpenAIConfiguration.ServiceId == defaultCompletionServiceId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,25 +129,19 @@ public sealed class Program
|
||||
OpenAIConfiguration? openAIConfiguration = configuration.GetSection("OpenAI").Get<OpenAIConfiguration>();
|
||||
if (openAIConfiguration != null)
|
||||
{
|
||||
sk.Config.AddOpenAITextCompletionService(
|
||||
builder.WithOpenAITextCompletionService(
|
||||
modelId: openAIConfiguration.ModelId,
|
||||
apiKey: openAIConfiguration.ApiKey);
|
||||
apiKey: openAIConfiguration.ApiKey,
|
||||
serviceId: openAIConfiguration.ServiceId,
|
||||
setAsDefault: openAIConfiguration.ServiceId == defaultCompletionServiceId);
|
||||
}
|
||||
}
|
||||
|
||||
string? defaultCompletionServiceId = configuration["DefaultCompletionServiceId"];
|
||||
if (string.IsNullOrWhiteSpace(defaultCompletionServiceId))
|
||||
{
|
||||
throw new InvalidOperationException("'DefaultCompletionServiceId' is not set in configuration.");
|
||||
}
|
||||
IKernel sk = builder.Build();
|
||||
|
||||
sk.Config.SetDefaultTextCompletionService(defaultCompletionServiceId);
|
||||
|
||||
string? currentAssemblyDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
if (string.IsNullOrWhiteSpace(currentAssemblyDirectory))
|
||||
{
|
||||
throw new InvalidOperationException("Unable to determine current assembly directory.");
|
||||
}
|
||||
var onedrive = sk.ImportSkill(oneDriveSkill, "onedrive");
|
||||
var todo = sk.ImportSkill(todoSkill, "todo");
|
||||
var outlook = sk.ImportSkill(outlookSkill, "outlook");
|
||||
|
||||
string skillParentDirectory = RepoUtils.RepoFiles.SampleSkillsPath();
|
||||
|
||||
|
||||
@@ -14,12 +14,11 @@ public static class Example04_CombineLLMPromptsAndNativeCode
|
||||
{
|
||||
Console.WriteLine("======== LLMPrompts ========");
|
||||
|
||||
IKernel kernel = new KernelBuilder().WithLogger(ConsoleLogger.Log).Build();
|
||||
|
||||
// OpenAI settings
|
||||
kernel.Config.AddOpenAITextCompletionService("text-davinci-002", Env.Var("OPENAI_API_KEY"), serviceId: "text-davinci-002");
|
||||
kernel.Config.AddOpenAITextCompletionService("text-davinci-003", Env.Var("OPENAI_API_KEY"), serviceId: "text-davinci-003");
|
||||
kernel.Config.SetDefaultTextCompletionService("text-davinci-003");
|
||||
IKernel kernel = new KernelBuilder()
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
.WithOpenAITextCompletionService("text-davinci-002", Env.Var("OPENAI_API_KEY"), serviceId: "text-davinci-002")
|
||||
.WithOpenAITextCompletionService("text-davinci-003", Env.Var("OPENAI_API_KEY"))
|
||||
.Build();
|
||||
|
||||
// Load native skill
|
||||
using var bingConnector = new BingConnector(Env.Var("BING_API_KEY"));
|
||||
|
||||
@@ -18,10 +18,10 @@ public static class Example05_InlineFunctionDefinition
|
||||
* function inline if you like.
|
||||
*/
|
||||
|
||||
IKernel kernel = new KernelBuilder().WithLogger(ConsoleLogger.Log).Build();
|
||||
|
||||
// OpenAI settings
|
||||
kernel.Config.AddOpenAITextCompletionService("text-davinci-003", Env.Var("OPENAI_API_KEY"));
|
||||
IKernel kernel = new KernelBuilder()
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
.WithOpenAITextCompletionService("text-davinci-003", Env.Var("OPENAI_API_KEY"))
|
||||
.Build();
|
||||
|
||||
// Function defined using few-shot design pattern
|
||||
const string FunctionDefinition = @"
|
||||
|
||||
@@ -18,8 +18,10 @@ public static class Example06_TemplateLanguage
|
||||
{
|
||||
Console.WriteLine("======== TemplateLanguage ========");
|
||||
|
||||
IKernel kernel = Kernel.Builder.WithLogger(ConsoleLogger.Log).Build();
|
||||
kernel.Config.AddOpenAITextCompletionService("text-davinci-003", Env.Var("OPENAI_API_KEY"));
|
||||
IKernel kernel = Kernel.Builder
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
.WithOpenAITextCompletionService("text-davinci-003", Env.Var("OPENAI_API_KEY"))
|
||||
.Build();
|
||||
|
||||
// Load native skill into the kernel skill collection, sharing its functions with prompt templates
|
||||
// Functions loaded here are available as "time.*"
|
||||
|
||||
@@ -21,9 +21,10 @@ public static class Example07_BingAndGoogleSkills
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
{
|
||||
IKernel kernel = new KernelBuilder().WithLogger(ConsoleLogger.Log).Build();
|
||||
|
||||
kernel.Config.AddOpenAITextCompletionService("text-davinci-003", Env.Var("OPENAI_API_KEY"));
|
||||
IKernel kernel = new KernelBuilder()
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
.WithOpenAITextCompletionService("text-davinci-003", Env.Var("OPENAI_API_KEY"))
|
||||
.Build();
|
||||
|
||||
// Load Bing skill
|
||||
using var bingConnector = new BingConnector(Env.Var("BING_API_KEY"));
|
||||
|
||||
@@ -47,7 +47,7 @@ public static class Example08_RetryHandler
|
||||
kernelBuilder = kernelBuilder.Configure(c => c.DefaultHttpRetryConfig.RetryableStatusCodes.Add(HttpStatusCode.Unauthorized));
|
||||
|
||||
// OpenAI settings - you can set the OPENAI_API_KEY to an invalid value to see the retry policy in play
|
||||
kernelBuilder = kernelBuilder.Configure(c => c.AddOpenAITextCompletionService("text-davinci-003", "BAD_KEY"));
|
||||
kernelBuilder = kernelBuilder.WithOpenAITextCompletionService("text-davinci-003", "BAD_KEY");
|
||||
|
||||
var kernel = kernelBuilder.Build();
|
||||
|
||||
@@ -56,9 +56,11 @@ public static class Example08_RetryHandler
|
||||
|
||||
private static IKernel InitializeKernel()
|
||||
{
|
||||
var kernel = Kernel.Builder.WithLogger(InfoLogger.Log).Build();
|
||||
// OpenAI settings - you can set the OPENAI_API_KEY to an invalid value to see the retry policy in play
|
||||
kernel.Config.AddOpenAITextCompletionService("text-davinci-003", "BAD_KEY");
|
||||
var kernel = Kernel.Builder
|
||||
.WithLogger(InfoLogger.Log)
|
||||
// OpenAI settings - you can set the OPENAI_API_KEY to an invalid value to see the retry policy in play
|
||||
.WithOpenAITextCompletionService("text-davinci-003", "BAD_KEY")
|
||||
.Build();
|
||||
|
||||
return kernel;
|
||||
}
|
||||
@@ -71,13 +73,11 @@ public static class Example08_RetryHandler
|
||||
|
||||
private static async Task RunRetryPolicyBuilderAsync(Type retryHandlerFactoryType)
|
||||
{
|
||||
var kernelBuilder = Kernel.Builder.WithLogger(InfoLogger.Log)
|
||||
.WithRetryHandlerFactory((Activator.CreateInstance(retryHandlerFactoryType) as IDelegatingHandlerFactory)!);
|
||||
|
||||
// OpenAI settings - you can set the OPENAI_API_KEY to an invalid value to see the retry policy in play
|
||||
kernelBuilder = kernelBuilder.Configure(c => c.AddOpenAITextCompletionService("text-davinci-003", "BAD_KEY"));
|
||||
|
||||
var kernel = kernelBuilder.Build();
|
||||
var kernel = Kernel.Builder.WithLogger(InfoLogger.Log)
|
||||
.WithRetryHandlerFactory((Activator.CreateInstance(retryHandlerFactoryType) as IDelegatingHandlerFactory)!)
|
||||
// OpenAI settings - you can set the OPENAI_API_KEY to an invalid value to see the retry policy in play
|
||||
.WithOpenAITextCompletionService("text-davinci-003", "BAD_KEY")
|
||||
.Build();
|
||||
|
||||
await ImportAndExecuteSkillAsync(kernel);
|
||||
}
|
||||
|
||||
@@ -18,8 +18,10 @@ public static class Example09_FunctionTypes
|
||||
|
||||
var fakeContext = new SKContext(logger: ConsoleLogger.Log);
|
||||
|
||||
var kernel = Kernel.Builder.WithLogger(ConsoleLogger.Log).Build();
|
||||
kernel.Config.AddOpenAITextCompletionService("text-davinci-003", Env.Var("OPENAI_API_KEY"));
|
||||
var kernel = Kernel.Builder
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
.WithOpenAITextCompletionService("text-davinci-003", Env.Var("OPENAI_API_KEY"))
|
||||
.Build();
|
||||
|
||||
// Load native skill into the kernel skill collection, sharing its functions with prompt templates
|
||||
var test = kernel.ImportSkill(new LocalExampleSkill(), "test");
|
||||
|
||||
@@ -20,8 +20,9 @@ public static class Example10_DescribeAllSkillsAndFunctions
|
||||
{
|
||||
Console.WriteLine("======== Describe all skills and functions ========");
|
||||
|
||||
var kernel = KernelBuilder.Create();
|
||||
kernel.Config.AddOpenAITextCompletionService("text-davinci-003", "none");
|
||||
var kernel = Kernel.Builder
|
||||
.WithOpenAITextCompletionService("text-davinci-003", "none")
|
||||
.Build();
|
||||
|
||||
// Import a native skill
|
||||
var skill1 = new StaticTextSkill();
|
||||
|
||||
@@ -25,11 +25,14 @@ internal static class Example12_SequentialPlanner
|
||||
private static async Task PoetrySamplesAsync()
|
||||
{
|
||||
Console.WriteLine("======== Sequential Planner - Create and Execute Poetry Plan ========");
|
||||
var kernel = new KernelBuilder().WithLogger(ConsoleLogger.Log).Build();
|
||||
kernel.Config.AddAzureTextCompletionService(
|
||||
Env.Var("AZURE_OPENAI_DEPLOYMENT_NAME"),
|
||||
Env.Var("AZURE_OPENAI_ENDPOINT"),
|
||||
Env.Var("AZURE_OPENAI_KEY"));
|
||||
var kernel = new KernelBuilder()
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
.WithAzureTextCompletionService(
|
||||
Env.Var("AZURE_OPENAI_SERVICE_ID"),
|
||||
Env.Var("AZURE_OPENAI_DEPLOYMENT_NAME"),
|
||||
Env.Var("AZURE_OPENAI_ENDPOINT"),
|
||||
Env.Var("AZURE_OPENAI_KEY"))
|
||||
.Build();
|
||||
|
||||
string folder = RepoFiles.SampleSkillsPath();
|
||||
kernel.ImportSemanticSkillFromDirectory(folder,
|
||||
@@ -135,19 +138,14 @@ internal static class Example12_SequentialPlanner
|
||||
|
||||
var kernel = new KernelBuilder()
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
.Configure(
|
||||
config =>
|
||||
{
|
||||
config.AddAzureTextCompletionService(
|
||||
.WithAzureTextCompletionService(
|
||||
Env.Var("AZURE_OPENAI_DEPLOYMENT_NAME"),
|
||||
Env.Var("AZURE_OPENAI_ENDPOINT"),
|
||||
Env.Var("AZURE_OPENAI_KEY"));
|
||||
|
||||
config.AddAzureTextEmbeddingGenerationService(
|
||||
Env.Var("AZURE_OPENAI_KEY"))
|
||||
.WithAzureTextEmbeddingGenerationService(
|
||||
Env.Var("AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT_NAME"),
|
||||
Env.Var("AZURE_OPENAI_EMBEDDINGS_ENDPOINT"),
|
||||
Env.Var("AZURE_OPENAI_EMBEDDINGS_KEY"));
|
||||
})
|
||||
Env.Var("AZURE_OPENAI_EMBEDDINGS_KEY"))
|
||||
.WithMemoryStorage(new VolatileMemoryStore())
|
||||
.Build();
|
||||
|
||||
@@ -182,11 +180,13 @@ internal static class Example12_SequentialPlanner
|
||||
|
||||
private static IKernel InitializeKernelAndPlanner(out SequentialPlanner planner, int maxTokens = 1024)
|
||||
{
|
||||
var kernel = new KernelBuilder().WithLogger(ConsoleLogger.Log).Build();
|
||||
kernel.Config.AddAzureTextCompletionService(
|
||||
Env.Var("AZURE_OPENAI_DEPLOYMENT_NAME"),
|
||||
Env.Var("AZURE_OPENAI_ENDPOINT"),
|
||||
Env.Var("AZURE_OPENAI_KEY"));
|
||||
var kernel = new KernelBuilder()
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
.WithAzureTextCompletionService(
|
||||
Env.Var("AZURE_OPENAI_DEPLOYMENT_NAME"),
|
||||
Env.Var("AZURE_OPENAI_ENDPOINT"),
|
||||
Env.Var("AZURE_OPENAI_KEY"))
|
||||
.Build();
|
||||
|
||||
planner = new SequentialPlanner(kernel, new SequentialPlannerConfig { MaxTokens = maxTokens });
|
||||
|
||||
|
||||
@@ -178,11 +178,13 @@ Jane: Goodbye!
|
||||
|
||||
private static IKernel InitializeKernel()
|
||||
{
|
||||
IKernel kernel = Kernel.Builder.WithLogger(ConsoleLogger.Log).Build();
|
||||
kernel.Config.AddAzureTextCompletionService(
|
||||
Env.Var("AZURE_OPENAI_DEPLOYMENT_NAME"),
|
||||
Env.Var("AZURE_OPENAI_ENDPOINT"),
|
||||
Env.Var("AZURE_OPENAI_KEY"));
|
||||
IKernel kernel = Kernel.Builder
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
.WithAzureTextCompletionService(
|
||||
Env.Var("AZURE_OPENAI_DEPLOYMENT_NAME"),
|
||||
Env.Var("AZURE_OPENAI_ENDPOINT"),
|
||||
Env.Var("AZURE_OPENAI_KEY"))
|
||||
.Build();
|
||||
|
||||
return kernel;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ public static class Example14_SemanticMemory
|
||||
|
||||
var kernelWithCustomDb = Kernel.Builder
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
.Configure(c => c.AddOpenAITextEmbeddingGenerationService("ada", "text-embedding-ada-002", Env.Var("OPENAI_API_KEY")))
|
||||
.WithOpenAITextEmbeddingGenerationService("ada", "text-embedding-ada-002", Env.Var("OPENAI_API_KEY"))
|
||||
.WithMemoryStorage(new VolatileMemoryStore())
|
||||
.Build();
|
||||
|
||||
|
||||
@@ -17,11 +17,8 @@ public static class Example15_MemorySkill
|
||||
{
|
||||
var kernel = Kernel.Builder
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
.Configure(c =>
|
||||
{
|
||||
c.AddOpenAITextCompletionService("text-davinci-003", Env.Var("OPENAI_API_KEY"));
|
||||
c.AddOpenAITextEmbeddingGenerationService("text-embedding-ada-002", Env.Var("OPENAI_API_KEY"));
|
||||
})
|
||||
.WithOpenAITextCompletionService("text-davinci-003", Env.Var("OPENAI_API_KEY"))
|
||||
.WithOpenAITextEmbeddingGenerationService("text-embedding-ada-002", Env.Var("OPENAI_API_KEY"))
|
||||
.WithMemoryStorage(new VolatileMemoryStore())
|
||||
.Build();
|
||||
|
||||
|
||||
@@ -85,12 +85,13 @@ public static class Example16_CustomLLM
|
||||
{
|
||||
Console.WriteLine("======== Custom LLM - Text Completion - SKFunction ========");
|
||||
|
||||
IKernel kernel = new KernelBuilder().WithLogger(ConsoleLogger.Log).Build();
|
||||
|
||||
ITextCompletion Factory(IKernel k) => new MyTextCompletionService();
|
||||
|
||||
// Add your text completion service
|
||||
kernel.Config.AddTextCompletionService(Factory);
|
||||
IKernel kernel = new KernelBuilder()
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
// Add your text completion service as a singleton instance
|
||||
.WithAIService<ITextCompletion>("myService1", new MyTextCompletionService())
|
||||
// Add your text completion service as a factory method
|
||||
.WithAIService<ITextCompletion>("myService2", (_) => new MyTextCompletionService())
|
||||
.Build();
|
||||
|
||||
const string FunctionDefinition = "Does the text contain grammar errors (Y/N)? Text: {{$input}}";
|
||||
|
||||
|
||||
@@ -52,10 +52,11 @@ public static class Example17_ChatGPT
|
||||
{
|
||||
Console.WriteLine("======== Open AI - ChatGPT ========");
|
||||
|
||||
IKernel kernel = new KernelBuilder().WithLogger(ConsoleLogger.Log).Build();
|
||||
|
||||
// Add your chat completion service
|
||||
kernel.Config.AddOpenAIChatCompletionService("gpt-3.5-turbo", Env.Var("OPENAI_API_KEY"));
|
||||
IKernel kernel = new KernelBuilder()
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
.WithOpenAIChatCompletionService("gpt-3.5-turbo", Env.Var("OPENAI_API_KEY"))
|
||||
.Build();
|
||||
|
||||
IChatCompletion chatGPT = kernel.GetService<IChatCompletion>();
|
||||
|
||||
@@ -66,13 +67,13 @@ public static class Example17_ChatGPT
|
||||
{
|
||||
Console.WriteLine("======== Azure Open AI - ChatGPT ========");
|
||||
|
||||
IKernel kernel = new KernelBuilder().WithLogger(ConsoleLogger.Log).Build();
|
||||
|
||||
// Add your chat completion service
|
||||
kernel.Config.AddAzureChatCompletionService(
|
||||
Env.Var("AZURE_OPENAI_CHAT_DEPLOYMENT_NAME"),
|
||||
Env.Var("AZURE_OPENAI_ENDPOINT"),
|
||||
Env.Var("AZURE_OPENAI_KEY"));
|
||||
IKernel kernel = new KernelBuilder()
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
.WithAzureChatCompletionService(
|
||||
Env.Var("AZURE_OPENAI_CHAT_DEPLOYMENT_NAME"),
|
||||
Env.Var("AZURE_OPENAI_ENDPOINT"),
|
||||
Env.Var("AZURE_OPENAI_KEY")) // Add your chat completion service
|
||||
.Build();
|
||||
|
||||
IChatCompletion chatGPT = kernel.GetService<IChatCompletion>();
|
||||
|
||||
|
||||
@@ -19,10 +19,13 @@ public static class Example18_DallE
|
||||
{
|
||||
Console.WriteLine("======== Dall-E 2 Image Generation ========");
|
||||
|
||||
IKernel kernel = new KernelBuilder().WithLogger(ConsoleLogger.Log).Build();
|
||||
|
||||
// Add your image generation service
|
||||
kernel.Config.AddOpenAIImageGenerationService(Env.Var("OPENAI_API_KEY"));
|
||||
IKernel kernel = new KernelBuilder()
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
// Add your image generation service
|
||||
.WithOpenAIImageGenerationService("dallE", Env.Var("OPENAI_API_KEY"))
|
||||
// Add your chat completion service
|
||||
.WithOpenAIChatCompletionService("gpt-3.5-turbo", Env.Var("OPENAI_API_KEY"))
|
||||
.Build();
|
||||
|
||||
IImageGeneration dallE = kernel.GetService<IImageGeneration>();
|
||||
|
||||
@@ -41,9 +44,6 @@ public static class Example18_DallE
|
||||
|
||||
Console.WriteLine("======== Chat with images ========");
|
||||
|
||||
// Add your chat completion service
|
||||
kernel.Config.AddOpenAIChatCompletionService("gpt-3.5-turbo", Env.Var("OPENAI_API_KEY"));
|
||||
|
||||
IChatCompletion chatGPT = kernel.GetService<IChatCompletion>();
|
||||
var chatHistory = (OpenAIChatHistory)chatGPT.CreateNewChat(
|
||||
"You're chatting with a user. Instead of replying directly to the user" +
|
||||
|
||||
@@ -19,11 +19,8 @@ public static class Example19_Qdrant
|
||||
QdrantMemoryStore memoryStore = new(Env.Var("QDRANT_ENDPOINT"), qdrantPort, vectorSize: 1536, ConsoleLogger.Log);
|
||||
IKernel kernel = Kernel.Builder
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
.Configure(c =>
|
||||
{
|
||||
c.AddOpenAITextCompletionService("text-davinci-003", Env.Var("OPENAI_API_KEY"));
|
||||
c.AddOpenAITextEmbeddingGenerationService("text-embedding-ada-002", Env.Var("OPENAI_API_KEY"));
|
||||
})
|
||||
.WithOpenAITextCompletionService("text-davinci-003", Env.Var("OPENAI_API_KEY"))
|
||||
.WithOpenAITextEmbeddingGenerationService("text-embedding-ada-002", Env.Var("OPENAI_API_KEY"))
|
||||
.WithMemoryStorage(memoryStore)
|
||||
.Build();
|
||||
|
||||
|
||||
@@ -17,10 +17,11 @@ public static class Example20_HuggingFace
|
||||
{
|
||||
Console.WriteLine("======== HuggingFace text completion AI ========");
|
||||
|
||||
IKernel kernel = new KernelBuilder().WithLogger(ConsoleLogger.Log).Build();
|
||||
|
||||
// Add HuggingFace text completion service
|
||||
kernel.Config.AddTextCompletionService(_ => new HuggingFaceTextCompletion(Env.Var("HF_API_KEY"), model: "gpt2"));
|
||||
IKernel kernel = new KernelBuilder()
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
// Add HuggingFace text completion service as a factory methods
|
||||
.WithDefaultAIService((_) => new HuggingFaceTextCompletion(Env.Var("HF_API_KEY"), "gpt2"))
|
||||
.Build();
|
||||
|
||||
const string FunctionDefinition = "Question: {{$input}}; Answer:";
|
||||
|
||||
|
||||
@@ -28,8 +28,6 @@ public static class Example26_AADAuth
|
||||
{
|
||||
Console.WriteLine("======== SK with AAD Auth ========");
|
||||
|
||||
IKernel kernel = new KernelBuilder().WithLogger(ConsoleLogger.Log).Build();
|
||||
|
||||
// Optional: choose which authentication to support
|
||||
var authOptions = new DefaultAzureCredentialOptions
|
||||
{
|
||||
@@ -42,11 +40,14 @@ public static class Example26_AADAuth
|
||||
ExcludeInteractiveBrowserCredential = true,
|
||||
};
|
||||
|
||||
// Add Azure chat completion service using DefaultAzureCredential AAD auth
|
||||
kernel.Config.AddAzureChatCompletionService(
|
||||
"gpt-35-turbo",
|
||||
"https://....openai.azure.com/",
|
||||
new DefaultAzureCredential(authOptions));
|
||||
IKernel kernel = new KernelBuilder()
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
// Add Azure chat completion service using DefaultAzureCredential AAD auth
|
||||
.WithAzureChatCompletionService(
|
||||
"gpt-35-turbo",
|
||||
"https://....openai.azure.com/",
|
||||
new DefaultAzureCredential(authOptions))
|
||||
.Build();
|
||||
|
||||
IChatCompletion chatGPT = kernel.GetService<IChatCompletion>();
|
||||
var chatHistory = (OpenAIChatHistory)chatGPT.CreateNewChat();
|
||||
|
||||
@@ -16,10 +16,11 @@ public static class Example27_SemanticFunctionsUsingChatGPT
|
||||
{
|
||||
Console.WriteLine("======== Using Chat GPT model for text completion ========");
|
||||
|
||||
IKernel kernel = new KernelBuilder().WithLogger(ConsoleLogger.Log).Build();
|
||||
|
||||
// Note: we use Chat Completion and GPT 3.5 Turbo
|
||||
kernel.Config.AddAzureChatCompletionService("gpt-35-turbo", "https://....openai.azure.com/", "...API KEY...");
|
||||
IKernel kernel = new KernelBuilder()
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
// Note: we use Chat Completion and GPT 3.5 Turbo
|
||||
.WithAzureChatCompletionService("gpt-35-turbo", "https://....openai.azure.com/", "...API KEY...")
|
||||
.Build();
|
||||
|
||||
var func = kernel.CreateSemanticFunction(
|
||||
"List the two planets closest to '{{$input}}', excluding moons, using bullet points.");
|
||||
|
||||
@@ -13,10 +13,10 @@ public static class Example28_ActionPlanner
|
||||
public static async Task RunAsync()
|
||||
{
|
||||
Console.WriteLine("======== Action Planner ========");
|
||||
var kernel = new KernelBuilder().WithLogger(ConsoleLogger.Log).Build();
|
||||
|
||||
// Note: Action Planner works with old models like text-davinci-002
|
||||
kernel.Config.AddOpenAITextCompletionService("text-davinci-002", Env.Var("OPENAI_API_KEY"));
|
||||
var kernel = new KernelBuilder()
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
.WithOpenAITextCompletionService("text-davinci-002", Env.Var("OPENAI_API_KEY"))// Note: Action Planner works with old models like text-davinci-002
|
||||
.Build();
|
||||
|
||||
string folder = RepoFiles.SampleSkillsPath();
|
||||
kernel.ImportSemanticSkillFromDirectory(folder, "SummarizeSkill");
|
||||
|
||||
@@ -63,8 +63,10 @@ public static class Example30_ChatWithPrompts
|
||||
var userPromptTemplate = EmbeddedResource.Read("30-user-prompt.txt");
|
||||
|
||||
// Usual kernel initialization, with GPT 3.5 Turbo
|
||||
IKernel kernel = new KernelBuilder().WithLogger(ConsoleLogger.Log).Build();
|
||||
kernel.Config.AddOpenAIChatCompletionService("gpt-3.5-turbo", Env.Var("OPENAI_API_KEY"));
|
||||
IKernel kernel = new KernelBuilder()
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
.WithOpenAIChatCompletionService("gpt-3.5-turbo", Env.Var("OPENAI_API_KEY"), serviceId: "chat")
|
||||
.Build();
|
||||
|
||||
// As an example, we import the time skill, which is used in system prompt to read the current date.
|
||||
// We could also use a variable, this is just to show that the prompt can invoke functions.
|
||||
|
||||
@@ -120,19 +120,14 @@ internal static class Example31_CustomPlanner
|
||||
{
|
||||
return new KernelBuilder()
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
.Configure(
|
||||
config =>
|
||||
{
|
||||
config.AddAzureTextCompletionService(
|
||||
Env.Var("AZURE_OPENAI_DEPLOYMENT_NAME"),
|
||||
Env.Var("AZURE_OPENAI_ENDPOINT"),
|
||||
Env.Var("AZURE_OPENAI_KEY"));
|
||||
|
||||
config.AddAzureTextEmbeddingGenerationService(
|
||||
Env.Var("AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT_NAME"),
|
||||
Env.Var("AZURE_OPENAI_EMBEDDINGS_ENDPOINT"),
|
||||
Env.Var("AZURE_OPENAI_EMBEDDINGS_KEY"));
|
||||
})
|
||||
.WithAzureTextCompletionService(
|
||||
Env.Var("AZURE_OPENAI_DEPLOYMENT_NAME"),
|
||||
Env.Var("AZURE_OPENAI_ENDPOINT"),
|
||||
Env.Var("AZURE_OPENAI_KEY"))
|
||||
.WithAzureTextEmbeddingGenerationService(
|
||||
Env.Var("AZURE_OPENAI_EMBEDDINGS_DEPLOYMENT_NAME"),
|
||||
Env.Var("AZURE_OPENAI_EMBEDDINGS_ENDPOINT"),
|
||||
Env.Var("AZURE_OPENAI_EMBEDDINGS_KEY"))
|
||||
.WithMemoryStorage(new VolatileMemoryStore())
|
||||
.Build();
|
||||
}
|
||||
|
||||
@@ -22,11 +22,13 @@ public static class Example32_StreamingCompletion
|
||||
{
|
||||
Console.WriteLine("======== Azure OpenAI - Text Completion - Raw Streaming ========");
|
||||
|
||||
IKernel kernel = new KernelBuilder().WithLogger(ConsoleLogger.Log).Build();
|
||||
kernel.Config.AddAzureTextCompletionService(
|
||||
Env.Var("AZURE_OPENAI_DEPLOYMENT_NAME"),
|
||||
Env.Var("AZURE_OPENAI_ENDPOINT"),
|
||||
Env.Var("AZURE_OPENAI_KEY"));
|
||||
IKernel kernel = new KernelBuilder()
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
.WithAzureTextCompletionService(
|
||||
Env.Var("AZURE_OPENAI_DEPLOYMENT_NAME"),
|
||||
Env.Var("AZURE_OPENAI_ENDPOINT"),
|
||||
Env.Var("AZURE_OPENAI_KEY"))
|
||||
.Build();
|
||||
|
||||
ITextCompletion textCompletion = kernel.GetService<ITextCompletion>();
|
||||
|
||||
@@ -37,8 +39,10 @@ public static class Example32_StreamingCompletion
|
||||
{
|
||||
Console.WriteLine("======== Open AI - Text Completion - Raw Streaming ========");
|
||||
|
||||
IKernel kernel = new KernelBuilder().WithLogger(ConsoleLogger.Log).Build();
|
||||
kernel.Config.AddOpenAITextCompletionService("text-davinci-003", Env.Var("OPENAI_API_KEY"), serviceId: "text-davinci-003");
|
||||
IKernel kernel = new KernelBuilder()
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
.WithOpenAITextCompletionService("text-davinci-003", Env.Var("OPENAI_API_KEY"), serviceId: "text-davinci-003")
|
||||
.Build();
|
||||
|
||||
ITextCompletion textCompletion = kernel.GetService<ITextCompletion>();
|
||||
|
||||
|
||||
@@ -24,10 +24,10 @@ public static class Example33_StreamingChat
|
||||
{
|
||||
Console.WriteLine("======== Open AI - ChatGPT Streaming ========");
|
||||
|
||||
IKernel kernel = new KernelBuilder().WithLogger(ConsoleLogger.Log).Build();
|
||||
|
||||
// Add your chat completion service
|
||||
kernel.Config.AddOpenAIChatCompletionService("gpt-3.5-turbo", Env.Var("OPENAI_API_KEY"));
|
||||
IKernel kernel = new KernelBuilder()
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
.WithOpenAIChatCompletionService("gpt-3.5-turbo", Env.Var("OPENAI_API_KEY")) // Add your chat completion service
|
||||
.Build();
|
||||
|
||||
IChatCompletion chatGPT = kernel.GetService<IChatCompletion>();
|
||||
|
||||
@@ -38,13 +38,10 @@ public static class Example33_StreamingChat
|
||||
{
|
||||
Console.WriteLine("======== Azure Open AI - ChatGPT Streaming ========");
|
||||
|
||||
IKernel kernel = new KernelBuilder().WithLogger(ConsoleLogger.Log).Build();
|
||||
|
||||
// Add your chat completion service
|
||||
kernel.Config.AddAzureChatCompletionService(
|
||||
Env.Var("AZURE_OPENAI_CHAT_DEPLOYMENT_NAME"),
|
||||
Env.Var("AZURE_OPENAI_ENDPOINT"),
|
||||
Env.Var("AZURE_OPENAI_KEY"));
|
||||
IKernel kernel = new KernelBuilder()
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
.WithAzureChatCompletionService(Env.Var("AZURE_OPENAI_CHAT_DEPLOYMENT_NAME"), Env.Var("AZURE_OPENAI_ENDPOINT"), Env.Var("OPENAI_API_KEY")) // Add your chat completion service
|
||||
.Build();
|
||||
|
||||
IChatCompletion chatGPT = kernel.GetService<IChatCompletion>();
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.AI.ChatCompletion;
|
||||
using RepoUtils;
|
||||
@@ -81,11 +82,12 @@ public static class Example34_CustomChatModel
|
||||
{
|
||||
Console.WriteLine("======== Custom LLM - Chat Completion ========");
|
||||
|
||||
IKernel kernel = new KernelBuilder().WithLogger(ConsoleLogger.Log).Build();
|
||||
IChatCompletion Factory(ILogger l) => new MyChatCompletionService();
|
||||
|
||||
IChatCompletion Factory(IKernel k) => new MyChatCompletionService();
|
||||
// Add your chat completion service
|
||||
kernel.Config.AddChatCompletionService(Factory);
|
||||
IKernel kernel = new KernelBuilder()
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
.WithDefaultAIService<IChatCompletion>(Factory)
|
||||
.Build();
|
||||
|
||||
IChatCompletion customChat = kernel.GetService<IChatCompletion>();
|
||||
|
||||
@@ -113,11 +115,12 @@ public static class Example34_CustomChatModel
|
||||
{
|
||||
Console.WriteLine("======== Custom LLM - Chat Completion Streaming ========");
|
||||
|
||||
IKernel kernel = new KernelBuilder().WithLogger(ConsoleLogger.Log).Build();
|
||||
IChatCompletion Factory(ILogger l) => new MyChatCompletionService();
|
||||
|
||||
IChatCompletion Factory(IKernel k) => new MyChatCompletionService();
|
||||
// Add your chat completion service
|
||||
kernel.Config.AddChatCompletionService(Factory);
|
||||
IKernel kernel = new KernelBuilder()
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
.WithDefaultAIService<IChatCompletion>(Factory)
|
||||
.Build();
|
||||
|
||||
IChatCompletion customChat = kernel.GetService<IChatCompletion>();
|
||||
|
||||
|
||||
@@ -22,11 +22,12 @@ public static class Example36_MultiCompletion
|
||||
{
|
||||
Console.WriteLine("======== Azure OpenAI - Multiple Text Completion ========");
|
||||
|
||||
IKernel kernel = new KernelBuilder().WithLogger(ConsoleLogger.Log).Build();
|
||||
kernel.Config.AddAzureTextCompletionService(
|
||||
Env.Var("AZURE_OPENAI_DEPLOYMENT_NAME"),
|
||||
Env.Var("AZURE_OPENAI_ENDPOINT"),
|
||||
Env.Var("AZURE_OPENAI_KEY"));
|
||||
IKernel kernel = new KernelBuilder()
|
||||
.WithAzureTextCompletionService(
|
||||
Env.Var("AZURE_OPENAI_DEPLOYMENT_NAME"),
|
||||
Env.Var("AZURE_OPENAI_ENDPOINT"),
|
||||
Env.Var("AZURE_OPENAI_KEY"))
|
||||
.WithLogger(ConsoleLogger.Log).Build();
|
||||
|
||||
ITextCompletion textCompletion = kernel.GetService<ITextCompletion>();
|
||||
|
||||
@@ -37,8 +38,9 @@ public static class Example36_MultiCompletion
|
||||
{
|
||||
Console.WriteLine("======== Open AI - Multiple Text Completion ========");
|
||||
|
||||
IKernel kernel = new KernelBuilder().WithLogger(ConsoleLogger.Log).Build();
|
||||
kernel.Config.AddOpenAITextCompletionService("text-davinci-003", Env.Var("OPENAI_API_KEY"), serviceId: "text-davinci-003");
|
||||
IKernel kernel = new KernelBuilder()
|
||||
.WithOpenAITextCompletionService("text-davinci-003", Env.Var("OPENAI_API_KEY"), serviceId: "text-davinci-003")
|
||||
.WithLogger(ConsoleLogger.Log).Build();
|
||||
|
||||
ITextCompletion textCompletion = kernel.GetService<ITextCompletion>();
|
||||
|
||||
|
||||
@@ -25,11 +25,12 @@ public static class Example37_MultiStreamingCompletion
|
||||
{
|
||||
Console.WriteLine("======== Azure OpenAI - Multiple Text Completion - Raw Streaming ========");
|
||||
|
||||
IKernel kernel = new KernelBuilder().WithLogger(ConsoleLogger.Log).Build();
|
||||
kernel.Config.AddAzureTextCompletionService(
|
||||
Env.Var("AZURE_OPENAI_DEPLOYMENT_NAME"),
|
||||
Env.Var("AZURE_OPENAI_ENDPOINT"),
|
||||
Env.Var("AZURE_OPENAI_KEY"));
|
||||
IKernel kernel = new KernelBuilder()
|
||||
.WithAzureTextCompletionService(
|
||||
Env.Var("AZURE_OPENAI_DEPLOYMENT_NAME"),
|
||||
Env.Var("AZURE_OPENAI_ENDPOINT"),
|
||||
Env.Var("AZURE_OPENAI_KEY"))
|
||||
.WithLogger(ConsoleLogger.Log).Build();
|
||||
|
||||
ITextCompletion textCompletion = kernel.GetService<ITextCompletion>();
|
||||
|
||||
@@ -40,8 +41,9 @@ public static class Example37_MultiStreamingCompletion
|
||||
{
|
||||
Console.WriteLine("======== Open AI - Multiple Text Completion - Raw Streaming ========");
|
||||
|
||||
IKernel kernel = new KernelBuilder().WithLogger(ConsoleLogger.Log).Build();
|
||||
kernel.Config.AddOpenAITextCompletionService("text-davinci-003", Env.Var("OPENAI_API_KEY"), serviceId: "text-davinci-003");
|
||||
IKernel kernel = new KernelBuilder()
|
||||
.WithOpenAITextCompletionService("text-davinci-003", Env.Var("OPENAI_API_KEY"), serviceId: "text-davinci-003")
|
||||
.WithLogger(ConsoleLogger.Log).Build();
|
||||
|
||||
ITextCompletion textCompletion = kernel.GetService<ITextCompletion>();
|
||||
|
||||
|
||||
@@ -29,11 +29,8 @@ public static class Example38_Pinecone
|
||||
|
||||
IKernel kernel = Kernel.Builder
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
.Configure(c =>
|
||||
{
|
||||
c.AddOpenAITextCompletionService("text-davinci-003", Env.Var("OPENAI_API_KEY"));
|
||||
c.AddOpenAITextEmbeddingGenerationService("text-embedding-ada-002", Env.Var("OPENAI_API_KEY"));
|
||||
})
|
||||
.WithOpenAITextCompletionService("text-davinci-003", Env.Var("OPENAI_API_KEY"))
|
||||
.WithOpenAITextEmbeddingGenerationService("text-embedding-ada-002", Env.Var("OPENAI_API_KEY"))
|
||||
.WithMemoryStorage(memoryStore)
|
||||
.Build();
|
||||
|
||||
|
||||
@@ -18,11 +18,8 @@ public static class Example39_Postgres
|
||||
using PostgresMemoryStore memoryStore = await PostgresMemoryStore.ConnectAsync(connectionString, vectorSize: 1536);
|
||||
IKernel kernel = Kernel.Builder
|
||||
.WithLogger(ConsoleLogger.Log)
|
||||
.Configure(c =>
|
||||
{
|
||||
c.AddOpenAITextCompletionService("text-davinci-003", Env.Var("OPENAI_API_KEY"));
|
||||
c.AddOpenAITextEmbeddingGenerationService("text-embedding-ada-002", Env.Var("OPENAI_API_KEY"));
|
||||
})
|
||||
.WithOpenAITextCompletionService("text-davinci-003", Env.Var("OPENAI_API_KEY"))
|
||||
.WithOpenAITextEmbeddingGenerationService("text-embedding-ada-002", Env.Var("OPENAI_API_KEY"))
|
||||
.WithMemoryStorage(memoryStore)
|
||||
.Build();
|
||||
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.AI.TextCompletion;
|
||||
using Microsoft.SemanticKernel.Connectors.AI.OpenAI.TextCompletion;
|
||||
using Microsoft.SemanticKernel.Memory;
|
||||
using Microsoft.SemanticKernel.Services;
|
||||
using Microsoft.SemanticKernel.SkillDefinition;
|
||||
using Microsoft.SemanticKernel.TemplateEngine;
|
||||
using RepoUtils;
|
||||
|
||||
/**
|
||||
* The following examples show how to use SK SDK in applications using DI/IoC containers.
|
||||
*/
|
||||
public static class Example40_DIContainer
|
||||
{
|
||||
public static async Task RunAsync()
|
||||
{
|
||||
await UseKernelInDIPowerAppAsync();
|
||||
|
||||
await UseKernelInDIPowerApp_AdvancedScenarioAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This example shows how to register a Kernel in a DI container using KernelBuilder instead of
|
||||
/// registering its dependencies.
|
||||
/// </summary>
|
||||
private static async Task UseKernelInDIPowerAppAsync()
|
||||
{
|
||||
//Bootstrapping code that initializes the modules, components, and classes that applications use.
|
||||
//For regular .NET applications, the bootstrapping code usually resides either in the Main method or very close to it.
|
||||
//In ASP.NET Core applications, the bootstrapping code is typically located in the ConfigureServices method of the Startup class.
|
||||
|
||||
//Registering Kernel dependencies
|
||||
var collection = new ServiceCollection();
|
||||
collection.AddTransient<ILogger>((_) => ConsoleLogger.Log);
|
||||
|
||||
//Registering Kernel
|
||||
collection.AddTransient<IKernel>((serviceProvider) =>
|
||||
{
|
||||
return Kernel.Builder
|
||||
.WithLogger(serviceProvider.GetRequiredService<ILogger>())
|
||||
.WithOpenAITextCompletionService("text-davinci-002", Env.Var("OPENAI_API_KEY"))
|
||||
.Build();
|
||||
});
|
||||
|
||||
//Registering class that uses Kernel to execute a skill
|
||||
collection.AddTransient<KernelClient>();
|
||||
|
||||
//Creating a service provider for resolving registered services
|
||||
var serviceProvider = collection.BuildServiceProvider();
|
||||
|
||||
//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
|
||||
var kernelClient = serviceProvider.GetRequiredService<KernelClient>();
|
||||
|
||||
//Execute the function
|
||||
await kernelClient.SummarizeAsync("What's the tallest building in South America?");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This example shows how to registered Kernel and all its dependencies in DI container.
|
||||
/// </summary>
|
||||
private static async Task UseKernelInDIPowerApp_AdvancedScenarioAsync()
|
||||
{
|
||||
//Bootstrapping code that initializes the modules, components, and classes that applications use.
|
||||
//For regular .NET applications, the bootstrapping code usually resides either in the Main method or very close to it.
|
||||
//In ASP.NET Core applications, the bootstrapping code is typically located in the ConfigureServices method of the Startup class.
|
||||
|
||||
//Registering AI services Kernel is going to use
|
||||
var aiServicesCollection = new AIServiceCollection();
|
||||
aiServicesCollection.SetService<ITextCompletion>(() => new OpenAITextCompletion("text-davinci-002", Env.Var("OPENAI_API_KEY")));
|
||||
|
||||
//Registering Kernel dependencies
|
||||
var collection = new ServiceCollection();
|
||||
collection.AddTransient<ILogger>((_) => ConsoleLogger.Log);
|
||||
collection.AddTransient<KernelConfig>();
|
||||
collection.AddTransient<ISkillCollection, SkillCollection>();
|
||||
collection.AddTransient<IPromptTemplateEngine, PromptTemplateEngine>();
|
||||
collection.AddTransient<ISemanticTextMemory>((_) => NullMemory.Instance);
|
||||
collection.AddTransient<IAIServiceProvider>((_) => aiServicesCollection.Build()); //Registering AI service provider that is used by Kernel to resolve AI services runtime
|
||||
|
||||
//Registering Kernel
|
||||
collection.AddTransient<IKernel, Kernel>();
|
||||
|
||||
//Registering class that uses Kernel to execute a skill
|
||||
collection.AddTransient<KernelClient>();
|
||||
|
||||
//Creating a service provider for resolving registered services
|
||||
var serviceProvider = collection.BuildServiceProvider();
|
||||
|
||||
//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
|
||||
var kernelClient = serviceProvider.GetRequiredService<KernelClient>();
|
||||
|
||||
//Execute the function
|
||||
await kernelClient.SummarizeAsync("What's the tallest building in South America?");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class that uses/references Kernel.
|
||||
/// </summary>
|
||||
#pragma warning disable CA1812 // Avoid uninstantiated internal classes
|
||||
private sealed class KernelClient
|
||||
#pragma warning restore CA1812 // Avoid uninstantiated internal classes
|
||||
{
|
||||
private readonly IKernel _kernel;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public KernelClient(IKernel kernel, ILogger logger)
|
||||
{
|
||||
this._kernel = kernel;
|
||||
this._logger = logger;
|
||||
}
|
||||
|
||||
public async Task SummarizeAsync(string ask)
|
||||
{
|
||||
string folder = RepoFiles.SampleSkillsPath();
|
||||
|
||||
var sumSkill = this._kernel.ImportSemanticSkillFromDirectory(folder, "SummarizeSkill");
|
||||
|
||||
var result = await this._kernel.RunAsync(ask, sumSkill["Summarize"]);
|
||||
|
||||
this._logger.LogWarning("Result - {0}", result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@
|
||||
<PackageReference Include="Azure.Identity" Version="1.9.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0-preview.3.23174.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="Polly" Version="7.2.3" />
|
||||
|
||||
@@ -124,5 +124,8 @@ public static class Program
|
||||
|
||||
await Example39_Postgres.RunAsync();
|
||||
Console.WriteLine("== DONE ==");
|
||||
|
||||
await Example40_DIContainer.RunAsync();
|
||||
Console.WriteLine("== DONE ==");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user