Skip to content

Commit 59bdf8f

Browse files
authored
Update the .NET ChatApp sample (#1075)
1 parent 151fd1f commit 59bdf8f

4 files changed

Lines changed: 157 additions & 21 deletions

File tree

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT license.
3+
//
4+
5+
namespace ChatApp
6+
{
7+
internal class AzureOpenAIConfiguration
8+
{
9+
public required string Endpoint { get; set; }
10+
11+
public required string DeploymentName { get; set; }
12+
13+
public string? ApiKey { get; set; }
14+
}
15+
}

examples/DotNetCore/ChatApp/ChatApp/ModelConfiguration.cs renamed to examples/DotNetCore/ChatApp/ChatApp/ChatCompletionConfiguration.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
namespace ChatApp
77
{
8-
internal class ModelConfiguration
8+
internal class ChatCompletionConfiguration
99
{
1010
[ConfigurationKeyName("model")]
1111
public string? Model { get; set; }

examples/DotNetCore/ChatApp/ChatApp/Program.cs

Lines changed: 51 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT license.
33
//
4+
45
using Azure.AI.OpenAI;
56
using Azure.Core;
67
using Azure.Identity;
@@ -16,8 +17,8 @@
1617
IConfiguration configuration = new ConfigurationBuilder()
1718
.AddAzureAppConfiguration(options =>
1819
{
19-
Uri endpoint = new(Environment.GetEnvironmentVariable("AZURE_APPCONFIG_ENDPOINT") ??
20-
throw new InvalidOperationException("The environment variable 'AZURE_APPCONFIG_ENDPOINT' is not set or is empty."));
20+
Uri endpoint = new(Environment.GetEnvironmentVariable("AZURE_APPCONFIGURATION_ENDPOINT") ??
21+
throw new InvalidOperationException("The environment variable 'AZURE_APPCONFIGURATION_ENDPOINT' is not set or is empty."));
2122
options.Connect(endpoint, credential)
2223
// Load all keys that start with "ChatApp:" and have no label.
2324
.Select("ChatApp:*")
@@ -26,50 +27,80 @@
2627
.ConfigureRefresh(refreshOptions =>
2728
{
2829
refreshOptions.RegisterAll();
30+
})
31+
.ConfigureKeyVault(keyVaultOptions =>
32+
{
33+
// Use the DefaultAzureCredential to access Key Vault secrets.
34+
keyVaultOptions.SetCredential(credential);
2935
});
3036

3137
refresher = options.GetRefresher();
3238
})
3339
.Build();
3440

3541
// Retrieve the OpenAI connection information from the configuration
36-
Uri openaiEndpoint = new (configuration["ChatApp:AzureOpenAI:Endpoint"]);
37-
string deploymentName = configuration["ChatApp:AzureOpenAI:DeploymentName"];
42+
var azureOpenAIConfiguration = configuration.GetSection("ChatApp:AzureOpenAI").Get<AzureOpenAIConfiguration>();
3843

39-
// Create a chat client
40-
AzureOpenAIClient azureClient = new(openaiEndpoint, credential);
41-
ChatClient chatClient = azureClient.GetChatClient(deploymentName);
44+
// Create a chat client using API key if available, otherwise use the DefaultAzureCredential
45+
AzureOpenAIClient azureClient;
46+
if (!string.IsNullOrEmpty(azureOpenAIConfiguration.ApiKey))
47+
{
48+
azureClient = new AzureOpenAIClient(new Uri(azureOpenAIConfiguration.Endpoint), new Azure.AzureKeyCredential(azureOpenAIConfiguration.ApiKey));
49+
}
50+
else
51+
{
52+
azureClient = new AzureOpenAIClient(new Uri(azureOpenAIConfiguration.Endpoint), credential);
53+
}
54+
ChatClient chatClient = azureClient.GetChatClient(azureOpenAIConfiguration.DeploymentName);
4255

56+
// Initialize chat conversation
57+
var chatConversation = new List<ChatMessage>();
58+
Console.WriteLine("Chat started! What's on your mind?");
4359
while (true)
4460
{
4561
// Refresh the configuration from Azure App Configuration
4662
await refresher.TryRefreshAsync();
4763

4864
// Configure chat completion with AI configuration
49-
var modelConfiguration = configuration.GetSection("ChatApp:Model").Get<ModelConfiguration>();
65+
var chatCompletionConfiguration = configuration.GetSection("ChatApp:ChatCompletion").Get<ChatCompletionConfiguration>();
5066
var requestOptions = new ChatCompletionOptions()
5167
{
52-
MaxOutputTokenCount = modelConfiguration.MaxTokens,
53-
Temperature = modelConfiguration.Temperature,
54-
TopP = modelConfiguration.TopP
68+
MaxOutputTokenCount = chatCompletionConfiguration.MaxTokens,
69+
Temperature = chatCompletionConfiguration.Temperature,
70+
TopP = chatCompletionConfiguration.TopP
5571
};
5672

57-
foreach (var message in modelConfiguration.Messages)
73+
// Get user input
74+
Console.Write("You: ");
75+
string? userInput = Console.ReadLine();
76+
77+
// Exit if user input is empty
78+
if (string.IsNullOrEmpty(userInput))
5879
{
59-
Console.WriteLine($"{message.Role}: {message.Content}");
80+
Console.WriteLine("Exiting chat. Goodbye!");
81+
break;
6082
}
6183

62-
// Get chat response from AI
63-
var response = await chatClient.CompleteChatAsync(GetChatMessages(modelConfiguration), requestOptions);
64-
System.Console.WriteLine($"AI response: {response.Value.Content[0].Text}");
84+
// Add user message to chat conversation
85+
chatConversation.Add(ChatMessage.CreateUserMessage(userInput));
86+
87+
// Get latest system message from AI configuration
88+
var chatMessages = new List<ChatMessage>(GetChatMessages(chatCompletionConfiguration));
89+
chatMessages.AddRange(chatConversation);
90+
91+
// Get AI response and add it to chat conversation
92+
var response = await chatClient.CompleteChatAsync(chatMessages, requestOptions);
93+
string aiResponse = response.Value.Content[0].Text;
94+
Console.WriteLine($"AI: {aiResponse}");
95+
chatConversation.Add(ChatMessage.CreateAssistantMessage(aiResponse));
6596

66-
Console.WriteLine("Press Enter to continue...");
67-
Console.ReadLine();
97+
Console.WriteLine();
6898
}
6999

70-
static IEnumerable<ChatMessage> GetChatMessages(ModelConfiguration modelConfiguration)
100+
// Helper method to convert configuration messages to ChatMessage objects
101+
static IEnumerable<ChatMessage> GetChatMessages(ChatCompletionConfiguration chatCompletionConfiguration)
71102
{
72-
return modelConfiguration.Messages.Select<Message, ChatMessage>(message => message.Role switch
103+
return chatCompletionConfiguration.Messages.Select<Message, ChatMessage>(message => message.Role switch
73104
{
74105
"system" => ChatMessage.CreateSystemMessage(message.Content),
75106
"user" => ChatMessage.CreateUserMessage(message.Content),
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# Azure App Configuration - .NET ChatApp Sample
2+
3+
An interactive console chat application that integrates with Azure OpenAI services using Azure App Configuration for dynamic AI Configuration management.
4+
5+
## Overview
6+
7+
This .NET console application provides a seamless chat experience with Azure OpenAI, featuring:
8+
9+
- Integration with Azure OpenAI for chat completions
10+
- Dynamic AI configuration refresh from Azure App Configuration
11+
- Secure authentication options using API key or Microsoft Entra ID
12+
13+
## Prerequisites
14+
15+
- .NET 8.0 SDK
16+
- Azure subscription
17+
- Azure OpenAI service instance
18+
- Azure App Configuration service instance
19+
20+
## Setup
21+
22+
### Environment Variables
23+
24+
Set the following environment variable:
25+
26+
- `AZURE_APPCONFIGURATION_ENDPOINT`: Endpoint URL of your Azure App Configuration instance
27+
28+
### Azure App Configuration Keys
29+
30+
Configure the following keys in your Azure App Configuration:
31+
32+
#### Azure OpenAI Connection Settings
33+
34+
- `ChatApp:AzureOpenAI:Endpoint` - Your Azure OpenAI endpoint URL
35+
- `ChatApp:AzureOpenAI:DeploymentName` - Your Azure OpenAI deployment name
36+
- `ChatApp:AzureOpenAI:ApiKey` - Key Vault reference to the API key for Azure OpenAI (optional)
37+
38+
#### Chat Completion Configuration
39+
40+
- `ChatApp:ChatCompletion` - An AI Configuration for chat completion containing the following settings:
41+
- `model` - Model name (e.g., "gpt-4o")
42+
- `max_tokens` - Maximum tokens for completion (e.g., 1000)
43+
- `temperature` - Temperature parameter (e.g., 0.7)
44+
- `top_p` - Top p parameter (e.g., 0.95)
45+
- `messages` - An array of messages with role and content for each message
46+
47+
## Authentication
48+
49+
The application supports the following authentication methods:
50+
51+
- **Azure App Configuration**: Uses `DefaultAzureCredential` for authentication via Microsoft Entra ID.
52+
- **Azure OpenAI**: Supports authentication using either an API key or `DefaultAzureCredential` via Microsoft Entra ID.
53+
- **Azure Key Vault** *(optional, if using Key Vault references for API keys)*: Authenticates using `DefaultAzureCredential` via Microsoft Entra ID.
54+
55+
## Usage
56+
57+
1. **Start the Application**: Run the application using `dotnet run`
58+
2. **Begin Chatting**: Type your messages when prompted with "You: "
59+
3. **Continue Conversation**: The AI will respond and maintain conversation context
60+
4. **Exit**: Press Enter without typing a message to exit gracefully
61+
62+
### Example Session
63+
```
64+
Chat started! What's on your mind?
65+
You: Hello, how are you?
66+
AI: Hello! I'm doing well, thank you for asking. How can I help you today?
67+
68+
You: What can you tell me about machine learning?
69+
AI: Machine learning is a subset of artificial intelligence that focuses on...
70+
71+
You: [Press Enter to exit]
72+
Exiting chat. Goodbye!
73+
```
74+
75+
## Troubleshooting
76+
77+
**"AZURE_APPCONFIGURATION_ENDPOINT environment variable not set"**
78+
- Ensure the environment variable is properly set
79+
- Verify the endpoint URL is correct
80+
81+
**Authentication Failures**
82+
- Ensure you have the `App Configuration Data Reader` role on the Azure App Configuration instance
83+
- For Microsoft Entra ID authentication: Verify you have the `Cognitive Services OpenAI User` role on the Azure OpenAI instance
84+
- For API key authentication:
85+
- Confirm you have secret read access to the Key Vault storing the API key
86+
- Verify that a Key Vault reference for the API key is properly configured in Azure App Configuration
87+
88+
**No AI Response**
89+
- Verify deployment name matches your Azure OpenAI deployment
90+
- Check token limits and quotas

0 commit comments

Comments
 (0)