-
Notifications
You must be signed in to change notification settings - Fork 77
Add Go chat app sample #1078
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
Merged
linglingye001
merged 6 commits into
Azure:main
from
linglingye001:linglingye/go/chatapp
Sep 23, 2025
Merged
Add Go chat app sample #1078
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
a00203c
add Go chat app sample
linglingye001 f066f1b
update
linglingye001 2ba30f6
update
linglingye001 1f9601d
update
linglingye001 640784c
simiplify code
linglingye001 833cfd3
default refresh interval for key values
linglingye001 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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,92 @@ | ||
| # Azure App Configuration - Go ChatApp Sample | ||
|
|
||
| An interactive console chat application that integrates with Azure OpenAI services using Azure App Configuration for dynamic AI Configuration management. | ||
|
|
||
| ## Overview | ||
|
|
||
| This Go console application provides a seamless chat experience with Azure OpenAI, featuring: | ||
|
|
||
| - Integration with Azure OpenAI for chat completions | ||
| - Dynamic AI configuration refresh from Azure App Configuration | ||
| - Secure authentication options using API key or Microsoft Entra ID | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - Go 1.23 or later | ||
| - Azure subscription | ||
| - Azure OpenAI service instance | ||
| - Azure App Configuration service instance | ||
|
|
||
| ## Setup | ||
|
|
||
| ### Environment Variables | ||
|
|
||
| Set the following environment variable: | ||
|
|
||
| - `AZURE_APPCONFIGURATION_ENDPOINT`: Endpoint URL of your Azure App Configuration instance | ||
|
|
||
| ### Azure App Configuration Keys | ||
|
|
||
| Configure the following keys in your Azure App Configuration: | ||
|
|
||
| #### Azure OpenAI Connection Settings | ||
|
|
||
| - `ChatApp:AzureOpenAI:Endpoint` - Your Azure OpenAI endpoint URL | ||
| - `ChatApp:AzureOpenAI:APIVersion` - the Azure OpenAI API version to target. See [Azure OpenAI apiversions](https://learn.microsoft.com/en-us/azure/ai-services/openai/reference#rest-api-versioning) for current API versions. | ||
| - `ChatApp:AzureOpenAI:ApiKey` - Key Vault reference to the API key for Azure OpenAI (optional) | ||
|
|
||
| #### Chat Completion Configuration | ||
|
|
||
| - `ChatApp:ChatCompletion` - An AI Configuration for chat completion containing the following settings: | ||
| - `model` - Model name (e.g., "gpt-4o") | ||
| - `max_tokens` - Maximum tokens for completion (e.g., 1000) | ||
| - `temperature` - Temperature parameter (e.g., 0.7) | ||
| - `top_p` - Top p parameter (e.g., 0.95) | ||
| - `messages` - An array of messages with role and content for each message | ||
|
|
||
| ## Authentication | ||
|
|
||
| The application supports the following authentication methods: | ||
|
|
||
| - **Azure App Configuration**: Uses `DefaultAzureCredential` for authentication via Microsoft Entra ID. | ||
| - **Azure OpenAI**: Supports authentication using either an API key or `DefaultAzureCredential` via Microsoft Entra ID. | ||
| - **Azure Key Vault** *(optional, if using Key Vault references for API keys)*: Authenticates using `DefaultAzureCredential` via Microsoft Entra ID. | ||
|
|
||
| ## Usage | ||
|
|
||
| 1. **Initialize a new Go module**: `go mod init chatapp-quickstart` | ||
| 1. **Install dependencies**: `go mod tidy` | ||
| 1. **Start the Application**: Run the application using `go run main.go` | ||
| 1. **Begin Chatting**: Type your messages when prompted with "You: " | ||
| 1. **Continue Conversation**: The AI will respond and maintain conversation context | ||
| 1. **Exit**: Press Enter without typing a message to exit gracefully | ||
|
|
||
| ### Example Session | ||
| ``` | ||
| Chat started! What's on your mind? | ||
| You: Hello, how are you? | ||
| AI: Hello! I'm doing well, thank you for asking. How can I help you today? | ||
|
|
||
| You: What can you tell me about machine learning? | ||
| AI: Machine learning is a subset of artificial intelligence that focuses on... | ||
|
|
||
| You: [Press Enter to exit] | ||
| Exiting chat. Goodbye! | ||
| ``` | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| **"AZURE_APPCONFIGURATION_ENDPOINT environment variable not set"** | ||
| - Ensure the environment variable is properly set | ||
| - Verify the endpoint URL is correct | ||
|
|
||
| **Authentication Failures** | ||
| - Ensure you have the `App Configuration Data Reader` role on the Azure App Configuration instance | ||
| - For Microsoft Entra ID authentication: Verify you have the `Cognitive Services OpenAI User` role on the Azure OpenAI instance | ||
| - For API key authentication: | ||
| - Confirm you have secret read access to the Key Vault storing the API key | ||
| - Verify that a Key Vault reference for the API key is properly configured in Azure App Configuration | ||
|
|
||
| **No AI Response** | ||
| - Verify deployment name matches your Azure OpenAI deployment | ||
| - Check token limits and quotas |
This file contains hidden or 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,160 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "bufio" | ||
| "context" | ||
| "fmt" | ||
| "log" | ||
| "os" | ||
|
|
||
| "github.com/Azure/AppConfiguration-GoProvider/azureappconfiguration" | ||
| "github.com/Azure/azure-sdk-for-go/sdk/azidentity" | ||
| openai "github.com/openai/openai-go" | ||
| "github.com/openai/openai-go/azure" | ||
| ) | ||
|
|
||
| type AIConfig struct { | ||
| ChatCompletion ChatCompletion | ||
| AzureOpenAI AzureOpenAI | ||
| } | ||
|
|
||
| type ChatCompletion struct { | ||
| Model string `json:"model"` | ||
| Messages []Message `json:"messages"` | ||
| MaxTokens int64 `json:"max_tokens"` | ||
| Temperature float64 `json:"temperature"` | ||
| TopP float64 `json:"top_p"` | ||
| } | ||
|
|
||
| type AzureOpenAI struct { | ||
| Endpoint string | ||
| APIVersion string | ||
| APIKey string | ||
| } | ||
|
|
||
| type Message struct { | ||
| Role string `json:"role"` | ||
| Content string `json:"content"` | ||
| } | ||
|
|
||
| var aiConfig AIConfig | ||
| var tokenCredential, _ = azidentity.NewDefaultAzureCredential(nil) | ||
|
|
||
| func main() { | ||
| configProvider, err := loadAzureAppConfiguration(context.Background()) | ||
| if err != nil { | ||
| log.Fatal("Error loading Azure App Configuration:", err) | ||
| } | ||
|
|
||
| // Configure chat completion with AI configuration | ||
| configProvider.Unmarshal(&aiConfig, &azureappconfiguration.ConstructionOptions{Separator: ":"}) | ||
|
|
||
| // Register a callback to refresh AI configuration on changes | ||
| configProvider.OnRefreshSuccess(func() { | ||
| configProvider.Unmarshal(&aiConfig, &azureappconfiguration.ConstructionOptions{Separator: ":"}) | ||
| }) | ||
|
|
||
| // Create a chat client using API key if available, otherwise use the DefaultAzureCredential | ||
| var openAIClient openai.Client | ||
| if aiConfig.AzureOpenAI.APIKey != "" { | ||
| openAIClient = openai.NewClient(azure.WithAPIKey(aiConfig.AzureOpenAI.APIKey), azure.WithEndpoint(aiConfig.AzureOpenAI.Endpoint, aiConfig.AzureOpenAI.APIVersion)) | ||
| } else { | ||
| openAIClient = openai.NewClient(azure.WithEndpoint(aiConfig.AzureOpenAI.Endpoint, aiConfig.AzureOpenAI.APIVersion), azure.WithTokenCredential(tokenCredential)) | ||
| } | ||
|
|
||
| // Initialize chat conversation | ||
| var chatConversation []openai.ChatCompletionMessageParamUnion | ||
| fmt.Println("Chat started! What's on your mind?") | ||
| reader := bufio.NewReader(os.Stdin) | ||
|
|
||
| for { | ||
| // Refresh the configuration from Azure App Configuration | ||
| configProvider.Refresh(context.Background()) | ||
|
|
||
| // Get user input | ||
| fmt.Print("You: ") | ||
| userInput, _ := reader.ReadString('\n') | ||
|
|
||
| // Exit if user input is empty | ||
| if userInput == "" { | ||
| fmt.Println("Exiting Chat. Goodbye!") | ||
| break | ||
| } | ||
|
|
||
| // Add user message to chat conversation | ||
| chatConversation = append(chatConversation, openai.UserMessage(userInput)) | ||
|
|
||
| // Get AI response and add it to chat conversation | ||
| response, _ := getAIResponse(openAIClient, chatConversation) | ||
| fmt.Printf("AI: %s\n", response) | ||
| chatConversation = append(chatConversation, openai.AssistantMessage(response)) | ||
|
|
||
| fmt.Println() | ||
| } | ||
| } | ||
|
|
||
| // Load configuration from Azure App Configuration | ||
| func loadAzureAppConfiguration(ctx context.Context) (*azureappconfiguration.AzureAppConfiguration, error) { | ||
| endpoint := os.Getenv("AZURE_APPCONFIGURATION_ENDPOINT") | ||
| if endpoint == "" { | ||
| return nil, fmt.Errorf("AZURE_APPCONFIGURATION_ENDPOINT environment variable is not set") | ||
| } | ||
|
|
||
| authOptions := azureappconfiguration.AuthenticationOptions{ | ||
| Endpoint: endpoint, | ||
| Credential: tokenCredential, | ||
| } | ||
|
|
||
| options := &azureappconfiguration.Options{ | ||
| Selectors: []azureappconfiguration.Selector{ | ||
| // Load all keys that start with "ChatApp:" and have no label | ||
| { | ||
| KeyFilter: "ChatApp:*", | ||
| }, | ||
| }, | ||
| TrimKeyPrefixes: []string{"ChatApp:"}, | ||
| // Reload configuration if any selected key-values have changed. | ||
| // Use the default refresh interval of 30 seconds. It can be overridden via RefreshOptions.Interval | ||
| RefreshOptions: azureappconfiguration.KeyValueRefreshOptions{ | ||
| Enabled: true, | ||
| }, | ||
linglingye001 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| KeyVaultOptions: azureappconfiguration.KeyVaultOptions{ | ||
| Credential: tokenCredential, | ||
| }, | ||
| } | ||
|
|
||
| return azureappconfiguration.Load(ctx, authOptions, options) | ||
| } | ||
|
|
||
| func getAIResponse(openAIClient openai.Client, chatConversation []openai.ChatCompletionMessageParamUnion) (string, error) { | ||
| var completionMessages []openai.ChatCompletionMessageParamUnion | ||
|
|
||
| for _, msg := range aiConfig.ChatCompletion.Messages { | ||
| switch msg.Role { | ||
linglingye001 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| case "system": | ||
| completionMessages = append(completionMessages, openai.SystemMessage(msg.Content)) | ||
| case "user": | ||
| completionMessages = append(completionMessages, openai.UserMessage(msg.Content)) | ||
| case "assistant": | ||
| completionMessages = append(completionMessages, openai.AssistantMessage(msg.Content)) | ||
| } | ||
| } | ||
|
|
||
| // Add the chat conversation history | ||
| completionMessages = append(completionMessages, chatConversation...) | ||
|
|
||
| // Create chat completion parameters | ||
| params := openai.ChatCompletionNewParams{ | ||
| Messages: completionMessages, | ||
| Model: aiConfig.ChatCompletion.Model, | ||
| MaxTokens: openai.Int(aiConfig.ChatCompletion.MaxTokens), | ||
| Temperature: openai.Float(aiConfig.ChatCompletion.Temperature), | ||
| TopP: openai.Float(aiConfig.ChatCompletion.TopP), | ||
| } | ||
|
|
||
| if completion, err := openAIClient.Chat.Completions.New(context.Background(), params); err != nil { | ||
| return "", err | ||
| } else { | ||
| return completion.Choices[0].Message.Content, nil | ||
| } | ||
| } | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.