Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
923c6a9
Implemented Log execution time per prompt in Report
Rohini-Microsoft Jun 12, 2025
4bb533e
updated readme
Rohini-Microsoft Jun 13, 2025
1ec9c09
test: Implemented Log execution time per prompt in Report
Avijit-Microsoft Jun 16, 2025
2b73b28
updated the code
Rohini-Microsoft Jun 18, 2025
abc5f09
added functions
Rohini-Microsoft Jun 18, 2025
84b7f58
test: Implemented Log execution time per prompt in Report
Avijit-Microsoft Jun 19, 2025
779694c
feat: added fdp changes, updated to use ai agents instead of openai a…
Harsh-Microsoft Jun 19, 2025
cee593c
refactor: couple of typo fix (#570)
Harsh-Microsoft Jun 19, 2025
075b222
test automation pipeline changes
Priyanka-Microsoft Jun 20, 2025
1ad6517
auth enabled default true
Priyanka-Microsoft Jun 20, 2025
c71af89
exisitng ai project
blessing-sanusi Jun 20, 2025
3b8f961
exisitng ai project
blessing-sanusi Jun 22, 2025
c9fed0f
Fixed deployment issue for existing AI project
Kanchan-Microsoft Jun 23, 2025
e0d3162
Existing foundry app insight connection
Avijit-Microsoft Jun 24, 2025
d7978d7
commented existing app insights
Kanchan-Microsoft Jun 24, 2025
3a3ae3d
permission updated
Priyanka-Microsoft Jun 25, 2025
ab6a0cf
Fixed sample data processing issue for existing ai project
Kanchan-Microsoft Jun 25, 2025
53c1cfc
Updated readme file
Kanchan-Microsoft Jun 25, 2025
4f94286
test automation updated
Priyanka-Microsoft Jun 26, 2025
c0d4b90
feat: quota check during azd up (#579)
Priyanka-Microsoft Jun 26, 2025
63f78cc
fixed app insights and search service role assignment
Kanchan-Microsoft Jun 26, 2025
3dadba7
fix: There is no progress/Process message when deleting chat history …
Bangarraju-Microsoft Jun 27, 2025
c0ea41f
updated openai version (#581)
Priyanka-Microsoft Jun 27, 2025
34be9f6
resolved conflict
Priyanka-Microsoft Jun 27, 2025
9b40fdd
deleted params
Priyanka-Microsoft Jun 27, 2025
a7c4e79
Merge branch 'dev' into ai-exisitngproject
Kanchan-Microsoft Jun 27, 2025
1d5742c
feat: Use of Existing AI Project
Avijit-Microsoft Jun 27, 2025
b45f263
conflict resolved
Priyanka-Microsoft Jun 27, 2025
970df01
ci: test automation pipeline changes
Avijit-Microsoft Jun 27, 2025
fc9bf71
feat: replaces on your data with ai search tool for ChatWithCallTrans…
Harsh-Microsoft Jun 30, 2025
a83da50
fix: improve Azure authentication messages in scripts (#584)
Harsh-Microsoft Jun 30, 2025
0f23384
fix: Changed the Prompt to avoid generating answer while comparing wi…
Dhruvkumar-Microsoft Jul 1, 2025
91a513c
Merge branch 'main' into dev
Harsh-Microsoft Jul 1, 2025
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
433 changes: 301 additions & 132 deletions .github/workflows/CAdeploy.yml

Large diffs are not rendered by default.

45 changes: 43 additions & 2 deletions .github/workflows/test_automation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,14 @@ on:
schedule:
- cron: '0 13 * * *' # Runs at 1 PM UTC
workflow_dispatch:
workflow_call:
inputs:
CA_WEB_URL:
required: true
type: string

env:
url: ${{ vars.CLIENT_ADVISOR_URL }}
url: ${{ inputs.CA_WEB_URL }}
accelerator_name: "Client Advisor"

jobs:
Expand All @@ -36,6 +41,42 @@ jobs:
- name: Ensure browsers are installed
run: python -m playwright install --with-deps chromium


- name: Validate URL
run: |
if [ -z "${{ env.url }}" ]; then
echo "ERROR: No URL provided for testing"
exit 1

fi

echo "Testing URL: ${{ env.url }}"


- name: Wait for Application to be Ready
run: |
echo "Waiting for application to be ready at ${{ env.url }} "
max_attempts=10
attempt=1

while [ $attempt -le $max_attempts ]; do
echo "Attempt $attempt: Checking if application is ready..."
if curl -f -s "${{ env.url }}" > /dev/null; then
echo "Application is ready!"
break

fi

if [ $attempt -eq $max_attempts ]; then
echo "Application is not ready after $max_attempts attempts"
exit 1
fi

echo "Application not ready, waiting 30 seconds..."
sleep 30
attempt=$((attempt + 1))
done

- name: Run tests(1)
id: test1
run: |
Expand Down Expand Up @@ -108,4 +149,4 @@ jobs:
# Send the notification
curl -X POST "${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA}}" \
-H "Content-Type: application/json" \
-d "$EMAIL_BODY" || echo "Failed to send notification"
-d "$EMAIL_BODY" || echo "Failed to send notification"
1 change: 1 addition & 0 deletions docs/CustomizingAzdParameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ By default this template will use the environment name as the prefix to prevent
| `AZURE_ENV_OPENAI_LOCATION` | string | `eastus2` | Location of the Azure OpenAI resource. Choose from (allowed values: `swedencentral`, `australiaeast`). |
| `AZURE_LOCATION` | string | `japaneast` | Sets the Azure region for resource deployment. |
| `AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID` | string | `<Existing Workspace Id>` | Reuses an existing Log Analytics Workspace instead of provisioning a new one. |
| `RESOURCE_GROUP_NAME_FOUNDRY` | string | `<Existing AI Foundry Project>` | Reuses an existing AI Foundry Project instead of provisioning a new one. |

## How to Set a Parameter
To customize any of the above values, run the following command **before** `azd up`:
Expand Down
1 change: 1 addition & 0 deletions docs/DeploymentGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ When you start the deployment, most parameters will have **default values**, but
| **Azure OpenAI API Version** | Set the API version for OpenAI model deployments. | `2025-04-01-preview` |
| **AZURE\_LOCATION** | Sets the Azure region for resource deployment. | `japaneast` |
| **Existing Log Analytics Workspace** | To reuse an existing Log Analytics Workspace ID instead of creating a new one. | *(empty)* |
| **Existing AI Foundry Project Resource ID** | To reuse an existing AI Foundry Project Resource ID instead of creating a new one. | *(empty)* |



Expand Down
160 changes: 104 additions & 56 deletions infra/deploy_ai_foundry.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ param gptDeploymentCapacity int
param embeddingModel string
param embeddingDeploymentCapacity int
param existingLogAnalyticsWorkspaceId string = ''
param azureExistingAIProjectResourceId string = ''

// Load the abbrevations file required to name the azure resources.
var abbrs = loadJsonContent('./abbreviations.json')
Expand Down Expand Up @@ -52,6 +53,31 @@ var existingLawSubscription = useExisting ? split(existingLogAnalyticsWorkspaceI
var existingLawResourceGroup = useExisting ? split(existingLogAnalyticsWorkspaceId, '/')[4] : ''
var existingLawName = useExisting ? split(existingLogAnalyticsWorkspaceId, '/')[8] : ''

var existingOpenAIEndpoint = !empty(azureExistingAIProjectResourceId)
? format('https://{0}.openai.azure.com/', split(azureExistingAIProjectResourceId, '/')[8])
: ''
var existingProjEndpoint = !empty(azureExistingAIProjectResourceId)
? format(
'https://{0}.services.ai.azure.com/api/projects/{1}',
split(azureExistingAIProjectResourceId, '/')[8],
split(azureExistingAIProjectResourceId, '/')[10]
)
: ''
var existingAIFoundryName = !empty(azureExistingAIProjectResourceId)
? split(azureExistingAIProjectResourceId, '/')[8]
: ''
var existingAIProjectName = !empty(azureExistingAIProjectResourceId)
? split(azureExistingAIProjectResourceId, '/')[10]
: ''
var existingAIServiceSubscription = !empty(azureExistingAIProjectResourceId)
? split(azureExistingAIProjectResourceId, '/')[2]
: ''
var existingAIServiceResourceGroup = !empty(azureExistingAIProjectResourceId)
? split(azureExistingAIProjectResourceId, '/')[4]
: ''
var aiSearchConnectionName = 'foundry-search-connection-${solutionName}'
var aiAppInsightConnectionName = 'foundry-app-insights-connection-${solutionName}'

resource existingLogAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' existing = if (useExisting) {
name: existingLawName
scope: resourceGroup(existingLawSubscription, existingLawResourceGroup)
Expand All @@ -69,25 +95,6 @@ resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2023-09-01' = if
}
}

// resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = {
// name: applicationInsightsName
// location: location
// kind: 'web'
// properties: {
// Application_Type: 'web'
// DisableIpMasking: false
// DisableLocalAuth: false
// Flow_Type: 'Bluefield'
// ForceCustomerStorageForProfiler: false
// ImmediatePurgeDataOn30Days: true
// IngestionMode: 'ApplicationInsights'
// publicNetworkAccessForIngestion: 'Enabled'
// publicNetworkAccessForQuery: 'Disabled'
// Request_Source: 'rest'
// WorkspaceResourceId: logAnalytics.id
// }
// }

resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = {
name: applicationInsightsName
location: location
Expand All @@ -100,7 +107,7 @@ resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = {
}
}

resource aiFoundry 'Microsoft.CognitiveServices/accounts@2025-04-01-preview' = {
resource aiFoundry 'Microsoft.CognitiveServices/accounts@2025-04-01-preview' = if (empty(azureExistingAIProjectResourceId)) {
name: aiFoundryName
location: location
sku: {
Expand All @@ -123,7 +130,7 @@ resource aiFoundry 'Microsoft.CognitiveServices/accounts@2025-04-01-preview' = {
}
}

resource aiFoundryProject 'Microsoft.CognitiveServices/accounts/projects@2025-04-01-preview' = {
resource aiFoundryProject 'Microsoft.CognitiveServices/accounts/projects@2025-04-01-preview' = if (empty(azureExistingAIProjectResourceId)) {
parent: aiFoundry
name: aiProjectName
location: location
Expand All @@ -138,7 +145,7 @@ resource aiFoundryProject 'Microsoft.CognitiveServices/accounts/projects@2025-04

@batchSize(1)
resource aiFModelDeployments 'Microsoft.CognitiveServices/accounts/deployments@2023-05-01' = [
for aiModeldeployment in aiModelDeployments: {
for aiModeldeployment in aiModelDeployments: if (empty(azureExistingAIProjectResourceId)) {
parent: aiFoundry
name: aiModeldeployment.name
properties: {
Expand Down Expand Up @@ -185,8 +192,8 @@ resource aiSearch 'Microsoft.Search/searchServices@2025-02-01-preview' = {
}
}

resource aiSearchFoundryConnection 'Microsoft.CognitiveServices/accounts/connections@2025-04-01-preview' ={
name: 'foundry-search-connection'
resource aiSearchFoundryConnection 'Microsoft.CognitiveServices/accounts/connections@2025-04-01-preview' = if (empty(azureExistingAIProjectResourceId)) {
name: aiSearchConnectionName
parent: aiFoundry
properties: {
category: 'CognitiveSearch'
Expand All @@ -201,18 +208,56 @@ resource aiSearchFoundryConnection 'Microsoft.CognitiveServices/accounts/connect
}
}

module existing_AIProject_SearchConnectionModule 'deploy_aifp_aisearch_connection.bicep' = if (!empty(azureExistingAIProjectResourceId)) {
name: 'aiProjectSearchConnectionDeployment'
scope: resourceGroup(existingAIServiceSubscription, existingAIServiceResourceGroup)
params: {
existingAIProjectName: existingAIProjectName
existingAIFoundryName: existingAIFoundryName
aiSearchName: aiSearchName
aiSearchResourceId: aiSearch.id
aiSearchLocation: aiSearch.location
aiSearchConnectionName: aiSearchConnectionName
}
}

resource cognitiveServicesOpenAIUser 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = {
name: '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd'
}

module assignOpenAIRoleToAISearch 'deploy_foundry_role_assignment.bicep' = {
name: 'assignOpenAIRoleToAISearch'
scope: resourceGroup(existingAIServiceSubscription, existingAIServiceResourceGroup)
params: {
roleDefinitionId: cognitiveServicesOpenAIUser.id
roleAssignmentName: guid(resourceGroup().id, aiSearch.id, cognitiveServicesOpenAIUser.id, 'openai-foundry')
aiFoundryName: !empty(azureExistingAIProjectResourceId) ? existingAIFoundryName : aiFoundryName
aiProjectName: !empty(azureExistingAIProjectResourceId) ? existingAIProjectName : aiProjectName
principalId: aiSearch.identity.principalId
}
}

@description('This is the built-in Search Index Data Reader role.')
resource searchIndexDataReaderRoleDefinition 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = {
scope: aiSearch
name: '1407120a-92aa-4202-b7e9-c0e197c71c8f'
}

resource searchIndexDataReaderRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(aiSearch.id, aiFoundry.id, searchIndexDataReaderRoleDefinition.id)
resource searchIndexDataReaderRoleAssignmentToAIFP 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (empty(azureExistingAIProjectResourceId)) {
name: guid(aiSearch.id, aiFoundryProject.id, searchIndexDataReaderRoleDefinition.id)
scope: aiSearch
properties: {
roleDefinitionId: searchIndexDataReaderRoleDefinition.id
principalId: aiFoundry.identity.principalId
principalId: aiFoundryProject.identity.principalId
principalType: 'ServicePrincipal'
}
}
resource assignSearchIndexDataReaderToExistingAiProject 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(azureExistingAIProjectResourceId)) {
name: guid(resourceGroup().id, existingAIProjectName, searchIndexDataReaderRoleDefinition.id, 'Existing')
scope: aiSearch
properties: {
roleDefinitionId: searchIndexDataReaderRoleDefinition.id
principalId: assignOpenAIRoleToAISearch.outputs.aiProjectPrincipalId
principalType: 'ServicePrincipal'
}
}
Expand All @@ -223,18 +268,28 @@ resource searchServiceContributorRoleDefinition 'Microsoft.Authorization/roleDef
name: '7ca78c08-252a-4471-8644-bb5ff32d4ba0'
}

resource searchServiceContributorRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(aiSearch.id, aiFoundry.id, searchServiceContributorRoleDefinition.id)
resource searchServiceContributorRoleAssignmentToAIFP 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (empty(azureExistingAIProjectResourceId)) {
name: guid(aiSearch.id, aiFoundryProject.id, searchServiceContributorRoleDefinition.id)
scope: aiSearch
properties: {
roleDefinitionId: searchServiceContributorRoleDefinition.id
principalId: aiFoundry.identity.principalId
principalId: aiFoundryProject.identity.principalId
principalType: 'ServicePrincipal'
}
}

resource appInsightsFoundryConnection 'Microsoft.CognitiveServices/accounts/connections@2025-04-01-preview' = {
name: 'foundry-app-insights-connection'
resource searchServiceContributorRoleAssignmentExisting 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(azureExistingAIProjectResourceId)) {
name: guid(resourceGroup().id, existingAIProjectName, searchServiceContributorRoleDefinition.id, 'Existing')
scope: aiSearch
properties: {
roleDefinitionId: searchServiceContributorRoleDefinition.id
principalId: assignOpenAIRoleToAISearch.outputs.aiProjectPrincipalId
principalType: 'ServicePrincipal'
}
}

resource appInsightsFoundryConnection 'Microsoft.CognitiveServices/accounts/connections@2025-04-01-preview' = if (empty(azureExistingAIProjectResourceId)) {
name: aiAppInsightConnectionName
parent: aiFoundry
properties: {
category: 'AppInsights'
Expand All @@ -251,14 +306,6 @@ resource appInsightsFoundryConnection 'Microsoft.CognitiveServices/accounts/conn
}
}

// resource azureOpenAIApiKeyEntry 'Microsoft.KeyVault/vaults/secrets@2021-11-01-preview' = {
// parent: keyVault
// name: 'AZURE-OPENAI-KEY'
// properties: {
// value: aiFoundry.listKeys().key1 //aiServices_m.listKeys().key1
// }
// }

resource azureOpenAIApiVersionEntry 'Microsoft.KeyVault/vaults/secrets@2021-11-01-preview' = {
parent: keyVault
name: 'AZURE-OPENAI-PREVIEW-API-VERSION'
Expand All @@ -271,7 +318,10 @@ resource azureOpenAIEndpointEntry 'Microsoft.KeyVault/vaults/secrets@2021-11-01-
parent: keyVault
name: 'AZURE-OPENAI-ENDPOINT'
properties: {
value: aiFoundry.properties.endpoints['OpenAI Language Model Instance API'] //aiServices_m.properties.endpoint
// value: aiFoundry.properties.endpoints['OpenAI Language Model Instance API'] //aiServices_m.properties.endpoint
value: !empty(existingOpenAIEndpoint)
? existingOpenAIEndpoint
: aiFoundry.properties.endpoints['OpenAI Language Model Instance API']
}
}

Expand All @@ -283,14 +333,6 @@ resource azureOpenAIEmbeddingModelEntry 'Microsoft.KeyVault/vaults/secrets@2021-
}
}

// resource azureSearchAdminKeyEntry 'Microsoft.KeyVault/vaults/secrets@2021-11-01-preview' = {
// parent: keyVault
// name: 'AZURE-SEARCH-KEY'
// properties: {
// value: aiSearch.listAdminKeys().primaryKey
// }
// }

resource azureSearchServiceEndpointEntry 'Microsoft.KeyVault/vaults/secrets@2021-11-01-preview' = {
parent: keyVault
name: 'AZURE-SEARCH-ENDPOINT'
Expand All @@ -310,21 +352,27 @@ resource azureSearchIndexEntry 'Microsoft.KeyVault/vaults/secrets@2021-11-01-pre
output keyvaultName string = keyvaultName
output keyvaultId string = keyVault.id

output aiFoundryProjectEndpoint string = aiFoundryProject.properties.endpoints['AI Foundry API']
output aiServicesTarget string = aiFoundry.properties.endpoint //aiServices_m.properties.endpoint
output aoaiEndpoint string = aiFoundry.properties.endpoints['OpenAI Language Model Instance API'] //aiServices_m.properties.endpoint
output aiFoundryName string = aiFoundryName //aiServicesName_m
output aiFoundryId string = aiFoundry.id //aiServices_m.id
output resourceGroupNameFoundry string = !empty(existingAIServiceResourceGroup)
? existingAIServiceResourceGroup
: resourceGroup().name
output aiFoundryProjectEndpoint string = !empty(existingProjEndpoint)
? existingProjEndpoint
: aiFoundryProject.properties.endpoints['AI Foundry API']
output aoaiEndpoint string = !empty(existingOpenAIEndpoint)
? existingOpenAIEndpoint
: aiFoundry.properties.endpoints['OpenAI Language Model Instance API'] //aiServices_m.properties.endpoint
output aiFoundryName string = !empty(existingAIFoundryName) ? existingAIFoundryName : aiFoundryName //aiServicesName_m

output aiSearchName string = aiSearchName
output aiSearchId string = aiSearch.id
output aiSearchTarget string = 'https://${aiSearch.name}.search.windows.net'
output aiSearchService string = aiSearch.name
output aiFoundryProjectName string = aiFoundryProject.name
output aiFoundryProjectName string = !empty(existingAIProjectName) ? existingAIProjectName : aiFoundryProject.name

output applicationInsightsId string = applicationInsights.id
output logAnalyticsWorkspaceResourceName string = useExisting ? existingLogAnalyticsWorkspace.name : logAnalytics.name
output logAnalyticsWorkspaceResourceGroup string = useExisting ? existingLawResourceGroup : resourceGroup().name


output applicationInsightsConnectionString string = applicationInsights.properties.ConnectionString

output aiSearchFoundryConnectionName string = aiSearchConnectionName
21 changes: 21 additions & 0 deletions infra/deploy_aifp_aisearch_connection.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
param existingAIProjectName string
param existingAIFoundryName string
param aiSearchName string
param aiSearchResourceId string
param aiSearchLocation string
param aiSearchConnectionName string

resource projectAISearchConnection 'Microsoft.CognitiveServices/accounts/projects/connections@2025-04-01-preview' = {
name: '${existingAIFoundryName}/${existingAIProjectName}/${aiSearchConnectionName}'
properties: {
category: 'CognitiveSearch'
target: 'https://${aiSearchName}.search.windows.net'
authType: 'AAD'
isSharedToAll: true
metadata: {
ApiType: 'Azure'
ResourceId: aiSearchResourceId
location: aiSearchLocation
}
}
}
Loading
Loading