Skip to content

Commit

Permalink
.Net: Switch from API keys to Azure Credentials when accessing Azure …
Browse files Browse the repository at this point in the history
…Cognitive Services (#8512)

### Motivation and Context

Closes: #6966
  • Loading branch information
markwallace-microsoft committed Sep 10, 2024
1 parent c59631d commit e44817d
Show file tree
Hide file tree
Showing 19 changed files with 136 additions and 55 deletions.
11 changes: 11 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 @@ -57,11 +58,13 @@ jobs:
os: "ubuntu-latest",
configuration: Release,
integration-tests: true,
environment: "integration",
}
- { dotnet: "8.0", os: "windows-latest", configuration: Debug }
- { dotnet: "8.0", os: "windows-latest", configuration: Release }

runs-on: ${{ matrix.os }}
environment: ${{ matrix.environment }}
steps:
- uses: actions/checkout@v4
- name: Setup dotnet ${{ matrix.dotnet }}
Expand All @@ -84,6 +87,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

0 comments on commit e44817d

Please sign in to comment.