From 1679251e6c033c2c282a777a38e2f741f83f1d87 Mon Sep 17 00:00:00 2001 From: SergeyMenshykh Date: Wed, 17 Jul 2024 14:41:07 +0100 Subject: [PATCH 1/7] feat(Azure.AI.OpenAI SDK v2): migrate TextGeneration, TextToAudio, and TextToImage concepts. --- dotnet/samples/Concepts/Concepts.csproj | 10 ---------- .../TextGeneration/OpenAI_TextGenerationStreaming.cs | 5 +++-- .../Connectors.OpenAIV2/Core/ClientCore.TextToImage.cs | 6 +++++- .../Services/OpenAITextToImageService.cs | 1 - 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/dotnet/samples/Concepts/Concepts.csproj b/dotnet/samples/Concepts/Concepts.csproj index a11241024bf9..a4fe79f98053 100644 --- a/dotnet/samples/Concepts/Concepts.csproj +++ b/dotnet/samples/Concepts/Concepts.csproj @@ -155,11 +155,6 @@ - - - - - @@ -212,10 +207,5 @@ - - - - - diff --git a/dotnet/samples/Concepts/TextGeneration/OpenAI_TextGenerationStreaming.cs b/dotnet/samples/Concepts/TextGeneration/OpenAI_TextGenerationStreaming.cs index 44b7806a1355..0bdd20eb996f 100644 --- a/dotnet/samples/Concepts/TextGeneration/OpenAI_TextGenerationStreaming.cs +++ b/dotnet/samples/Concepts/TextGeneration/OpenAI_TextGenerationStreaming.cs @@ -1,5 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. +using Microsoft.SemanticKernel.Connectors.AzureOpenAI; using Microsoft.SemanticKernel.Connectors.OpenAI; using Microsoft.SemanticKernel.TextGeneration; @@ -22,7 +23,7 @@ public Task AzureOpenAITextGenerationStreamAsync() { Console.WriteLine("======== Azure OpenAI - Text Generation - Raw Streaming ========"); - var textGeneration = new AzureOpenAITextGenerationService( + var textGeneration = new AzureOpenAIChatCompletionService( deploymentName: TestConfiguration.AzureOpenAI.DeploymentName, endpoint: TestConfiguration.AzureOpenAI.Endpoint, apiKey: TestConfiguration.AzureOpenAI.ApiKey, @@ -36,7 +37,7 @@ public Task OpenAITextGenerationStreamAsync() { Console.WriteLine("======== Open AI - Text Generation - Raw Streaming ========"); - var textGeneration = new OpenAITextGenerationService("gpt-3.5-turbo-instruct", TestConfiguration.OpenAI.ApiKey); + var textGeneration = new OpenAIChatCompletionService("gpt-3.5-turbo-instruct", TestConfiguration.OpenAI.ApiKey); return this.TextGenerationStreamAsync(textGeneration); } diff --git a/dotnet/src/Connectors/Connectors.OpenAIV2/Core/ClientCore.TextToImage.cs b/dotnet/src/Connectors/Connectors.OpenAIV2/Core/ClientCore.TextToImage.cs index 26d8480fd004..cb6a681ca0e1 100644 --- a/dotnet/src/Connectors/Connectors.OpenAIV2/Core/ClientCore.TextToImage.cs +++ b/dotnet/src/Connectors/Connectors.OpenAIV2/Core/ClientCore.TextToImage.cs @@ -45,7 +45,11 @@ internal async Task GenerateImageAsync( ResponseFormat = GeneratedImageFormat.Uri }; - ClientResult response = await RunRequestAsync(() => this.Client.GetImageClient(this.ModelId).GenerateImageAsync(prompt, imageOptions, cancellationToken)).ConfigureAwait(false); + // The model is not required by the OpenAI API and defaults to the DALL-E 2 server-side - https://platform.openai.com/docs/api-reference/images/create#images-create-model. + // However, considering that the model is required by the OpenAI SDK and the ModelId property is optional, it defaults to DALL-E 2 in the line below. + var model = string.IsNullOrEmpty(this.ModelId) ? "dall-e-2" : this.ModelId; + + ClientResult response = await RunRequestAsync(() => this.Client.GetImageClient(model).GenerateImageAsync(prompt, imageOptions, cancellationToken)).ConfigureAwait(false); var generatedImage = response.Value; return generatedImage.ImageUri?.ToString() ?? throw new KernelException("The generated image is not in url format"); diff --git a/dotnet/src/Connectors/Connectors.OpenAIV2/Services/OpenAITextToImageService.cs b/dotnet/src/Connectors/Connectors.OpenAIV2/Services/OpenAITextToImageService.cs index cca9073bfe9c..5bbff66c761e 100644 --- a/dotnet/src/Connectors/Connectors.OpenAIV2/Services/OpenAITextToImageService.cs +++ b/dotnet/src/Connectors/Connectors.OpenAIV2/Services/OpenAITextToImageService.cs @@ -50,7 +50,6 @@ public OpenAITextToImageService( HttpClient? httpClient = null, ILoggerFactory? loggerFactory = null) { - Verify.NotNullOrWhiteSpace(modelId, nameof(modelId)); this._client = new(modelId, apiKey, organization, null, httpClient, loggerFactory?.CreateLogger(this.GetType())); } From 67da54927fcfbc3f6c0eb3afc07214ae1ad6326d Mon Sep 17 00:00:00 2001 From: SergeyMenshykh Date: Wed, 17 Jul 2024 18:11:04 +0100 Subject: [PATCH 2/7] feat(Azure.AI.OpenAI SDK v2): migrate samples from the concepts project to new {azure}openai connectors --- .../AzureOpenAIWithData_ChatCompletion.cs | 27 ++-- .../ChatCompletion/ChatHistoryAuthorName.cs | 1 + .../ChatCompletion/OpenAI_ChatCompletion.cs | 1 + .../OpenAI_ChatCompletionMultipleChoices.cs | 133 ------------------ .../OpenAI_ChatCompletionStreaming.cs | 1 + ..._ChatCompletionStreamingMultipleChoices.cs | 114 --------------- .../OpenAI_CustomAzureOpenAIClient.cs | 10 +- dotnet/samples/Concepts/Concepts.csproj | 70 --------- .../OpenAI_TextGenerationStreaming.cs | 6 +- 9 files changed, 22 insertions(+), 341 deletions(-) delete mode 100644 dotnet/samples/Concepts/ChatCompletion/OpenAI_ChatCompletionMultipleChoices.cs delete mode 100644 dotnet/samples/Concepts/ChatCompletion/OpenAI_ChatCompletionStreamingMultipleChoices.cs diff --git a/dotnet/samples/Concepts/ChatCompletion/AzureOpenAIWithData_ChatCompletion.cs b/dotnet/samples/Concepts/ChatCompletion/AzureOpenAIWithData_ChatCompletion.cs index dcfdf7b511f0..39ce395b27b7 100644 --- a/dotnet/samples/Concepts/ChatCompletion/AzureOpenAIWithData_ChatCompletion.cs +++ b/dotnet/samples/Concepts/ChatCompletion/AzureOpenAIWithData_ChatCompletion.cs @@ -1,9 +1,9 @@ // Copyright (c) Microsoft. All rights reserved. -using Azure.AI.OpenAI; +using Azure.AI.OpenAI.Chat; using Microsoft.SemanticKernel; using Microsoft.SemanticKernel.ChatCompletion; -using Microsoft.SemanticKernel.Connectors.OpenAI; +using Microsoft.SemanticKernel.Connectors.AzureOpenAI; using xRetry; namespace ChatCompletion; @@ -47,8 +47,8 @@ public async Task ExampleWithChatCompletionAsync() chatHistory.AddUserMessage(ask); // Chat Completion example - var chatExtensionsOptions = GetAzureChatExtensionsOptions(); - var promptExecutionSettings = new OpenAIPromptExecutionSettings { AzureChatExtensionsOptions = chatExtensionsOptions }; + var dataSource = GetAzureSearchDataSource(); + var promptExecutionSettings = new AzureOpenAIPromptExecutionSettings { AzureChatDataSource = dataSource }; var chatCompletion = kernel.GetRequiredService(); @@ -98,8 +98,8 @@ public async Task ExampleWithKernelAsync() var function = kernel.CreateFunctionFromPrompt("Question: {{$input}}"); - var chatExtensionsOptions = GetAzureChatExtensionsOptions(); - var promptExecutionSettings = new OpenAIPromptExecutionSettings { AzureChatExtensionsOptions = chatExtensionsOptions }; + var dataSource = GetAzureSearchDataSource(); + var promptExecutionSettings = new AzureOpenAIPromptExecutionSettings { AzureChatDataSource = dataSource }; // First question without previous context based on uploaded content. var response = await kernel.InvokeAsync(function, new(promptExecutionSettings) { ["input"] = ask }); @@ -125,20 +125,15 @@ public async Task ExampleWithKernelAsync() } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - private static AzureChatExtensionsOptions GetAzureChatExtensionsOptions() + private static AzureSearchChatDataSource GetAzureSearchDataSource() { - var azureSearchExtensionConfiguration = new AzureSearchChatExtensionConfiguration + return new AzureSearchChatDataSource { - SearchEndpoint = new Uri(TestConfiguration.AzureAISearch.Endpoint), - Authentication = new OnYourDataApiKeyAuthenticationOptions(TestConfiguration.AzureAISearch.ApiKey), + Endpoint = new Uri(TestConfiguration.AzureAISearch.Endpoint), + Authentication = DataSourceAuthentication.FromApiKey(TestConfiguration.AzureAISearch.ApiKey), IndexName = TestConfiguration.AzureAISearch.IndexName }; - - return new AzureChatExtensionsOptions - { - Extensions = { azureSearchExtensionConfiguration } - }; } } diff --git a/dotnet/samples/Concepts/ChatCompletion/ChatHistoryAuthorName.cs b/dotnet/samples/Concepts/ChatCompletion/ChatHistoryAuthorName.cs index 05346974da2f..2d08c507aa4c 100644 --- a/dotnet/samples/Concepts/ChatCompletion/ChatHistoryAuthorName.cs +++ b/dotnet/samples/Concepts/ChatCompletion/ChatHistoryAuthorName.cs @@ -2,6 +2,7 @@ using Microsoft.SemanticKernel; using Microsoft.SemanticKernel.ChatCompletion; +using Microsoft.SemanticKernel.Connectors.AzureOpenAI; using Microsoft.SemanticKernel.Connectors.OpenAI; namespace ChatCompletion; diff --git a/dotnet/samples/Concepts/ChatCompletion/OpenAI_ChatCompletion.cs b/dotnet/samples/Concepts/ChatCompletion/OpenAI_ChatCompletion.cs index 22b6eec9baaf..758af2acc389 100644 --- a/dotnet/samples/Concepts/ChatCompletion/OpenAI_ChatCompletion.cs +++ b/dotnet/samples/Concepts/ChatCompletion/OpenAI_ChatCompletion.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. using Microsoft.SemanticKernel.ChatCompletion; +using Microsoft.SemanticKernel.Connectors.AzureOpenAI; using Microsoft.SemanticKernel.Connectors.OpenAI; namespace ChatCompletion; diff --git a/dotnet/samples/Concepts/ChatCompletion/OpenAI_ChatCompletionMultipleChoices.cs b/dotnet/samples/Concepts/ChatCompletion/OpenAI_ChatCompletionMultipleChoices.cs deleted file mode 100644 index 9534cac09a63..000000000000 --- a/dotnet/samples/Concepts/ChatCompletion/OpenAI_ChatCompletionMultipleChoices.cs +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Microsoft.SemanticKernel; -using Microsoft.SemanticKernel.ChatCompletion; -using Microsoft.SemanticKernel.Connectors.OpenAI; - -namespace ChatCompletion; - -/// -/// The following example shows how to use Semantic Kernel with multiple chat completion results. -/// -public class OpenAI_ChatCompletionMultipleChoices(ITestOutputHelper output) : BaseTest(output) -{ - /// - /// Example with multiple chat completion results using . - /// - [Fact] - public async Task MultipleChatCompletionResultsUsingKernelAsync() - { - var kernel = Kernel - .CreateBuilder() - .AddOpenAIChatCompletion( - modelId: TestConfiguration.OpenAI.ChatModelId, - apiKey: TestConfiguration.OpenAI.ApiKey) - .Build(); - - // Execution settings with configured ResultsPerPrompt property. - var executionSettings = new OpenAIPromptExecutionSettings { MaxTokens = 200, ResultsPerPrompt = 3 }; - - var contents = await kernel.InvokePromptAsync>("Write a paragraph about why AI is awesome", new(executionSettings)); - - foreach (var content in contents!) - { - Console.Write(content.ToString() ?? string.Empty); - Console.WriteLine("\n-------------\n"); - } - } - - /// - /// Example with multiple chat completion results using . - /// - [Fact] - public async Task MultipleChatCompletionResultsUsingChatCompletionServiceAsync() - { - var kernel = Kernel - .CreateBuilder() - .AddOpenAIChatCompletion( - modelId: TestConfiguration.OpenAI.ChatModelId, - apiKey: TestConfiguration.OpenAI.ApiKey) - .Build(); - - // Execution settings with configured ResultsPerPrompt property. - var executionSettings = new OpenAIPromptExecutionSettings { MaxTokens = 200, ResultsPerPrompt = 3 }; - - var chatHistory = new ChatHistory(); - chatHistory.AddUserMessage("Write a paragraph about why AI is awesome"); - - var chatCompletionService = kernel.GetRequiredService(); - - foreach (var chatMessageContent in await chatCompletionService.GetChatMessageContentsAsync(chatHistory, executionSettings)) - { - Console.Write(chatMessageContent.Content ?? string.Empty); - Console.WriteLine("\n-------------\n"); - } - } - - /// - /// This example shows how to handle multiple results in case if prompt template contains a call to another prompt function. - /// is used for result selection. - /// - [Fact] - public async Task MultipleChatCompletionResultsInPromptTemplateAsync() - { - var kernel = Kernel - .CreateBuilder() - .AddOpenAIChatCompletion( - modelId: TestConfiguration.OpenAI.ChatModelId, - apiKey: TestConfiguration.OpenAI.ApiKey) - .Build(); - - var executionSettings = new OpenAIPromptExecutionSettings { MaxTokens = 200, ResultsPerPrompt = 3 }; - - // Initializing a function with execution settings for multiple results. - // We ask AI to write one paragraph, but in execution settings we specified that we want 3 different results for this request. - var function = KernelFunctionFactory.CreateFromPrompt("Write a paragraph about why AI is awesome", executionSettings, "GetParagraph"); - var plugin = KernelPluginFactory.CreateFromFunctions("MyPlugin", [function]); - - kernel.Plugins.Add(plugin); - - // Add function result selection filter. - kernel.FunctionInvocationFilters.Add(new FunctionResultSelectionFilter(this.Output)); - - // Inside our main request, we call MyPlugin.GetParagraph function for text summarization. - // Taking into account that MyPlugin.GetParagraph function produces 3 results, for text summarization we need to choose only one of them. - // Registered filter will be invoked during execution, which will select and return only 1 result, and this result will be inserted in our main request for summarization. - var result = await kernel.InvokePromptAsync("Summarize this text: {{MyPlugin.GetParagraph}}"); - - // It's possible to check what prompt was rendered for our main request. - Console.WriteLine($"Rendered prompt: '{result.RenderedPrompt}'"); - - // Output: - // Rendered prompt: 'Summarize this text: AI is awesome because...' - } - - /// - /// Example of filter which is responsible for result selection in case if some function produces multiple results. - /// - private sealed class FunctionResultSelectionFilter(ITestOutputHelper output) : IFunctionInvocationFilter - { - public async Task OnFunctionInvocationAsync(FunctionInvocationContext context, Func next) - { - await next(context); - - // Selection logic for function which is expected to produce multiple results. - if (context.Function.Name == "GetParagraph") - { - // Get multiple results from function invocation - var contents = context.Result.GetValue>()!; - - output.WriteLine("Multiple results:"); - - foreach (var content in contents) - { - output.WriteLine(content.ToString()); - } - - // Select first result for correct prompt rendering - var selectedContent = contents[0]; - context.Result = new FunctionResult(context.Function, selectedContent, context.Kernel.Culture, selectedContent.Metadata); - } - } - } -} diff --git a/dotnet/samples/Concepts/ChatCompletion/OpenAI_ChatCompletionStreaming.cs b/dotnet/samples/Concepts/ChatCompletion/OpenAI_ChatCompletionStreaming.cs index 4836dcf03d9f..bd1285e29af3 100644 --- a/dotnet/samples/Concepts/ChatCompletion/OpenAI_ChatCompletionStreaming.cs +++ b/dotnet/samples/Concepts/ChatCompletion/OpenAI_ChatCompletionStreaming.cs @@ -2,6 +2,7 @@ using Microsoft.SemanticKernel; using Microsoft.SemanticKernel.ChatCompletion; +using Microsoft.SemanticKernel.Connectors.AzureOpenAI; using Microsoft.SemanticKernel.Connectors.OpenAI; namespace ChatCompletion; diff --git a/dotnet/samples/Concepts/ChatCompletion/OpenAI_ChatCompletionStreamingMultipleChoices.cs b/dotnet/samples/Concepts/ChatCompletion/OpenAI_ChatCompletionStreamingMultipleChoices.cs deleted file mode 100644 index 6a23a43ae9f8..000000000000 --- a/dotnet/samples/Concepts/ChatCompletion/OpenAI_ChatCompletionStreamingMultipleChoices.cs +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -using Microsoft.SemanticKernel; -using Microsoft.SemanticKernel.ChatCompletion; -using Microsoft.SemanticKernel.Connectors.OpenAI; - -namespace ChatCompletion; - -// The following example shows how to use Semantic Kernel with multiple streaming chat completion results. -public class OpenAI_ChatCompletionStreamingMultipleChoices(ITestOutputHelper output) : BaseTest(output) -{ - [Fact] - public Task AzureOpenAIMultiStreamingChatCompletionAsync() - { - Console.WriteLine("======== Azure OpenAI - Multiple Chat Completions - Raw Streaming ========"); - - AzureOpenAIChatCompletionService chatCompletionService = new( - deploymentName: TestConfiguration.AzureOpenAI.ChatDeploymentName, - endpoint: TestConfiguration.AzureOpenAI.Endpoint, - apiKey: TestConfiguration.AzureOpenAI.ApiKey, - modelId: TestConfiguration.AzureOpenAI.ChatModelId); - - return StreamingChatCompletionAsync(chatCompletionService, 3); - } - - [Fact] - public Task OpenAIMultiStreamingChatCompletionAsync() - { - Console.WriteLine("======== OpenAI - Multiple Chat Completions - Raw Streaming ========"); - - OpenAIChatCompletionService chatCompletionService = new( - modelId: TestConfiguration.OpenAI.ChatModelId, - apiKey: TestConfiguration.OpenAI.ApiKey); - - return StreamingChatCompletionAsync(chatCompletionService, 3); - } - - /// - /// Streams the results of a chat completion request to the console. - /// - /// Chat completion service to use - /// Number of results to get for each chat completion request - private async Task StreamingChatCompletionAsync(IChatCompletionService chatCompletionService, - int numResultsPerPrompt) - { - var executionSettings = new OpenAIPromptExecutionSettings() - { - MaxTokens = 200, - FrequencyPenalty = 0, - PresencePenalty = 0, - Temperature = 1, - TopP = 0.5, - ResultsPerPrompt = numResultsPerPrompt - }; - - var consoleLinesPerResult = 10; - - // Uncomment this if you want to use a console app to display the results - // ClearDisplayByAddingEmptyLines(); - - var prompt = "Hi, I'm looking for 5 random title names for sci-fi books"; - - await ProcessStreamAsyncEnumerableAsync(chatCompletionService, prompt, executionSettings, consoleLinesPerResult); - - Console.WriteLine(); - - // Set cursor position to after displayed results - // Console.SetCursorPosition(0, executionSettings.ResultsPerPrompt * consoleLinesPerResult); - - Console.WriteLine(); - } - - /// - /// Does the actual streaming and display of the chat completion. - /// - private async Task ProcessStreamAsyncEnumerableAsync(IChatCompletionService chatCompletionService, string prompt, - OpenAIPromptExecutionSettings executionSettings, int consoleLinesPerResult) - { - var messagesPerChoice = new Dictionary(); - var chatHistory = new ChatHistory(prompt); - - // For each chat completion update - await foreach (StreamingChatMessageContent chatUpdate in chatCompletionService.GetStreamingChatMessageContentsAsync(chatHistory, executionSettings)) - { - // Set cursor position to the beginning of where this choice (i.e. this result of - // a single multi-result request) is to be displayed. - // Console.SetCursorPosition(0, chatUpdate.ChoiceIndex * consoleLinesPerResult + 1); - - // The first time around, start choice text with role information - if (!messagesPerChoice.ContainsKey(chatUpdate.ChoiceIndex)) - { - messagesPerChoice[chatUpdate.ChoiceIndex] = $"Role: {chatUpdate.Role ?? new AuthorRole()}\n"; - Console.Write($"Choice index: {chatUpdate.ChoiceIndex}, Role: {chatUpdate.Role ?? new AuthorRole()}"); - } - - // Add latest completion bit, if any - if (chatUpdate.Content is { Length: > 0 }) - { - messagesPerChoice[chatUpdate.ChoiceIndex] += chatUpdate.Content; - } - - // Overwrite what is currently in the console area for the updated choice - // Console.Write(messagesPerChoice[chatUpdate.ChoiceIndex]); - Console.Write($"Choice index: {chatUpdate.ChoiceIndex}, Content: {chatUpdate.Content}"); - } - - // Display the aggregated results - foreach (string message in messagesPerChoice.Values) - { - Console.WriteLine("-------------------"); - Console.WriteLine(message); - } - } -} diff --git a/dotnet/samples/Concepts/ChatCompletion/OpenAI_CustomAzureOpenAIClient.cs b/dotnet/samples/Concepts/ChatCompletion/OpenAI_CustomAzureOpenAIClient.cs index 9e63e4b46975..64228f692799 100644 --- a/dotnet/samples/Concepts/ChatCompletion/OpenAI_CustomAzureOpenAIClient.cs +++ b/dotnet/samples/Concepts/ChatCompletion/OpenAI_CustomAzureOpenAIClient.cs @@ -1,8 +1,8 @@ // Copyright (c) Microsoft. All rights reserved. +using System.ClientModel.Primitives; using Azure; using Azure.AI.OpenAI; -using Azure.Core.Pipeline; using Microsoft.SemanticKernel; namespace ChatCompletion; @@ -28,12 +28,12 @@ public async Task RunAsync() var httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Add("My-Custom-Header", "My Custom Value"); - // Configure OpenAIClient to use the customized HttpClient - var clientOptions = new OpenAIClientOptions + // Configure AzureOpenAIClient to use the customized HttpClient + var clientOptions = new AzureOpenAIClientOptions { - Transport = new HttpClientTransport(httpClient), + Transport = new HttpClientPipelineTransport(httpClient), }; - var openAIClient = new OpenAIClient(new Uri(endpoint), new AzureKeyCredential(apiKey), clientOptions); + var openAIClient = new AzureOpenAIClient(new Uri(endpoint), new AzureKeyCredential(apiKey), clientOptions); IKernelBuilder builder = Kernel.CreateBuilder(); builder.AddAzureOpenAIChatCompletion(deploymentName, openAIClient); diff --git a/dotnet/samples/Concepts/Concepts.csproj b/dotnet/samples/Concepts/Concepts.csproj index a4fe79f98053..98e4c257f415 100644 --- a/dotnet/samples/Concepts/Concepts.csproj +++ b/dotnet/samples/Concepts/Concepts.csproj @@ -120,41 +120,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -172,40 +137,5 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/dotnet/samples/Concepts/TextGeneration/OpenAI_TextGenerationStreaming.cs b/dotnet/samples/Concepts/TextGeneration/OpenAI_TextGenerationStreaming.cs index 0bdd20eb996f..bb906bb6d05c 100644 --- a/dotnet/samples/Concepts/TextGeneration/OpenAI_TextGenerationStreaming.cs +++ b/dotnet/samples/Concepts/TextGeneration/OpenAI_TextGenerationStreaming.cs @@ -24,10 +24,10 @@ public Task AzureOpenAITextGenerationStreamAsync() Console.WriteLine("======== Azure OpenAI - Text Generation - Raw Streaming ========"); var textGeneration = new AzureOpenAIChatCompletionService( - deploymentName: TestConfiguration.AzureOpenAI.DeploymentName, + deploymentName: TestConfiguration.AzureOpenAI.ChatDeploymentName, endpoint: TestConfiguration.AzureOpenAI.Endpoint, apiKey: TestConfiguration.AzureOpenAI.ApiKey, - modelId: TestConfiguration.AzureOpenAI.ModelId); + modelId: TestConfiguration.AzureOpenAI.ChatModelId); return this.TextGenerationStreamAsync(textGeneration); } @@ -37,7 +37,7 @@ public Task OpenAITextGenerationStreamAsync() { Console.WriteLine("======== Open AI - Text Generation - Raw Streaming ========"); - var textGeneration = new OpenAIChatCompletionService("gpt-3.5-turbo-instruct", TestConfiguration.OpenAI.ApiKey); + var textGeneration = new OpenAIChatCompletionService(TestConfiguration.OpenAI.ChatModelId, TestConfiguration.OpenAI.ApiKey); return this.TextGenerationStreamAsync(textGeneration); } From b49f12c2a8ba6fc1dbced6add5e204fd19b2f2a0 Mon Sep 17 00:00:00 2001 From: SergeyMenshykh Date: Wed, 17 Jul 2024 18:35:56 +0100 Subject: [PATCH 3/7] fix: test text-to-image service use default model --- .../OpenAI/OpenAITextToImageTests.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/dotnet/src/IntegrationTestsV2/Connectors/OpenAI/OpenAITextToImageTests.cs b/dotnet/src/IntegrationTestsV2/Connectors/OpenAI/OpenAITextToImageTests.cs index b2addba05188..85512760dcd0 100644 --- a/dotnet/src/IntegrationTestsV2/Connectors/OpenAI/OpenAITextToImageTests.cs +++ b/dotnet/src/IntegrationTestsV2/Connectors/OpenAI/OpenAITextToImageTests.cs @@ -39,4 +39,25 @@ public async Task OpenAITextToImageByModelTestAsync(string modelId, int width, i Assert.NotNull(result); Assert.NotEmpty(result); } + + [Fact] + public async Task OpenAITextToImageUseDallE2ByDefaultAsync() + { + // Arrange + OpenAIConfiguration? openAIConfiguration = this._configuration.GetSection("OpenAITextToImage").Get(); + Assert.NotNull(openAIConfiguration); + + var kernel = Kernel.CreateBuilder() + .AddOpenAITextToImage(apiKey: openAIConfiguration.ApiKey, modelId: null) + .Build(); + + var service = kernel.GetRequiredService(); + + // Act + var result = await service.GenerateImageAsync("The sun rises in the east and sets in the west.", 256, 256); + + // Assert + Assert.NotNull(result); + Assert.NotEmpty(result); + } } From 3b69d19dcebc3001c1cb77b2d2e51e28b8181577 Mon Sep 17 00:00:00 2001 From: SergeyMenshykh Date: Wed, 17 Jul 2024 20:28:15 +0100 Subject: [PATCH 4/7] fix: fix compilation issues --- .../samples/Concepts/Planners/AutoFunctionCallingPlanning.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dotnet/samples/Concepts/Planners/AutoFunctionCallingPlanning.cs b/dotnet/samples/Concepts/Planners/AutoFunctionCallingPlanning.cs index 4c287a63a216..38e3e53a0e74 100644 --- a/dotnet/samples/Concepts/Planners/AutoFunctionCallingPlanning.cs +++ b/dotnet/samples/Concepts/Planners/AutoFunctionCallingPlanning.cs @@ -7,13 +7,13 @@ using System.Security.Cryptography; using System.Text; using System.Text.Json; -using Azure.AI.OpenAI; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.SemanticKernel; using Microsoft.SemanticKernel.ChatCompletion; using Microsoft.SemanticKernel.Connectors.OpenAI; using Microsoft.SemanticKernel.Planning; +using OpenAI.Chat; namespace Planners; @@ -328,7 +328,7 @@ private int GetChatHistoryTokens(ChatHistory? chatHistory) { if (message.Metadata is not null && message.Metadata.TryGetValue("Usage", out object? usage) && - usage is CompletionsUsage completionsUsage && + usage is ChatTokenUsage completionsUsage && completionsUsage is not null) { tokens += completionsUsage.TotalTokens; From cd7ecbfb6f17a04ce2d18be216f8797346ab13b3 Mon Sep 17 00:00:00 2001 From: SergeyMenshykh Date: Wed, 17 Jul 2024 20:33:13 +0100 Subject: [PATCH 5/7] feat(Azure.AI.OpenAI SDK v2): migrate StepwisePlannerMigration app to the new OpenAI connector --- .../StepwisePlannerMigration/StepwisePlannerMigration.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dotnet/samples/Demos/StepwisePlannerMigration/StepwisePlannerMigration.csproj b/dotnet/samples/Demos/StepwisePlannerMigration/StepwisePlannerMigration.csproj index 1475397e7eb2..adeeb1f6471b 100644 --- a/dotnet/samples/Demos/StepwisePlannerMigration/StepwisePlannerMigration.csproj +++ b/dotnet/samples/Demos/StepwisePlannerMigration/StepwisePlannerMigration.csproj @@ -9,7 +9,7 @@ - + From b5e8eacfa0055acc6e538203a8fea61de2d03f06 Mon Sep 17 00:00:00 2001 From: SergeyMenshykh Date: Wed, 17 Jul 2024 21:49:04 +0100 Subject: [PATCH 6/7] fix: fix unit tests --- .../Services/OpenAIAudioToTextServiceTests.cs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/dotnet/src/Connectors/Connectors.OpenAIV2.UnitTests/Services/OpenAIAudioToTextServiceTests.cs b/dotnet/src/Connectors/Connectors.OpenAIV2.UnitTests/Services/OpenAIAudioToTextServiceTests.cs index 3ab5c0b7f960..2e8c3844cc49 100644 --- a/dotnet/src/Connectors/Connectors.OpenAIV2.UnitTests/Services/OpenAIAudioToTextServiceTests.cs +++ b/dotnet/src/Connectors/Connectors.OpenAIV2.UnitTests/Services/OpenAIAudioToTextServiceTests.cs @@ -43,18 +43,6 @@ public void ConstructorWithApiKeyWorksCorrectly(bool includeLoggerFactory) Assert.Equal("model-id", service.Attributes["ModelId"]); } - [Fact] - public void ItThrowsIfModelIdIsNotProvided() - { - // Act & Assert - Assert.Throws(() => new OpenAIAudioToTextService(" ", "apikey")); - Assert.Throws(() => new OpenAIAudioToTextService(" ", openAIClient: new("apikey"))); - Assert.Throws(() => new OpenAIAudioToTextService("", "apikey")); - Assert.Throws(() => new OpenAIAudioToTextService("", openAIClient: new("apikey"))); - Assert.Throws(() => new OpenAIAudioToTextService(null!, "apikey")); - Assert.Throws(() => new OpenAIAudioToTextService(null!, openAIClient: new("apikey"))); - } - [Theory] [InlineData(true)] [InlineData(false)] From fd1ccfb13751630ece7acbd13e0d63c9c9ca5fd8 Mon Sep 17 00:00:00 2001 From: SergeyMenshykh Date: Wed, 17 Jul 2024 22:20:30 +0100 Subject: [PATCH 7/7] fix: removeirrelevant unit test and restore deleted one --- .../Services/OpenAIAudioToTextServiceTests.cs | 12 ++++++++++++ .../Services/OpenAITextToImageServiceTests.cs | 9 --------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/dotnet/src/Connectors/Connectors.OpenAIV2.UnitTests/Services/OpenAIAudioToTextServiceTests.cs b/dotnet/src/Connectors/Connectors.OpenAIV2.UnitTests/Services/OpenAIAudioToTextServiceTests.cs index 2e8c3844cc49..3ab5c0b7f960 100644 --- a/dotnet/src/Connectors/Connectors.OpenAIV2.UnitTests/Services/OpenAIAudioToTextServiceTests.cs +++ b/dotnet/src/Connectors/Connectors.OpenAIV2.UnitTests/Services/OpenAIAudioToTextServiceTests.cs @@ -43,6 +43,18 @@ public void ConstructorWithApiKeyWorksCorrectly(bool includeLoggerFactory) Assert.Equal("model-id", service.Attributes["ModelId"]); } + [Fact] + public void ItThrowsIfModelIdIsNotProvided() + { + // Act & Assert + Assert.Throws(() => new OpenAIAudioToTextService(" ", "apikey")); + Assert.Throws(() => new OpenAIAudioToTextService(" ", openAIClient: new("apikey"))); + Assert.Throws(() => new OpenAIAudioToTextService("", "apikey")); + Assert.Throws(() => new OpenAIAudioToTextService("", openAIClient: new("apikey"))); + Assert.Throws(() => new OpenAIAudioToTextService(null!, "apikey")); + Assert.Throws(() => new OpenAIAudioToTextService(null!, openAIClient: new("apikey"))); + } + [Theory] [InlineData(true)] [InlineData(false)] diff --git a/dotnet/src/Connectors/Connectors.OpenAIV2.UnitTests/Services/OpenAITextToImageServiceTests.cs b/dotnet/src/Connectors/Connectors.OpenAIV2.UnitTests/Services/OpenAITextToImageServiceTests.cs index f59fea554eda..1528986b9064 100644 --- a/dotnet/src/Connectors/Connectors.OpenAIV2.UnitTests/Services/OpenAITextToImageServiceTests.cs +++ b/dotnet/src/Connectors/Connectors.OpenAIV2.UnitTests/Services/OpenAITextToImageServiceTests.cs @@ -46,15 +46,6 @@ public void ConstructorWorksCorrectly() Assert.Equal("model", sut.Attributes[AIServiceExtensions.ModelIdKey]); } - [Fact] - public void ItThrowsIfModelIdIsNotProvided() - { - // Act & Assert - Assert.Throws(() => new OpenAITextToImageService("apikey", modelId: " ")); - Assert.Throws(() => new OpenAITextToImageService("apikey", modelId: string.Empty)); - Assert.Throws(() => new OpenAITextToImageService("apikey", modelId: null!)); - } - [Theory] [InlineData(256, 256, "dall-e-2")] [InlineData(512, 512, "dall-e-2")]