Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding support to configure a pre-existing Open AI service #45

Merged
merged 4 commits into from
May 11, 2024
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
56 changes: 48 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,30 @@ This solution deploys to either Azure Kubernetes Service (**AKS**) or Azure Cont

#### AKS deployment

```bash
cd ./aks
azd up
```
1. **Optional**: Bring Your Own Azure OpenAI Instance

If you have an existing Azure OpenAI instance, you can use it by setting the following environment variables:

```pwsh
cd ./aks
azd env set OPENAI_NAME <OpenAI Name>
azd env set OPENAI_RESOURCE_GROUP <OpenAI Resource Group>
azd env set OPENAI_SUBSCRIPTION_ID <OpenAI Subscription ID>
```
> [!NOTE]
> Configuration of an external Azure OpenAI service assumes that appropriately named and configured deployments for `completions` and `embeddings` already exist in the configured external Azure OpenAI service. Typical deployment configurations for `completions` and `embeddings` are reflected in the following table:

| Deployment | Model | Capacity |
|-------------|------------------------|----------|
| completions | gpt-35-turbo (0613) | 120K TPM |
| embeddings | text-embedding-ada-002 | 120K TPM |

2. Deploy the solution

```pwsh
cd ./aks
azd up
```

After running `azd up` on the **AKS** deployment and the deployment finishes, you will see the output of the script which will include the URL of the web application. You can click on this URL to open the web application in your browser. The URL is beneath the "Done: Deploying service web" message, and is the second endpoint (the Ingress endpoint of type `LoadBalancer`).

Expand All @@ -106,10 +126,30 @@ If you closed the window and need to find the external IP address of the service

#### ACA deployment

```bash
cd ./aca
azd up
```
1. **Optional**: Bring Your Own Azure OpenAI Instance

If you have an existing Azure OpenAI instance, you can use it by setting the following environment variables:

```pwsh
cd ./aca
azd env set OPENAI_NAME <OpenAI Name>
azd env set OPENAI_RESOURCE_GROUP <OpenAI Resource Group>
azd env set OPENAI_SUBSCRIPTION_ID <OpenAI Subscription ID>
```
> [!NOTE]
> Configuration of an external Azure OpenAI service assumes that appropriately named and configured deployments for `completions` and `embeddings` already exist in the configured external Azure OpenAI service. Typical deployment configurations for `completions` and `embeddings` are reflected in the following table:

| Deployment | Model | Capacity |
|-------------|------------------------|----------|
| completions | gpt-35-turbo (0613) | 120K TPM |
| embeddings | text-embedding-ada-002 | 120K TPM |

2. Deploy the solution

```pwsh
cd ./aca
azd up
```

After running `azd up` on the **ACA** deployment and the deployment finishes, you can locate the URL of the web application by navigating to the deployed resource group in the Azure portal. Click on the link to the new resource group in the output of the script to open the Azure portal.

Expand Down
43 changes: 38 additions & 5 deletions aca/infra/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ param environmentName string
@description('Primary location for all resources')
param location string

param existingOpenAiInstance object

param chatServiceWebApiExists bool
@secure()
param chatServiceWebApiDefinition object
Expand All @@ -19,6 +21,15 @@ param searchDefinition object
@description('Id of the user or app to assign application roles')
param principalId string

var deployOpenAi = empty(existingOpenAiInstance.name)
var azureOpenAiEndpoint = deployOpenAi ? openAi.outputs.endpoint : customerOpenAi.properties.endpoint
var azureOpenAi = deployOpenAi ? openAiInstance : existingOpenAiInstance
var openAiInstance = {
name: openAi.outputs.name
resourceGroup: rg.name
subscriptionId: subscription().subscriptionId
}

// Tags that should be applied to all resources.
//
// Note that 'azd-service-name' tags should be applied separately to service host resources.
Expand All @@ -37,6 +48,18 @@ resource rg 'Microsoft.Resources/resourceGroups@2022-09-01' = {
tags: tags
}

resource customerOpenAiResourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' existing =
if (!deployOpenAi) {
scope: subscription(existingOpenAiInstance.subscriptionId)
name: existingOpenAiInstance.resourceGroup
}

resource customerOpenAi 'Microsoft.CognitiveServices/accounts@2023-05-01' existing =
if (!deployOpenAi) {
name: existingOpenAiInstance.name
scope: customerOpenAiResourceGroup
}

module monitoring './shared/monitoring.bicep' = {
name: 'monitoring'
params: {
Expand Down Expand Up @@ -115,7 +138,7 @@ module keyVault './shared/keyvault.bicep' = {
scope: rg
}

module openAi './shared/openai.bicep' = {
module openAi './shared/openai.bicep' = if (deployOpenAi) {
name: 'openai'
params: {
deployments: [
Expand All @@ -142,7 +165,6 @@ module openAi './shared/openai.bicep' = {
}
}
]
keyvaultName: keyVault.outputs.name
location: location
name: '${abbrs.openAiAccounts}${resourceToken}'
sku: 'S0'
Expand All @@ -163,6 +185,17 @@ module cogSearch './shared/search.bicep' = {
scope: rg
}

module openAiSecrets './shared/openai-secrets.bicep' = {
name: 'openaiSecrets'
scope: rg

params: {
keyvaultName: keyVault.outputs.name
openAiInstance: azureOpenAi
tags: tags
}
}

module storage './shared/storage.bicep' = {
name: 'storage'
params: {
Expand Down Expand Up @@ -270,7 +303,7 @@ module chatServiceWebApi './app/ChatServiceWebApi.bicep' = {
}
{
name: 'MSCosmosDBOpenAI__OpenAI__Endpoint'
value: openAi.outputs.endpoint
value: azureOpenAiEndpoint
}
{
name: 'MSCosmosDBOpenAI__CosmosDB__Endpoint'
Expand All @@ -289,8 +322,8 @@ module chatServiceWebApi './app/ChatServiceWebApi.bicep' = {
}
{
name: 'MSCosmosDBOpenAI__OpenAI__Key'
value: openAi.outputs.keySecretRef
secretRef: openAi.outputs.keySecretName
value: openAiSecrets.outputs.keySecretRef
secretRef: openAiSecrets.outputs.keySecretName
}
{
name: 'MSCosmosDBOpenAI__CosmosDB__Key'
Expand Down
7 changes: 7 additions & 0 deletions aca/infra/main.parameters.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@
"location": {
"value": "${AZURE_LOCATION}"
},
"existingOpenAiInstance": {
"value": {
"name": "${OPENAI_NAME}",
"resourceGroup": "${OPENAI_RESOURCE_GROUP}",
"subscriptionId": "${OPENAI_SUBSCRIPTION_ID}"
}
},
"chatServiceWebApiExists": {
"value": "${SERVICE_CHATSERVICEWEBAPI_RESOURCE_EXISTS=false}"
},
Expand Down
25 changes: 25 additions & 0 deletions aca/infra/shared/openai-secrets.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
param keyvaultName string
param openAiInstance object
param tags object = {}

resource apiKeySecret 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = {
name: '${keyvaultName}/openai-apikey'
tags: tags

properties: {
value: openAi.listKeys().key1
}
}

resource openAiResourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' existing = {
scope: subscription(openAiInstance.subscriptionId)
name: openAiInstance.resourceGroup
}

resource openAi 'Microsoft.CognitiveServices/accounts@2023-05-01' existing = {
name: openAiInstance.name
scope: openAiResourceGroup
}

output keySecretName string = apiKeySecret.name
output keySecretRef string = apiKeySecret.properties.secretUri
16 changes: 0 additions & 16 deletions aca/infra/shared/openai.bicep
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
param deployments array
param keyvaultName string
param location string = resourceGroup().location
param name string
param sku string = 'S0'
Expand Down Expand Up @@ -39,20 +38,5 @@ resource openAiDeployments 'Microsoft.CognitiveServices/accounts/deployments@202
}
]

resource keyvault 'Microsoft.KeyVault/vaults@2023-02-01' existing = {
name: keyvaultName
}

resource apiKeySecret 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = {
name: 'openai-apikey'
parent: keyvault
tags: tags
properties: {
value: openAi.listKeys().key1
}
}

output endpoint string = openAi.properties.endpoint
output keySecretName string = apiKeySecret.name
output keySecretRef string = apiKeySecret.properties.secretUri
output name string = openAi.name
41 changes: 37 additions & 4 deletions aks/infra/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ param environmentName string
@description('Primary location for all resources')
param location string

param existingOpenAiInstance object

@description('Id of the user or app to assign application roles')
param principalId string = ''

Expand All @@ -19,6 +21,15 @@ var abbrs = loadJsonContent('./abbreviations.json')
var resourceToken = toLower(uniqueString(subscription().id, environmentName, location))
var tags = { 'azd-env-name': environmentName }

var deployOpenAi = empty(existingOpenAiInstance.name)
var azureOpenAiEndpoint = deployOpenAi ? openAi.outputs.endpoint : customerOpenAi.properties.endpoint
var azureOpenAi = deployOpenAi ? openAiInstance : existingOpenAiInstance
var openAiInstance = {
name: openAi.outputs.name
resourceGroup: resourceGroup.name
subscriptionId: subscription().subscriptionId
}

// Resource group to hold all resources
resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = {
name: '${abbrs.resourcesResourceGroups}${environmentName}'
Expand Down Expand Up @@ -64,6 +75,18 @@ module containerRegistryAccess './role-assignments/aks-acr-role-assignment.bicep
}
}

resource customerOpenAiResourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' existing =
if (!deployOpenAi) {
scope: subscription(existingOpenAiInstance.subscriptionId)
name: existingOpenAiInstance.resourceGroup
}

resource customerOpenAi 'Microsoft.CognitiveServices/accounts@2023-05-01' existing =
if (!deployOpenAi) {
name: existingOpenAiInstance.name
scope: customerOpenAiResourceGroup
}

// Monitor application with Azure Monitor
module monitoring './monitoring/monitoring.bicep' = {
name: 'monitoring'
Expand Down Expand Up @@ -125,7 +148,7 @@ module keyVault './resources/keyvault.bicep' = {
scope: resourceGroup
}

module openAi './resources/openai.bicep' = {
module openAi './resources/openai.bicep' = if (deployOpenAi) {
name: 'openai'
params: {
deployments: [
Expand All @@ -152,7 +175,6 @@ module openAi './resources/openai.bicep' = {
}
}
]
keyvaultName: keyVault.outputs.name
location: location
name: '${abbrs.openAiAccounts}${resourceToken}'
sku: 'S0'
Expand All @@ -173,6 +195,17 @@ module cogSearch './resources/search.bicep' = {
scope: resourceGroup
}

module openAiSecrets './resources/openai-secrets.bicep' = {
name: 'openaiSecrets'
scope: resourceGroup

params: {
keyvaultName: keyVault.outputs.name
openAiInstance: azureOpenAi
tags: tags
}
}

module storage './resources/storage.bicep' = {
name: 'storage'
params: {
Expand Down Expand Up @@ -361,7 +394,7 @@ output AZURE_COSMOS_DB_NAME string = cosmos.outputs.name
output AZURE_COSMOS_DB_ENDPOINT string = cosmos.outputs.endpoint
output AZURE_COGNITIVE_SEARCH_NAME string = cogSearch.outputs.name
output AZURE_COGNITIVE_SEARCH_ENDPOINT string = cogSearch.outputs.endpoint
output AZURE_OPENAI_NAME string = openAi.outputs.name
output AZURE_OPENAI_ENDPOINT string = openAi.outputs.endpoint
output AZURE_OPENAI_NAME string = openAiInstance.name
output AZURE_OPENAI_ENDPOINT string = azureOpenAiEndpoint
output AZURE_STORAGE_ACCOUNT_NAME string = storage.outputs.name

9 changes: 8 additions & 1 deletion aks/infra/main.parameters.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,18 @@
"location": {
"value": "${AZURE_LOCATION}"
},
"existingOpenAiInstance": {
"value": {
"name": "${OPENAI_NAME}",
"resourceGroup": "${OPENAI_RESOURCE_GROUP}",
"subscriptionId": "${OPENAI_SUBSCRIPTION_ID}"
}
},
"principalId": {
"value": "${AZURE_PRINCIPAL_ID}"
},
"kubernetesVersion": {
"value": "1.26"
"value": "1.28"
}
}
}
25 changes: 25 additions & 0 deletions aks/infra/resources/openai-secrets.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
param keyvaultName string
param openAiInstance object
param tags object = {}

resource apiKeySecret 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = {
name: '${keyvaultName}/openai-apikey'
tags: tags

properties: {
value: openAi.listKeys().key1
}
}

resource openAiResourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' existing = {
scope: subscription(openAiInstance.subscriptionId)
name: openAiInstance.resourceGroup
}

resource openAi 'Microsoft.CognitiveServices/accounts@2023-05-01' existing = {
name: openAiInstance.name
scope: openAiResourceGroup
}

output keySecretName string = apiKeySecret.name
output keySecretRef string = apiKeySecret.properties.secretUri
16 changes: 0 additions & 16 deletions aks/infra/resources/openai.bicep
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
param deployments array
param keyvaultName string
param location string = resourceGroup().location
param name string
param sku string = 'S0'
Expand Down Expand Up @@ -39,20 +38,5 @@ resource openAiDeployments 'Microsoft.CognitiveServices/accounts/deployments@202
}
]

resource keyvault 'Microsoft.KeyVault/vaults@2023-02-01' existing = {
name: keyvaultName
}

resource apiKeySecret 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = {
name: 'openai-apikey'
parent: keyvault
tags: tags
properties: {
value: openAi.listKeys().key1
}
}

output endpoint string = openAi.properties.endpoint
output keySecretName string = apiKeySecret.name
output keySecretRef string = apiKeySecret.properties.secretUri
output name string = openAi.name