Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# For Azure OpenAI:
AZURE_OPENAI_ENDPOINT=
# Azure OpenAI API version
AZURE_OPENAI_API_VERSION="2024-02-15-preview"
# Name of the Azure OpenAI GPT deployment (different from the model name)
AZURE_OPENAI_CHATGPT_DEPLOYMENT=chatgpt
# This only needs to be specified when using the key instead of DefaultCredentials
Expand Down
5 changes: 0 additions & 5 deletions infra/aca.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ param serviceName string = 'aca'
param exists bool
param openAiDeploymentName string
param openAiEndpoint string
param openAiApiVersion string
param openAiComAPIKeySecretName string
param azureKeyVaultName string

Expand Down Expand Up @@ -58,10 +57,6 @@ module app 'core/host/container-app-upsert.bicep' = {
name: 'AZURE_OPENAI_ENDPOINT'
value: openAiEndpoint
}
{
name: 'AZURE_OPENAI_API_VERSION'
value: openAiApiVersion
}
{
name: 'RUNNING_IN_PRODUCTION'
value: 'true'
Expand Down
3 changes: 0 additions & 3 deletions infra/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ param openAiResourceLocation string
param openAiDeploymentName string = 'chatgpt'
param openAiSkuName string = ''
param openAiDeploymentCapacity int // Set in main.parameters.json
param openAiApiVersion string = ''

var openAiConfig = {
modelName: 'gpt-4o-mini'
Expand Down Expand Up @@ -201,7 +200,6 @@ module aca 'aca.bicep' = {
containerRegistryName: containerApps.outputs.registryName
openAiDeploymentName: deployAzureOpenAi ? openAiConfig.deploymentName : ''
openAiEndpoint: deployAzureOpenAi ? openAi.outputs.endpoint : ''
openAiApiVersion: deployAzureOpenAi ? openAiApiVersion : ''
openAiComAPIKeySecretName: openAiComAPIKeySecretName
exists: acaExists
authClientId: authClientId
Expand Down Expand Up @@ -239,7 +237,6 @@ module openAiRoleBackend 'core/security/role.bicep' = if (deployAzureOpenAi) {
output AZURE_LOCATION string = location

output AZURE_OPENAI_CHATGPT_DEPLOYMENT string = deployAzureOpenAi ? openAiConfig.deploymentName : ''
output AZURE_OPENAI_API_VERSION string = deployAzureOpenAi ? openAiApiVersion : ''
output AZURE_OPENAI_ENDPOINT string = deployAzureOpenAi ? openAi.outputs.endpoint : ''
output AZURE_OPENAI_RESOURCE string = deployAzureOpenAi ? openAi.outputs.name : ''
output AZURE_OPENAI_RESOURCE_GROUP string = deployAzureOpenAi ? openAiResourceGroup.name : ''
Expand Down
2 changes: 1 addition & 1 deletion src/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ dependencies = [
"werkzeug",
"gunicorn",
"uvicorn[standard]",
"openai",
"openai>=1.0.0",
"azure-identity",
"azure-keyvault-secrets",
"aiohttp",
Expand Down
8 changes: 4 additions & 4 deletions src/quartapp/chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ async def configure_openai():
bp.openai_client = openai.AsyncOpenAI(
**client_args,
)
bp.openai_model_arg = os.getenv("OPENAI_MODEL_NAME") or "gpt-4o-mini"
elif os.getenv("AZURE_OPENAI_ENDPOINT"):
# Use an Azure OpenAI endpoint instead,
# either with a key or with keyless authentication
Expand All @@ -49,16 +50,15 @@ async def configure_openai():
# This should work on ACA as long as AZURE_CLIENT_ID is set to the user-assigned managed identity
current_app.logger.info("Using Azure OpenAI with default credential")
default_credential = get_azure_credential()
client_args["azure_ad_token_provider"] = azure.identity.aio.get_bearer_token_provider(
client_args["api_key"] = azure.identity.aio.get_bearer_token_provider(
default_credential, "https://cognitiveservices.azure.com/.default"
)
if not os.getenv("AZURE_OPENAI_ENDPOINT"):
raise ValueError("AZURE_OPENAI_ENDPOINT is required for Azure OpenAI")
if not os.getenv("AZURE_OPENAI_CHATGPT_DEPLOYMENT"):
raise ValueError("AZURE_OPENAI_CHATGPT_DEPLOYMENT is required for Azure OpenAI")
bp.openai_client = openai.AsyncAzureOpenAI(
api_version=os.getenv("AZURE_OPENAI_API_VERSION") or "2024-02-15-preview",
azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"),
bp.openai_client = openai.AsyncOpenAI(
base_url=os.getenv("AZURE_OPENAI_ENDPOINT"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This URL needs to end in "/openai/v1"

**client_args,
)
# Note: Azure OpenAI takes the deployment name as the model name
Expand Down
11 changes: 6 additions & 5 deletions tests/test_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,12 @@ async def test_azure_openai_key(monkeypatch, mock_keyvault_secretclient):
monkeypatch.setenv("AZURE_OPENAI_KEY", "test-key")
monkeypatch.setenv("AZURE_OPENAI_ENDPOINT", "test-openai-service.openai.azure.com")
monkeypatch.setenv("AZURE_OPENAI_CHATGPT_DEPLOYMENT", "test-chatgpt")
monkeypatch.setenv("AZURE_OPENAI_VERSION", "2023-10-01-preview")

quart_app = quartapp.create_app()

async with quart_app.test_app():
assert quart_app.blueprints["chat"].openai_client.api_key == "test-key"
assert quart_app.blueprints["chat"].openai_client._azure_ad_token_provider is None
assert str(quart_app.blueprints["chat"].openai_client.base_url).rstrip('/') == "test-openai-service.openai.azure.com"
assert isinstance(quart_app.blueprints["chat"].openai_client, openai.AsyncOpenAI)


@pytest.mark.asyncio
Expand All @@ -68,14 +67,16 @@ async def test_azure_openai_managedidentity(monkeypatch):
monkeypatch.setenv("AZURE_OPENAI_CLIENT_ID", "test-client-id")
monkeypatch.setenv("AZURE_OPENAI_ENDPOINT", "test-openai-service.openai.azure.com")
monkeypatch.setenv("AZURE_OPENAI_CHATGPT_DEPLOYMENT", "test-chatgpt")
monkeypatch.setenv("AZURE_OPENAI_VERSION", "2023-10-01-preview")

monkeypatch.setattr("azure.identity.aio.ManagedIdentityCredential", mock_cred.MockAzureCredential)

quart_app = quartapp.create_app()

async with quart_app.test_app():
assert quart_app.blueprints["chat"].openai_client._azure_ad_token_provider is not None
assert str(quart_app.blueprints["chat"].openai_client.base_url).rstrip('/') == "test-openai-service.openai.azure.com"
assert isinstance(quart_app.blueprints["chat"].openai_client, openai.AsyncOpenAI)
# The api_key should now be a token provider function
assert callable(quart_app.blueprints["chat"].openai_client.api_key)


@pytest.mark.asyncio
Expand Down
Loading