Skip to content

Improved client creation for Azure OpenAI (inc Entra ) #8

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
25 changes: 25 additions & 0 deletions src/RxAI.Realtime/Helpers/EnvironmentWellKnown.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RxAI.Realtime;

public static class EnvironmentWellKnown
{
private static string? _deploymentName;
public static string DeploymentName => _deploymentName ??= Environment.GetEnvironmentVariable(Wellknown.AzureOpenAIDeployment);

private static string? _endpoint;
public static string Endpoint => _endpoint ??= Environment.GetEnvironmentVariable(Wellknown.AzureOpenAIEndpoint);

private static string? _apiKey;
public static string ApiKey => _apiKey ??= Environment.GetEnvironmentVariable(Wellknown.AzureOpenAIApiKey);

private static string? _bingApiKey;
public static string BingApiKey => _bingApiKey ??= Environment.GetEnvironmentVariable(Wellknown.BingApiKey);

private static string? _openAIApiKey;
public static string OpenAIApiKey => _openAIApiKey ??= Environment.GetEnvironmentVariable(Wellknown.OpenAIApiKey);
}
File renamed without changes.
84 changes: 84 additions & 0 deletions src/RxAI.Realtime/Helpers/RealtimeClientProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
using Azure.AI.OpenAI;
using Azure.Identity;
using OpenAI;
using OpenAI.RealtimeConversation;
using System.ClientModel;

namespace RxAI.Realtime;

#pragma warning disable OPENAI002
public static class RealtimeClientProvider
{
public static RealtimeConversationClient GetConfiguredClient()
{
string? aoaiEndpoint = EnvironmentWellKnown.Endpoint;
string? aoaiUseEntra = Environment.GetEnvironmentVariable(Wellknown.AzureOpenAIUseEntra);
string? aoaiDeployment = EnvironmentWellKnown.DeploymentName;
string? aoaiApiKey = EnvironmentWellKnown.ApiKey;
string? oaiApiKey = EnvironmentWellKnown.OpenAIApiKey;

if (aoaiEndpoint is not null && bool.TryParse(aoaiUseEntra, out bool useEntra) && useEntra)
{
return GetConfiguredClientForAzureOpenAIWithEntra(aoaiEndpoint, aoaiDeployment);
}
else if (aoaiEndpoint is not null && aoaiApiKey is not null)
{
return GetConfiguredClientForAzureOpenAIWithKey(aoaiEndpoint, aoaiDeployment, aoaiApiKey);
}
else if (aoaiEndpoint is not null)
{
throw new InvalidOperationException(
$"AZURE_OPENAI_ENDPOINT configured without AZURE_OPENAI_USE_ENTRA=true or AZURE_OPENAI_API_KEY.");
}
else if (oaiApiKey is not null)
{
return GetConfiguredClientForOpenAIWithKey(oaiApiKey);
}
else
{
throw new InvalidOperationException(
$"No environment configuration present. Please provide one of:\n"
+ " - AZURE_OPENAI_ENDPOINT with AZURE_OPENAI_USE_ENTRA=true or AZURE_OPENAI_API_KEY\n"
+ " - OPENAI_API_KEY");
}
}

private static RealtimeConversationClient GetConfiguredClientForAzureOpenAIWithEntra(
string aoaiEndpoint,
string? aoaiDeployment)
{
Console.WriteLine($" * Connecting to Azure OpenAI endpoint (AZURE_OPENAI_ENDPOINT): {aoaiEndpoint}");
Console.WriteLine($" * Using Entra token-based authentication (AZURE_OPENAI_USE_ENTRA)");
Console.WriteLine(string.IsNullOrEmpty(aoaiDeployment)
? " * Using no deployment (AZURE_OPENAI_DEPLOYMENT)"
: $" * Using deployment (AZURE_OPENAI_DEPLOYMENT): {aoaiDeployment}");

AzureOpenAIClient aoaiClient = new(new Uri(aoaiEndpoint), new DefaultAzureCredential());
return aoaiClient.GetRealtimeConversationClient(aoaiDeployment);
}

private static RealtimeConversationClient GetConfiguredClientForAzureOpenAIWithKey(
string aoaiEndpoint,
string? aoaiDeployment,
string aoaiApiKey)
{
Console.WriteLine($" * Connecting to Azure OpenAI endpoint (AZURE_OPENAI_ENDPOINT): {aoaiEndpoint}");
Console.WriteLine($" * Using API key (AZURE_OPENAI_API_KEY): {aoaiApiKey[..5]}**");
Console.WriteLine(string.IsNullOrEmpty(aoaiDeployment)
? " * Using no deployment (AZURE_OPENAI_DEPLOYMENT)"
: $" * Using deployment (AZURE_OPENAI_DEPLOYMENT): {aoaiDeployment}");

AzureOpenAIClient aoaiClient = new(new Uri(aoaiEndpoint), new ApiKeyCredential(aoaiApiKey));
return aoaiClient.GetRealtimeConversationClient(aoaiDeployment);
}

private static RealtimeConversationClient GetConfiguredClientForOpenAIWithKey(string oaiApiKey)
{
string oaiEndpoint = Wellknown.OpenAIEndpoint;
Console.WriteLine($" * Connecting to OpenAI endpoint (OPENAI_ENDPOINT): {oaiEndpoint}");
Console.WriteLine($" * Using API key (OPENAI_API_KEY): {oaiApiKey[..5]}**");

OpenAIClient aoaiClient = new(new ApiKeyCredential(oaiApiKey));
return aoaiClient.GetRealtimeConversationClient("gpt-4o-realtime-preview-2024-10-01");
}
}
20 changes: 20 additions & 0 deletions src/RxAI.Realtime/Helpers/Wellknown.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RxAI.Realtime;

public static class Wellknown
{
public const string WhisperModel = "whisper-1";
public const string FinishConversationToolName = "user_wants_to_finish_conversation";
public const string AzureOpenAIEndpoint = "AZURE_OPENAI_EASTUS2_ENDPOINT";
public const string AzureOpenAIUseEntra = "AZURE_OPENAI_USE_ENTRA";
public const string AzureOpenAIDeployment = "AZURE_OPENAI_EASTUS2_DEPLOYMENT";
public const string AzureOpenAIApiKey = "AZURE_OPENAI_EASTUS2_API_KEY";
public const string OpenAIEndpoint = "https://api.openai.com/v1";
public const string OpenAIApiKey = "OPENAI_API_KEY";
public const string BingApiKey = "Bing_ApiKey";
}
12 changes: 12 additions & 0 deletions src/RxAI.Realtime/RealtimeConversationClientRX.cs
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,18 @@ public static RealtimeConversationClientRX FromAzureCredential(
return FromOpenAIClient(client, model);
}

/// <summary>
/// Creates a RealtimeConverstionClientRX instance from the default configuration
/// stored in the system's environment variables.
/// This will construct a client for Azure OpenAI (including EntraID auth) or OpenAI .
/// </summary>
/// <returns></returns>
public static RealtimeConversationClientRX GetConfiguredClient()
{
var conversationClient = RealtimeClientProvider.GetConfiguredClient();
return new RealtimeConversationClientRX(conversationClient);
}

/// <summary>
/// Creates a <see cref="RealtimeConversationClientRX"/> instance from an OpenAI client.
/// </summary>
Expand Down
1 change: 1 addition & 0 deletions src/RxAI.Realtime/RxAI.Realtime.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<ItemGroup>
<PackageReference Include="Azure.AI.OpenAI" Version="2.1.0-beta.1" />
<PackageReference Include="System.Reactive" Version="6.0.1" />
<PackageReference Include="Azure.Identity" Version="1.12.1" />
</ItemGroup>

</Project>