mirror of
https://github.com/microsoft/semantic-kernel.git
synced 2026-10-12 02:19:06 +00:00
.Net: Update telemetry sample and documentation (#6191)
### Motivation and Context <!-- Thank you for your contribution to the semantic-kernel repo! Please help reviewers and future users, providing the following information: 1. Why is this change required? 2. What problem does it solve? 3. What scenario does it contribute to? 4. If it fixes an open issue, please link to the issue here. --> SK has included the OTel semantic conventions as an experimental feature. ### Description <!-- Describe your changes, the overall approach, the underlying design. These notes will help understanding how your code works. Thanks! --> This PR updates the telemetry sample app to show case the feature and removes the use of planners in the sample app as not all connectors work with the Handlebars planner (The Handlebars planner has multiple system messages, but the Gemini connector doesn't allow that). This PR also updates the documentations for telemetry. ### Contribution Checklist <!-- Before submitting this PR, please make sure: --> - [ ] The code builds clean without any errors or warnings - [ ] The PR follows the [SK Contribution Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts) raises no violations - [ ] All unit tests pass, and I have added new tests where possible - [ ] I didn't break anyone 😄
This commit is contained in:
@@ -58,13 +58,13 @@ block-beta
|
||||
columns 1
|
||||
Models
|
||||
blockArrowId1<[" "]>(y)
|
||||
block:Connectors
|
||||
block:Clients
|
||||
columns 3
|
||||
ConnectorTypeClientA["Instrumented client SDK<br>(i.e. Azure OpenAI client)"]
|
||||
ConnectorTypeClientB["Un-instrumented Client SDK"]
|
||||
ConnectorTypeClientC["Custom client on REST API<br>(i.e. HuggingFaceClient)"]
|
||||
end
|
||||
Services["AI Services"]
|
||||
Connectors["AI Connectors"]
|
||||
blockArrowId2<[" "]>(y)
|
||||
SemanticKernel["Semantic Kernel"]
|
||||
block:Kernel
|
||||
@@ -259,8 +259,8 @@ internal static class ModelDiagnostics
|
||||
private static readonly string s_namespace = typeof(ModelDiagnostics).Namespace;
|
||||
private static readonly ActivitySource s_activitySource = new(s_namespace);
|
||||
|
||||
private const string EnableModelDiagnosticsSettingName = "Microsoft.SemanticKernel.Experimental.EnableModelDiagnostics";
|
||||
private const string EnableSensitiveEventsSettingName = "Microsoft.SemanticKernel.Experimental.EnableModelDiagnosticsWithSensitiveData";
|
||||
private const string EnableModelDiagnosticsSettingName = "Microsoft.SemanticKernel.Experimental.GenAI.EnableOTelDiagnostics";
|
||||
private const string EnableSensitiveEventsSettingName = "Microsoft.SemanticKernel.Experimental.GenAI.EnableOTelDiagnosticsSensitive";
|
||||
|
||||
private static readonly bool s_enableSensitiveEvents = AppContextSwitchHelper.GetConfigValue(EnableSensitiveEventsSettingName);
|
||||
private static readonly bool s_enableModelDiagnostics = AppContextSwitchHelper.GetConfigValue(EnableModelDiagnosticsSettingName) || s_enableSensitiveEvents;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# Telemetry
|
||||
|
||||
Telemetry in Semantic Kernel (SK) .NET implementation includes _logging_, _metering_ and _tracing_.
|
||||
The code is instrumented using native .NET instrumentation tools, which means that it's possible to use different monitoring platforms (e.g. Application Insights, Prometheus, Grafana etc.).
|
||||
The code is instrumented using native .NET instrumentation tools, which means that it's possible to use different monitoring platforms (e.g. Application Insights, Aspire dashboard, Prometheus, Grafana etc.).
|
||||
|
||||
Code example using Application Insights can be found [here](https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/TelemetryExample).
|
||||
Code example using Application Insights can be found [here](../samples/Demos/TelemetryWithAppInsights/).
|
||||
|
||||
## Logging
|
||||
|
||||
@@ -108,7 +108,7 @@ Tracing is implemented with `Activity` class from `System.Diagnostics` namespace
|
||||
Available activity sources:
|
||||
|
||||
- _Microsoft.SemanticKernel.Planning_ - creates activities for all planners.
|
||||
- _Microsoft.SemanticKernel_ - creates activities for `KernelFunction`.
|
||||
- _Microsoft.SemanticKernel_ - creates activities for `KernelFunction` as well as requests to models.
|
||||
|
||||
### Examples
|
||||
|
||||
|
||||
@@ -2,16 +2,23 @@
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Azure.Monitor.OpenTelemetry.Exporter;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Planning.Handlebars;
|
||||
using Microsoft.SemanticKernel.Connectors.Google;
|
||||
using Microsoft.SemanticKernel.Connectors.HuggingFace;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Microsoft.SemanticKernel.Services;
|
||||
using OpenTelemetry;
|
||||
using OpenTelemetry.Logs;
|
||||
using OpenTelemetry.Metrics;
|
||||
using OpenTelemetry.Resources;
|
||||
using OpenTelemetry.Trace;
|
||||
|
||||
/// <summary>
|
||||
@@ -19,6 +26,65 @@ using OpenTelemetry.Trace;
|
||||
/// </summary>
|
||||
public sealed class Program
|
||||
{
|
||||
/// <summary>
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
public static async Task Main()
|
||||
{
|
||||
// Enable model diagnostics with sensitive data.
|
||||
AppContext.SetSwitch("Microsoft.SemanticKernel.Experimental.GenAI.EnableOTelDiagnosticsSensitive", true);
|
||||
|
||||
// Load configuration from environment variables or user secrets.
|
||||
LoadUserSecrets();
|
||||
|
||||
var connectionString = TestConfiguration.ApplicationInsights.ConnectionString;
|
||||
var resourceBuilder = ResourceBuilder
|
||||
.CreateDefault()
|
||||
.AddService("TelemetryExample");
|
||||
|
||||
using var traceProvider = Sdk.CreateTracerProviderBuilder()
|
||||
.SetResourceBuilder(resourceBuilder)
|
||||
.AddSource("Microsoft.SemanticKernel*")
|
||||
.AddSource("Telemetry.Example")
|
||||
.AddAzureMonitorTraceExporter(options => options.ConnectionString = connectionString)
|
||||
.Build();
|
||||
|
||||
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
||||
.SetResourceBuilder(resourceBuilder)
|
||||
.AddMeter("Microsoft.SemanticKernel*")
|
||||
.AddAzureMonitorMetricExporter(options => options.ConnectionString = connectionString)
|
||||
.Build();
|
||||
|
||||
using var loggerFactory = LoggerFactory.Create(builder =>
|
||||
{
|
||||
// Add OpenTelemetry as a logging provider
|
||||
builder.AddOpenTelemetry(options =>
|
||||
{
|
||||
options.SetResourceBuilder(resourceBuilder);
|
||||
options.AddAzureMonitorLogExporter(options => options.ConnectionString = connectionString);
|
||||
// Format log messages. This is default to false.
|
||||
options.IncludeFormattedMessage = true;
|
||||
options.IncludeScopes = true;
|
||||
});
|
||||
builder.SetMinimumLevel(MinLogLevel);
|
||||
});
|
||||
|
||||
var kernel = GetKernel(loggerFactory);
|
||||
|
||||
using var activity = s_activitySource.StartActivity("Main");
|
||||
Console.WriteLine($"Operation/Trace ID: {Activity.Current?.TraceId}");
|
||||
Console.WriteLine();
|
||||
|
||||
Console.WriteLine("Write a poem about John Doe and translate it to Italian.");
|
||||
await RunAzureOpenAIChatAsync(kernel);
|
||||
Console.WriteLine();
|
||||
await RunGoogleAIChatAsync(kernel);
|
||||
Console.WriteLine();
|
||||
await RunHuggingFaceChatAsync(kernel);
|
||||
}
|
||||
|
||||
#region Private
|
||||
/// <summary>
|
||||
/// Log level to be used by <see cref="ILogger"/>.
|
||||
/// </summary>
|
||||
@@ -33,57 +99,79 @@ public sealed class Program
|
||||
/// </summary>
|
||||
private static readonly ActivitySource s_activitySource = new("Telemetry.Example");
|
||||
|
||||
/// <summary>
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
public static async Task Main()
|
||||
private const string AzureOpenAIChatServiceKey = "AzureOpenAIChat";
|
||||
private const string GoogleAIGeminiChatServiceKey = "GoogleAIGeminiChat";
|
||||
private const string HuggingFaceChatServiceKey = "HuggingFaceChat";
|
||||
|
||||
private static async Task RunAzureOpenAIChatAsync(Kernel kernel)
|
||||
{
|
||||
// Load configuration from environment variables or user secrets.
|
||||
LoadUserSecrets();
|
||||
Console.WriteLine("============= Azure OpenAI Chat Completion =============");
|
||||
|
||||
var connectionString = TestConfiguration.ApplicationInsights.ConnectionString;
|
||||
|
||||
using var traceProvider = Sdk.CreateTracerProviderBuilder()
|
||||
.AddSource("Microsoft.SemanticKernel*")
|
||||
.AddSource("Telemetry.Example")
|
||||
.AddAzureMonitorTraceExporter(options => options.ConnectionString = connectionString)
|
||||
.Build();
|
||||
|
||||
using var meterProvider = Sdk.CreateMeterProviderBuilder()
|
||||
.AddMeter("Microsoft.SemanticKernel*")
|
||||
.AddAzureMonitorMetricExporter(options => options.ConnectionString = connectionString)
|
||||
.Build();
|
||||
|
||||
using var loggerFactory = LoggerFactory.Create(builder =>
|
||||
using var activity = s_activitySource.StartActivity(AzureOpenAIChatServiceKey);
|
||||
SetTargetService(kernel, AzureOpenAIChatServiceKey);
|
||||
try
|
||||
{
|
||||
// Add OpenTelemetry as a logging provider
|
||||
builder.AddOpenTelemetry(options =>
|
||||
await RunChatAsync(kernel);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
activity?.SetStatus(ActivityStatusCode.Error, ex.Message);
|
||||
Console.WriteLine($"Error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task RunGoogleAIChatAsync(Kernel kernel)
|
||||
{
|
||||
Console.WriteLine("============= Google Gemini Chat Completion =============");
|
||||
|
||||
using var activity = s_activitySource.StartActivity(GoogleAIGeminiChatServiceKey);
|
||||
SetTargetService(kernel, GoogleAIGeminiChatServiceKey);
|
||||
|
||||
try
|
||||
{
|
||||
await RunChatAsync(kernel);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
activity?.SetStatus(ActivityStatusCode.Error, ex.Message);
|
||||
Console.WriteLine($"Error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task RunHuggingFaceChatAsync(Kernel kernel)
|
||||
{
|
||||
Console.WriteLine("============= HuggingFace Chat Completion =============");
|
||||
|
||||
using var activity = s_activitySource.StartActivity(HuggingFaceChatServiceKey);
|
||||
SetTargetService(kernel, HuggingFaceChatServiceKey);
|
||||
|
||||
try
|
||||
{
|
||||
await RunChatAsync(kernel);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
activity?.SetStatus(ActivityStatusCode.Error, ex.Message);
|
||||
Console.WriteLine($"Error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task RunChatAsync(Kernel kernel)
|
||||
{
|
||||
var poem = await kernel.InvokeAsync<string>(
|
||||
"WriterPlugin",
|
||||
"ShortPoem",
|
||||
new KernelArguments { ["input"] = "Write a poem about John Doe." });
|
||||
var translatedPoem = await kernel.InvokeAsync<string>(
|
||||
"WriterPlugin",
|
||||
"Translate",
|
||||
new KernelArguments
|
||||
{
|
||||
options.AddAzureMonitorLogExporter(options => options.ConnectionString = connectionString);
|
||||
// Format log messages. This is default to false.
|
||||
options.IncludeFormattedMessage = true;
|
||||
["input"] = poem,
|
||||
["language"] = "Italian"
|
||||
});
|
||||
builder.SetMinimumLevel(MinLogLevel);
|
||||
});
|
||||
|
||||
var kernel = GetKernel(loggerFactory);
|
||||
var planner = CreatePlanner();
|
||||
|
||||
using var activity = s_activitySource.StartActivity("Main");
|
||||
|
||||
Console.WriteLine("Operation/Trace ID:");
|
||||
Console.WriteLine(Activity.Current?.TraceId);
|
||||
|
||||
var plan = await planner.CreatePlanAsync(kernel, "Write a poem about John Doe, then translate it into Italian.");
|
||||
|
||||
Console.WriteLine("Original plan:");
|
||||
Console.WriteLine(plan.ToString());
|
||||
|
||||
var result = await plan.InvokeAsync(kernel).ConfigureAwait(false);
|
||||
|
||||
Console.WriteLine("Result:");
|
||||
Console.WriteLine(result);
|
||||
Console.WriteLine($"Poem:\n{poem}\n\nTranslated Poem:\n{translatedPoem}");
|
||||
}
|
||||
|
||||
private static Kernel GetKernel(ILoggerFactory loggerFactory)
|
||||
@@ -93,22 +181,39 @@ public sealed class Program
|
||||
IKernelBuilder builder = Kernel.CreateBuilder();
|
||||
|
||||
builder.Services.AddSingleton(loggerFactory);
|
||||
builder.AddAzureOpenAIChatCompletion(
|
||||
deploymentName: TestConfiguration.AzureOpenAI.ChatDeploymentName,
|
||||
modelId: TestConfiguration.AzureOpenAI.ChatModelId,
|
||||
endpoint: TestConfiguration.AzureOpenAI.Endpoint,
|
||||
apiKey: TestConfiguration.AzureOpenAI.ApiKey
|
||||
).Build();
|
||||
builder
|
||||
.AddAzureOpenAIChatCompletion(
|
||||
deploymentName: TestConfiguration.AzureOpenAI.ChatDeploymentName,
|
||||
modelId: TestConfiguration.AzureOpenAI.ChatModelId,
|
||||
endpoint: TestConfiguration.AzureOpenAI.Endpoint,
|
||||
apiKey: TestConfiguration.AzureOpenAI.ApiKey,
|
||||
serviceId: AzureOpenAIChatServiceKey)
|
||||
.AddGoogleAIGeminiChatCompletion(
|
||||
modelId: TestConfiguration.GoogleAI.Gemini.ModelId,
|
||||
apiKey: TestConfiguration.GoogleAI.ApiKey,
|
||||
serviceId: GoogleAIGeminiChatServiceKey)
|
||||
.AddHuggingFaceChatCompletion(
|
||||
model: TestConfiguration.HuggingFace.ModelId,
|
||||
endpoint: new Uri("https://api-inference.huggingface.co"),
|
||||
apiKey: TestConfiguration.HuggingFace.ApiKey,
|
||||
serviceId: HuggingFaceChatServiceKey);
|
||||
|
||||
builder.Services.AddSingleton<IAIServiceSelector>(new AIServiceSelector());
|
||||
builder.Plugins.AddFromPromptDirectory(Path.Combine(folder, "WriterPlugin"));
|
||||
|
||||
return builder.Build();
|
||||
}
|
||||
|
||||
private static HandlebarsPlanner CreatePlanner()
|
||||
private static void SetTargetService(Kernel kernel, string targetServiceKey)
|
||||
{
|
||||
var plannerOptions = new HandlebarsPlannerOptions();
|
||||
return new HandlebarsPlanner(plannerOptions);
|
||||
if (kernel.Data.ContainsKey("TargetService"))
|
||||
{
|
||||
kernel.Data["TargetService"] = targetServiceKey;
|
||||
}
|
||||
else
|
||||
{
|
||||
kernel.Data.Add("TargetService", targetServiceKey);
|
||||
}
|
||||
}
|
||||
|
||||
private static void LoadUserSecrets()
|
||||
@@ -119,4 +224,36 @@ public sealed class Program
|
||||
.Build();
|
||||
TestConfiguration.Initialize(configRoot);
|
||||
}
|
||||
|
||||
private sealed class AIServiceSelector : IAIServiceSelector
|
||||
{
|
||||
public bool TrySelectAIService<T>(
|
||||
Kernel kernel, KernelFunction function, KernelArguments arguments,
|
||||
[NotNullWhen(true)] out T? service, out PromptExecutionSettings? serviceSettings) where T : class, IAIService
|
||||
{
|
||||
var targetServiceKey = kernel.Data.TryGetValue("TargetService", out object? value) ? value : null;
|
||||
if (targetServiceKey is not null)
|
||||
{
|
||||
var targetService = kernel.Services.GetKeyedServices<T>(targetServiceKey).FirstOrDefault();
|
||||
if (targetService is not null)
|
||||
{
|
||||
service = targetService;
|
||||
serviceSettings = targetServiceKey switch
|
||||
{
|
||||
AzureOpenAIChatServiceKey => new OpenAIPromptExecutionSettings(),
|
||||
GoogleAIGeminiChatServiceKey => new GeminiPromptExecutionSettings(),
|
||||
HuggingFaceChatServiceKey => new HuggingFacePromptExecutionSettings(),
|
||||
_ => null,
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
service = null;
|
||||
serviceSettings = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -16,12 +16,28 @@ For more information, please refer to the following articles:
|
||||
|
||||
## What to expect
|
||||
|
||||
In this example project, the Handlebars planner will be invoked to achieve a goal. The planner will request the model to create a plan, comprising three steps, with two of them being prompt-based kernel functions. The plan will be executed to produce the desired output, effectively fulfilling the goal.
|
||||
|
||||
The Semantic Kernel SDK is designed to efficiently generate comprehensive logs, traces, and metrics throughout the planner invocation, as well as during function and plan execution. This allows you to effectively monitor your AI application's performance and accurately track token consumption.
|
||||
The Semantic Kernel SDK is designed to efficiently generate comprehensive logs, traces, and metrics throughout the flow of function execution and model invocation. This allows you to effectively monitor your AI application's performance and accurately track token consumption.
|
||||
|
||||
> `ActivitySource.StartActivity` internally determines if there are any listeners recording the Activity. If there are no registered listeners or there are listeners that are not interested, StartActivity() will return null and avoid creating the Activity object. Read more [here](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/distributed-tracing-instrumentation-walkthroughs).
|
||||
|
||||
## OTel Semantic Conventions
|
||||
|
||||
Semantic Kernel is also committed to provide the best developer experience while complying with the industry standards for observability. For more information, please review [ADR](../../../../docs/decisions/0044-OTel-semantic-convention.md).
|
||||
|
||||
The OTel GenAI semantic conventions are experimental. There are two options to enable the feature:
|
||||
|
||||
1. AppContext switch:
|
||||
|
||||
- `Microsoft.SemanticKernel.Experimental.GenAI.EnableOTelDiagnostics`
|
||||
- `Microsoft.SemanticKernel.Experimental.GenAI.EnableOTelDiagnosticsSensitive`
|
||||
|
||||
2. Environment variable
|
||||
|
||||
- `SEMANTICKERNEL_EXPERIMENTAL_GENAI_ENABLE_OTEL_DIAGNOSTICS`
|
||||
- `SEMANTICKERNEL_EXPERIMENTAL_GENAI_ENABLE_OTEL_DIAGNOSTICS_SENSITIVE`
|
||||
|
||||
> Enabling the collection of sensitive data including prompts and responses will implicitly enable the feature.
|
||||
|
||||
## Configuration
|
||||
|
||||
### Require resources
|
||||
@@ -46,6 +62,12 @@ dotnet user-secrets set "AzureOpenAI:ChatModelId" "..."
|
||||
dotnet user-secrets set "AzureOpenAI:Endpoint" "https://... .openai.azure.com/"
|
||||
dotnet user-secrets set "AzureOpenAI:ApiKey" "..."
|
||||
|
||||
dotnet user-secrets set "GoogleAI:Gemini:ModelId" "..."
|
||||
dotnet user-secrets set "GoogleAI:ApiKey" "..."
|
||||
|
||||
dotnet user-secrets set "HuggingFace:ModelId" "..."
|
||||
dotnet user-secrets set "HuggingFace:ApiKey" "..."
|
||||
|
||||
dotnet user-secrets set "ApplicationInsights:ConnectionString" "..."
|
||||
```
|
||||
|
||||
@@ -134,7 +156,30 @@ customMetrics
|
||||
|
||||
You can create an Azure Dashboard to visualize the custom telemetry items. You can read more here: [Create a new dashboard](https://learn.microsoft.com/en-us/azure/azure-monitor/app/overview-dashboard#create-a-new-dashboard).
|
||||
|
||||
## Aspire Dashboard
|
||||
|
||||
You can also use the [Aspire dashboard](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/dashboard/overview) for local development.
|
||||
|
||||
### Steps
|
||||
|
||||
- Follow this [code sample](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/dashboard/overview) to start an Aspire dashboard in a docker container.
|
||||
- Add the package to the project: **`OpenTelemetry.Exporter.OpenTelemetryProtocol`**
|
||||
- Replace all occurrences of
|
||||
|
||||
```c#
|
||||
.AddAzureMonitorLogExporter(...)
|
||||
```
|
||||
|
||||
with
|
||||
|
||||
```c#
|
||||
.AddOtlpExporter(options => options.Endpoint = new Uri("http://localhost:4317"))
|
||||
```
|
||||
|
||||
- Run the app and you can visual the traces in the Aspire dashboard.
|
||||
|
||||
## More information
|
||||
|
||||
- [Telemetry docs](../../../docs/TELEMETRY.md)
|
||||
- [Planner telemetry improvement ADR](../../../../docs/decisions/0025-planner-telemetry-enhancement.md)
|
||||
- [OTel Semantic Conventions ADR](../../../../docs/decisions/0044-OTel-semantic-convention.md)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<ImplicitUsings>disable</ImplicitUsings>
|
||||
<IsPackable>false</IsPackable>
|
||||
<!-- Suppress: "Declare types in namespaces", "Require ConfigureAwait" -->
|
||||
<NoWarn>$(NoWarn);CA1050;CA1707;CA2007;CS1591;VSTHRD111,SKEXP0050,SKEXP0060</NoWarn>
|
||||
<NoWarn>$(NoWarn);CA1050;CA1707;CA2007;CS1591;VSTHRD111,SKEXP0050,SKEXP0060,SKEXP0070</NoWarn>
|
||||
<UserSecretsId>5ee045b0-aea3-4f08-8d31-32d1a6f8fed0</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -19,10 +19,13 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\src\Connectors\Connectors.OpenAI\Connectors.OpenAI.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Connectors\Connectors.Google\Connectors.Google.csproj" />
|
||||
<ProjectReference
|
||||
Include="..\..\..\src\Connectors\Connectors.HuggingFace\Connectors.HuggingFace.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Planners\Planners.Handlebars\Planners.Handlebars.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\SemanticKernel.Core\SemanticKernel.Core.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Plugins\Plugins.Core\Plugins.Core.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Plugins\Plugins.Web\Plugins.Web.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -24,6 +24,10 @@ public sealed class TestConfiguration
|
||||
|
||||
public static ApplicationInsightsConfig ApplicationInsights => LoadSection<ApplicationInsightsConfig>();
|
||||
|
||||
public static GoogleAIConfig GoogleAI => LoadSection<GoogleAIConfig>();
|
||||
|
||||
public static HuggingFaceConfig HuggingFace => LoadSection<HuggingFaceConfig>();
|
||||
|
||||
private static T LoadSection<T>([CallerMemberName] string? caller = null)
|
||||
{
|
||||
if (s_instance is null)
|
||||
@@ -55,5 +59,24 @@ public sealed class TestConfiguration
|
||||
public string ConnectionString { get; set; }
|
||||
}
|
||||
|
||||
public class GoogleAIConfig
|
||||
{
|
||||
public string ApiKey { get; set; }
|
||||
public string EmbeddingModelId { get; set; }
|
||||
public GeminiConfig Gemini { get; set; }
|
||||
|
||||
public class GeminiConfig
|
||||
{
|
||||
public string ModelId { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
public class HuggingFaceConfig
|
||||
{
|
||||
public string ApiKey { get; set; }
|
||||
public string ModelId { get; set; }
|
||||
public string EmbeddingModelId { get; set; }
|
||||
}
|
||||
|
||||
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor.
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user