diff --git a/.env.sample b/.env.sample index 331045a4..8d821001 100644 --- a/.env.sample +++ b/.env.sample @@ -1,4 +1,3 @@ -AZURE_OPENAI_API_VERSION=2024-02-15-preview AZURE_OPENAI_ENDPOINT=https://YOUR-ENDPOINT-HERE.openai.azure.com/ # Name of the Azure OpenAI GPT deployment (different from the model name) AZURE_OPENAI_CHAT_DEPLOYMENT=gpt4o-mini diff --git a/.gitignore b/.gitignore index a9b542e9..1aec4f7a 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,6 @@ venv/ # Bicep build artifacts (exclude .json files except parameters) infra/**/*.json !infra/**/main.parameters.json + +# Pip artifacts and temporary files +=* diff --git a/infra/aca.bicep b/infra/aca.bicep index e842ce0d..79a4664d 100644 --- a/infra/aca.bicep +++ b/infra/aca.bicep @@ -9,7 +9,6 @@ param serviceName string = 'aca' param exists bool param openAiDeploymentName string param openAiEndpoint string -param openAiApiVersion string resource acaIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { name: identityName @@ -25,10 +24,6 @@ var env = [ name: 'AZURE_OPENAI_ENDPOINT' value: openAiEndpoint } - { - name: 'AZURE_OPENAI_API_VERSION' - value: openAiApiVersion - } { name: 'RUNNING_IN_PRODUCTION' value: 'true' diff --git a/infra/main.bicep b/infra/main.bicep index a28ba4f0..ee565806 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -55,7 +55,6 @@ param openAiResourceGroupName string = '' }) param openAiResourceLocation string param openAiSkuName string = '' -param openAiApiVersion string = '' // Used by the SDK in the app code param disableKeyBasedAuth bool = true // Parameters for the specific Azure OpenAI deployment: @@ -152,7 +151,6 @@ module aca 'aca.bicep' = { containerRegistryName: containerApps.outputs.registryName openAiDeploymentName: openAiDeploymentName openAiEndpoint: createAzureOpenAi ? openAi.outputs.endpoint : openAiEndpoint - openAiApiVersion: openAiApiVersion exists: acaExists } } @@ -185,7 +183,6 @@ output AZURE_TENANT_ID string = tenant().tenantId output AZURE_OPENAI_RESOURCE_GROUP string = openAiResourceGroup.name output AZURE_OPENAI_RESOURCE_NAME string = openAi.outputs.name output AZURE_OPENAI_CHAT_DEPLOYMENT string = openAiDeploymentName -output AZURE_OPENAI_API_VERSION string = openAiApiVersion output AZURE_OPENAI_ENDPOINT string = createAzureOpenAi ? openAi.outputs.endpoint : openAiEndpoint output SERVICE_ACA_IDENTITY_PRINCIPAL_ID string = aca.outputs.SERVICE_ACA_IDENTITY_PRINCIPAL_ID diff --git a/src/pyproject.toml b/src/pyproject.toml index 541b8d17..7267ad51 100644 --- a/src/pyproject.toml +++ b/src/pyproject.toml @@ -13,7 +13,7 @@ dependencies = [ "httptools", # Used by uvicorn for reload functionality "watchfiles", - "openai", + "openai>=1.108.1", "azure-identity", "aiohttp>=3.11.0", "python-dotenv", diff --git a/src/quartapp/chat.py b/src/quartapp/chat.py index 29bd5423..c3198b64 100644 --- a/src/quartapp/chat.py +++ b/src/quartapp/chat.py @@ -7,7 +7,7 @@ ManagedIdentityCredential, get_bearer_token_provider, ) -from openai import AsyncAzureOpenAI +from openai import AsyncOpenAI from quart import ( Blueprint, Response, @@ -47,11 +47,10 @@ async def configure_openai(): if not os.getenv("AZURE_OPENAI_CHAT_DEPLOYMENT"): raise ValueError("AZURE_OPENAI_CHAT_DEPLOYMENT is required for Azure OpenAI") - # Create the Asynchronous Azure OpenAI client - bp.openai_client = AsyncAzureOpenAI( - api_version=os.getenv("AZURE_OPENAI_API_VERSION") or "2024-02-15-preview", - azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"), - azure_ad_token_provider=token_provider, + # Create the Asynchronous OpenAI client + bp.openai_client = AsyncOpenAI( + base_url=os.getenv("AZURE_OPENAI_ENDPOINT"), + api_key=token_provider, ) # Set the model name to the Azure OpenAI model deployment name bp.openai_model = os.getenv("AZURE_OPENAI_CHAT_DEPLOYMENT") diff --git a/src/requirements.txt b/src/requirements.txt index 9c3bd59e..b8cf3f40 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -1,15 +1,15 @@ -# -# This file is autogenerated by pip-compile with Python 3.12 -# by the following command: -# -# pip-compile pyproject.toml +# +# This file is autogenerated by pip-compile with Python 3.12 +# by the following command: +# +# pip-compile --output-file=src/requirements.txt src/pyproject.toml # aiofiles==24.1.0 # via quart aiohappyeyeballs==2.6.1 # via aiohttp -aiohttp==3.12.15 - # via quartapp (pyproject.toml) +aiohttp==3.12.15 + # via quartapp (src/pyproject.toml) aiosignal==1.4.0 # via aiohttp annotated-types==0.7.0 @@ -24,7 +24,7 @@ attrs==25.3.0 azure-core==1.35.1 # via azure-identity azure-identity==1.25.0 - # via quartapp (pyproject.toml) + # via quartapp (src/pyproject.toml) blinker==1.9.0 # via # flask @@ -57,26 +57,26 @@ frozenlist==1.7.0 # aiohttp # aiosignal gunicorn==23.0.0 - # via quartapp (pyproject.toml) + # via quartapp (src/pyproject.toml) h11==0.16.0 # via # httpcore # hypercorn # uvicorn # wsproto -h2==4.3.0 - # via hypercorn -hpack==4.1.0 +h2==4.3.0 + # via hypercorn +hpack==4.1.0 # via h2 httpcore==1.0.9 # via httpx httptools==0.6.4 - # via quartapp (pyproject.toml) -httpx==0.28.1 + # via quartapp (src/pyproject.toml) +httpx==0.28.1 # via openai hypercorn==0.17.3 # via quart -hyperframe==6.1.0 +hyperframe==6.1.0 # via h2 idna==3.10 # via @@ -110,13 +110,13 @@ multidict==6.6.4 # via # aiohttp # yarl -openai==1.107.2 - # via quartapp (pyproject.toml) +openai==1.109.0 + # via quartapp (src/pyproject.toml) packaging==25.0 # via gunicorn priority==2.0.0 # via hypercorn -propcache==0.3.2 +propcache==0.3.2 # via # aiohttp # yarl @@ -126,16 +126,16 @@ pydantic==2.11.9 # via openai pydantic-core==2.33.2 # via pydantic -pyjwt[crypto]==2.10.1 - # via - # msal - # pyjwt -python-dotenv==1.1.1 - # via quartapp (pyproject.toml) +pyjwt[crypto]==2.10.1 + # via + # msal + # pyjwt +python-dotenv==1.1.1 + # via quartapp (src/pyproject.toml) pyyaml==6.0.2 - # via quartapp (pyproject.toml) + # via quartapp (src/pyproject.toml) quart==0.20.0 - # via quartapp (pyproject.toml) + # via quartapp (src/pyproject.toml) requests==2.32.5 # via # azure-core @@ -163,16 +163,16 @@ typing-inspection==0.4.1 urllib3==2.5.0 # via requests uvicorn==0.36.0 - # via quartapp (pyproject.toml) + # via quartapp (src/pyproject.toml) uvloop==0.21.0 ; sys_platform != "win32" and (sys_platform != "cygwin" and platform_python_implementation != "PyPy") - # via quartapp (pyproject.toml) + # via quartapp (src/pyproject.toml) watchfiles==1.1.0 - # via quartapp (pyproject.toml) + # via quartapp (src/pyproject.toml) werkzeug==3.1.3 # via # flask # quart - # quartapp (pyproject.toml) + # quartapp (src/pyproject.toml) wsproto==1.2.0 # via hypercorn yarl==1.20.1 diff --git a/tests/test_app.py b/tests/test_app.py index b8de7a65..f0d508ab 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -48,11 +48,10 @@ async def test_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_CHAT_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(testing=True) async with quart_app.test_app(): - assert quart_app.blueprints["chat"].openai_client._azure_ad_token_provider is not None + assert quart_app.blueprints["chat"].openai_client.api_key is not None