Skip to content

Commit 3c08331

Browse files
Copilotmrm9084zhenlanCopilot
authored
Create Python ChatApp example for AI configuration (#1065)
* Initial plan for issue * Create Python ChatApp example for AI configuration Co-authored-by: mrm9084 <1054559+mrm9084@users.noreply.github.com> * Convert Flask web app to console app Co-authored-by: mrm9084 <1054559+mrm9084@users.noreply.github.com> * Update azure-appconfiguration-provider to version 2.1.0 Co-authored-by: mrm9084 <1054559+mrm9084@users.noreply.github.com> * Address review feedback for Python ChatApp example Co-authored-by: mrm9084 <1054559+mrm9084@users.noreply.github.com> * Implement data binding for Python ChatApp configuration Co-authored-by: zhenlan <10566826+zhenlan@users.noreply.github.com> * Implement data binding without Pydantic dependency for Python ChatApp Co-authored-by: mrm9084 <1054559+mrm9084@users.noreply.github.com> * Update Python ChatApp README.md based on review feedback Co-authored-by: zhenlan <10566826+zhenlan@users.noreply.github.com> * Read API version from App Configuration Co-authored-by: zhenlan <10566826+zhenlan@users.noreply.github.com> * Update ChatApp:Model description to specify JSON object with AI chat completion MIME profile Co-authored-by: mrm9084 <1054559+mrm9084@users.noreply.github.com> * Read API key from App Configuration with Key Vault reference support Co-authored-by: zhenlan <10566826+zhenlan@users.noreply.github.com> * Revert ChatApp:Model description to focus on AI configuration Co-authored-by: zhenlan <10566826+zhenlan@users.noreply.github.com> * Address reviewers' feedback on Python ChatApp example Co-authored-by: mrm9084 <1054559+mrm9084@users.noreply.github.com> * Add Key Vault credential for loading API key from Key Vault references Co-authored-by: mrm9084 <1054559+mrm9084@users.noreply.github.com> * Fix credential parameter name from key_vault_credential to keyvault_credential Co-authored-by: mrm9084 <1054559+mrm9084@users.noreply.github.com> * Fixing * Fixing auth * Add user input chat functionality to Python ChatApp Co-authored-by: mrm9084 <1054559+mrm9084@users.noreply.github.com> * Updated to use black formating * Fixing a few pylint issues * Update examples/Python/ChatApp/app.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Updated to match dotnet * review items * review changes * review comments * Update app.py * rework to remove global need * code cleanup * fixed formatting * moved deployment type to AzureOpenAI * Update models.py * formatting * review changes * refresh update * review comments * review comments --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: mrm9084 <1054559+mrm9084@users.noreply.github.com> Co-authored-by: zhenlan <10566826+zhenlan@users.noreply.github.com> Co-authored-by: Matt Metcalf <mrm9084@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 466d33e commit 3c08331

6 files changed

Lines changed: 242 additions & 0 deletions

File tree

examples/Python/ChatApp/README.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Azure App Configuration - Python ChatApp Sample
2+
3+
This sample demonstrates using Azure App Configuration to configure Azure OpenAI settings for a chat application built with Python.
4+
5+
## Features
6+
7+
- Integrates with Azure OpenAI for chat completions
8+
- Dynamically refreshes configuration from Azure App Configuration
9+
10+
## Prerequisites
11+
12+
- Python 3.8 or later
13+
- An Azure subscription with access to:
14+
- Azure App Configuration service
15+
- Azure OpenAI service
16+
- Required environment variables:
17+
- `AZURE_APPCONFIGURATION_ENDPOINT`: Endpoint URL of your Azure App Configuration instance
18+
- `AZURE_OPENAI_API_KEY`: API key for Azure OpenAI (optional if stored in Azure App Configuration)
19+
20+
## Setup
21+
22+
1. Clone the repository
23+
1. Install the required packages:
24+
25+
```bash
26+
pip install -r requirements.txt
27+
```
28+
29+
1. Configure your Azure App Configuration store with these settings:
30+
31+
```console
32+
ChatApp:AzureOpenAI:Endpoint - Your Azure OpenAI endpoint URL
33+
ChatApp:AzureOpenAI:DeploymentName - Your Azure OpenAI deployment name
34+
ChatApp:AzureOpenAI:ApiVersion - API version for Azure OpenAI (e.g., "2023-05-15")
35+
ChatApp:AzureOpenAI:ApiKey - Your Azure OpenAI API key (Optional only required when not using AAD, preferably as a Key Vault reference)
36+
ChatApp:Model - An AI configuration entry containing the following settings:
37+
- model - Model name (e.g., "gpt-35-turbo")
38+
- max_tokens - Maximum tokens for completion (e.g., 1000)
39+
- temperature - Temperature parameter (e.g., 0.7)
40+
- top_p - Top p parameter (e.g., 0.95)
41+
- messages - An array of messages with role and content for each message
42+
ChatApp:Sentinel - A sentinel key to trigger configuration refreshes
43+
```
44+
45+
1. Set the required environment variables:
46+
47+
```bash
48+
export AZURE_APPCONFIGURATION_ENDPOINT="https://your-appconfig.azconfig.io"
49+
export AZURE_OPENAI_API_KEY="your-openai-api-key" # Optional if stored in Azure App Configuration
50+
```
51+
52+
## Running the Application
53+
54+
Start the console application:
55+
56+
```bash
57+
python app.py
58+
```
59+
60+
The application will:
61+
62+
1. Display the initial configured messages from Azure App Configuration
63+
2. Generate a response from the AI
64+
3. Prompt you to enter your message (Just select enter to quit)
65+
4. Maintain conversation history during the session
66+
67+
## Configuration Refresh
68+
69+
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.

examples/Python/ChatApp/app.py

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# -------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See License.txt in the project root for
4+
# license information.
5+
# --------------------------------------------------------------------------
6+
"""
7+
Azure OpenAI Chat Application using Azure App Configuration.
8+
This script demonstrates how to create a chat application that uses Azure App Configuration
9+
to manage settings and Azure OpenAI to power chat interactions.
10+
"""
11+
12+
import os
13+
from azure.identity import DefaultAzureCredential, get_bearer_token_provider
14+
from azure.appconfiguration.provider import load, SettingSelector, WatchKey
15+
from openai import AzureOpenAI
16+
from models import AzureOpenAIConfiguration, ChatCompletionConfiguration
17+
18+
APP_CONFIG_ENDPOINT_KEY = "AZURE_APPCONFIGURATION_ENDPOINT"
19+
20+
21+
# Initialize CREDENTIAL
22+
CREDENTIAL = DefaultAzureCredential()
23+
24+
APPCONFIG = None
25+
CHAT_COMPLETION_CONFIG = None
26+
27+
28+
def main():
29+
global APPCONFIG
30+
app_config_endpoint = os.environ.get(APP_CONFIG_ENDPOINT_KEY)
31+
if not app_config_endpoint:
32+
raise ValueError(f"The environment variable '{APP_CONFIG_ENDPOINT_KEY}' is not set or is empty.")
33+
34+
# Load configuration
35+
APPCONFIG = load(
36+
endpoint=app_config_endpoint,
37+
selects=[SettingSelector(key_filter="ChatApp:*")],
38+
credential=CREDENTIAL,
39+
keyvault_credential=CREDENTIAL,
40+
trim_prefixes=["ChatApp:"],
41+
refresh_on=[WatchKey(key="ChatApp:Sentinel")],
42+
on_refresh_success=configure_app,
43+
)
44+
configure_app()
45+
46+
azure_openai_config = AzureOpenAIConfiguration(
47+
api_key=APPCONFIG.get("AzureOpenAI:ApiKey", ""),
48+
endpoint=APPCONFIG.get("AzureOpenAI:Endpoint", ""),
49+
deployment_name=APPCONFIG.get("AzureOpenAI:DeploymentName", ""),
50+
api_version=APPCONFIG.get("AzureOpenAI:ApiVersion", ""),
51+
)
52+
azure_client = create_azure_openai_client(azure_openai_config)
53+
54+
chat_conversation = []
55+
56+
print("Chat started! What's on your mind?")
57+
58+
while True:
59+
# Refresh the configuration from Azure App Configuration
60+
APPCONFIG.refresh()
61+
62+
# Get user input
63+
user_input = input("You: ")
64+
65+
# Exit if user input is empty
66+
if not user_input.strip():
67+
print("Exiting chat. Goodbye!")
68+
break
69+
70+
# Add user message to chat conversation
71+
chat_conversation.append({"role": "user", "content": user_input})
72+
73+
chat_messages = list(CHAT_COMPLETION_CONFIG.messages)
74+
chat_messages.extend(chat_conversation)
75+
76+
# Get AI response and add it to chat conversation
77+
response = azure_client.chat.completions.create(
78+
model=azure_openai_config.deployment_name,
79+
messages=chat_messages,
80+
max_tokens=CHAT_COMPLETION_CONFIG.max_tokens,
81+
temperature=CHAT_COMPLETION_CONFIG.temperature,
82+
top_p=CHAT_COMPLETION_CONFIG.top_p,
83+
)
84+
85+
ai_response = response.choices[0].message.content
86+
chat_conversation .append({"role": "assistant", "content": ai_response})
87+
print(f"AI: {ai_response}")
88+
89+
90+
def configure_app():
91+
"""
92+
Configure the chat application with settings from Azure App Configuration.
93+
"""
94+
global CHAT_COMPLETION_CONFIG
95+
# Configure chat completion with AI configuration
96+
CHAT_COMPLETION_CONFIG = ChatCompletionConfiguration(**APPCONFIG["ChatCompletion"])
97+
98+
99+
def create_azure_openai_client(azure_openai_config: AzureOpenAIConfiguration) -> AzureOpenAI:
100+
"""
101+
Create an Azure OpenAI client using the configuration from Azure App Configuration.
102+
"""
103+
if azure_openai_config.api_key:
104+
return AzureOpenAI(
105+
azure_endpoint=azure_openai_config.endpoint,
106+
api_key=azure_openai_config.api_key,
107+
api_version=azure_openai_config.api_version,
108+
azure_deployment=azure_openai_config.deployment_name,
109+
)
110+
else:
111+
return AzureOpenAI(
112+
azure_endpoint=azure_openai_config.endpoint,
113+
azure_ad_token_provider=get_bearer_token_provider(
114+
CREDENTIAL,
115+
"https://cognitiveservices.azure.com/.default",
116+
),
117+
api_version=azure_openai_config.api_version,
118+
azure_deployment=azure_openai_config.deployment_name,
119+
)
120+
121+
122+
if __name__ == "__main__":
123+
main()

examples/Python/ChatApp/models.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# -------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See License.txt in the project root for
4+
# license information.
5+
# --------------------------------------------------------------------------
6+
"""
7+
Model classes for Azure OpenAI Chat Application.
8+
"""
9+
from dataclasses import dataclass
10+
from typing import List, Optional, Dict
11+
12+
13+
@dataclass
14+
class AzureOpenAIConfiguration:
15+
"""
16+
Represents the configuration for Azure OpenAI service.
17+
"""
18+
19+
api_key: str
20+
endpoint: str
21+
deployment_name: str
22+
api_version: Optional[str] = None
23+
24+
25+
@dataclass
26+
class ChatCompletionConfiguration:
27+
"""
28+
Represents the configuration for an AI model including messages and parameters.
29+
"""
30+
31+
max_tokens: int
32+
temperature: float
33+
top_p: float
34+
model: Optional[str] = None
35+
messages: Optional[List[Dict[str, str]]] = None
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[tool.black]
2+
line-length = 120
3+
target-version = ['py38']
4+
include = '\.pyi?$'
5+
6+
[tool.pylint.format]
7+
max-line-length = 120
8+
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
azure-identity
2+
azure-appconfiguration-provider
3+
openai

pyproject.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[tool.black]
2+
line-length = 120
3+
target-version = ['py38']
4+
include = '\.pyi?$'

0 commit comments

Comments
 (0)