Skip to content
Merged
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
14 changes: 8 additions & 6 deletions .github/workflows/deploy-waf.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,15 @@ jobs:
--resource-group ${{ env.RESOURCE_GROUP_NAME }} \
--template-file infra/main.bicep \
--parameters \
environmentName=${{ env.SOLUTION_PREFIX }} \
useWafAlignedArchitecture=true \
aiDeploymentsLocation='${{ env.AZURE_LOCATION }}' \
solutionName=${{ env.SOLUTION_PREFIX }} \
location="${{ env.AZURE_LOCATION }}" \
azureAiServiceLocation='${{ env.AZURE_LOCATION }}' \
gptModelCapacity=5 \
virtualMachineConfiguration='{"adminUsername": "adminuser", "adminPassword": "P@ssw0rd1234"}' \
logAnalyticsWorkspaceConfiguration='{"existingWorkspaceResourceId": ""}'
enableTelemetry=true \
enableMonitoring=true \
enablePrivateNetworking=true \
enableScalability=true \
- name: Send Notification on Failure
if: failure()
Expand Down
13 changes: 4 additions & 9 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -129,19 +129,14 @@ jobs:
--resource-group ${{ env.RESOURCE_GROUP_NAME }} \
--template-file infra/main.bicep \
--parameters \
environmentName=${{ env.SOLUTION_PREFIX }} \
solutionLocation="${{ env.AZURE_LOCATION }}" \
modelDeploymentType="GlobalStandard" \
solutionName=${{ env.SOLUTION_PREFIX }} \
location="${{ env.AZURE_LOCATION }}" \
gptModelDeploymentType="GlobalStandard" \
gptModelName="gpt-4o" \
gptModelVersion="2024-08-06" \
imageTag="${IMAGE_TAG}" \
useWafAlignedArchitecture=false \
aiDeploymentsLocation='${{ env.AZURE_LOCATION }}' \
azureAiServiceLocation='${{ env.AZURE_LOCATION }}' \
gptModelCapacity=150 \
logAnalyticsWorkspaceConfiguration='{"dataRetentionInDays": 30, "existingWorkspaceResourceId": ""}' \
applicationInsightsConfiguration='{"retentionInDays": 30}' \
virtualNetworkConfiguration='{"enabled": false}' \
webServerFarmConfiguration='{"skuCapacity": 1, "skuName": "B2"}' \
--output json
- name: Extract Web App and API App URLs
Expand Down
49 changes: 12 additions & 37 deletions docs/DeploymentGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,8 @@ When you start the deployment, most parameters will have **default values**, but
| **GPT Model Capacity** | Sets the GPT model capacity. | 150 |
| **Image Tag** | Docker image tag used for container deployments. | latest |
| **Enable Telemetry** | Enables telemetry for monitoring and diagnostics. | true |

| **Existing Log Analytics Workspace** | To reuse an existing Log Analytics Workspace ID instead of creating a new one. | *(none)* |
| **Existing Azure AI Foundry Project** | To reuse an existing Azure AI Foundry Project ID instead of creating a new one. | *(none)* |

</details>

Expand All @@ -176,6 +177,14 @@ To adjust quota settings, follow these [steps](./AzureGPTQuotaSettings.md).

</details>

<details>

<summary><b>Reusing an Existing Azure AI Foundry Project</b></summary>

Guide to get your [Existing Project ID](/docs/re-use-foundry-project.md)

</details>

### Deploying with AZD

Once you've opened the project in [Codespaces](#github-codespaces), [Dev Containers](#vs-code-dev-containers), or [locally](#local-environment), you can deploy it to Azure by following these steps:
Expand Down Expand Up @@ -206,43 +215,9 @@ Once you've opened the project in [Codespaces](#github-codespaces), [Dev Contain

5. Once the deployment has completed successfully, open the [Azure Portal](https://portal.azure.com/), go to the deployed resource group, find the App Service, and get the app URL from `Default domain`.

6. If you are done trying out the application, you can delete the resources by running `azd down`.

### Publishing Local Build Container to Azure Container Registry

If you need to rebuild the source code and push the updated container to the deployed Azure Container Registry, follow these steps:

1. Set the environment variable `USE_LOCAL_BUILD` to `True`:

- **Linux/macOS**:

```bash
export USE_LOCAL_BUILD=True
```

- **Windows (PowerShell)**:
```powershell
$env:USE_LOCAL_BUILD = $true
```

2. Run the `az login` command

```bash
az login
```

3. Run the `azd up` command again to rebuild and push the updated container:
```bash
azd up
```

This will rebuild the source code, package it into a container, and push it to the Azure Container Registry associated with your deployment.

This guide provides step-by-step instructions for deploying your application using Azure Container Registry (ACR) and Azure Container Apps.

There are several ways to deploy the solution. You can deploy to run in Azure in one click, or manually, or you can deploy locally.
6. When Deployment is complete, follow steps in [Set Up Authentication in Azure App Service](../docs/azure_app_service_auth_setup.md) to add app authentication to your web app running on Azure App Service

When Deployment is complete, follow steps in [Set Up Authentication in Azure App Service](../docs/azure_app_service_auth_setup.md) to add app authentication to your web app running on Azure App Service
7. If you are done trying out the application, you can delete the resources by running `azd down`.

# Local setup

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
44 changes: 44 additions & 0 deletions docs/re-use-foundry-project.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
[← Back to *DEPLOYMENT* guide](/docs/DeploymentGuide.md#deployment-steps)

# Reusing an Existing Azure AI Foundry Project
To configure your environment to use an existing Azure AI Foundry Project, follow these steps:
---
### 1. Go to Azure Portal
Go to https://portal.azure.com

### 2. Search for Azure AI Foundry
In the search bar at the top, type "Azure AI Foundry" and click on it. Then select the Foundry service instance where your project exists.

![alt text](../docs/images/re_use_foundry_project/azure_ai_foundry_list.png)

### 3. Navigate to Projects under Resource Management
On the left sidebar of the Foundry service blade:

- Expand the Resource Management section
- Click on Projects (this refers to the active Foundry project tied to the service)

### 4. Click on the Project
From the Projects view: Click on the project name to open its details

Note: You will see only one project listed here, as each Foundry service maps to a single project in this accelerator

![alt text](../docs/images/re_use_foundry_project/navigate_to_projects.png)

### 5. Copy Resource ID
In the left-hand menu of the project blade:

- Click on Properties under Resource Management
- Locate the Resource ID field
- Click on the copy icon next to the Resource ID value

![alt text](../docs/images/re_use_foundry_project/project_resource_id.png)

### 6. Set the Foundry Project Resource ID in Your Environment
Run the following command in your terminal
```bash
azd env set AZURE_ENV_FOUNDRY_PROJECT_ID '<Existing Foundry Project Resource ID>'
```
Replace `<Existing Foundry Project Resource ID>` with the value obtained from Step 5.

### 7. Continue Deployment
Proceed with the next steps in the [deployment guide](/docs/DeploymentGuide.md#deployment-steps).
4 changes: 2 additions & 2 deletions docs/re-use-log-analytics.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[← Back to *DEPLOYMENT* guide](/docs/DeploymentGuide.md#deployment-options--steps)
[← Back to *DEPLOYMENT* guide](/docs/DeploymentGuide.md#deployment-steps)

# Reusing an Existing Log Analytics Workspace
To configure your environment to use an existing Log Analytics Workspace, follow these steps:
Expand Down Expand Up @@ -28,4 +28,4 @@ azd env set AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID '<Existing Log Analytics Worksp
Replace `<Existing Log Analytics Workspace Id>` with the value obtained from Step 3.

### 5. Continue Deployment
Proceed with the next steps in the [deployment guide](/docs/DeploymentGuide.md#deployment-options--steps).
Proceed with the next steps in the [deployment guide](/docs/DeploymentGuide.md#deployment-steps).
60 changes: 48 additions & 12 deletions infra/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ param solutionName string = 'macae'
param solutionUniqueText string = take(uniqueString(subscription().id, resourceGroup().name, solutionName), 5)

@metadata({ azd: { type: 'location' } })
@description('Optional. Azure region for all services. Regions are restricted to guarantee compatibility with paired regions and replica locations for data redundancy and failover scenarios based on articles [Azure regions list](https://learn.microsoft.com/azure/reliability/regions-list) and [Azure Database for MySQL Flexible Server - Azure Regions](https://learn.microsoft.com/azure/mysql/flexible-server/overview#azure-regions).')
@description('Required. Azure region for all services. Regions are restricted to guarantee compatibility with paired regions and replica locations for data redundancy and failover scenarios based on articles [Azure regions list](https://learn.microsoft.com/azure/reliability/regions-list) and [Azure Database for MySQL Flexible Server - Azure Regions](https://learn.microsoft.com/azure/mysql/flexible-server/overview#azure-regions).')
@allowed([
'australiaeast'
'centralus'
Expand All @@ -30,13 +30,38 @@ param solutionUniqueText string = take(uniqueString(subscription().id, resourceG
'westeurope'
'uksouth'
])
param location string = 'australiaeast'
param location string

// Restricting deployment to only supported Azure OpenAI regions validated with GPT-4o model
@allowed(['australiaeast', 'eastus2', 'francecentral', 'japaneast', 'norwayeast', 'swedencentral', 'uksouth', 'westus'])
@metadata({ azd: { type: 'location' } })
@description('Optional. Location for all AI service resources. This should be one of the supported Azure AI Service locations.')
param azureAiServiceLocation string = 'australiaeast'
@metadata({
azd : {
type: 'location'
usageName : [
'OpenAI.GlobalStandard.gpt-4o, 150'
]
}
})
@description('Required. Location for all AI service resources. This should be one of the supported Azure AI Service locations.')
param azureAiServiceLocation string

@minLength(1)
@description('Optional. Name of the GPT model to deploy:')
param gptModelName string = 'gpt-4o'

@description('Optional. Version of the GPT model to deploy. Defaults to 2024-08-06.')
param gptModelVersion string = '2024-08-06'

@minLength(1)
@allowed([
'Standard'
'GlobalStandard'
])
@description('Optional. GPT model deployment type. Defaults to GlobalStandard.')
param gptModelDeploymentType string = 'GlobalStandard'

@description('Optional. AI model deployment token capacity. Defaults to 150 for optimal performance.')
param gptModelCapacity int = 150

@description('Optional. The tags to apply to all deployed Azure resources.')
param tags resourceInput<'Microsoft.Resources/resourceGroups@2025-04-01'>.tags = {}
Expand Down Expand Up @@ -86,7 +111,15 @@ param enableTelemetry bool = true
// Variables //
// ============== //

var solutionSuffix = '${solutionName}${solutionUniqueText}'
var solutionSuffix = toLower(trim(replace(
replace(
replace(replace(replace(replace('${solutionName}${solutionUniqueText}', '-', ''), '_', ''), '.', ''), '/', ''),
' ',
''
),
'*',
''
)))

// Region pairs list based on article in [Azure regions list](https://learn.microsoft.com/azure/reliability/regions-list)
// var azureRegionPairs = {
Expand Down Expand Up @@ -895,12 +928,11 @@ var aiFoundryAiServicesAiProjectResourceName = 'proj-${solutionSuffix}'
var aiFoundryAIservicesEnabled = true
var aiFoundryAiServicesModelDeployment = {
format: 'OpenAI'
name: 'gpt-4o'
version: '2024-08-06'
name: gptModelName
version: gptModelVersion
sku: {
name: 'GlobalStandard'
//Currently the capacity is set to 140 for optimal performance.
capacity: 140
name: gptModelDeploymentType
capacity: gptModelCapacity
}
raiPolicyName: 'Microsoft.Default'
}
Expand Down Expand Up @@ -1141,7 +1173,7 @@ module containerAppEnvironment 'br/public:avm/res/app/managed-environment:0.11.2
destination: 'log-analytics'
logAnalyticsConfiguration: {
customerId: logAnalyticsWorkspace!.outputs.logAnalyticsWorkspaceId
sharedKey: logAnalyticsWorkspace!.outputs.primarySharedKey
sharedKey: logAnalyticsWorkspace.outputs.primarySharedKey
}
}
: null
Expand Down Expand Up @@ -1331,6 +1363,10 @@ module containerApp 'br/public:avm/res/app/container-app:0.18.1' = {
name: 'AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME'
value: aiFoundryAiServicesModelDeployment.name
}
{
name: 'AZURE_CLIENT_ID'
value: userAssignedIdentity.outputs.clientId // NOTE: This is the client ID of the managed identity, not the Entra application, and is needed for the App Service to access the Cosmos DB account.
}
]
}
]
Expand Down
12 changes: 12 additions & 0 deletions infra/main.parameters.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,18 @@
"azureAiServiceLocation": {
"value": "${AZURE_ENV_OPENAI_LOCATION}"
},
"gptModelDeploymentType": {
"value": "${AZURE_ENV_MODEL_DEPLOYMENT_TYPE}"
},
"gptModelName": {
"value": "${AZURE_ENV_MODEL_NAME}"
},
"gptModelVersion": {
"value": "${AZURE_ENV_MODEL_VERSION}"
},
"gptModelCapacity": {
"value": "${AZURE_ENV_MODEL_CAPACITY}"
},
"backendContainerImageTag": {
"value": "${AZURE_ENV_IMAGE_TAG}"
},
Expand Down
12 changes: 12 additions & 0 deletions infra/main.waf.parameters.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@
"azureAiServiceLocation": {
"value": "${AZURE_ENV_OPENAI_LOCATION}"
},
"gptModelDeploymentType": {
"value": "${AZURE_ENV_MODEL_DEPLOYMENT_TYPE}"
},
"gptModelName": {
"value": "${AZURE_ENV_MODEL_NAME}"
},
"gptModelVersion": {
"value": "${AZURE_ENV_MODEL_VERSION}"
},
"gptModelCapacity": {
"value": "${AZURE_ENV_MODEL_CAPACITY}"
},
"backendContainerImageTag": {
"value": "${AZURE_ENV_IMAGE_TAG}"
},
Expand Down
4 changes: 2 additions & 2 deletions src/backend/app_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ def get_cosmos_database_client(self):
try:
if self._cosmos_client is None:
self._cosmos_client = CosmosClient(
self.COSMOSDB_ENDPOINT, credential=get_azure_credential()
self.COSMOSDB_ENDPOINT, credential=get_azure_credential(self.AZURE_CLIENT_ID)
)

if self._cosmos_database is None:
Expand Down Expand Up @@ -152,7 +152,7 @@ def get_ai_project_client(self):
return self._ai_project_client

try:
credential = get_azure_credential()
credential = get_azure_credential(self.AZURE_CLIENT_ID)
if credential is None:
raise RuntimeError(
"Unable to acquire Azure credentials; ensure Managed Identity is configured"
Expand Down
6 changes: 3 additions & 3 deletions src/backend/app_kernel.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
# Add this near the top of your app.py, after initializing the app
app.add_middleware(
CORSMiddleware,
allow_origins=[frontend_url],
allow_origins=[frontend_url], # Allow all origins for development; restrict in production
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
Expand Down Expand Up @@ -269,7 +269,7 @@ async def input_task_endpoint(input_task: InputTask, request: Request):
if "Rate limit is exceeded" in error_msg:
match = re.search(r"Rate limit is exceeded\. Try again in (\d+) seconds?\.", error_msg)
if match:
error_msg = f"Rate limit is exceeded. Try again in {match.group(1)} seconds."
error_msg = "Application temporarily unavailable due to quota limits. Please try again later."

track_event_if_configured(
"InputTaskError",
Expand All @@ -279,7 +279,7 @@ async def input_task_endpoint(input_task: InputTask, request: Request):
"error": str(e),
},
)
raise HTTPException(status_code=400, detail=f"Error creating plan: {error_msg}") from e
raise HTTPException(status_code=400, detail=f"{error_msg}") from e


@app.post("/api/human_feedback")
Expand Down
2 changes: 1 addition & 1 deletion src/backend/config_kernel.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class Config:
@staticmethod
def GetAzureCredentials():
"""Get Azure credentials using the AppConfig implementation."""
return get_azure_credential()
return get_azure_credential(config.AZURE_CLIENT_ID)

@staticmethod
def GetCosmosDatabaseClient():
Expand Down
2 changes: 1 addition & 1 deletion src/backend/context/cosmos_memory_kernel.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ async def initialize(self):
if not self._database:
# Create Cosmos client
cosmos_client = CosmosClient(
self._cosmos_endpoint, credential=get_azure_credential()
self._cosmos_endpoint, credential=get_azure_credential(config.AZURE_CLIENT_ID)
)
self._database = cosmos_client.get_database_client(
self._cosmos_database
Expand Down
1 change: 1 addition & 0 deletions src/backend/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ dependencies = [
"azure-ai-evaluation>=1.5.0",
"azure-ai-inference>=1.0.0b9",
"azure-ai-projects>=1.0.0b9",
"azure-ai-agents>=1.2.0b1",
"azure-cosmos>=4.9.0",
"azure-identity>=1.21.0",
"azure-monitor-events-extension>=0.1.0",
Expand Down
2 changes: 1 addition & 1 deletion src/backend/utils_kernel.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ async def rai_success(description: str, is_task_creation: bool) -> bool:
"""
try:
# Use managed identity for authentication to Azure OpenAI
credential = get_azure_credential()
credential = get_azure_credential(config.AZURE_CLIENT_ID)
access_token = credential.get_token(
"https://cognitiveservices.azure.com/.default"
).token
Expand Down
Loading