diff --git a/.github/workflows/azure-dev.yml b/.github/workflows/azure-dev.yml index cb211948..64fb457d 100644 --- a/.github/workflows/azure-dev.yml +++ b/.github/workflows/azure-dev.yml @@ -33,6 +33,7 @@ jobs: AZURE_OPENAI_4_EVAL_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_4_EVAL_DEPLOYMENT_NAME }} AZURE_OPENAI_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_DEPLOYMENT_NAME }} AZURE_OPENAI_35_TURBO_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_35_TURBO_DEPLOYMENT_NAME }} + AZURE_OPENAI_NAME: ${{ vars.AZURE_OPENAI_NAME }} AZURE_SEARCH_ENDPOINT: ${{ vars.AZURE_SEARCH_ENDPOINT }} BING_SEARCH_ENDPOINT: ${{ vars.BING_SEARCH_ENDPOINT }} BING_SEARCH_KEY: ${{ secrets.BING_SEARCH_KEY }} diff --git a/.github/workflows/evaluate.yml b/.github/workflows/evaluate.yml index b3b08ba2..94473c8e 100644 --- a/.github/workflows/evaluate.yml +++ b/.github/workflows/evaluate.yml @@ -29,6 +29,7 @@ jobs: AZURE_OPENAI_35_TURBO_DEPLOYMENT_NAME: ${{ vars.AZURE_OPENAI_35_TURBO_DEPLOYMENT_NAME }} AZURE_RESOURCE_GROUP: ${{ vars.AZURE_RESOURCE_GROUP }} AZURE_SEARCH_ENDPOINT: ${{ vars.AZURE_SEARCH_ENDPOINT }} + AZURE_OPENAI_NAME: ${{ vars.AZURE_OPENAI_NAME }} BING_SEARCH_ENDPOINT: ${{ vars.BING_SEARCH_ENDPOINT }} BING_SEARCH_KEY: ${{ secrets.BING_SEARCH_KEY }} diff --git a/azure.yaml b/azure.yaml index 07f94bc0..6ca5d841 100644 --- a/azure.yaml +++ b/azure.yaml @@ -33,5 +33,6 @@ pipeline: - AZURE_OPENAI_35_TURBO_DEPLOYMENT_NAME - AZURE_SEARCH_ENDPOINT - BING_SEARCH_ENDPOINT + - AZURE_OPENAI_NAME secrets: - BING_SEARCH_KEY \ No newline at end of file diff --git a/infra/abbreviations.json b/infra/abbreviations.json new file mode 100644 index 00000000..292beefb --- /dev/null +++ b/infra/abbreviations.json @@ -0,0 +1,136 @@ +{ + "analysisServicesServers": "as", + "apiManagementService": "apim-", + "appConfigurationStores": "appcs-", + "appManagedEnvironments": "cae-", + "appContainerApps": "ca-", + "authorizationPolicyDefinitions": "policy-", + "automationAutomationAccounts": "aa-", + "blueprintBlueprints": "bp-", + "blueprintBlueprintsArtifacts": "bpa-", + "cacheRedis": "redis-", + "cdnProfiles": "cdnp-", + "cdnProfilesEndpoints": "cdne-", + "cognitiveServicesAccounts": "cog-", + "cognitiveServicesFormRecognizer": "cog-fr-", + "cognitiveServicesTextAnalytics": "cog-ta-", + "computeAvailabilitySets": "avail-", + "computeCloudServices": "cld-", + "computeDiskEncryptionSets": "des", + "computeDisks": "disk", + "computeDisksOs": "osdisk", + "computeGalleries": "gal", + "computeSnapshots": "snap-", + "computeVirtualMachines": "vm", + "computeVirtualMachineScaleSets": "vmss-", + "containerInstanceContainerGroups": "ci", + "containerRegistryRegistries": "cr", + "containerServiceManagedClusters": "aks-", + "databricksWorkspaces": "dbw-", + "dataFactoryFactories": "adf-", + "dataLakeAnalyticsAccounts": "dla", + "dataLakeStoreAccounts": "dls", + "dataMigrationServices": "dms-", + "dBforMySQLServers": "mysql-", + "dBforPostgreSQLServers": "psql-", + "devicesIotHubs": "iot-", + "devicesProvisioningServices": "provs-", + "devicesProvisioningServicesCertificates": "pcert-", + "documentDBDatabaseAccounts": "cosmos-", + "eventGridDomains": "evgd-", + "eventGridDomainsTopics": "evgt-", + "eventGridEventSubscriptions": "evgs-", + "eventHubNamespaces": "evhns-", + "eventHubNamespacesEventHubs": "evh-", + "hdInsightClustersHadoop": "hadoop-", + "hdInsightClustersHbase": "hbase-", + "hdInsightClustersKafka": "kafka-", + "hdInsightClustersMl": "mls-", + "hdInsightClustersSpark": "spark-", + "hdInsightClustersStorm": "storm-", + "hybridComputeMachines": "arcs-", + "insightsActionGroups": "ag-", + "insightsComponents": "appi-", + "keyVaultVaults": "kv-", + "kubernetesConnectedClusters": "arck", + "kustoClusters": "dec", + "kustoClustersDatabases": "dedb", + "loadTesting": "lt-", + "logicIntegrationAccounts": "ia-", + "logicWorkflows": "logic-", + "machineLearningServicesWorkspaces": "mlw-", + "managedIdentityUserAssignedIdentities": "id-", + "managementManagementGroups": "mg-", + "migrateAssessmentProjects": "migr-", + "networkApplicationGateways": "agw-", + "networkApplicationSecurityGroups": "asg-", + "networkAzureFirewalls": "afw-", + "networkBastionHosts": "bas-", + "networkConnections": "con-", + "networkDnsZones": "dnsz-", + "networkExpressRouteCircuits": "erc-", + "networkFirewallPolicies": "afwp-", + "networkFirewallPoliciesWebApplication": "waf", + "networkFirewallPoliciesRuleGroups": "wafrg", + "networkFrontDoors": "fd-", + "networkFrontdoorWebApplicationFirewallPolicies": "fdfp-", + "networkLoadBalancersExternal": "lbe-", + "networkLoadBalancersInternal": "lbi-", + "networkLoadBalancersInboundNatRules": "rule-", + "networkLocalNetworkGateways": "lgw-", + "networkNatGateways": "ng-", + "networkNetworkInterfaces": "nic-", + "networkNetworkSecurityGroups": "nsg-", + "networkNetworkSecurityGroupsSecurityRules": "nsgsr-", + "networkNetworkWatchers": "nw-", + "networkPrivateDnsZones": "pdnsz-", + "networkPrivateLinkServices": "pl-", + "networkPublicIPAddresses": "pip-", + "networkPublicIPPrefixes": "ippre-", + "networkRouteFilters": "rf-", + "networkRouteTables": "rt-", + "networkRouteTablesRoutes": "udr-", + "networkTrafficManagerProfiles": "traf-", + "networkVirtualNetworkGateways": "vgw-", + "networkVirtualNetworks": "vnet-", + "networkVirtualNetworksSubnets": "snet-", + "networkVirtualNetworksVirtualNetworkPeerings": "peer-", + "networkVirtualWans": "vwan-", + "networkVpnGateways": "vpng-", + "networkVpnGatewaysVpnConnections": "vcn-", + "networkVpnGatewaysVpnSites": "vst-", + "notificationHubsNamespaces": "ntfns-", + "notificationHubsNamespacesNotificationHubs": "ntf-", + "operationalInsightsWorkspaces": "log-", + "portalDashboards": "dash-", + "powerBIDedicatedCapacities": "pbi-", + "purviewAccounts": "pview-", + "recoveryServicesVaults": "rsv-", + "resourcesResourceGroups": "rg-", + "searchSearchServices": "srch-", + "serviceBusNamespaces": "sb-", + "serviceBusNamespacesQueues": "sbq-", + "serviceBusNamespacesTopics": "sbt-", + "serviceEndPointPolicies": "se-", + "serviceFabricClusters": "sf-", + "signalRServiceSignalR": "sigr", + "sqlManagedInstances": "sqlmi-", + "sqlServers": "sql-", + "sqlServersDataWarehouse": "sqldw-", + "sqlServersDatabases": "sqldb-", + "sqlServersDatabasesStretch": "sqlstrdb-", + "storageStorageAccounts": "st", + "storageStorageAccountsVm": "stvm", + "storSimpleManagers": "ssimp", + "streamAnalyticsCluster": "asa-", + "synapseWorkspaces": "syn", + "synapseWorkspacesAnalyticsWorkspaces": "synw", + "synapseWorkspacesSqlPoolsDedicated": "syndp", + "synapseWorkspacesSqlPoolsSpark": "synsp", + "timeSeriesInsightsEnvironments": "tsi-", + "webServerFarms": "plan-", + "webSitesAppService": "app-", + "webSitesAppServiceEnvironment": "ase-", + "webSitesFunctions": "func-", + "webStaticSites": "stapp-" +} \ No newline at end of file diff --git a/infra/ai.yaml b/infra/ai.yaml new file mode 100644 index 00000000..c1614333 --- /dev/null +++ b/infra/ai.yaml @@ -0,0 +1,28 @@ +# yaml-language-server: $schema=ai.yaml.json + +deployments: + - name: gpt-35-turbo + model: + format: OpenAI + name: gpt-35-turbo + version: "0613" + sku: + name: Standard + capacity: 20 + - name: text-embedding-ada-002 + model: + format: OpenAI + name: text-embedding-ada-002 + version: "2" + sku: + name: "Standard" + capacity: 20 + - name: gpt-4 + model: + format: OpenAI + name: gpt-4o + version: "2024-05-13" + sku: + name: "Standard" + capacity: 20 + diff --git a/infra/ai.yaml.json b/infra/ai.yaml.json new file mode 100644 index 00000000..4910a1f6 --- /dev/null +++ b/infra/ai.yaml.json @@ -0,0 +1,70 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "deployments": { + "type": "array", + "title": "The Azure Open AI model deployments", + "description": "Deploys the listed Azure Open AI models to an Azure Open AI service", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "title": "The model deployment name" + }, + "model": { + "type": "object", + "title": "The Azure Open AI model to deploy", + "description": "Full list of supported models and versions are available at https://learn.microsoft.com/azure/ai-services/openai/concepts/models", + "properties": { + "format": { + "type": "string", + "default": "OpenAI", + "title": "The format of the model" + }, + "name": { + "type": "string", + "title": "The well known name of the model." + }, + "version": { + "type": "string", + "title": "The well known version of the model." + } + }, + "required": [ + "format", + "name", + "version" + ] + }, + "sku": { + "type": "object", + "title": "The SKU to use for deployment. Defaults to Standard with 20 capacity if not specified", + "properties": { + "name": { + "type": "string", + "title": "The SKU name of the deployment. Defaults to Standard if not specified" + }, + "capacity": { + "type": "integer", + "title": "The capacity of the deployment. Defaults to 20 if not specified" + } + }, + "required": [ + "name", + "capacity" + ] + } + }, + "required": [ + "name", + "model" + ] + } + } + }, + "required": [ + "deployments" + ] +} \ No newline at end of file diff --git a/infra/app/aca.bicep b/infra/app/aca.bicep index 2e3c06ba..615a6f65 100644 --- a/infra/app/aca.bicep +++ b/infra/app/aca.bicep @@ -8,13 +8,11 @@ param containerAppsEnvironmentName string param containerRegistryName string param serviceName string = 'aca' -@secure() -param bingApiKey string -param bingApiEndpoint string param openAi_35_turbo_DeploymentName string param openAi_4_DeploymentName string param openAi_4_eval_DeploymentName string param openAiEndpoint string +param openAiName string param openAiApiVersion string param openAiEmbeddingDeploymentName string param openAiType string @@ -22,6 +20,10 @@ param aiSearchEndpoint string param aiSearchIndexName string param appinsights_Connectionstring string +@secure() +param bingApiKey string +param bingApiEndpoint string + module app '../core/host/container-app-upsert.bicep' = { name: '${serviceName}-container-app-module' @@ -61,6 +63,10 @@ module app '../core/host/container-app-upsert.bicep' = { name: 'AZURE_OPENAI_ENDPOINT' value: openAiEndpoint } + { + name: 'AZURE_OPENAI_NAME' + value: openAiName + } { name: 'AZURE_OPENAI_35_TURBO_DEPLOYMENT_NAME' value: openAi_35_turbo_DeploymentName diff --git a/infra/core/ai/cognitiveservices.bicep b/infra/core/ai/cognitiveservices.bicep index fe979c14..47f94bbc 100644 --- a/infra/core/ai/cognitiveservices.bicep +++ b/infra/core/ai/cognitiveservices.bicep @@ -49,6 +49,7 @@ resource deployment 'Microsoft.CognitiveServices/accounts/deployments@2023-05-01 }] output endpoint string = account.properties.endpoint +output endpoints object = account.properties.endpoints output id string = account.id output name string = account.name output skuName string = account.sku.name diff --git a/infra/core/ai/hub-dependencies.bicep b/infra/core/ai/hub-dependencies.bicep new file mode 100644 index 00000000..842db22d --- /dev/null +++ b/infra/core/ai/hub-dependencies.bicep @@ -0,0 +1,170 @@ +param location string = resourceGroup().location +param tags object = {} + +@description('Name of the key vault') +param keyVaultName string +@description('Name of the storage account') +param storageAccountName string +@description('Name of the OpenAI cognitive services') +param openAiName string +@description('Array of OpenAI model deployments') +param openAiModelDeployments array = [] +@description('Name of the Log Analytics workspace') +param logAnalyticsName string = '' +@description('Name of the Application Insights instance') +param applicationInsightsName string = '' +@description('Name of the container registry') +param containerRegistryName string = '' +@description('Name of the Azure Cognitive Search service') +param searchServiceName string = '' + +module keyVault '../security/keyvault.bicep' = { + name: 'keyvault' + params: { + location: location + tags: tags + name: keyVaultName + } +} + +module storageAccount '../storage/storage-account.bicep' = { + name: 'storageAccount' + params: { + location: location + tags: tags + name: storageAccountName + containers: [ + { + name: 'default' + } + ] + files: [ + { + name: 'default' + } + ] + queues: [ + { + name: 'default' + } + ] + tables: [ + { + name: 'default' + } + ] + corsRules: [ + { + allowedOrigins: [ + 'https://mlworkspace.azure.ai' + 'https://ml.azure.com' + 'https://*.ml.azure.com' + 'https://ai.azure.com' + 'https://*.ai.azure.com' + 'https://mlworkspacecanary.azure.ai' + 'https://mlworkspace.azureml-test.net' + ] + allowedMethods: [ + 'GET' + 'HEAD' + 'POST' + 'PUT' + 'DELETE' + 'OPTIONS' + 'PATCH' + ] + maxAgeInSeconds: 1800 + exposedHeaders: [ + '*' + ] + allowedHeaders: [ + '*' + ] + } + ] + deleteRetentionPolicy: { + allowPermanentDelete: false + enabled: false + } + shareDeleteRetentionPolicy: { + enabled: true + days: 7 + } + } +} + +module logAnalytics '../monitor/loganalytics.bicep' = + if (!empty(logAnalyticsName)) { + name: 'logAnalytics' + params: { + location: location + tags: tags + name: logAnalyticsName + } + } + +module applicationInsights '../monitor/applicationinsights.bicep' = + if (!empty(applicationInsightsName) && !empty(logAnalyticsName)) { + name: 'applicationInsights' + params: { + location: location + tags: tags + name: applicationInsightsName + logAnalyticsWorkspaceId: !empty(logAnalyticsName) ? logAnalytics.outputs.id : '' + } + } + +module containerRegistry '../host/container-registry.bicep' = + if (!empty(containerRegistryName)) { + name: 'containerRegistry' + params: { + location: location + tags: tags + name: containerRegistryName + } + } + +module cognitiveServices '../ai/cognitiveservices.bicep' = { + name: 'cognitiveServices' + params: { + location: location + tags: tags + name: openAiName + kind: 'AIServices' + deployments: openAiModelDeployments + } +} + +module searchService '../search/search-services.bicep' = { + name: 'search' + params: { + name: searchServiceName + location: location + semanticSearch: 'standard' + disableLocalAuth: true + } + } +output keyVaultId string = keyVault.outputs.id +output keyVaultName string = keyVault.outputs.name +output keyVaultEndpoint string = keyVault.outputs.endpoint + +output storageAccountId string = storageAccount.outputs.id +output storageAccountName string = storageAccount.outputs.name + +output containerRegistryId string = !empty(containerRegistryName) ? containerRegistry.outputs.id : '' +output containerRegistryName string = !empty(containerRegistryName) ? containerRegistry.outputs.name : '' +output containerRegistryEndpoint string = !empty(containerRegistryName) ? containerRegistry.outputs.loginServer : '' + +output applicationInsightsId string = !empty(applicationInsightsName) ? applicationInsights.outputs.id : '' +output applicationInsightsName string = !empty(applicationInsightsName) ? applicationInsights.outputs.name : '' +output applicationInsightsConnectionString string = !empty(applicationInsightsName) ? applicationInsights.outputs.connectionString : '' +output logAnalyticsWorkspaceId string = !empty(logAnalyticsName) ? logAnalytics.outputs.id : '' +output logAnalyticsWorkspaceName string = !empty(logAnalyticsName) ? logAnalytics.outputs.name : '' + +output openAiId string = cognitiveServices.outputs.id +output openAiName string = cognitiveServices.outputs.name +output openAiEndpoint string = cognitiveServices.outputs.endpoints['OpenAI Language Model Instance API'] + +output searchServiceId string = !empty(searchServiceName) ? searchService.outputs.id : '' +output searchServiceName string = !empty(searchServiceName) ? searchService.outputs.name : '' +output searchServiceEndpoint string = !empty(searchServiceName) ? searchService.outputs.endpoint : '' diff --git a/infra/core/ai/hub.bicep b/infra/core/ai/hub.bicep new file mode 100644 index 00000000..c4b95360 --- /dev/null +++ b/infra/core/ai/hub.bicep @@ -0,0 +1,124 @@ +@description('The AI Studio Hub Resource name') +param name string +@description('The display name of the AI Studio Hub Resource') +param displayName string = name +@description('The storage account ID to use for the AI Studio Hub Resource') +param storageAccountId string +@description('The key vault ID to use for the AI Studio Hub Resource') +param keyVaultId string +@description('The application insights ID to use for the AI Studio Hub Resource') +param applicationInsightsId string = '' +@description('The container registry ID to use for the AI Studio Hub Resource') +param containerRegistryId string = '' +@description('The OpenAI Cognitive Services account name to use for the AI Studio Hub Resource') +param openAiName string +@description('The OpenAI Cognitive Services account connection name to use for the AI Studio Hub Resource') +param openAiConnectionName string +@description('The Azure Cognitive Search service name to use for the AI Studio Hub Resource') +param aiSearchName string = '' +@description('The Azure Cognitive Search service connection name to use for the AI Studio Hub Resource') +param aiSearchConnectionName string +@description('The OpenAI Content Safety connection name to use for the AI Studio Hub Resource') +param openAiContentSafetyConnectionName string + +@description('The SKU name to use for the AI Studio Hub Resource') +param skuName string = 'Basic' +@description('The SKU tier to use for the AI Studio Hub Resource') +@allowed(['Basic', 'Free', 'Premium', 'Standard']) +param skuTier string = 'Basic' +@description('The public network access setting to use for the AI Studio Hub Resource') +@allowed(['Enabled','Disabled']) +param publicNetworkAccess string = 'Enabled' + +param location string = resourceGroup().location +param tags object = {} + +resource hub 'Microsoft.MachineLearningServices/workspaces@2024-01-01-preview' = { + name: name + location: location + tags: tags + sku: { + name: skuName + tier: skuTier + } + kind: 'Hub' + identity: { + type: 'SystemAssigned' + } + properties: { + friendlyName: displayName + storageAccount: storageAccountId + keyVault: keyVaultId + applicationInsights: !empty(applicationInsightsId) ? applicationInsightsId : null + containerRegistry: !empty(containerRegistryId) ? containerRegistryId : null + hbiWorkspace: false + managedNetwork: { + isolationMode: 'Disabled' + } + v1LegacyMode: false + publicNetworkAccess: publicNetworkAccess + } + + resource openAiConnection 'connections' = { + name: openAiConnectionName + properties: { + category: 'AzureOpenAI' + authType: 'ApiKey' + isSharedToAll: true + target: openAi.properties.endpoints['OpenAI Language Model Instance API'] + metadata: { + ApiVersion: '2023-07-01-preview' + ApiType: 'azure' + ResourceId: openAi.id + } + credentials: { + key: openAi.listKeys().key1 + } + } + } + + resource contentSafetyConnection 'connections' = { + name: openAiContentSafetyConnectionName + properties: { + category: 'AzureOpenAI' + authType: 'ApiKey' + isSharedToAll: true + target: openAi.properties.endpoints['Content Safety'] + metadata: { + ApiVersion: '2023-07-01-preview' + ApiType: 'azure' + ResourceId: openAi.id + } + credentials: { + key: openAi.listKeys().key1 + } + } + } + + resource searchConnection 'connections' = + if (!empty(aiSearchName)) { + name: aiSearchConnectionName + properties: { + category: 'CognitiveSearch' + authType: 'ApiKey' + isSharedToAll: true + target: 'https://${search.name}.search.windows.net/' + credentials: { + key: !empty(aiSearchName) ? search.listAdminKeys().primaryKey : '' + } + } + } +} + +resource openAi 'Microsoft.CognitiveServices/accounts@2023-05-01' existing = { + name: openAiName +} + +resource search 'Microsoft.Search/searchServices@2021-04-01-preview' existing = + if (!empty(aiSearchName)) { + name: aiSearchName + } + +output name string = hub.name +output id string = hub.id +output principalId string = hub.identity.principalId diff --git a/infra/core/ai/project.bicep b/infra/core/ai/project.bicep new file mode 100644 index 00000000..78b0d527 --- /dev/null +++ b/infra/core/ai/project.bicep @@ -0,0 +1,75 @@ +@description('The AI Studio Hub Resource name') +param name string +@description('The display name of the AI Studio Hub Resource') +param displayName string = name +@description('The name of the AI Studio Hub Resource where this project should be created') +param hubName string +@description('The name of the key vault resource to grant access to the project') +param keyVaultName string + +@description('The SKU name to use for the AI Studio Hub Resource') +param skuName string = 'Basic' +@description('The SKU tier to use for the AI Studio Hub Resource') +@allowed(['Basic', 'Free', 'Premium', 'Standard']) +param skuTier string = 'Basic' +@description('The public network access setting to use for the AI Studio Hub Resource') +@allowed(['Enabled','Disabled']) +param publicNetworkAccess string = 'Enabled' + +param location string = resourceGroup().location +param tags object = {} + +resource project 'Microsoft.MachineLearningServices/workspaces@2024-01-01-preview' = { + name: name + location: location + tags: tags + sku: { + name: skuName + tier: skuTier + } + kind: 'Project' + identity: { + type: 'SystemAssigned' + } + properties: { + friendlyName: displayName + hbiWorkspace: false + v1LegacyMode: false + publicNetworkAccess: publicNetworkAccess + hubResourceId: hub.id + } +} + +module keyVaultAccess '../security/keyvault-access.bicep' = { + name: 'keyvault-access' + params: { + keyVaultName: keyVaultName + principalId: project.identity.principalId + } +} + +module mlServiceRoleDataScientist '../security/role.bicep' = { + name: 'ml-service-role-data-scientist' + params: { + principalId: project.identity.principalId + roleDefinitionId: 'f6c7c914-8db3-469d-8ca1-694a8f32e121' + principalType: 'ServicePrincipal' + } +} + +module mlServiceRoleSecretsReader '../security/role.bicep' = { + name: 'ml-service-role-secrets-reader' + params: { + principalId: project.identity.principalId + roleDefinitionId: 'ea01e6af-a1c1-4350-9563-ad00f8c72ec5' + principalType: 'ServicePrincipal' + } +} + +resource hub 'Microsoft.MachineLearningServices/workspaces@2024-01-01-preview' existing = { + name: hubName +} + +output id string = project.id +output name string = project.name +output principalId string = project.identity.principalId diff --git a/infra/core/host/ai-environment.bicep b/infra/core/host/ai-environment.bicep new file mode 100644 index 00000000..528a46d9 --- /dev/null +++ b/infra/core/host/ai-environment.bicep @@ -0,0 +1,114 @@ +@minLength(1) +@description('Primary location for all resources') +param location string + +@description('The AI Hub resource name.') +param hubName string +@description('The AI Project resource name.') +param projectName string +@description('The Key Vault resource name.') +param keyVaultName string +@description('The Storage Account resource name.') +param storageAccountName string +@description('The Open AI resource name.') +param openAiName string +@description('The Open AI connection name.') +param openAiConnectionName string +@description('The Open AI model deployments.') +param openAiModelDeployments array = [] +@description('The Open AI content safety connection name.') +param openAiContentSafetyConnectionName string +@description('The Log Analytics resource name.') +param logAnalyticsName string = '' +@description('The Application Insights resource name.') +param applicationInsightsName string = '' +@description('The Container Registry resource name.') +param containerRegistryName string = '' +@description('The Azure Search resource name.') +param searchServiceName string = '' +@description('The Azure Search connection name.') +param searchConnectionName string = '' +param tags object = {} + +module hubDependencies '../ai/hub-dependencies.bicep' = { + name: 'hubDependencies' + params: { + location: location + tags: tags + keyVaultName: keyVaultName + storageAccountName: storageAccountName + containerRegistryName: containerRegistryName + applicationInsightsName: applicationInsightsName + logAnalyticsName: logAnalyticsName + openAiName: openAiName + openAiModelDeployments: openAiModelDeployments + searchServiceName: searchServiceName + } +} + +module hub '../ai/hub.bicep' = { + name: 'hub' + params: { + location: location + tags: tags + name: hubName + displayName: hubName + keyVaultId: hubDependencies.outputs.keyVaultId + storageAccountId: hubDependencies.outputs.storageAccountId + containerRegistryId: hubDependencies.outputs.containerRegistryId + applicationInsightsId: hubDependencies.outputs.applicationInsightsId + openAiName: hubDependencies.outputs.openAiName + openAiConnectionName: openAiConnectionName + openAiContentSafetyConnectionName: openAiContentSafetyConnectionName + aiSearchName: hubDependencies.outputs.searchServiceName + aiSearchConnectionName: searchConnectionName + } +} + +module project '../ai/project.bicep' = { + name: 'project' + params: { + location: location + tags: tags + name: projectName + displayName: projectName + hubName: hub.outputs.name + keyVaultName: hubDependencies.outputs.keyVaultName + } +} + +// Outputs +// Resource Group +output resourceGroupName string = resourceGroup().name + +// Hub +output hubName string = hub.outputs.name +output hubPrincipalId string = hub.outputs.principalId + +// Project +output projectName string = project.outputs.name +output projectPrincipalId string = project.outputs.principalId + +// Key Vault +output keyVaultName string = hubDependencies.outputs.keyVaultName +output keyVaultEndpoint string = hubDependencies.outputs.keyVaultEndpoint + +// Application Insights +output applicationInsightsName string = hubDependencies.outputs.applicationInsightsName +output applicationInsightsConnectionString string = hubDependencies.outputs.applicationInsightsConnectionString +output logAnalyticsWorkspaceName string = hubDependencies.outputs.logAnalyticsWorkspaceName + +// Container Registry +output containerRegistryName string = hubDependencies.outputs.containerRegistryName +output containerRegistryEndpoint string = hubDependencies.outputs.containerRegistryEndpoint + +// Storage Account +output storageAccountName string = hubDependencies.outputs.storageAccountName + +// Open AI +output openAiName string = hubDependencies.outputs.openAiName +output openAiEndpoint string = hubDependencies.outputs.openAiEndpoint + +// Search +output searchServiceName string = hubDependencies.outputs.searchServiceName +output searchServiceEndpoint string = hubDependencies.outputs.searchServiceEndpoint diff --git a/infra/core/host/ml-online-endpoint.bicep b/infra/core/host/ml-online-endpoint.bicep new file mode 100644 index 00000000..cf03e79c --- /dev/null +++ b/infra/core/host/ml-online-endpoint.bicep @@ -0,0 +1,82 @@ +metadata description = 'Creates an Azure Container Registry.' +param name string +param serviceName string +param location string = resourceGroup().location +param tags object = {} +param aiProjectName string +param aiHubName string +param keyVaultName string +param kind string = 'Managed' +param authMode string = 'Key' + +resource endpoint 'Microsoft.MachineLearningServices/workspaces/onlineEndpoints@2023-10-01' = { + name: name + location: location + parent: workspace + kind: kind + tags: union(tags, { 'azd-service-name': serviceName }) + identity: { + type: 'SystemAssigned' + } + properties: { + authMode: authMode + } +} + +var azureMLDataScientist = resourceId('Microsoft.Authorization/roleDefinitions', 'f6c7c914-8db3-469d-8ca1-694a8f32e121') + +resource azureMLDataScientistRoleHub 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(subscription().id, resourceGroup().id, aiHubName, name, azureMLDataScientist) + scope: hubWorkspace + properties: { + principalId: endpoint.identity.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: azureMLDataScientist + } +} + +resource azureMLDataScientistRoleWorkspace 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(subscription().id, resourceGroup().id, aiProjectName, name, azureMLDataScientist) + scope: workspace + properties: { + principalId: endpoint.identity.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: azureMLDataScientist + } +} + +var azureMLWorkspaceConnectionSecretsReader = resourceId( + 'Microsoft.Authorization/roleDefinitions', + 'ea01e6af-a1c1-4350-9563-ad00f8c72ec5' +) + +resource azureMLWorkspaceConnectionSecretsReaderRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(subscription().id, resourceGroup().id, aiProjectName, name, azureMLWorkspaceConnectionSecretsReader) + scope: endpoint + properties: { + principalId: endpoint.identity.principalId + principalType: 'ServicePrincipal' + roleDefinitionId: azureMLWorkspaceConnectionSecretsReader + } +} + +module keyVaultAccess '../security/keyvault-access.bicep' = { + name: '${name}-keyvault-access' + params: { + keyVaultName: keyVaultName + principalId: endpoint.identity.principalId + } +} + +resource hubWorkspace 'Microsoft.MachineLearningServices/workspaces@2023-08-01-preview' existing = { + name: aiHubName +} + +resource workspace 'Microsoft.MachineLearningServices/workspaces@2023-08-01-preview' existing = { + name: aiProjectName +} + +output name string = endpoint.name +output scoringEndpoint string = endpoint.properties.scoringUri +output swaggerEndpoint string = endpoint.properties.swaggerUri +output principalId string = endpoint.identity.principalId diff --git a/infra/core/storage/storage-account.bicep b/infra/core/storage/storage-account.bicep new file mode 100644 index 00000000..6149fb2f --- /dev/null +++ b/infra/core/storage/storage-account.bicep @@ -0,0 +1,101 @@ +metadata description = 'Creates an Azure storage account.' +param name string +param location string = resourceGroup().location +param tags object = {} + +@allowed([ + 'Cool' + 'Hot' + 'Premium' ]) +param accessTier string = 'Hot' +param allowBlobPublicAccess bool = true +param allowCrossTenantReplication bool = true +param allowSharedKeyAccess bool = true +param containers array = [] +param corsRules array = [] +param defaultToOAuthAuthentication bool = false +param deleteRetentionPolicy object = {} +@allowed([ 'AzureDnsZone', 'Standard' ]) +param dnsEndpointType string = 'Standard' +param files array = [] +param kind string = 'StorageV2' +param minimumTlsVersion string = 'TLS1_2' +param queues array = [] +param shareDeleteRetentionPolicy object = {} +param supportsHttpsTrafficOnly bool = true +param tables array = [] +param networkAcls object = { + bypass: 'AzureServices' + defaultAction: 'Allow' +} +@allowed([ 'Enabled', 'Disabled' ]) +param publicNetworkAccess string = 'Enabled' +param sku object = { name: 'Standard_LRS' } + +resource storage 'Microsoft.Storage/storageAccounts@2023-01-01' = { + name: name + location: location + tags: tags + kind: kind + sku: sku + properties: { + accessTier: accessTier + allowBlobPublicAccess: allowBlobPublicAccess + allowCrossTenantReplication: allowCrossTenantReplication + allowSharedKeyAccess: allowSharedKeyAccess + defaultToOAuthAuthentication: defaultToOAuthAuthentication + dnsEndpointType: dnsEndpointType + minimumTlsVersion: minimumTlsVersion + networkAcls: networkAcls + publicNetworkAccess: publicNetworkAccess + supportsHttpsTrafficOnly: supportsHttpsTrafficOnly + } + + resource blobServices 'blobServices' = if (!empty(containers)) { + name: 'default' + properties: { + cors: { + corsRules: corsRules + } + deleteRetentionPolicy: deleteRetentionPolicy + } + resource container 'containers' = [for container in containers: { + name: container.name + properties: { + publicAccess: contains(container, 'publicAccess') ? container.publicAccess : 'None' + } + }] + } + + resource fileServices 'fileServices' = if (!empty(files)) { + name: 'default' + properties: { + cors: { + corsRules: corsRules + } + shareDeleteRetentionPolicy: shareDeleteRetentionPolicy + } + } + + resource queueServices 'queueServices' = if (!empty(queues)) { + name: 'default' + properties: { + + } + resource queue 'queues' = [for queue in queues: { + name: queue.name + properties: { + metadata: {} + } + }] + } + + resource tableServices 'tableServices' = if (!empty(tables)) { + name: 'default' + properties: {} + } +} + +output id string = storage.id +output name string = storage.name +output primaryEndpoints object = storage.properties.primaryEndpoints diff --git a/infra/hooks/postprovision.ps1 b/infra/hooks/postprovision.ps1 index 002a0f07..a0b66a80 100644 --- a/infra/hooks/postprovision.ps1 +++ b/infra/hooks/postprovision.ps1 @@ -40,7 +40,7 @@ azd env get-values > .env Write-Host "Script execution completed successfully." Write-Host 'Installing dependencies from "requirements.txt"' -python -m pip install -r ./src/requirements.txt > $null +python -m pip install -r ./requirements.txt > $null # populate data Write-Host "Populating data ...." diff --git a/infra/hooks/postprovision.sh b/infra/hooks/postprovision.sh index e7618088..7c1eba96 100755 --- a/infra/hooks/postprovision.sh +++ b/infra/hooks/postprovision.sh @@ -45,7 +45,7 @@ COGNITIVE_SERVICE_URL="https://oai.azure.com/portal/${INTERNAL_ID}?tenantid=${AZ echo "--- ✅ | 1. Post-provisioning - env configured ---" # Setup to run notebooks -echo 'Installing dependencies from "src/api/requirements.txt"' +echo 'Installing dependencies from "requirements.txt"' python -m pip install -r src/api/requirements.txt > /dev/null python -m pip install ipython ipykernel > /dev/null # Install ipython and ipykernel ipython kernel install --name=python3 --user > /dev/null # Configure the IPython kernel diff --git a/infra/main.bicep b/infra/main.bicep index 6f7ed8cc..61865f02 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -14,37 +14,40 @@ param environmentName string }) param location string -@description('The name of the OpenAI resource') -param openAiResourceName string = '' - -@description('The name of the resource group for the OpenAI resource') -param openAiResourceGroupName string = '' - -@description('Location for the OpenAI resource') -@allowed([ - 'canadaeast' - 'eastus' - 'eastus2' - 'francecentral' - 'switzerlandnorth' - 'uksouth' - 'japaneast' - 'northcentralus' - 'australiaeast' - 'swedencentral' -]) -@metadata({ - azd: { - type: 'location' - } -}) -param openAiResourceLocation string - -@description('The SKU name of the OpenAI resource') -param openAiSkuName string = '' +param containerRegistryName string = '' +param aiHubName string = '' +@description('The Azure AI Studio project name. If ommited will be generated') +param aiProjectName string = '' +@description('The application insights resource name. If ommited will be generated') +param applicationInsightsName string = '' +@description('The Open AI resource name. If ommited will be generated') +param openAiName string = '' +@description('The Open AI connection name. If ommited will use a default value') +param openAiConnectionName string = '' +@description('The Open AI content safety connection name. If ommited will use a default value') +param openAiContentSafetyConnectionName string = '' +param keyVaultName string = '' +@description('The Azure Storage Account resource name. If ommited will be generated') +param storageAccountName string = '' + +var abbrs = loadJsonContent('./abbreviations.json') +@description('The log analytics workspace name. If ommited will be generated') +param logAnalyticsWorkspaceName string = '' +param useApplicationInsights bool = true +param useContainerRegistry bool = true +param useSearch bool = true +var aiConfig = loadYamlContent('./ai.yaml') +@description('The name of the machine learning online endpoint. If ommited will be generated') +param endpointName string = '' +@description('The name of the azd service to use for the machine learning endpoint') +param endpointServiceName string = 'chat' +param resourceGroupName string = '' + +@description('The Azure Search connection name. If ommited will use a default value') +param searchConnectionName string = '' @description('The API version of the OpenAI resource') -param openAiApiVersion string = '' +param openAiApiVersion string = '2023-07-01-preview' @description('The type of the OpenAI resource') param openAiType string = 'azure' @@ -59,34 +62,18 @@ param bingSearchName string = '' param aiSearchIndexName string = 'contoso-products' @description('The name of the 35 turbo OpenAI deployment') -param openAi_35_turbo_DeploymentName string = '' +param openAi_35_turbo_DeploymentName string = 'gpt-35-turbo' -@description('The name of the 35 turbo OpenAI model') -param openAi_35_ModelName string = '' - -@description('The version of the 35 turbo OpenAI model') -param openAi_35_ModelVersion string = '' @description('The name of the 4 OpenAI deployment') -param openAi_4_DeploymentName string = '' - -@description('The name of the 4 OpenAI model') -param openAi_4_ModelName string = '' +param openAi_4_DeploymentName string = 'gpt-4' -@description('The version of the 4 OpenAI model') -param openAi_4_ModelVersion string = '' @description('The name of the 4 eval OpenAI deployment') -param openAi_4_eval_DeploymentName string = '' - -@description('The name of the 4 eval OpenAI model') -param openAi_4_eval_ModelName string = '' - -@description('The version of the 4 eval OpenAI model') -param openAi_4_eval_ModelVersion string = '' +param openAi_4_eval_DeploymentName string = 'gpt-4' @description('The name of the OpenAI embedding deployment') -param openAiEmbeddingDeploymentName string = '' +param openAiEmbeddingDeploymentName string = 'text-embedding-ada-002' @description('Id of the user or app to assign application roles') param principalId string = '' @@ -101,22 +88,15 @@ var resourceToken = toLower(uniqueString(subscription().id, environmentName, loc var tags = { 'azd-env-name': environmentName } resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { - name: 'rg-${environmentName}' + name: !empty(resourceGroupName) ? resourceGroupName : '${abbrs.resourcesResourceGroups}${environmentName}' location: location tags: tags } -resource openAiResourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' existing = if (!empty(openAiResourceGroupName)) { - name: !empty(openAiResourceGroupName) ? openAiResourceGroupName : resourceGroup.name -} - var prefix = toLower('${environmentName}-${resourceToken}') -//var keyVaultName = replace('${take(prefix, 18)}-vault', '--', '-') - // USER ROLES var principalType = empty(runningOnGh) && empty(runningOnAdo) ? 'User' : 'ServicePrincipal' - module managedIdentity 'core/security/managed-identity.bicep' = { name: 'managed-identity' scope: resourceGroup @@ -127,77 +107,49 @@ module managedIdentity 'core/security/managed-identity.bicep' = { } } -module openAi 'core/ai/cognitiveservices.bicep' = { - name: 'openai' - scope: openAiResourceGroup +module ai 'core/host/ai-environment.bicep' = { + name: 'ai' + scope: resourceGroup params: { - name: !empty(openAiResourceName) ? openAiResourceName : '${resourceToken}-cog' - location: !empty(openAiResourceLocation) ? openAiResourceLocation : location + location: location tags: tags - sku: { - name: !empty(openAiSkuName) ? openAiSkuName : 'S0' - } - deployments: [ - { - name: openAi_35_turbo_DeploymentName - model: { - format: 'OpenAI' - name: openAi_35_ModelName - version: openAi_35_ModelVersion - } - sku: { - name: 'Standard' - capacity: 30 - } - } - { - name: openAi_4_DeploymentName - model: { - format: 'OpenAI' - name: openAi_4_ModelName - version: openAi_4_ModelVersion - } - sku: { - name: 'Standard' - capacity: 20 - } - } - { - name: openAi_4_eval_DeploymentName - model: { - format: 'OpenAI' - name: openAi_4_eval_ModelName - version: openAi_4_eval_ModelVersion - } - sku: { - name: 'Standard' - capacity: 20 - } - } - { - name: openAiEmbeddingDeploymentName - model: { - format: 'OpenAI' - name: 'text-embedding-ada-002' - version: '2' - } - sku: { - name: 'Standard' - capacity: 20 - } - } - ] + hubName: !empty(aiHubName) ? aiHubName : 'ai-hub-${resourceToken}' + projectName: !empty(aiProjectName) ? aiProjectName : 'ai-project-${resourceToken}' + keyVaultName: !empty(keyVaultName) ? keyVaultName : '${abbrs.keyVaultVaults}${resourceToken}' + storageAccountName: !empty(storageAccountName) + ? storageAccountName + : '${abbrs.storageStorageAccounts}${resourceToken}' + openAiName: !empty(openAiName) ? openAiName : 'aoai-${resourceToken}' + openAiConnectionName: !empty(openAiConnectionName) ? openAiConnectionName : 'aoai-connection' + openAiContentSafetyConnectionName: !empty(openAiContentSafetyConnectionName) ? openAiContentSafetyConnectionName : 'aoai-content-safety-connection' + openAiModelDeployments: array(contains(aiConfig, 'deployments') ? aiConfig.deployments : []) + logAnalyticsName: !useApplicationInsights + ? '' + : !empty(logAnalyticsWorkspaceName) + ? logAnalyticsWorkspaceName + : '${abbrs.operationalInsightsWorkspaces}${resourceToken}' + applicationInsightsName: !useApplicationInsights + ? '' + : !empty(applicationInsightsName) ? applicationInsightsName : '${abbrs.insightsComponents}${resourceToken}' + containerRegistryName: !useContainerRegistry + ? '' + : !empty(containerRegistryName) ? containerRegistryName : '${abbrs.containerRegistryRegistries}${resourceToken}' + searchServiceName: !useSearch ? '' : !empty(searchServiceName) ? searchServiceName : '${abbrs.searchSearchServices}${resourceToken}' + searchConnectionName: !useSearch ? '' : !empty(searchConnectionName) ? searchConnectionName : 'search-service-connection' } } -module search 'core/search/search-services.bicep' = { - name: 'search' +module machineLearningEndpoint './core/host/ml-online-endpoint.bicep' = { + name: 'endpoint' scope: resourceGroup params: { - name: !empty(searchServiceName) ? searchServiceName : '${prefix}-search-contoso' + name: !empty(endpointName) ? endpointName : 'mloe-${resourceToken}' location: location - semanticSearch: 'standard' - disableLocalAuth: true + tags: tags + serviceName: endpointServiceName + aiHubName: ai.outputs.hubName + aiProjectName: ai.outputs.projectName + keyVaultName: ai.outputs.keyVaultName } } @@ -210,57 +162,6 @@ module bing 'core/bing/bing-search.bicep' = { } } -//module keyVault 'core/security/keyvault.bicep' = { -// name: 'keyvault' -// scope: resourceGroup -// params: { -// location: location -// tags: tags -// name: keyVaultName -// } -//} -// -//module bingSecret 'core/security/keyvault-secret.bicep' = { -// name: 'bingSecret' -// scope: resourceGroup -// params: { -// name: 'bingApiKey' -// keyVaultName: keyVaultName -// secretValue: bing.outputs.bingApiKey -// } -//} -// -//module keyVaultAccess 'core/security/keyvault-access.bicep' = { -// name: '${prefix}-keyvault-access' -// scope: resourceGroup -// params: { -// keyVaultName: keyVaultName -// principalId: principalId -// } -//} - -module logAnalyticsWorkspace 'core/monitor/loganalytics.bicep' = { - name: 'loganalytics' - scope: resourceGroup - params: { - name: '${prefix}-loganalytics' - location: location - tags: tags - } -} - -module monitoring 'core/monitor/monitoring.bicep' = { - name: 'monitoring' - scope: resourceGroup - params: { - location: location - tags: tags - logAnalyticsName: logAnalyticsWorkspace.name - applicationInsightsName: '${prefix}-appinsights' - applicationInsightsDashboardName: '${prefix}-dashboard' - } -} - // Container apps host (including container registry) module containerApps 'core/host/container-apps.bicep' = { name: 'container-apps' @@ -270,8 +171,8 @@ module containerApps 'core/host/container-apps.bicep' = { location: location tags: tags containerAppsEnvironmentName: '${prefix}-containerapps-env' - containerRegistryName: '${replace(prefix, '-', '')}registry' - logAnalyticsWorkspaceName: logAnalyticsWorkspace.outputs.name + containerRegistryName: ai.outputs.containerRegistryName + logAnalyticsWorkspaceName: ai.outputs.logAnalyticsWorkspaceName } } @@ -290,12 +191,13 @@ module aca 'app/aca.bicep' = { openAi_4_DeploymentName: !empty(openAi_4_DeploymentName) ? openAi_4_DeploymentName : 'gpt-4' openAi_4_eval_DeploymentName: !empty(openAi_4_eval_DeploymentName) ? openAi_4_eval_DeploymentName : 'gpt-4' openAiEmbeddingDeploymentName: openAiEmbeddingDeploymentName - openAiEndpoint: openAi.outputs.endpoint + openAiEndpoint: ai.outputs.openAiEndpoint + openAiName: ai.outputs.openAiName openAiType: openAiType openAiApiVersion: openAiApiVersion - aiSearchEndpoint: search.outputs.endpoint + aiSearchEndpoint: ai.outputs.searchServiceEndpoint aiSearchIndexName: aiSearchIndexName - appinsights_Connectionstring: monitoring.outputs.applicationInsightsConnectionString + appinsights_Connectionstring: ai.outputs.applicationInsightsConnectionString bingApiEndpoint: bing.outputs.endpoint bingApiKey: bing.outputs.bingApiKey } @@ -379,11 +281,10 @@ output AZURE_OPENAI_35_TURBO_DEPLOYMENT_NAME string = openAi_35_turbo_Deployment output AZURE_OPENAI_DEPLOYMENT_NAME string = openAi_4_DeploymentName output AZURE_OPENAI_4_EVAL_DEPLOYMENT_NAME string = openAi_4_eval_DeploymentName output AZURE_OPENAI_API_VERSION string = openAiApiVersion -output AZURE_OPENAI_ENDPOINT string = openAi.outputs.endpoint -output AZURE_OPENAI_NAME string = openAi.outputs.name -output AZURE_OPENAI_RESOURCE_GROUP string = openAiResourceGroup.name -output AZURE_OPENAI_SKU_NAME string = openAi.outputs.skuName -output AZURE_OPENAI_RESOURCE_GROUP_LOCATION string = openAiResourceGroup.location +output AZURE_OPENAI_ENDPOINT string = ai.outputs.openAiEndpoint +output AZURE_OPENAI_NAME string = ai.outputs.openAiName +output AZURE_OPENAI_RESOURCE_GROUP string = resourceGroup.name +output AZURE_OPENAI_RESOURCE_GROUP_LOCATION string = resourceGroup.location output SERVICE_ACA_NAME string = aca.outputs.SERVICE_ACA_NAME output SERVICE_ACA_URI string = aca.outputs.SERVICE_ACA_URI @@ -393,13 +294,13 @@ output AZURE_CONTAINER_ENVIRONMENT_NAME string = containerApps.outputs.environme output AZURE_CONTAINER_REGISTRY_ENDPOINT string = containerApps.outputs.registryLoginServer output AZURE_CONTAINER_REGISTRY_NAME string = containerApps.outputs.registryName -output APPINSIGHTS_CONNECTIONSTRING string = monitoring.outputs.applicationInsightsConnectionString +output APPINSIGHTS_CONNECTIONSTRING string = ai.outputs.applicationInsightsConnectionString output OPENAI_TYPE string = 'azure' output AZURE_EMBEDDING_NAME string = openAiEmbeddingDeploymentName -output AZURE_SEARCH_ENDPOINT string = search.outputs.endpoint -output AZURE_SEARCH_NAME string = search.outputs.name +output AZURE_SEARCH_ENDPOINT string = ai.outputs.searchServiceEndpoint +output AZURE_SEARCH_NAME string = ai.outputs.searchServiceName output BING_SEARCH_ENDPOINT string = bing.outputs.endpoint output BING_SEARCH_KEY string = bing.outputs.bingApiKey diff --git a/infra/main.bicepparam b/infra/main.bicepparam new file mode 100644 index 00000000..a733a0bf --- /dev/null +++ b/infra/main.bicepparam @@ -0,0 +1,22 @@ +using './main.bicep' + +param environmentName = readEnvironmentVariable('AZURE_ENV_NAME', 'MY_ENV') +param location = readEnvironmentVariable('AZURE_LOCATION', 'eastus2') +param principalId = readEnvironmentVariable('AZURE_PRINCIPAL_ID', '') +param resourceGroupName = readEnvironmentVariable('AZURE_RESOURCE_GROUP', '') + +param aiHubName = readEnvironmentVariable('AZUREAI_HUB_NAME', '') +param aiProjectName = readEnvironmentVariable('AZUREAI_PROJECT_NAME', '') +param endpointName = readEnvironmentVariable('AZUREAI_ENDPOINT_NAME', '') + +param openAiName = readEnvironmentVariable('AZURE_OPENAI_NAME', '') +param searchServiceName = readEnvironmentVariable('AZURE_SEARCH_SERVICE_NAME', '') + +param applicationInsightsName = readEnvironmentVariable('AZURE_APPLICATION_INSIGHTS_NAME', '') +param keyVaultName = readEnvironmentVariable('AZURE_KEYVAULT_NAME', '') +param storageAccountName = readEnvironmentVariable('AZURE_STORAGE_ACCOUNT_NAME', '') +param logAnalyticsWorkspaceName = readEnvironmentVariable('AZURE_LOG_ANALYTICS_WORKSPACE_NAME', '') + +param useContainerRegistry = bool(readEnvironmentVariable('USE_CONTAINER_REGISTRY', 'true')) +param useApplicationInsights = bool(readEnvironmentVariable('USE_APPLICATION_INSIGHTS', 'true')) +param useSearch = bool(readEnvironmentVariable('USE_SEARCH_SERVICE', 'true')) diff --git a/infra/main.parameters.json b/infra/main.parameters.json index 22fc28ba..f6d8f10e 100644 --- a/infra/main.parameters.json +++ b/infra/main.parameters.json @@ -57,4 +57,4 @@ "value": "${TF_BUILD}" } } -} \ No newline at end of file +} diff --git a/src/api/api/agents/designer/designer.py b/src/api/api/agents/designer/designer.py index 38f010b6..a2053168 100644 --- a/src/api/api/agents/designer/designer.py +++ b/src/api/api/agents/designer/designer.py @@ -9,7 +9,7 @@ def design(request, instructions, feedback): configuration = AzureOpenAIModelConfiguration( azure_deployment=os.getenv("AZURE_OPENAI_DEPLOYMENT_NAME"), api_version=os.getenv("AZURE_OPENAI_API_VERSION"), - azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT") + azure_endpoint=f"https://{os.getenv('AZURE_OPENAI_NAME')}.cognitiveservices.azure.com/" ) override_model = { diff --git a/src/api/api/agents/editor/editor.py b/src/api/api/agents/editor/editor.py index f37b97e6..da8555d5 100644 --- a/src/api/api/agents/editor/editor.py +++ b/src/api/api/agents/editor/editor.py @@ -14,7 +14,7 @@ def edit(article, feedback): configuration = AzureOpenAIModelConfiguration( azure_deployment=os.getenv("AZURE_OPENAI_DEPLOYMENT_NAME"), api_version=os.getenv("AZURE_OPENAI_API_VERSION"), - azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT") + azure_endpoint=f"https://{os.getenv('AZURE_OPENAI_NAME')}.cognitiveservices.azure.com/" ) override_model = { "configuration": configuration, diff --git a/src/api/api/agents/product/product.py b/src/api/api/agents/product/product.py index 6a65b831..d82111df 100644 --- a/src/api/api/agents/product/product.py +++ b/src/api/api/agents/product/product.py @@ -22,7 +22,7 @@ def get_embedding(request: str): ) client = AzureOpenAI( - azure_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT"), + azure_endpoint = f"https://{os.getenv('AZURE_OPENAI_NAME')}.cognitiveservices.azure.com/", api_version=os.environ["AZURE_OPENAI_API_VERSION"], azure_ad_token_provider=token_provider ) diff --git a/src/api/api/agents/researcher/researcher.py b/src/api/api/agents/researcher/researcher.py index b54a8eed..127c6285 100644 --- a/src/api/api/agents/researcher/researcher.py +++ b/src/api/api/agents/researcher/researcher.py @@ -92,8 +92,8 @@ def execute(context: str, instructions: str, feedback: str = ""): # create path to prompty file configuration = AzureOpenAIModelConfiguration( azure_deployment=os.getenv("AZURE_OPENAI_35_TURBO_DEPLOYMENT_NAME"), - api_version=os.getenv("AZURE_OPENAI_API_VERSION"), - azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT") + api_version="2023-07-01-preview", + azure_endpoint=f"https://{os.getenv('AZURE_OPENAI_NAME')}.cognitiveservices.azure.com/" ) override_model = { "configuration": configuration, diff --git a/src/api/api/agents/writer/writer.py b/src/api/api/agents/writer/writer.py index 979243ba..eb5944df 100644 --- a/src/api/api/agents/writer/writer.py +++ b/src/api/api/agents/writer/writer.py @@ -14,7 +14,7 @@ def execute(context, feedback, instructions, research, products): configuration = AzureOpenAIModelConfiguration( azure_deployment=os.getenv("AZURE_OPENAI_DEPLOYMENT_NAME"), api_version=os.getenv("AZURE_OPENAI_API_VERSION"), - azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT") + azure_endpoint=f"https://{os.getenv('AZURE_OPENAI_NAME')}.cognitiveservices.azure.com/" ) override_model = { diff --git a/src/api/api/evaluate/evaluate.py b/src/api/api/evaluate/evaluate.py index ea9b9ff0..2fcfd917 100644 --- a/src/api/api/evaluate/evaluate.py +++ b/src/api/api/evaluate/evaluate.py @@ -137,7 +137,7 @@ def evaluate_row(request, instructions): model_config = AzureOpenAIModelConfiguration( azure_deployment=os.environ["AZURE_OPENAI_4_EVAL_DEPLOYMENT_NAME"], api_version=os.environ["AZURE_OPENAI_API_VERSION"], - azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"] + azure_endpoint=f"https://{os.getenv('AZURE_OPENAI_NAME')}.cognitiveservices.azure.com/" ) start=time.time() diff --git a/src/api/api/evaluate/evaluators.py b/src/api/api/evaluate/evaluators.py index 83a69717..bca38cf7 100644 --- a/src/api/api/evaluate/evaluators.py +++ b/src/api/api/evaluate/evaluators.py @@ -36,7 +36,7 @@ def evaluate_article(data, trace_context): configuration = AzureOpenAIModelConfiguration( azure_deployment=os.environ["AZURE_OPENAI_4_EVAL_DEPLOYMENT_NAME"], api_version=os.environ["AZURE_OPENAI_API_VERSION"], - azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"] + azure_endpoint=f"https://{os.getenv('AZURE_OPENAI_NAME')}.cognitiveservices.azure.com/" ) evaluator = ArticleEvaluator(configuration) results = evaluator(query=data['query'], context=data['context'], response=data['response'])