Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.Net: Switch from API keys to Azure Credentials when accessing Azure Cognitive Services #8512

Merged
merged 13 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/dotnet-build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ concurrency:

permissions:
contents: read
id-token: "write"

jobs:
paths-filter:
Expand Down Expand Up @@ -84,6 +85,14 @@ jobs:
dotnet test -c ${{ matrix.configuration }} $project --no-build -v Normal --logger trx --collect:"XPlat Code Coverage" --results-directory:"TestResults/Coverage/" -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.ExcludeByAttribute=GeneratedCodeAttribute,CompilerGeneratedAttribute,ExcludeFromCodeCoverageAttribute
done

- name: Azure CLI Login
if: github.event_name != 'pull_request' && matrix.integration-tests
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

- name: Run Integration Tests
shell: bash
if: github.event_name != 'pull_request' && matrix.integration-tests
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,43 @@ public static IKernelBuilder AddAzureOpenAITextEmbeddingGeneration(
return builder;
}

/// <summary>
/// Adds the <see cref="AzureOpenAITextToAudioService"/> to the <see cref="IKernelBuilder.Services"/>.
/// </summary>
/// <param name="builder">The <see cref="IKernelBuilder"/> instance to augment.</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="modelId">Model identifier, see https://learn.microsoft.com/azure/cognitive-services/openai/quickstart</param>
/// <param name="httpClient">The HttpClient to use with this service.</param>
/// <returns>The same instance as <paramref name="builder"/>.</returns>
[Experimental("SKEXP0010")]
public static IKernelBuilder AddAzureOpenAITextToAudio(
this IKernelBuilder builder,
string deploymentName,
string endpoint,
TokenCredential credential,
string? serviceId = null,
string? modelId = null,
HttpClient? httpClient = null)
{
Verify.NotNull(builder);
Verify.NotNullOrWhiteSpace(endpoint);
Verify.NotNull(credential);

builder.Services.AddKeyedSingleton<ITextToAudioService>(serviceId, (serviceProvider, _) =>
new AzureOpenAITextToAudioService(
deploymentName,
endpoint,
credential,
modelId,
HttpClientProvider.GetHttpClient(httpClient, serviceProvider),
serviceProvider.GetService<ILoggerFactory>()));

return builder;
}

#endregion

#region Text-to-Audio
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Threading;
using System.Threading.Tasks;
using Azure.AI.OpenAI;
using Azure.Core;
using Microsoft.Extensions.Logging;
using Microsoft.SemanticKernel.Services;
using Microsoft.SemanticKernel.TextToAudio;
Expand Down Expand Up @@ -69,6 +70,38 @@ public AzureOpenAITextToAudioService(
this._modelId = modelId;
}

/// <summary>
/// Initializes a new instance of the <see cref="AzureOpenAITextToAudioService"/> class.
/// </summary>
/// <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="modelId">Azure OpenAI model id, see https://learn.microsoft.com/azure/cognitive-services/openai/how-to/create-resource</param>
/// <param name="httpClient">Custom <see cref="HttpClient"/> for HTTP requests.</param>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/> to use for logging. If null, no logging will be performed.</param>
public AzureOpenAITextToAudioService(
string deploymentName,
string endpoint,
TokenCredential credential,
string? modelId = null,
HttpClient? httpClient = null,
ILoggerFactory? loggerFactory = null)
{
var url = !string.IsNullOrWhiteSpace(httpClient?.BaseAddress?.AbsoluteUri) ? httpClient!.BaseAddress!.AbsoluteUri : endpoint;

var options = AzureClientCore.GetAzureOpenAIClientOptions(
httpClient,
AzureOpenAIClientOptions.ServiceVersion.V2024_05_01_Preview); // https://learn.microsoft.com/en-us/azure/ai-services/openai/reference#text-to-speech

var azureOpenAIClient = new AzureOpenAIClient(new Uri(url), credential, options);

this._client = new(deploymentName, azureOpenAIClient, loggerFactory?.CreateLogger(typeof(AzureOpenAITextToAudioService)));

this._client.AddAttribute(AIServiceExtensions.ModelIdKey, modelId);

this._modelId = modelId;
}

/// <inheritdoc/>
public Task<IReadOnlyList<AudioContent>> GetAudioContentsAsync(
string text,
Expand Down
10 changes: 5 additions & 5 deletions dotnet/src/IntegrationTests/Agents/ChatCompletionAgentTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Azure.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.AzureOpenAI;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using SemanticKernel.IntegrationTests.TestSettings;
using Xunit;
Expand Down Expand Up @@ -43,9 +43,9 @@ public async Task AzureChatCompletionAgentAsync(string input, string expectedAns
KernelPlugin plugin = KernelPluginFactory.CreateFromType<MenuPlugin>();

this._kernelBuilder.AddAzureOpenAIChatCompletion(
configuration.ChatDeploymentName!,
configuration.Endpoint,
configuration.ApiKey);
deploymentName: configuration.ChatDeploymentName!,
endpoint: configuration.Endpoint,
credentials: new AzureCliCredential());

if (useAutoFunctionTermination)
{
Expand Down Expand Up @@ -107,7 +107,7 @@ public async Task AzureChatCompletionStreamingAsync()
this._kernelBuilder.AddAzureOpenAIChatCompletion(
configuration.ChatDeploymentName!,
configuration.Endpoint,
configuration.ApiKey);
new AzureCliCredential());

this._kernelBuilder.Plugins.Add(plugin);

Expand Down
9 changes: 5 additions & 4 deletions dotnet/src/IntegrationTests/Agents/MixedAgentTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.ComponentModel;
using System.Text;
using System.Threading.Tasks;
using Azure.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
Expand Down Expand Up @@ -55,7 +56,7 @@ public async Task AzureOpenAIMixedAgentAsync()
// Arrange, Act & Assert
await this.VerifyAgentExecutionAsync(
this.CreateChatCompletionKernel(azureOpenAISettings),
OpenAIClientProvider.ForAzureOpenAI(azureOpenAISettings.ApiKey, new Uri(azureOpenAISettings.Endpoint)),
OpenAIClientProvider.ForAzureOpenAI(new AzureCliCredential(), new Uri(azureOpenAISettings.Endpoint)),
azureOpenAISettings.ChatDeploymentName!);
}

Expand Down Expand Up @@ -120,9 +121,9 @@ private Kernel CreateChatCompletionKernel(AzureOpenAIConfiguration configuration
IKernelBuilder kernelBuilder = Kernel.CreateBuilder();

kernelBuilder.AddAzureOpenAIChatCompletion(
configuration.ChatDeploymentName!,
configuration.Endpoint,
configuration.ApiKey);
deploymentName: configuration.ChatDeploymentName!,
endpoint: configuration.Endpoint,
credentials: new AzureCliCredential());

return kernelBuilder.Build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Azure.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
Expand Down Expand Up @@ -55,7 +56,7 @@ public async Task AzureOpenAIAssistantAgentAsync(string input, string expectedAn
Assert.NotNull(azureOpenAIConfiguration);

await this.ExecuteAgentAsync(
OpenAIClientProvider.ForAzureOpenAI(azureOpenAIConfiguration.ApiKey, new Uri(azureOpenAIConfiguration.Endpoint)),
OpenAIClientProvider.ForAzureOpenAI(new AzureCliCredential(), new Uri(azureOpenAIConfiguration.Endpoint)),
azureOpenAIConfiguration.ChatDeploymentName!,
input,
expectedAnswerContains);
Expand Down Expand Up @@ -91,7 +92,7 @@ public async Task AzureOpenAIAssistantAgentStreamingAsync(string input, string e
Assert.NotNull(azureOpenAIConfiguration);

await this.ExecuteStreamingAgentAsync(
OpenAIClientProvider.ForAzureOpenAI(azureOpenAIConfiguration.ApiKey, new Uri(azureOpenAIConfiguration.Endpoint)),
OpenAIClientProvider.ForAzureOpenAI(new AzureCliCredential(), new Uri(azureOpenAIConfiguration.Endpoint)),
azureOpenAIConfiguration.ChatDeploymentName!,
input,
expectedAnswerContains);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System;
using System.IO;
using System.Threading.Tasks;
using Azure.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.AudioToText;
Expand Down Expand Up @@ -33,9 +34,9 @@ public async Task AzureOpenAIAudioToTextTestAsync()

var kernel = Kernel.CreateBuilder()
.AddAzureOpenAIAudioToText(
azureOpenAIConfiguration.DeploymentName,
azureOpenAIConfiguration.Endpoint,
azureOpenAIConfiguration.ApiKey)
deploymentName: azureOpenAIConfiguration.DeploymentName,
endpoint: azureOpenAIConfiguration.Endpoint,
credentials: new AzureCliCredential())
.Build();

var service = kernel.GetRequiredService<IAudioToTextService>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Azure.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
Expand Down Expand Up @@ -865,7 +866,6 @@ private Kernel CreateAndInitializeKernel(bool importHelperPlugin = false)
var azureOpenAIConfiguration = this._configuration.GetSection("AzureOpenAI").Get<AzureOpenAIConfiguration>();
Assert.NotNull(azureOpenAIConfiguration);
Assert.NotNull(azureOpenAIConfiguration.ChatDeploymentName);
Assert.NotNull(azureOpenAIConfiguration.ApiKey);
Assert.NotNull(azureOpenAIConfiguration.Endpoint);

var kernelBuilder = base.CreateKernelBuilder();
Expand All @@ -874,7 +874,7 @@ private Kernel CreateAndInitializeKernel(bool importHelperPlugin = false)
deploymentName: azureOpenAIConfiguration.ChatDeploymentName,
modelId: azureOpenAIConfiguration.ChatModelId,
endpoint: azureOpenAIConfiguration.Endpoint,
apiKey: azureOpenAIConfiguration.ApiKey);
credentials: new AzureCliCredential());

var kernel = kernelBuilder.Build();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Text.Json;
using System.Threading.Tasks;
using Azure.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.SemanticKernel;
Expand Down Expand Up @@ -147,7 +148,6 @@ private Kernel CreateAndInitializeKernel()
var azureOpenAIConfiguration = this._configuration.GetSection("AzureOpenAI").Get<AzureOpenAIConfiguration>();
Assert.NotNull(azureOpenAIConfiguration);
Assert.NotNull(azureOpenAIConfiguration.ChatDeploymentName);
Assert.NotNull(azureOpenAIConfiguration.ApiKey);
Assert.NotNull(azureOpenAIConfiguration.Endpoint);

var kernelBuilder = base.CreateKernelBuilder();
Expand All @@ -156,7 +156,7 @@ private Kernel CreateAndInitializeKernel()
deploymentName: azureOpenAIConfiguration.ChatDeploymentName,
modelId: azureOpenAIConfiguration.ChatModelId,
endpoint: azureOpenAIConfiguration.Endpoint,
apiKey: azureOpenAIConfiguration.ApiKey);
credentials: new AzureCliCredential());

return kernelBuilder.Build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Azure.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.SemanticKernel;
Expand Down Expand Up @@ -148,7 +149,6 @@ private Kernel CreateAndInitializeKernel()
var azureOpenAIConfiguration = this._configuration.GetSection("AzureOpenAI").Get<AzureOpenAIConfiguration>();
Assert.NotNull(azureOpenAIConfiguration);
Assert.NotNull(azureOpenAIConfiguration.ChatDeploymentName);
Assert.NotNull(azureOpenAIConfiguration.ApiKey);
Assert.NotNull(azureOpenAIConfiguration.Endpoint);

var kernelBuilder = base.CreateKernelBuilder();
Expand All @@ -157,7 +157,7 @@ private Kernel CreateAndInitializeKernel()
deploymentName: azureOpenAIConfiguration.ChatDeploymentName,
modelId: azureOpenAIConfiguration.ChatModelId,
endpoint: azureOpenAIConfiguration.Endpoint,
apiKey: azureOpenAIConfiguration.ApiKey);
credentials: new AzureCliCredential());

return kernelBuilder.Build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Azure.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Http.Resilience;
Expand Down Expand Up @@ -232,7 +233,6 @@ private Kernel CreateAndInitializeKernel(HttpClient? httpClient = null)
var azureOpenAIConfiguration = this._configuration.GetSection("AzureOpenAI").Get<AzureOpenAIConfiguration>();
Assert.NotNull(azureOpenAIConfiguration);
Assert.NotNull(azureOpenAIConfiguration.ChatDeploymentName);
Assert.NotNull(azureOpenAIConfiguration.ApiKey);
Assert.NotNull(azureOpenAIConfiguration.Endpoint);
Assert.NotNull(azureOpenAIConfiguration.ServiceId);

Expand All @@ -242,7 +242,7 @@ private Kernel CreateAndInitializeKernel(HttpClient? httpClient = null)
deploymentName: azureOpenAIConfiguration.ChatDeploymentName,
modelId: azureOpenAIConfiguration.ChatModelId,
endpoint: azureOpenAIConfiguration.Endpoint,
apiKey: azureOpenAIConfiguration.ApiKey,
credentials: new AzureCliCredential(),
serviceId: azureOpenAIConfiguration.ServiceId,
httpClient: httpClient);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft. All rights reserved.

using System.Threading.Tasks;
using Azure.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.SemanticKernel.Connectors.AzureOpenAI;
using Microsoft.SemanticKernel.Embeddings;
Expand All @@ -24,9 +25,9 @@ public async Task AzureOpenAITestAsync(string testInputString)
{
// Arrange
var embeddingGenerator = new AzureOpenAITextEmbeddingGenerationService(
this._azureOpenAIConfiguration.DeploymentName,
this._azureOpenAIConfiguration.Endpoint,
this._azureOpenAIConfiguration.ApiKey);
deploymentName: this._azureOpenAIConfiguration.DeploymentName,
endpoint: this._azureOpenAIConfiguration.Endpoint,
credential: new AzureCliCredential());

// Act
var singleResult = await embeddingGenerator.GenerateEmbeddingAsync(testInputString);
Expand All @@ -46,9 +47,9 @@ public async Task AzureOpenAIWithDimensionsAsync(int? dimensions, int expectedVe
const string TestInputString = "test sentence";

var embeddingGenerator = new AzureOpenAITextEmbeddingGenerationService(
"text-embedding-3-large",
this._azureOpenAIConfiguration.Endpoint,
this._azureOpenAIConfiguration.ApiKey,
deploymentName: "text-embedding-3-large",
endpoint: this._azureOpenAIConfiguration.Endpoint,
credential: new AzureCliCredential(),
dimensions: dimensions);

// Act
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft. All rights reserved.

using System.Threading.Tasks;
using Azure.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.TextToAudio;
Expand All @@ -27,9 +28,9 @@ public async Task AzureOpenAITextToAudioTestAsync()

var kernel = Kernel.CreateBuilder()
.AddAzureOpenAITextToAudio(
azureOpenAIConfiguration.DeploymentName,
azureOpenAIConfiguration.Endpoint,
azureOpenAIConfiguration.ApiKey)
deploymentName: azureOpenAIConfiguration.DeploymentName,
endpoint: azureOpenAIConfiguration.Endpoint,
credential: new AzureCliCredential())
.Build();

var service = kernel.GetRequiredService<ITextToAudioService>();
Expand Down
Loading
Loading