Skip to content

Commit a3a3e6f

Browse files
committed
Add support for using ConversationID for AzureOpenAI and OpenAI
1 parent c1dfbf0 commit a3a3e6f

File tree

14 files changed

+110
-8
lines changed

14 files changed

+110
-8
lines changed

src/ProjectTemplates/Microsoft.Extensions.AI.Templates/src/ChatWithCustomData/.template.config/template.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,17 @@
6060
"ChatWithCustomData-CSharp.AppHost/**",
6161
"ChatWithCustomData-CSharp.ServiceDefaults/**",
6262
"ChatWithCustomData-CSharp.Web/Program.Aspire.cs",
63+
"ChatWithCustomData-CSharp.Web/ResponseClientHelper.cs",
6364
"README.Aspire.md",
6465
"*.sln"
6566
]
6667
},
68+
{
69+
"condition": "(IsAspire && !IsOpenAI && !IsAzureOpenAI)",
70+
"exclude": [
71+
"ChatWithCustomData-CSharp.Web/ResponseClientHelper.cs"
72+
]
73+
},
6774
{
6875
"condition": "(IsAspire)",
6976
"exclude": [

src/ProjectTemplates/Microsoft.Extensions.AI.Templates/src/ChatWithCustomData/ChatWithCustomData-CSharp.Web/ChatWithCustomData-CSharp.Web.csproj.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
<Nullable>enable</Nullable>
66
<ImplicitUsings>enable</ImplicitUsings>
77
<UserSecretsId>d5681fae-b21b-4114-b781-48180f08c0c4</UserSecretsId>
8+
<!--#if (IsAzureOpenAI || IsOpenAI)
9+
<NoWarn>OPENAI001</NoWarn>
10+
#endif -->
811
</PropertyGroup>
912

1013
<ItemGroup>

src/ProjectTemplates/Microsoft.Extensions.AI.Templates/src/ChatWithCustomData/ChatWithCustomData-CSharp.Web/Components/Pages/Chat/Chat.razor

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,22 @@
6666
var responseText = new TextContent("");
6767
currentResponseMessage = new ChatMessage(ChatRole.Assistant, [responseText]);
6868
currentResponseCancellation = new();
69+
@*#if (IsAzureOpenAI || IsOpenAI)
70+
await foreach (var update in ChatClient.GetStreamingResponseAsync([userMessage], chatOptions, currentResponseCancellation.Token))
71+
{
72+
messages.AddMessages(update, filter: c => c is not TextContent);
73+
responseText.Text += update.Text;
74+
chatOptions.ConversationId = update.ConversationId; //Update conversation ID from current response
75+
ChatMessageItem.NotifyChanged(currentResponseMessage);
76+
}
77+
#else*@
6978
await foreach (var update in ChatClient.GetStreamingResponseAsync([.. messages], chatOptions, currentResponseCancellation.Token))
7079
{
7180
messages.AddMessages(update, filter: c => c is not TextContent);
7281
responseText.Text += update.Text;
7382
ChatMessageItem.NotifyChanged(currentResponseMessage);
7483
}
84+
@*#endif*@
7585

7686
// Store the final response in the conversation, and begin getting suggestions
7787
messages.Add(currentResponseMessage!);
@@ -96,6 +106,9 @@
96106
CancelAnyCurrentResponse();
97107
messages.Clear();
98108
messages.Add(new(ChatRole.System, SystemPrompt));
109+
@*#if (IsAzureOpenAI || IsOpenAI)
110+
chatOptions.ConversationId = null;
111+
#endif*@
99112
chatSuggestions?.Clear();
100113
await chatInput!.FocusAsync();
101114
}

src/ProjectTemplates/Microsoft.Extensions.AI.Templates/src/ChatWithCustomData/ChatWithCustomData-CSharp.Web/Program.Aspire.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
#else
2828
var openai = builder.AddAzureOpenAIClient("openai");
2929
#endif
30-
openai.AddChatClient("gpt-4o-mini")
30+
openai.AddResponsesChatClient("gpt-4o-mini")
3131
.UseFunctionInvocation()
3232
.UseOpenTelemetry(configure: c =>
3333
c.EnableSensitiveData = builder.Environment.IsDevelopment());

src/ProjectTemplates/Microsoft.Extensions.AI.Templates/src/ChatWithCustomData/ChatWithCustomData-CSharp.Web/Program.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
// dotnet user-secrets set OpenAI:Key YOUR-API-KEY
4848
var openAIClient = new OpenAIClient(
4949
new ApiKeyCredential(builder.Configuration["OpenAI:Key"] ?? throw new InvalidOperationException("Missing configuration: OpenAI:Key. See the README for details.")));
50-
var chatClient = openAIClient.GetChatClient("gpt-4o-mini").AsIChatClient();
50+
var chatClient = openAIClient.GetOpenAIResponseClient("gpt-4o-mini").AsIChatClient();
5151
var embeddingGenerator = openAIClient.GetEmbeddingClient("text-embedding-3-small").AsIEmbeddingGenerator();
5252
#elif (IsAzureAiFoundry)
5353

@@ -66,7 +66,7 @@
6666
#else
6767
new ApiKeyCredential(builder.Configuration["AzureOpenAI:Key"] ?? throw new InvalidOperationException("Missing configuration: AzureOpenAi:Key. See the README for details.")));
6868
#endif
69-
var chatClient = azureOpenAi.GetChatClient("gpt-4o-mini").AsIChatClient();
69+
var chatClient = azureOpenAi.GetOpenAIResponseClient("gpt-4o-mini").AsIChatClient();
7070
var embeddingGenerator = azureOpenAi.GetEmbeddingClient("text-embedding-3-small").AsIEmbeddingGenerator();
7171
#endif
7272

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using Microsoft.Extensions.AI;
2+
using Aspire.OpenAI;
3+
using OpenAI;
4+
5+
//namespace chat.aspire.Web;
6+
namespace Microsoft.Extensions.Hosting;
7+
8+
public static class ResponseClientHelper
9+
{
10+
11+
public static ChatClientBuilder AddResponsesChatClient(this AspireOpenAIClientBuilder builder, string? deploymentName)
12+
{
13+
ArgumentNullException.ThrowIfNull(builder, "builder");
14+
15+
return builder.HostBuilder.Services.AddChatClient((IServiceProvider services) => CreateInnerChatClient(services, builder, deploymentName));
16+
}
17+
private static IChatClient CreateInnerChatClient(IServiceProvider services, AspireOpenAIClientBuilder builder, string? deploymentName)
18+
{
19+
OpenAIClient openAIClient = builder.ServiceKey is null ? services.GetRequiredService<OpenAIClient>() : services.GetRequiredKeyedService<OpenAIClient>(builder.ServiceKey);
20+
21+
if (deploymentName is null)
22+
{
23+
deploymentName = "gpt-4o-mini";
24+
}
25+
26+
IChatClient chatClient = openAIClient.GetOpenAIResponseClient(deploymentName).AsIChatClient();
27+
28+
if (builder.DisableTracing)
29+
{
30+
return chatClient;
31+
}
32+
33+
var loggerFactory = services.GetService<ILoggerFactory>();
34+
return new OpenTelemetryChatClient(chatClient, loggerFactory?.CreateLogger(typeof(OpenTelemetryChatClient)));
35+
}
36+
}

test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb.AzureOpenAI_Qdrant_Aspire.verified/aichatweb/aichatweb.Web/Components/Pages/Chat/Chat.razor

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,11 @@
6666
var responseText = new TextContent("");
6767
currentResponseMessage = new ChatMessage(ChatRole.Assistant, [responseText]);
6868
currentResponseCancellation = new();
69-
await foreach (var update in ChatClient.GetStreamingResponseAsync([.. messages], chatOptions, currentResponseCancellation.Token))
69+
await foreach (var update in ChatClient.GetStreamingResponseAsync([userMessage], chatOptions, currentResponseCancellation.Token))
7070
{
7171
messages.AddMessages(update, filter: c => c is not TextContent);
7272
responseText.Text += update.Text;
73+
chatOptions.ConversationId = update.ConversationId; //Update conversation ID from current response
7374
ChatMessageItem.NotifyChanged(currentResponseMessage);
7475
}
7576

@@ -96,6 +97,7 @@
9697
CancelAnyCurrentResponse();
9798
messages.Clear();
9899
messages.Add(new(ChatRole.System, SystemPrompt));
100+
chatOptions.ConversationId = null;
99101
chatSuggestions?.Clear();
100102
await chatInput!.FocusAsync();
101103
}

test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb.AzureOpenAI_Qdrant_Aspire.verified/aichatweb/aichatweb.Web/Program.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
using aichatweb.Web.Services.Ingestion;
55

66
var builder = WebApplication.CreateBuilder(args);
7+
78
builder.AddServiceDefaults();
89
builder.Services.AddRazorComponents().AddInteractiveServerComponents();
910

1011
var openai = builder.AddAzureOpenAIClient("openai");
11-
openai.AddChatClient("gpt-4o-mini")
12+
openai.AddResponsesChatClient("gpt-4o-mini")
1213
.UseFunctionInvocation()
1314
.UseOpenTelemetry(configure: c =>
1415
c.EnableSensitiveData = builder.Environment.IsDevelopment());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using Microsoft.Extensions.AI;
2+
using Aspire.OpenAI;
3+
using OpenAI;
4+
5+
//namespace chat.aspire.Web;
6+
namespace Microsoft.Extensions.Hosting;
7+
8+
public static class ResponseClientHelper
9+
{
10+
11+
public static ChatClientBuilder AddResponsesChatClient(this AspireOpenAIClientBuilder builder, string? deploymentName)
12+
{
13+
ArgumentNullException.ThrowIfNull(builder, "builder");
14+
15+
return builder.HostBuilder.Services.AddChatClient((IServiceProvider services) => CreateInnerChatClient(services, builder, deploymentName));
16+
}
17+
private static IChatClient CreateInnerChatClient(IServiceProvider services, AspireOpenAIClientBuilder builder, string? deploymentName)
18+
{
19+
OpenAIClient openAIClient = builder.ServiceKey is null ? services.GetRequiredService<OpenAIClient>() : services.GetRequiredKeyedService<OpenAIClient>(builder.ServiceKey);
20+
21+
if (deploymentName is null)
22+
{
23+
deploymentName = "gpt-4o-mini";
24+
}
25+
26+
IChatClient chatClient = openAIClient.GetOpenAIResponseClient(deploymentName).AsIChatClient();
27+
28+
if (builder.DisableTracing)
29+
{
30+
return chatClient;
31+
}
32+
33+
var loggerFactory = services.GetService<ILoggerFactory>();
34+
return new OpenTelemetryChatClient(chatClient, loggerFactory?.CreateLogger(typeof(OpenTelemetryChatClient)));
35+
}
36+
}

test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb.AzureOpenAI_Qdrant_Aspire.verified/aichatweb/aichatweb.Web/aichatweb.Web.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<Nullable>enable</Nullable>
66
<ImplicitUsings>enable</ImplicitUsings>
77
<UserSecretsId>secret</UserSecretsId>
8+
<NoWarn>OPENAI001</NoWarn>
89
</PropertyGroup>
910

1011
<ItemGroup>

0 commit comments

Comments
 (0)