Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit fb28566

Browse files
committed
Update environment infrastructure deployment to use AI Studio/Services
1 parent 0cb352e commit fb28566

27 files changed

+1136
-356
lines changed

Setup-Environment.ps1

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@ param
2222
[string]$DeploymentName,
2323
[Parameter(Mandatory = $true)]
2424
[string]$Location,
25-
[Parameter(Mandatory = $true)]
26-
[string]$IsLocal,
27-
[Parameter(Mandatory = $true)]
28-
[string]$SkipInfrastructure
25+
[Parameter(Mandatory = $false)]
26+
[bool]$IsLocal,
27+
[Parameter(Mandatory = $false)]
28+
[bool]$SkipInfrastructure
2929
)
3030

3131
Write-Host "Starting environment setup..."
3232

33-
if ($SkipInfrastructure -eq '$false' || -not (Test-Path -Path './infra/InfrastructureOutputs.json')) {
33+
if ($SkipInfrastructure -eq $false) {
3434
Write-Host "Deploying infrastructure..."
3535
$InfrastructureOutputs = (./infra/Deploy-Infrastructure.ps1 `
3636
-DeploymentName $DeploymentName `
@@ -42,10 +42,8 @@ else {
4242
$InfrastructureOutputs = Get-Content -Path './infra/InfrastructureOutputs.json' -Raw | ConvertFrom-Json
4343
}
4444

45-
$OpenAIEndpoint = $InfrastructureOutputs.openAIInfo.value.endpoint
46-
$OpenAICompletionDeployment = $InfrastructureOutputs.openAIInfo.value.completionModelDeploymentName
47-
$OpenAIVisionCompletionDeployment = $InfrastructureOutputs.openAIInfo.value.visionCompletionModelDeploymentName
48-
$DocumentIntelligenceEndpoint = $InfrastructureOutputs.documentIntelligenceInfo.value.endpoint
45+
$OpenAIEndpoint = $InfrastructureOutputs.aiServicesInfo.value.openAIEndpoint
46+
$OpenAICompletionDeployment = $InfrastructureOutputs.aiServicesInfo.value.modelDeploymentName
4947
$StorageAccountName = $InfrastructureOutputs.storageAccountInfo.value.name
5048

5149
Write-Host "Updating local settings..."
@@ -54,12 +52,10 @@ $LocalSettingsPath = './src/AIDocumentPipeline/local.settings.json'
5452
$LocalSettings = Get-Content -Path $LocalSettingsPath -Raw | ConvertFrom-Json
5553
$LocalSettings.Values.OPENAI_ENDPOINT = $OpenAIEndpoint
5654
$LocalSettings.Values.OPENAI_COMPLETION_DEPLOYMENT = $OpenAICompletionDeployment
57-
$LocalSettings.Values.OPENAI_VISION_COMPLETION_DEPLOYMENT = $OpenAIVisionCompletionDeployment
58-
$LocalSettings.Values.DOCUMENT_INTELLIGENCE_ENDPOINT = $DocumentIntelligenceEndpoint
5955
$LocalSettings.Values.INVOICES_STORAGE_ACCOUNT_NAME = $StorageAccountName
6056
$LocalSettings | ConvertTo-Json | Out-File -FilePath $LocalSettingsPath -Encoding utf8
6157

62-
if ($IsLocal -eq '$true') {
58+
if ($IsLocal -eq $true) {
6359
Write-Host "Starting local environment..."
6460

6561
docker-compose up

infra/Deploy-Infrastructure.ps1

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,13 @@ Write-Host "Starting infrastructure deployment..."
2626

2727
Push-Location -Path $PSScriptRoot
2828

29-
az --version
29+
$UserPrincipalId = ((az rest --method GET --uri "https://graph.microsoft.com/v1.0/me") | ConvertFrom-Json).id
3030

3131
$DeploymentOutputs = (az deployment sub create --name $DeploymentName --location $Location --template-file './main.bicep' `
3232
--parameters './main.parameters.json' `
3333
--parameters workloadName=$DeploymentName `
3434
--parameters location=$Location `
35+
--parameters userPrincipalId=$UserPrincipalId `
3536
--query properties.outputs -o json) | ConvertFrom-Json
3637
$DeploymentOutputs | ConvertTo-Json | Out-File -FilePath './InfrastructureOutputs.json' -Encoding utf8
3738

infra/abbreviations.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
"languageService": "lang-",
1919
"speechService": "spch-",
2020
"translator": "trsl-",
21-
"aiHub": "aih-"
21+
"aiHub": "aih-",
22+
"aiHubProject": "aihp-"
2223
},
2324
"analytics": {
2425
"analysisServicesServer": "as",
@@ -223,4 +224,4 @@
223224
"virtualDesktopWorkspace": "vdws-",
224225
"virtualDesktopScalingPlan": "vdscaling-"
225226
}
226-
}
227+
}

infra/ai_ml/ai-hub-connection.bicep

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
@export()
2+
@description('Connection information for the AI Hub/Project workspace.')
3+
type connectionInfo = {
4+
@description('Name of the connection.')
5+
name: string
6+
@description('Category of the connection.')
7+
category: string
8+
@description('Indicates whether the connection is shared to all projects.')
9+
isSharedToAll: bool
10+
@description('Target of the connection.')
11+
target: string?
12+
@description('Authentication type for the connection target.')
13+
authType:
14+
| 'AAD'
15+
| 'AccessKey'
16+
| 'AccountKey'
17+
| 'ApiKey'
18+
| 'CustomKeys'
19+
| 'ManagedIdentity'
20+
| 'None'
21+
| 'OAuth2'
22+
| 'PAT'
23+
| 'SAS'
24+
| 'ServicePrincipal'
25+
| 'UsernamePassword'
26+
@description('Credentials for the connection target.')
27+
credentials: object?
28+
@description('Metadata for the connection target.')
29+
metadata: object?
30+
}
31+
32+
@description('Name of the AI Hub/Project workspace associated with the connection.')
33+
param aiHubName string
34+
@description('Connection information.')
35+
param connection connectionInfo
36+
37+
resource hub 'Microsoft.MachineLearningServices/workspaces@2024-04-01-preview' existing = {
38+
name: aiHubName
39+
40+
resource hubConnection 'connections@2024-01-01-preview' = {
41+
name: connection.name
42+
properties: {
43+
category: connection.category
44+
target: connection.target
45+
isSharedToAll: connection.isSharedToAll
46+
authType: connection.authType
47+
credentials: connection.credentials
48+
metadata: connection.metadata
49+
}
50+
}
51+
}
52+
53+
@description('ID for the deployed AI Hub/Project workspace connection resource.')
54+
output id string = hub::hubConnection.id
55+
@description('Name for the deployed AI Hub/Project workspace connection resource.')
56+
output name string = hub::hubConnection.name
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
@description('Name of the resource.')
2+
param name string
3+
@description('Location to deploy the resource. Defaults to the location of the resource group.')
4+
param location string = resourceGroup().location
5+
@description('Tags for the resource.')
6+
param tags object = {}
7+
8+
@export()
9+
@description('Key Vault configuration information for storing keys for serverless endpoint deployments.')
10+
type keyVaultConfigInfo = {
11+
@description('Name of the key vault.')
12+
name: string
13+
@description('Name of the key for the primary key.')
14+
primaryKeySecretName: string
15+
@description('Name of the key for the secondary key.')
16+
secondaryKeySecretName: string
17+
}
18+
19+
@export()
20+
@description('Serverless model information for serverless endpoint deployments.')
21+
type serverlessModelInfo = {
22+
@description('Name of the model. The model ID will be determined by the template.')
23+
name: 'Phi-3-mini-128k-instruct' | null
24+
@description('Model ID. Optional override if the expected model name is not supported. Value may start with azureml://.')
25+
id: string?
26+
}
27+
28+
@export()
29+
@description('Serverless model deployment information.')
30+
type serverlessModelDeploymentInfo = {
31+
@description('Name for the serverless model deployment.')
32+
name: string
33+
@description('Serverless model information.')
34+
model: serverlessModelInfo
35+
@description('Key Vault configuration for the serverless model deployment.')
36+
keyVaultConfig: keyVaultConfigInfo
37+
}
38+
39+
@export()
40+
@description('Output information for serverless endpoint deployments.')
41+
type serverlessModelDeploymentOutputInfo = {
42+
@description('ID for the deployed AI model serverless endpoint resource.')
43+
id: string
44+
@description('Name for the deployed AI model serverless endpoint resource.')
45+
name: string
46+
@description('Inference endpoint for the deployed AI model serverless endpoint resource.')
47+
endpoint: string
48+
@description('Primary key secret name for the deployed AI model serverless endpoint resource.')
49+
primaryKeySecretName: string
50+
@description('Secondary key secret name for the deployed AI model serverless endpoint resource.')
51+
secondaryKeySecretName: string
52+
}
53+
54+
@description('Name for the AI Hub resource to deploy the serverless endpoint to.')
55+
param aiHubName string
56+
@description('Model to deploy as a serverless endpoint.')
57+
param model serverlessModelInfo
58+
@description('Key Vault configuration to store endpoint keys.')
59+
param keyVaultConfig keyVaultConfigInfo?
60+
61+
var models = loadJsonContent('./models.json')
62+
var modelId = contains(model, 'id') ? model.id! : models.serverless[model.name!]
63+
64+
resource aiHub 'Microsoft.MachineLearningServices/workspaces@2024-04-01-preview' existing = {
65+
name: aiHubName
66+
}
67+
68+
resource modelServerlessEndpoint 'Microsoft.MachineLearningServices/workspaces/serverlessEndpoints@2024-04-01-preview' = {
69+
name: name
70+
location: location
71+
tags: tags
72+
parent: aiHub
73+
sku: {
74+
name: 'Consumption'
75+
}
76+
properties: {
77+
modelSettings: {
78+
modelId: modelId
79+
}
80+
}
81+
}
82+
83+
module primaryKeySecret '../security/key-vault-secret.bicep' = if (keyVaultConfig != null) {
84+
name: keyVaultConfig!.primaryKeySecretName
85+
params: {
86+
name: keyVaultConfig!.primaryKeySecretName
87+
keyVaultName: keyVaultConfig!.name
88+
value: modelServerlessEndpoint.listKeys().primaryKey
89+
}
90+
}
91+
92+
module secondaryKeySecret '../security/key-vault-secret.bicep' = if (keyVaultConfig != null) {
93+
name: keyVaultConfig!.secondaryKeySecretName
94+
params: {
95+
name: keyVaultConfig!.secondaryKeySecretName
96+
keyVaultName: keyVaultConfig!.name
97+
value: modelServerlessEndpoint.listKeys().secondaryKey
98+
}
99+
}
100+
101+
@description('ID for the deployed AI model serverless endpoint resource.')
102+
output id string = modelServerlessEndpoint.id
103+
@description('Name for the deployed AI model serverless endpoint resource.')
104+
output name string = modelServerlessEndpoint.name
105+
@description('Inference endpoint for the deployed AI model serverless endpoint resource.')
106+
output endpoint string = modelServerlessEndpoint.properties.inferenceEndpoint.uri
107+
@description('Primary key secret name for the deployed AI model serverless endpoint resource.')
108+
output primaryKeySecretName string = keyVaultConfig != null ? keyVaultConfig!.primaryKeySecretName : ''
109+
@description('Secondary key secret name for the deployed AI model serverless endpoint resource.')
110+
output secondaryKeySecretName string = keyVaultConfig != null ? keyVaultConfig!.secondaryKeySecretName : ''

infra/ai_ml/ai-hub-project.bicep

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import { roleAssignmentInfo } from '../security/managed-identity.bicep'
2+
import { serverlessModelDeploymentInfo, serverlessModelDeploymentOutputInfo } from './ai-hub-model-serverless-endpoint.bicep'
3+
import { connectionInfo } from 'ai-hub-connection.bicep'
4+
5+
@description('Name of the resource.')
6+
param name string
7+
@description('Location to deploy the resource. Defaults to the location of the resource group.')
8+
param location string = resourceGroup().location
9+
@description('Tags for the resource.')
10+
param tags object = {}
11+
12+
@description('Name for the AI Hub resource associated with the AI Hub project.')
13+
param aiHubName string
14+
@description('Friendly name for the AI Hub project.')
15+
param friendlyName string = name
16+
@description('Description for the AI Hub project.')
17+
param descriptionInfo string = 'Azure AI Hub Project'
18+
@description('Whether to enable public network access. Defaults to Enabled.')
19+
@allowed([
20+
'Enabled'
21+
'Disabled'
22+
])
23+
param publicNetworkAccess string = 'Enabled'
24+
@description('Whether or not to use credentials for the system datastores of the workspace. Defaults to identity.')
25+
@allowed([
26+
'accessKey'
27+
'identity'
28+
])
29+
param systemDatastoresAuthMode string = 'identity'
30+
@description('ID for the Managed Identity associated with the AI Hub project. Defaults to the system-assigned identity.')
31+
param identityId string?
32+
@description('Serverless model deployments for the AI Hub project.')
33+
param serverlessModels serverlessModelDeploymentInfo[] = []
34+
@description('Resource connections associated with the AI Hub project.')
35+
param connections connectionInfo[] = []
36+
@description('Role assignments to create for the AI Hub project instance.')
37+
param roleAssignments roleAssignmentInfo[] = []
38+
39+
resource aiHub 'Microsoft.MachineLearningServices/workspaces@2024-04-01-preview' existing = {
40+
name: aiHubName
41+
}
42+
43+
resource aiHubProject 'Microsoft.MachineLearningServices/workspaces@2024-04-01-preview' = {
44+
name: name
45+
location: location
46+
tags: tags
47+
kind: 'Project'
48+
identity: {
49+
type: identityId == null ? 'SystemAssigned' : 'UserAssigned'
50+
userAssignedIdentities: identityId == null
51+
? null
52+
: {
53+
'${identityId}': {}
54+
}
55+
}
56+
sku: {
57+
name: 'Basic'
58+
tier: 'Basic'
59+
}
60+
properties: {
61+
friendlyName: friendlyName
62+
description: descriptionInfo
63+
hubResourceId: aiHub.id
64+
publicNetworkAccess: publicNetworkAccess
65+
systemDatastoresAuthMode: systemDatastoresAuthMode
66+
primaryUserAssignedIdentity: identityId
67+
}
68+
}
69+
70+
module aiHubConnections 'ai-hub-connection.bicep' = [
71+
for connection in connections: {
72+
name: connection.name
73+
params: {
74+
aiHubName: aiHubProject.name
75+
connection: connection
76+
}
77+
}
78+
]
79+
80+
module serverlessModelEndpoints 'ai-hub-model-serverless-endpoint.bicep' = [
81+
for serverlessModel in serverlessModels: {
82+
name: serverlessModel.name
83+
params: {
84+
name: serverlessModel.name
85+
aiHubName: aiHubProject.name
86+
model: serverlessModel.model
87+
keyVaultConfig: serverlessModel.keyVaultConfig
88+
}
89+
}
90+
]
91+
92+
resource assignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [
93+
for roleAssignment in roleAssignments: {
94+
name: guid(aiHubProject.id, roleAssignment.principalId, roleAssignment.roleDefinitionId)
95+
scope: aiHubProject
96+
properties: {
97+
principalId: roleAssignment.principalId
98+
roleDefinitionId: roleAssignment.roleDefinitionId
99+
principalType: roleAssignment.principalType
100+
}
101+
}
102+
]
103+
104+
@description('ID for the deployed AI Hub project resource.')
105+
output id string = aiHubProject.id
106+
@description('Name for the deployed AI Hub project resource.')
107+
output name string = aiHubProject.name
108+
@description('Identity principal ID for the deployed AI Hub project resource.')
109+
output identityPrincipalId string? = identityId == null ? aiHubProject.identity.principalId : identityId
110+
@description('Serverless model deployments for the AI Hub project.')
111+
output serverlessModelDeployments serverlessModelDeploymentOutputInfo[] = [
112+
for (item, index) in serverlessModels: {
113+
id: serverlessModelEndpoints[index].outputs.id
114+
name: serverlessModelEndpoints[index].outputs.name
115+
endpoint: serverlessModelEndpoints[index].outputs.endpoint
116+
primaryKeySecretName: serverlessModelEndpoints[index].outputs.primaryKeySecretName
117+
secondaryKeySecretName: serverlessModelEndpoints[index].outputs.secondaryKeySecretName
118+
}
119+
]

0 commit comments

Comments
 (0)