// Copyright (c) Microsoft. All rights reserved. using System.Text; using Microsoft.SemanticKernel; using Microsoft.SemanticKernel.ChatCompletion; using Microsoft.SemanticKernel.Connectors.OpenAI; namespace ChatCompletion; /// /// These examples demonstrate different ways of using chat completion with OpenAI API. /// public class OpenAI_ChatCompletion(ITestOutputHelper output) : BaseTest(output) { /// /// Sample showing how to use directly with a . /// [Fact] public async Task ServicePromptAsync() { Assert.NotNull(TestConfiguration.OpenAI.ChatModelId); Assert.NotNull(TestConfiguration.OpenAI.ApiKey); Console.WriteLine("======== Open AI - Chat Completion ========"); OpenAIChatCompletionService chatService = new(TestConfiguration.OpenAI.ChatModelId, TestConfiguration.OpenAI.ApiKey); Console.WriteLine("Chat content:"); Console.WriteLine("------------------------"); var chatHistory = new ChatHistory("You are a librarian, expert about books"); // First user message chatHistory.AddUserMessage("Hi, I'm looking for book suggestions"); OutputLastMessage(chatHistory); // First assistant message var reply = await chatService.GetChatMessageContentAsync(chatHistory); chatHistory.Add(reply); OutputLastMessage(chatHistory); // Second user message chatHistory.AddUserMessage("I love history and philosophy, I'd like to learn something new about Greece, any suggestion"); OutputLastMessage(chatHistory); // Second assistant message reply = await chatService.GetChatMessageContentAsync(chatHistory); chatHistory.Add(reply); OutputLastMessage(chatHistory); } /// /// Sample showing how to use directly with a also exploring the /// breaking glass approach capturing the underlying instance via . /// [Fact] public async Task ServicePromptWithInnerContentAsync() { Assert.NotNull(TestConfiguration.OpenAI.ChatModelId); Assert.NotNull(TestConfiguration.OpenAI.ApiKey); Console.WriteLine("======== Open AI - Chat Completion ========"); OpenAIChatCompletionService chatService = new(TestConfiguration.OpenAI.ChatModelId, TestConfiguration.OpenAI.ApiKey); Console.WriteLine("Chat content:"); Console.WriteLine("------------------------"); var chatHistory = new ChatHistory("You are a librarian, expert about books"); // First user message chatHistory.AddUserMessage("Hi, I'm looking for book suggestions"); this.OutputLastMessage(chatHistory); // First assistant message var reply = await chatService.GetChatMessageContentAsync(chatHistory, new OpenAIPromptExecutionSettings { Logprobs = true, TopLogprobs = 3 }); // Assistant message details var replyInnerContent = reply.InnerContent as OpenAI.Chat.ChatCompletion; OutputInnerContent(replyInnerContent!); } /// /// Sample showing how to use with chat completion and chat prompt syntax. /// [Fact] public async Task ChatPromptAsync() { Assert.NotNull(TestConfiguration.OpenAI.ChatModelId); Assert.NotNull(TestConfiguration.OpenAI.ApiKey); StringBuilder chatPrompt = new(""" You are a librarian, expert about books Hi, I'm looking for book suggestions """); var kernel = Kernel.CreateBuilder() .AddOpenAIChatCompletion(TestConfiguration.OpenAI.ChatModelId, TestConfiguration.OpenAI.ApiKey) .Build(); var reply = await kernel.InvokePromptAsync(chatPrompt.ToString()); chatPrompt.AppendLine($""); chatPrompt.AppendLine("I love history and philosophy, I'd like to learn something new about Greece, any suggestion"); reply = await kernel.InvokePromptAsync(chatPrompt.ToString()); Console.WriteLine(reply); } /// /// Demonstrates how you can template a chat history call and get extra information from the response while using the kernel for invocation. /// /// /// This is a breaking glass scenario, any attempt on running with different versions of OpenAI SDK that introduces breaking changes /// may cause breaking changes in the code below. /// [Fact] public async Task ChatPromptWithInnerContentAsync() { Assert.NotNull(TestConfiguration.OpenAI.ChatModelId); Assert.NotNull(TestConfiguration.OpenAI.ApiKey); StringBuilder chatPrompt = new(""" You are a librarian, expert about books Hi, I'm looking for book suggestions """); var kernel = Kernel.CreateBuilder() .AddOpenAIChatCompletion(TestConfiguration.OpenAI.ChatModelId, TestConfiguration.OpenAI.ApiKey) .Build(); var functionResult = await kernel.InvokePromptAsync(chatPrompt.ToString(), new(new OpenAIPromptExecutionSettings { Logprobs = true, TopLogprobs = 3 })); var messageContent = functionResult.GetValue(); // Retrieves underlying chat message content from FunctionResult. var replyInnerContent = messageContent!.InnerContent as OpenAI.Chat.ChatCompletion; // Retrieves inner content from ChatMessageContent. OutputInnerContent(replyInnerContent!); } /// /// Demonstrates how you can store the output of a chat completion request for use in the OpenAI model distillation or evals products. /// /// /// This sample adds metadata to the chat completion request which allows the requests to be filtered in the OpenAI dashboard. /// [Fact] public async Task ChatPromptStoreWithMetadataAsync() { Assert.NotNull(TestConfiguration.OpenAI.ChatModelId); Assert.NotNull(TestConfiguration.OpenAI.ApiKey); StringBuilder chatPrompt = new(""" You are a librarian, expert about books Hi, I'm looking for book suggestions about Artificial Intelligence """); var kernel = Kernel.CreateBuilder() .AddOpenAIChatCompletion(TestConfiguration.OpenAI.ChatModelId, TestConfiguration.OpenAI.ApiKey) .Build(); var functionResult = await kernel.InvokePromptAsync(chatPrompt.ToString(), new(new OpenAIPromptExecutionSettings { Store = true, Metadata = new Dictionary() { { "concept", "chatcompletion" } } })); var messageContent = functionResult.GetValue(); // Retrieves underlying chat message content from FunctionResult. var replyInnerContent = messageContent!.InnerContent as OpenAI.Chat.ChatCompletion; // Retrieves inner content from ChatMessageContent. OutputInnerContent(replyInnerContent!); } /// /// Retrieve extra information from a inner content of type . /// /// An instance of retrieved as an inner content of . /// /// This is a breaking glass scenario, any attempt on running with different versions of OpenAI SDK that introduces breaking changes /// may break the code below. /// private void OutputInnerContent(OpenAI.Chat.ChatCompletion innerContent) { Console.WriteLine($$""" Message role: {{innerContent.Role}} // Available as a property of ChatMessageContent Message content: {{innerContent.Content[0].Text}} // Available as a property of ChatMessageContent Model: {{innerContent.Model}} // Model doesn't change per chunk, so we can get it from the first chunk only Created At: {{innerContent.CreatedAt}} Finish reason: {{innerContent.FinishReason}} Input tokens usage: {{innerContent.Usage.InputTokenCount}} Output tokens usage: {{innerContent.Usage.OutputTokenCount}} Total tokens usage: {{innerContent.Usage.TotalTokenCount}} Refusal: {{innerContent.Refusal}} Id: {{innerContent.Id}} System fingerprint: {{innerContent.SystemFingerprint}} """); if (innerContent.ContentTokenLogProbabilities.Count > 0) { Console.WriteLine("Content token log probabilities:"); foreach (var contentTokenLogProbability in innerContent.ContentTokenLogProbabilities) { Console.WriteLine($"Token: {contentTokenLogProbability.Token}"); Console.WriteLine($"Log probability: {contentTokenLogProbability.LogProbability}"); Console.WriteLine(" Top log probabilities for this token:"); foreach (var topLogProbability in contentTokenLogProbability.TopLogProbabilities) { Console.WriteLine($" Token: {topLogProbability.Token}"); Console.WriteLine($" Log probability: {topLogProbability.LogProbability}"); Console.WriteLine(" ======="); } Console.WriteLine("--------------"); } } if (innerContent.RefusalTokenLogProbabilities.Count > 0) { Console.WriteLine("Refusal token log probabilities:"); foreach (var refusalTokenLogProbability in innerContent.RefusalTokenLogProbabilities) { Console.WriteLine($"Token: {refusalTokenLogProbability.Token}"); Console.WriteLine($"Log probability: {refusalTokenLogProbability.LogProbability}"); Console.WriteLine(" Refusal top log probabilities for this token:"); foreach (var topLogProbability in refusalTokenLogProbability.TopLogProbabilities) { Console.WriteLine($" Token: {topLogProbability.Token}"); Console.WriteLine($" Log probability: {topLogProbability.LogProbability}"); Console.WriteLine(" ======="); } } } } }