-
Notifications
You must be signed in to change notification settings - Fork 80
Create Python ChatApp example for AI configuration #1065
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
Merged
Changes from all commits
Commits
Show all changes
36 commits
Select commit
Hold shift + click to select a range
68fc507
Initial plan for issue
Copilot 0c6960e
Create Python ChatApp example for AI configuration
Copilot caf9cd0
Convert Flask web app to console app
Copilot e19bc99
Update azure-appconfiguration-provider to version 2.1.0
Copilot 5d8b373
Address review feedback for Python ChatApp example
Copilot 6466ad8
Implement data binding for Python ChatApp configuration
Copilot d377f84
Implement data binding without Pydantic dependency for Python ChatApp
Copilot 4cfe6d2
Update Python ChatApp README.md based on review feedback
Copilot f36d608
Read API version from App Configuration
Copilot da033f9
Update ChatApp:Model description to specify JSON object with AI chat …
Copilot bf6b106
Read API key from App Configuration with Key Vault reference support
Copilot 97c5be0
Revert ChatApp:Model description to focus on AI configuration
Copilot e2fd91f
Address reviewers' feedback on Python ChatApp example
Copilot 7325b6f
Add Key Vault credential for loading API key from Key Vault references
Copilot e3daa4d
Fix credential parameter name from key_vault_credential to keyvault_c…
Copilot c2c1e17
Fixing
mrm9084 907227e
Fixing auth
mrm9084 00136bd
Add user input chat functionality to Python ChatApp
Copilot 433030d
Updated to use black formating
mrm9084 3a0f7fe
Fixing a few pylint issues
mrm9084 334fb2c
Update examples/Python/ChatApp/app.py
mrm9084 5064f99
Updated to match dotnet
mrm9084 2afb137
review items
mrm9084 20e9d6d
review changes
mrm9084 b8e8a55
review comments
mrm9084 18fbda0
Update app.py
mrm9084 320a372
rework to remove global need
mrm9084 5fa4fff
code cleanup
mrm9084 0b34fc7
fixed formatting
mrm9084 e573db5
moved deployment type to AzureOpenAI
mrm9084 3ef2148
Update models.py
mrm9084 6cf8451
formatting
mrm9084 295c876
review changes
mrm9084 24aecfb
refresh update
mrm9084 d3cf9c5
review comments
mrm9084 c21857c
review comments
mrm9084 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,69 @@ | ||
| # Azure App Configuration - Python ChatApp Sample | ||
|
|
||
| This sample demonstrates using Azure App Configuration to configure Azure OpenAI settings for a chat application built with Python. | ||
|
|
||
| ## Features | ||
|
|
||
| - Integrates with Azure OpenAI for chat completions | ||
| - Dynamically refreshes configuration from Azure App Configuration | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - Python 3.8 or later | ||
| - An Azure subscription with access to: | ||
| - Azure App Configuration service | ||
| - Azure OpenAI service | ||
| - Required environment variables: | ||
| - `AZURE_APPCONFIGURATION_ENDPOINT`: Endpoint URL of your Azure App Configuration instance | ||
| - `AZURE_OPENAI_API_KEY`: API key for Azure OpenAI (optional if stored in Azure App Configuration) | ||
|
|
||
| ## Setup | ||
|
|
||
| 1. Clone the repository | ||
| 1. Install the required packages: | ||
|
|
||
| ```bash | ||
| pip install -r requirements.txt | ||
| ``` | ||
|
|
||
| 1. Configure your Azure App Configuration store with these settings: | ||
|
|
||
| ```console | ||
| ChatApp:AzureOpenAI:Endpoint - Your Azure OpenAI endpoint URL | ||
| ChatApp:AzureOpenAI:DeploymentName - Your Azure OpenAI deployment name | ||
| ChatApp:AzureOpenAI:ApiVersion - API version for Azure OpenAI (e.g., "2023-05-15") | ||
| ChatApp:AzureOpenAI:ApiKey - Your Azure OpenAI API key (Optional only required when not using AAD, preferably as a Key Vault reference) | ||
| ChatApp:Model - An AI configuration entry containing the following settings: | ||
| - model - Model name (e.g., "gpt-35-turbo") | ||
| - 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 | ||
| ChatApp:Sentinel - A sentinel key to trigger configuration refreshes | ||
| ``` | ||
|
|
||
| 1. Set the required environment variables: | ||
|
|
||
| ```bash | ||
| export AZURE_APPCONFIGURATION_ENDPOINT="https://your-appconfig.azconfig.io" | ||
| export AZURE_OPENAI_API_KEY="your-openai-api-key" # Optional if stored in Azure App Configuration | ||
| ``` | ||
|
|
||
| ## Running the Application | ||
|
|
||
| Start the console application: | ||
|
|
||
| ```bash | ||
| python app.py | ||
| ``` | ||
|
|
||
| The application will: | ||
|
|
||
| 1. Display the initial configured messages from Azure App Configuration | ||
| 2. Generate a response from the AI | ||
| 3. Prompt you to enter your message (Just select enter to quit) | ||
| 4. Maintain conversation history during the session | ||
|
|
||
| ## Configuration Refresh | ||
|
|
||
| The application refreshes the configuration at the beginning of each conversation cycle, so any changes made to the base configuration in Azure App Configuration will be incorporated into the model parameters (temperature, max_tokens, etc.) while maintaining your ongoing conversation history. Updating the configuration in Azure App Configuration will automatically reflect in the application without requiring a restart, once the `ChatApp:Sentinel` key is updated. | ||
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,123 @@ | ||
| # ------------------------------------------------------------------------- | ||
| # Copyright (c) Microsoft Corporation. All rights reserved. | ||
| # Licensed under the MIT License. See License.txt in the project root for | ||
| # license information. | ||
| # -------------------------------------------------------------------------- | ||
| """ | ||
| Azure OpenAI Chat Application using Azure App Configuration. | ||
| This script demonstrates how to create a chat application that uses Azure App Configuration | ||
| to manage settings and Azure OpenAI to power chat interactions. | ||
| """ | ||
|
|
||
| import os | ||
| from azure.identity import DefaultAzureCredential, get_bearer_token_provider | ||
| from azure.appconfiguration.provider import load, SettingSelector, WatchKey | ||
| from openai import AzureOpenAI | ||
| from models import AzureOpenAIConfiguration, ChatCompletionConfiguration | ||
|
|
||
| APP_CONFIG_ENDPOINT_KEY = "AZURE_APPCONFIGURATION_ENDPOINT" | ||
|
|
||
|
|
||
| # Initialize CREDENTIAL | ||
| CREDENTIAL = DefaultAzureCredential() | ||
|
|
||
| APPCONFIG = None | ||
mrm9084 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| CHAT_COMPLETION_CONFIG = None | ||
|
|
||
|
|
||
| def main(): | ||
| global APPCONFIG | ||
| app_config_endpoint = os.environ.get(APP_CONFIG_ENDPOINT_KEY) | ||
| if not app_config_endpoint: | ||
| raise ValueError(f"The environment variable '{APP_CONFIG_ENDPOINT_KEY}' is not set or is empty.") | ||
|
|
||
| # Load configuration | ||
| APPCONFIG = load( | ||
| endpoint=app_config_endpoint, | ||
| selects=[SettingSelector(key_filter="ChatApp:*")], | ||
| credential=CREDENTIAL, | ||
| keyvault_credential=CREDENTIAL, | ||
| trim_prefixes=["ChatApp:"], | ||
| refresh_on=[WatchKey(key="ChatApp:Sentinel")], | ||
| on_refresh_success=configure_app, | ||
| ) | ||
| configure_app() | ||
|
|
||
| azure_openai_config = AzureOpenAIConfiguration( | ||
| api_key=APPCONFIG.get("AzureOpenAI:ApiKey", ""), | ||
| endpoint=APPCONFIG.get("AzureOpenAI:Endpoint", ""), | ||
| deployment_name=APPCONFIG.get("AzureOpenAI:DeploymentName", ""), | ||
| api_version=APPCONFIG.get("AzureOpenAI:ApiVersion", ""), | ||
| ) | ||
| azure_client = create_azure_openai_client(azure_openai_config) | ||
|
|
||
| chat_conversation = [] | ||
|
|
||
| print("Chat started! What's on your mind?") | ||
|
|
||
| while True: | ||
| # Refresh the configuration from Azure App Configuration | ||
| APPCONFIG.refresh() | ||
|
|
||
| # Get user input | ||
| user_input = input("You: ") | ||
|
|
||
| # Exit if user input is empty | ||
| if not user_input.strip(): | ||
| print("Exiting chat. Goodbye!") | ||
| break | ||
|
|
||
mrm9084 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| # Add user message to chat conversation | ||
| chat_conversation.append({"role": "user", "content": user_input}) | ||
|
|
||
| chat_messages = list(CHAT_COMPLETION_CONFIG.messages) | ||
| chat_messages.extend(chat_conversation) | ||
|
|
||
| # Get AI response and add it to chat conversation | ||
| response = azure_client.chat.completions.create( | ||
| model=azure_openai_config.deployment_name, | ||
mrm9084 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| messages=chat_messages, | ||
| max_tokens=CHAT_COMPLETION_CONFIG.max_tokens, | ||
| temperature=CHAT_COMPLETION_CONFIG.temperature, | ||
| top_p=CHAT_COMPLETION_CONFIG.top_p, | ||
| ) | ||
mrm9084 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| ai_response = response.choices[0].message.content | ||
| chat_conversation .append({"role": "assistant", "content": ai_response}) | ||
| print(f"AI: {ai_response}") | ||
|
|
||
|
|
||
| def configure_app(): | ||
| """ | ||
| Configure the chat application with settings from Azure App Configuration. | ||
| """ | ||
| global CHAT_COMPLETION_CONFIG | ||
| # Configure chat completion with AI configuration | ||
| CHAT_COMPLETION_CONFIG = ChatCompletionConfiguration(**APPCONFIG["ChatCompletion"]) | ||
|
|
||
|
|
||
| def create_azure_openai_client(azure_openai_config: AzureOpenAIConfiguration) -> AzureOpenAI: | ||
| """ | ||
| Create an Azure OpenAI client using the configuration from Azure App Configuration. | ||
| """ | ||
| if azure_openai_config.api_key: | ||
| return AzureOpenAI( | ||
| azure_endpoint=azure_openai_config.endpoint, | ||
| api_key=azure_openai_config.api_key, | ||
| api_version=azure_openai_config.api_version, | ||
| azure_deployment=azure_openai_config.deployment_name, | ||
| ) | ||
| else: | ||
| return AzureOpenAI( | ||
| azure_endpoint=azure_openai_config.endpoint, | ||
| azure_ad_token_provider=get_bearer_token_provider( | ||
| CREDENTIAL, | ||
| "https://cognitiveservices.azure.com/.default", | ||
| ), | ||
| api_version=azure_openai_config.api_version, | ||
| azure_deployment=azure_openai_config.deployment_name, | ||
| ) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() | ||
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,35 @@ | ||
| # ------------------------------------------------------------------------- | ||
| # Copyright (c) Microsoft Corporation. All rights reserved. | ||
| # Licensed under the MIT License. See License.txt in the project root for | ||
| # license information. | ||
| # -------------------------------------------------------------------------- | ||
| """ | ||
| Model classes for Azure OpenAI Chat Application. | ||
| """ | ||
| from dataclasses import dataclass | ||
| from typing import List, Optional, Dict | ||
|
|
||
|
|
||
mrm9084 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| @dataclass | ||
| class AzureOpenAIConfiguration: | ||
| """ | ||
| Represents the configuration for Azure OpenAI service. | ||
| """ | ||
|
|
||
| api_key: str | ||
| endpoint: str | ||
| deployment_name: str | ||
| api_version: Optional[str] = None | ||
|
|
||
|
|
||
| @dataclass | ||
| class ChatCompletionConfiguration: | ||
| """ | ||
| Represents the configuration for an AI model including messages and parameters. | ||
mrm9084 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| """ | ||
|
|
||
| max_tokens: int | ||
| temperature: float | ||
| top_p: float | ||
| model: Optional[str] = None | ||
| messages: Optional[List[Dict[str, str]]] = None | ||
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,8 @@ | ||
| [tool.black] | ||
| line-length = 120 | ||
| target-version = ['py38'] | ||
| include = '\.pyi?$' | ||
|
|
||
| [tool.pylint.format] | ||
| max-line-length = 120 | ||
|
|
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,3 @@ | ||
| azure-identity | ||
| azure-appconfiguration-provider | ||
| openai |
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,4 @@ | ||
| [tool.black] | ||
| line-length = 120 | ||
| target-version = ['py38'] | ||
| include = '\.pyi?$' |
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.