// Copyright (c) Microsoft. All rights reserved. using System.ComponentModel; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.SemanticKernel; namespace GettingStarted; /// /// This example shows how to using Dependency Injection with the Semantic Kernel /// public sealed class Step4_Dependency_Injection(ITestOutputHelper output) : BaseTest(output) { /// /// Show how to create a that participates in Dependency Injection. /// [Fact] public async Task GetKernelUsingDependencyInjection() { // 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 serviceProvider = BuildServiceProvider(); var kernel = serviceProvider.GetRequiredService(); // Invoke the kernel with a templated prompt and stream the results to the display KernelArguments arguments = new() { { "topic", "earth when viewed from space" } }; await foreach (var update in kernel.InvokePromptStreamingAsync("What color is the {{$topic}}? Provide a detailed explanation.", arguments)) { Console.Write(update); } } /// /// Show how to use a plugin that participates in Dependency Injection. /// [Fact] public async Task PluginUsingDependencyInjection() { // If an application follows DI guidelines, the following line is unnecessary because DI will inject an instance of the Kernel class to a class that references it. // DI container guidelines - https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection-guidelines#recommendations var serviceProvider = BuildServiceProvider(); var kernel = serviceProvider.GetRequiredService(); // Invoke the prompt which relies on invoking a plugin that depends on a service made available using Dependency Injection. PromptExecutionSettings settings = new() { FunctionChoiceBehavior = FunctionChoiceBehavior.Auto() }; Console.WriteLine(await kernel.InvokePromptAsync("Greet the current user by name.", new(settings))); } /// /// Build a ServiceProvider that can be used to resolve services. /// private ServiceProvider BuildServiceProvider() { var collection = new ServiceCollection(); collection.AddSingleton(new XunitLogger(this.Output)); collection.AddSingleton(new FakeUserService()); // Add ChatClient using OpenAI collection.AddOpenAIChatClient( modelId: TestConfiguration.OpenAI.ChatModelId, apiKey: TestConfiguration.OpenAI.ApiKey); var kernelBuilder = collection.AddKernel(); kernelBuilder.Plugins.AddFromType(); kernelBuilder.Plugins.AddFromType(); return collection.BuildServiceProvider(); } /// /// A plugin that returns the current time. /// public class TimeInformation(ILoggerFactory loggerFactory) { private readonly ILogger _logger = loggerFactory.CreateLogger(); [KernelFunction] [Description("Retrieves the current time in UTC.")] public string GetCurrentUtcTime() { var utcNow = DateTime.UtcNow.ToString("R"); this._logger.LogInformation("Returning current time {0}", utcNow); return utcNow; } } /// /// A plugin that returns the current time. /// public class UserInformation(IUserService userService) { [KernelFunction] [Description("Retrieves the current users name.")] public string GetUsername() { return userService.GetCurrentUsername(); } } /// /// Interface for a service to get the current user id. /// public interface IUserService { /// /// Return the user id for the current user. /// string GetCurrentUsername(); } /// /// Fake implementation of /// public class FakeUserService : IUserService { /// public string GetCurrentUsername() => "Bob"; } }