-
Notifications
You must be signed in to change notification settings - Fork 481
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Integrate OpenAI/AzureOpenAI support with Microsoft.Extensions.AI (#6225
- Loading branch information
1 parent
111d4e8
commit 04cf1fe
Showing
25 changed files
with
1,272 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 0 additions & 1 deletion
1
playground/OpenAIEndToEnd/OpenAIEndToEnd.WebStory/Components/Pages/Home.razor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
37 changes: 37 additions & 0 deletions
37
playground/OpenAIEndToEnd/OpenAIEndToEnd.WebStory/Components/Pages/UseIChatClient.razor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
@page "/useichatclient" | ||
@using Microsoft.Extensions.AI | ||
@inject IChatClient aiClient | ||
@inject ILogger<Home> logger | ||
@inject IConfiguration configuration | ||
|
||
<div class="storybox" style="margin: 25%"> | ||
@foreach (var message in chatMessages.Where(m => m.Role == ChatRole.Assistant)) | ||
{ | ||
<p style="font-size: 3em;">@message.Text</p> | ||
} | ||
|
||
<button @onclick="GenerateNextParagraph" autofocus>Generate</button> | ||
</div> | ||
|
||
@code { | ||
private List<ChatMessage> chatMessages = new List<ChatMessage> | ||
{ | ||
new(ChatRole.System, "Pick a random topic and write a sentence of a fictional story about it.") | ||
}; | ||
|
||
private async Task GenerateNextParagraph() | ||
{ | ||
if (chatMessages.Count > 1) | ||
{ | ||
chatMessages.Add(new (ChatRole.User, "Write the next sentence in the story.")); | ||
} | ||
|
||
var response = await aiClient.CompleteAsync(chatMessages); | ||
chatMessages.Add(response.Message); | ||
} | ||
|
||
protected override async Task OnInitializedAsync() | ||
{ | ||
await GenerateNextParagraph(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 29 additions & 0 deletions
29
src/Components/Aspire.Azure.AI.OpenAI/AspireAzureOpenAIClientBuilder.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using Aspire.OpenAI; | ||
using Azure.AI.OpenAI; | ||
using Microsoft.Extensions.Hosting; | ||
|
||
namespace Aspire.Azure.AI.OpenAI; | ||
|
||
/// <summary> | ||
/// A builder for configuring an <see cref="AzureOpenAIClient"/> service registration. | ||
/// </summary> | ||
public class AspireAzureOpenAIClientBuilder : AspireOpenAIClientBuilder | ||
{ | ||
/// <summary> | ||
/// Constructs a new instance of <see cref="AspireAzureOpenAIClientBuilder"/>. | ||
/// </summary> | ||
/// <param name="hostBuilder">The <see cref="IHostApplicationBuilder"/> with which services are being registered.</param> | ||
/// <param name="connectionName">The name used to retrieve the connection string from the ConnectionStrings configuration section.</param> | ||
/// <param name="serviceKey">The service key used to register the <see cref="AzureOpenAIClient"/> service, if any.</param> | ||
/// <param name="disableTracing">A flag to indicate whether tracing should be disabled.</param> | ||
public AspireAzureOpenAIClientBuilder(IHostApplicationBuilder hostBuilder, string connectionName, string? serviceKey, bool disableTracing) | ||
: base(hostBuilder, connectionName, serviceKey, disableTracing) | ||
{ | ||
} | ||
|
||
/// <inheritdoc /> | ||
public override string ConfigurationSectionName => AspireAzureOpenAIExtensions.DefaultConfigSectionName; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using Microsoft.Extensions.Configuration; | ||
using System.Data.Common; | ||
using Microsoft.Extensions.Hosting; | ||
using OpenAI; | ||
|
||
namespace Aspire.OpenAI; | ||
|
||
/// <summary> | ||
/// A builder for configuring an <see cref="OpenAIClient"/> service registration. | ||
/// </summary> | ||
public class AspireOpenAIClientBuilder | ||
{ | ||
private const string DeploymentKey = "Deployment"; | ||
private const string ModelKey = "Model"; | ||
|
||
/// <summary> | ||
/// Constructs a new instance of <see cref="AspireOpenAIClientBuilder"/>. | ||
/// </summary> | ||
/// <param name="hostBuilder">The <see cref="IHostApplicationBuilder"/> with which services are being registered.</param> | ||
/// <param name="connectionName">The name used to retrieve the connection string from the ConnectionStrings configuration section.</param> | ||
/// <param name="serviceKey">The service key used to register the <see cref="OpenAIClient"/> service, if any.</param> | ||
/// <param name="disableTracing">A flag to indicate whether tracing should be disabled.</param> | ||
public AspireOpenAIClientBuilder(IHostApplicationBuilder hostBuilder, string connectionName, string? serviceKey, bool disableTracing) | ||
{ | ||
HostBuilder = hostBuilder; | ||
ConnectionName = connectionName; | ||
ServiceKey = serviceKey; | ||
DisableTracing = disableTracing; | ||
} | ||
|
||
/// <summary> | ||
/// Gets the <see cref="IHostApplicationBuilder"/> with which services are being registered. | ||
/// </summary> | ||
public IHostApplicationBuilder HostBuilder { get; } | ||
|
||
/// <summary> | ||
/// Gets the name used to retrieve the connection string from the ConnectionStrings configuration section. | ||
/// </summary> | ||
public string ConnectionName { get; } | ||
|
||
/// <summary> | ||
/// Gets the service key used to register the <see cref="OpenAIClient"/> service, if any. | ||
/// </summary> | ||
public string? ServiceKey { get; } | ||
|
||
/// <summary> | ||
/// Gets a flag indicating whether tracing should be disabled. | ||
/// </summary> | ||
public bool DisableTracing { get; } | ||
|
||
/// <summary> | ||
/// Gets the name of the configuration section for this component type. | ||
/// </summary> | ||
public virtual string ConfigurationSectionName => AspireOpenAIExtensions.DefaultConfigSectionName; | ||
|
||
internal string GetRequiredDeploymentName() | ||
{ | ||
string? deploymentName = null; | ||
|
||
var configuration = HostBuilder.Configuration; | ||
if (configuration.GetConnectionString(ConnectionName) is string connectionString) | ||
{ | ||
// The reason we accept either 'Deployment' or 'Model' as the key is because OpenAI's terminology | ||
// is 'Model' and Azure OpenAI's terminology is 'Deployment'. It may seem awkward if we picked just | ||
// one of these, as it might not match the usage scenario. We could restrict it based on which backend | ||
// you're using, but that adds an unnecessary failure case for no clear benefit. | ||
var connectionBuilder = new DbConnectionStringBuilder { ConnectionString = connectionString }; | ||
var deploymentValue = ConnectionStringValue(connectionBuilder, DeploymentKey); | ||
var modelValue = ConnectionStringValue(connectionBuilder, ModelKey); | ||
if (deploymentValue is not null && modelValue is not null) | ||
{ | ||
throw new InvalidOperationException( | ||
$"The connection string '{ConnectionName}' contains both '{DeploymentKey}' and '{ModelKey}' keys. Either of these may be specified, but not both."); | ||
} | ||
|
||
deploymentName = deploymentValue ?? modelValue; | ||
} | ||
|
||
if (string.IsNullOrEmpty(deploymentName)) | ||
{ | ||
var configSection = configuration.GetSection(ConfigurationSectionName); | ||
deploymentName = configSection[DeploymentKey]; | ||
} | ||
|
||
if (string.IsNullOrEmpty(deploymentName)) | ||
{ | ||
throw new InvalidOperationException($"The deployment could not be determined. Ensure a '{DeploymentKey}' or '{ModelKey}' value is provided in 'ConnectionStrings:{ConnectionName}', or specify a '{DeploymentKey}' in the '{ConfigurationSectionName}' configuration section, or specify a '{nameof(deploymentName)}' in the call."); | ||
} | ||
|
||
return deploymentName; | ||
} | ||
|
||
private static string? ConnectionStringValue(DbConnectionStringBuilder connectionString, string key) | ||
=> connectionString.TryGetValue(key, out var value) ? value as string : null; | ||
} |
Oops, something went wrong.