diff --git a/.github/workflows/copilot-deploy-infra.yml b/.github/workflows/copilot-deploy-infra.yml index 8c243fd29..63a549182 100644 --- a/.github/workflows/copilot-deploy-infra.yml +++ b/.github/workflows/copilot-deploy-infra.yml @@ -59,4 +59,4 @@ jobs: inlineScript: | AI_SERVICE_KEY=$(az cognitiveservices account keys list --name ${{vars.AZUREOPENAI__NAME}} --resource-group ${{vars.AZUREOPENAI_DEPLOYMENT_GROUP_NAME}} | jq -r '.key1') echo "::add-mask::$AI_SERVICE_KEY" - scripts/deploy/deploy-azure.sh --subscription ${{secrets.AZURE_SUBSCRIPTION_ID}} --resource-group ${{vars.CC_DEPLOYMENT_GROUP_NAME}} --deployment-name ${{steps.deployment-id.outputs.deployment_name}} --region ${{vars.CC_DEPLOYMENT_REGION}} --client-id ${{vars.BACKEND_CLIENT_ID}} --frontend-client-id ${{vars.APPLICATION_CLIENT_ID}} --tenant-id ${{secrets.AZURE_TENANT_ID}} --instance ${{vars.AZURE_INSTANCE}} --ai-service AzureOpenAI --ai-endpoint ${{secrets.AZURE_OPENAI_ENDPOINT}} --ai-service-key $AI_SERVICE_KEY --app-service-sku ${{vars.WEBAPP_API_SKU}} --no-deploy-package --debug-deployment + scripts/deploy/deploy-azure.sh --subscription ${{secrets.AZURE_SUBSCRIPTION_ID}} --resource-group ${{vars.CC_DEPLOYMENT_GROUP_NAME}} --deployment-name ${{steps.deployment-id.outputs.deployment_name}} --region ${{vars.CC_DEPLOYMENT_REGION}} --client-id ${{vars.BACKEND_CLIENT_ID}} --frontend-client-id ${{vars.APPLICATION_CLIENT_ID}} --tenant-id ${{secrets.AZURE_TENANT_ID}} --instance ${{vars.AZURE_INSTANCE}} --ai-service AzureOpenAI --ai-endpoint ${{secrets.AZURE_OPENAI_ENDPOINT}} --ai-service-key $AI_SERVICE_KEY --app-service-sku ${{vars.WEBAPP_API_SKU}} --no-deploy-package --debug-deployment --deploy-web-searcher-plugin diff --git a/scripts/deploy/README.md b/scripts/deploy/README.md index 400716a4a..5b93a17e6 100644 --- a/scripts/deploy/README.md +++ b/scripts/deploy/README.md @@ -152,10 +152,13 @@ chmod +x ./deploy-webapi.sh # Deploy Hosted Plugins -> **_NOTE:_** This step can be skipped if the previous Azure Resources creation step succeeded without errors. The `deployWebSearcherPackage = true` setting in main.bicep ensures that the WebSearcher is deployed. +> **_NOTE:_** This step can be skipped if the required resources for the web searcher plugin are not deployed. The required resources include a Bing resource and an Azure Function. The required resources are NOT deployed by default. To deploy the required resources, use the `-DeployWebSearcherPlugin` or `--deploy-web-searcher-plugin` flag when running the **deploy-azure.ps1/deploy-azure.sh** script. + +> **_NOTE:_** This step can be skipped if the previous Azure Resources creation step, including the resources required by the Web Search plugin, succeeded without errors. The `deployPackages = true` setting in main.bicep ensures that the WebSearcher is deployed. + > **_NOTE:_** More hosted plugins will be available. -To deploy the plugins, build the packages first and deploy then to the Azure resources created above. +To deploy the plugins, build the packages first and deploy them to the Azure resources created above. ## PowerShell @@ -177,9 +180,9 @@ chmod +x ./deploy-plugins.sh # (Optional) Deploy Memory Pipeline -> **_NOTE:_** This step can be skipped if the WebApi is not configured to run asynchronously for document processing. By default, the WebApi is configured to run asynchronously for document processing in deployment. +> **_NOTE:_** This step can be skipped if the WebApi is NOT configured to run asynchronously for document processing. By default, the WebApi is configured to run asynchronously for document processing in deployment. -> **_NOTE:_** This step can be skipped if the previous Azure Resources creation step succeeded without errors. The deployMemoryPipelinePackage = true setting in main.bicep ensures that the latest Chat Copilot memory pipeline is deployed. +> **_NOTE:_** This step can be skipped if the previous Azure Resources creation step succeeded without errors. The deployPackages = true setting in main.bicep ensures that the latest Chat Copilot memory pipeline is deployed. To deploy the memorypipeline, build the deployment package first and deploy it to the Azure resources created above. diff --git a/scripts/deploy/deploy-azure.ps1 b/scripts/deploy/deploy-azure.ps1 index 6fe55ceb9..c82787f6a 100644 --- a/scripts/deploy/deploy-azure.ps1 +++ b/scripts/deploy/deploy-azure.ps1 @@ -71,6 +71,10 @@ param( # Don't deploy Speech Services to enable speech as chat input $NoSpeechServices, + [switch] + # Deploy the web searcher plugin + $DeployWebSearcherPlugin, + [switch] # Switches on verbose template deployment output $DebugDeployment, @@ -118,7 +122,8 @@ $jsonConfig = " `\`"deployNewAzureOpenAI`\`": { `\`"value`\`": $(If ($DeployAzureOpenAI) {"true"} Else {"false"}) }, `\`"memoryStore`\`": { `\`"value`\`": `\`"$MemoryStore`\`" }, `\`"deployCosmosDB`\`": { `\`"value`\`": $(If (!($NoCosmosDb)) {"true"} Else {"false"}) }, - `\`"deploySpeechServices`\`": { `\`"value`\`": $(If (!($NoSpeechServices)) {"true"} Else {"false"}) } + `\`"deploySpeechServices`\`": { `\`"value`\`": $(If (!($NoSpeechServices)) {"true"} Else {"false"}) }, + `\`"deployWebSearcherPlugin`\`": { `\`"value`\`": $(If ($DeployWebSearcherPlugin) {"true"} Else {"false"}) } } " diff --git a/scripts/deploy/deploy-azure.sh b/scripts/deploy/deploy-azure.sh index dac1f827e..81f89d522 100755 --- a/scripts/deploy/deploy-azure.sh +++ b/scripts/deploy/deploy-azure.sh @@ -25,6 +25,7 @@ usage() { echo " \"AzureCognitiveSearch\" (default) and \"Qdrant\"" echo " -nc, --no-cosmos-db Don't deploy Cosmos DB for chat storage - Use volatile memory instead" echo " -ns, --no-speech-services Don't deploy Speech Services to enable speech as chat input" + echo " -ws, --deploy-web-searcher-plugin Deploy the web searcher plugin" echo " -dd, --debug-deployment Switches on verbose template deployment output" echo " -ndp, --no-deploy-package Skips deploying binary packages to cloud when set." } @@ -105,6 +106,10 @@ while [[ $# -gt 0 ]]; do NO_SPEECH_SERVICES=true shift ;; + -ws | --deploy-web-searcher-plugin) + DEPLOY_WEB_SEARCHER_PLUGIN=true + shift + ;; -dd | --debug-deployment) DEBUG_DEPLOYMENT=true shift @@ -182,6 +187,7 @@ az account set -s "$SUBSCRIPTION" : "${MEMORY_STORE:="AzureCognitiveSearch"}" : "${NO_COSMOS_DB:=false}" : "${NO_SPEECH_SERVICES:=false}" +: "${DEPLOY_WEB_SEARCHER_PLUGIN:=false}" # Create JSON config JSON_CONFIG=$( @@ -199,7 +205,8 @@ JSON_CONFIG=$( "deployNewAzureOpenAI": { "value": $([ "$NO_NEW_AZURE_OPENAI" = true ] && echo "false" || echo "true") }, "memoryStore": { "value": "$MEMORY_STORE" }, "deployCosmosDB": { "value": $([ "$NO_COSMOS_DB" = true ] && echo "false" || echo "true") }, - "deploySpeechServices": { "value": $([ "$NO_SPEECH_SERVICES" = true ] && echo "false" || echo "true") } + "deploySpeechServices": { "value": $([ "$NO_SPEECH_SERVICES" = true ] && echo "false" || echo "true") }, + "deployWebSearcherPlugin": { "value": $([ "$DEPLOY_WEB_SEARCHER_PLUGIN" = true ] && echo "true" || echo "false") } } EOF ) diff --git a/scripts/deploy/main.bicep b/scripts/deploy/main.bicep index 13f6c34c6..a3d2d66b1 100644 --- a/scripts/deploy/main.bicep +++ b/scripts/deploy/main.bicep @@ -75,6 +75,9 @@ param memoryStore string = 'AzureCognitiveSearch' @description('Whether to deploy Azure Speech Services to enable input by voice') param deploySpeechServices bool = true +@description('Whether to deploy the web searcher plugin, which requires a Bing resource') +param deployWebSearcherPlugin bool = false + @description('Whether to deploy binary packages to the cloud') param deployPackages bool = true @@ -177,232 +180,235 @@ resource appServiceWebConfig 'Microsoft.Web/sites/config@2022-09-01' = { use32BitWorkerProcess: false vnetRouteAllEnabled: true webSocketsEnabled: true - appSettings: [ - { - name: 'Authentication:Type' - value: 'AzureAd' - } - { - name: 'Authentication:AzureAd:Instance' - value: azureAdInstance - } - { - name: 'Authentication:AzureAd:TenantId' - value: azureAdTenantId - } - { - name: 'Authentication:AzureAd:ClientId' - value: webApiClientId - } - { - name: 'Authentication:AzureAd:Scopes' - value: 'access_as_user' - } - { - name: 'Planner:Model' - value: plannerModel - } - { - name: 'ChatStore:Type' - value: deployCosmosDB ? 'cosmos' : 'volatile' - } - { - name: 'ChatStore:Cosmos:Database' - value: 'CopilotChat' - } - { - name: 'ChatStore:Cosmos:ChatSessionsContainer' - value: 'chatsessions' - } - { - name: 'ChatStore:Cosmos:ChatMessagesContainer' - value: 'chatmessages' - } - { - name: 'ChatStore:Cosmos:ChatMemorySourcesContainer' - value: 'chatmemorysources' - } - { - name: 'ChatStore:Cosmos:ChatParticipantsContainer' - value: 'chatparticipants' - } - { - name: 'ChatStore:Cosmos:ConnectionString' - value: deployCosmosDB ? cosmosAccount.listConnectionStrings().connectionStrings[0].connectionString : '' - } - { - name: 'AzureSpeech:Region' - value: location - } - { - name: 'AzureSpeech:Key' - value: deploySpeechServices ? speechAccount.listKeys().key1 : '' - } - { - name: 'AllowedOrigins' - value: '[*]' // Defer list of allowed origins to the Azure service app's CORS configuration - } - { - name: 'Kestrel:Endpoints:Https:Url' - value: 'https://localhost:443' - } - { - name: 'Frontend:AadClientId' - value: frontendClientId - } - { - name: 'Logging:LogLevel:Default' - value: 'Warning' - } - { - name: 'Logging:LogLevel:CopilotChat.WebApi' - value: 'Warning' - } - { - name: 'Logging:LogLevel:Microsoft.SemanticKernel' - value: 'Warning' - } - { - name: 'Logging:LogLevel:Microsoft.AspNetCore.Hosting' - value: 'Warning' - } - { - name: 'Logging:LogLevel:Microsoft.Hosting.Lifetimel' - value: 'Warning' - } - { - name: 'Logging:ApplicationInsights:LogLevel:Default' - value: 'Warning' - } - { - name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' - value: appInsights.properties.ConnectionString - } - { - name: 'ApplicationInsightsAgent_EXTENSION_VERSION' - value: '~2' - } - { - name: 'SemanticMemory:ContentStorageType' - value: 'AzureBlobs' - } - { - name: 'SemanticMemory:TextGeneratorType' - value: aiService - } - { - name: 'SemanticMemory:DataIngestion:OrchestrationType' - value: 'Distributed' - } - { - name: 'SemanticMemory:DataIngestion:DistributedOrchestration:QueueType' - value: 'AzureQueue' - } - { - name: 'SemanticMemory:DataIngestion:EmbeddingGeneratorTypes:0' - value: aiService - } - { - name: 'SemanticMemory:DataIngestion:VectorDbTypes:0' - value: memoryStore - } - { - name: 'SemanticMemory:Retrieval:VectorDbType' - value: memoryStore - } - { - name: 'SemanticMemory:Retrieval:EmbeddingGeneratorType' - value: aiService - } - { - name: 'SemanticMemory:Services:AzureBlobs:Auth' - value: 'ConnectionString' - } - { - name: 'SemanticMemory:Services:AzureBlobs:ConnectionString' - value: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};AccountKey=${storage.listKeys().keys[1].value}' - } - { - name: 'SemanticMemory:Services:AzureBlobs:Container' - value: 'chatmemory' - } - { - name: 'SemanticMemory:Services:AzureQueue:Auth' - value: 'ConnectionString' - } - { - name: 'SemanticMemory:Services:AzureQueue:ConnectionString' - value: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};AccountKey=${storage.listKeys().keys[1].value}' - } - { - name: 'SemanticMemory:Services:AzureCognitiveSearch:Auth' - value: 'ApiKey' - } - { - name: 'SemanticMemory:Services:AzureCognitiveSearch:Endpoint' - value: memoryStore == 'AzureCognitiveSearch' ? 'https://${azureCognitiveSearch.name}.search.windows.net' : '' - } - { - name: 'SemanticMemory:Services:AzureCognitiveSearch:APIKey' - value: memoryStore == 'AzureCognitiveSearch' ? azureCognitiveSearch.listAdminKeys().primaryKey : '' - } - { - name: 'SemanticMemory:Services:Qdrant:Endpoint' - value: memoryStore == 'Qdrant' ? 'https://${appServiceQdrant.properties.defaultHostName}' : '' - } - { - name: 'SemanticMemory:Services:AzureOpenAIText:Auth' - value: 'ApiKey' - } - { - name: 'SemanticMemory:Services:AzureOpenAIText:Endpoint' - value: deployNewAzureOpenAI ? openAI.properties.endpoint : aiEndpoint - } - { - name: 'SemanticMemory:Services:AzureOpenAIText:APIKey' - value: deployNewAzureOpenAI ? openAI.listKeys().key1 : aiApiKey - } - { - name: 'SemanticMemory:Services:AzureOpenAIText:Deployment' - value: completionModel - } - { - name: 'SemanticMemory:Services:AzureOpenAIEmbedding:Auth' - value: 'ApiKey' - } - { - name: 'SemanticMemory:Services:AzureOpenAIEmbedding:Endpoint' - value: deployNewAzureOpenAI ? openAI.properties.endpoint : aiEndpoint - } - { - name: 'SemanticMemory:Services:AzureOpenAIEmbedding:APIKey' - value: deployNewAzureOpenAI ? openAI.listKeys().key1 : aiApiKey - } - { - name: 'SemanticMemory:Services:AzureOpenAIEmbedding:Deployment' - value: embeddingModel - } - { - name: 'Plugins:0:Name' - value: 'Klarna Shopping' - } - { - name: 'Plugins:0:ManifestDomain' - value: 'https://www.klarna.com' - } - { - name: 'Plugins:1:Name' - value: 'WebSearcher' - } - { - name: 'Plugins:1:ManifestDomain' - value: 'https://${functionAppWebSearcherPlugin.properties.defaultHostName}' - } - { - name: 'Plugins:1:Key' - value: listkeys('${functionAppWebSearcherPlugin.id}/host/default/', '2022-09-01').functionKeys.default - } - ] + appSettings: concat([ + { + name: 'Authentication:Type' + value: 'AzureAd' + } + { + name: 'Authentication:AzureAd:Instance' + value: azureAdInstance + } + { + name: 'Authentication:AzureAd:TenantId' + value: azureAdTenantId + } + { + name: 'Authentication:AzureAd:ClientId' + value: webApiClientId + } + { + name: 'Authentication:AzureAd:Scopes' + value: 'access_as_user' + } + { + name: 'Planner:Model' + value: plannerModel + } + { + name: 'ChatStore:Type' + value: deployCosmosDB ? 'cosmos' : 'volatile' + } + { + name: 'ChatStore:Cosmos:Database' + value: 'CopilotChat' + } + { + name: 'ChatStore:Cosmos:ChatSessionsContainer' + value: 'chatsessions' + } + { + name: 'ChatStore:Cosmos:ChatMessagesContainer' + value: 'chatmessages' + } + { + name: 'ChatStore:Cosmos:ChatMemorySourcesContainer' + value: 'chatmemorysources' + } + { + name: 'ChatStore:Cosmos:ChatParticipantsContainer' + value: 'chatparticipants' + } + { + name: 'ChatStore:Cosmos:ConnectionString' + value: deployCosmosDB ? cosmosAccount.listConnectionStrings().connectionStrings[0].connectionString : '' + } + { + name: 'AzureSpeech:Region' + value: location + } + { + name: 'AzureSpeech:Key' + value: deploySpeechServices ? speechAccount.listKeys().key1 : '' + } + { + name: 'AllowedOrigins' + value: '[*]' // Defer list of allowed origins to the Azure service app's CORS configuration + } + { + name: 'Kestrel:Endpoints:Https:Url' + value: 'https://localhost:443' + } + { + name: 'Frontend:AadClientId' + value: frontendClientId + } + { + name: 'Logging:LogLevel:Default' + value: 'Warning' + } + { + name: 'Logging:LogLevel:CopilotChat.WebApi' + value: 'Warning' + } + { + name: 'Logging:LogLevel:Microsoft.SemanticKernel' + value: 'Warning' + } + { + name: 'Logging:LogLevel:Microsoft.AspNetCore.Hosting' + value: 'Warning' + } + { + name: 'Logging:LogLevel:Microsoft.Hosting.Lifetimel' + value: 'Warning' + } + { + name: 'Logging:ApplicationInsights:LogLevel:Default' + value: 'Warning' + } + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: appInsights.properties.ConnectionString + } + { + name: 'ApplicationInsightsAgent_EXTENSION_VERSION' + value: '~2' + } + { + name: 'SemanticMemory:ContentStorageType' + value: 'AzureBlobs' + } + { + name: 'SemanticMemory:TextGeneratorType' + value: aiService + } + { + name: 'SemanticMemory:DataIngestion:OrchestrationType' + value: 'Distributed' + } + { + name: 'SemanticMemory:DataIngestion:DistributedOrchestration:QueueType' + value: 'AzureQueue' + } + { + name: 'SemanticMemory:DataIngestion:EmbeddingGeneratorTypes:0' + value: aiService + } + { + name: 'SemanticMemory:DataIngestion:VectorDbTypes:0' + value: memoryStore + } + { + name: 'SemanticMemory:Retrieval:VectorDbType' + value: memoryStore + } + { + name: 'SemanticMemory:Retrieval:EmbeddingGeneratorType' + value: aiService + } + { + name: 'SemanticMemory:Services:AzureBlobs:Auth' + value: 'ConnectionString' + } + { + name: 'SemanticMemory:Services:AzureBlobs:ConnectionString' + value: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};AccountKey=${storage.listKeys().keys[1].value}' + } + { + name: 'SemanticMemory:Services:AzureBlobs:Container' + value: 'chatmemory' + } + { + name: 'SemanticMemory:Services:AzureQueue:Auth' + value: 'ConnectionString' + } + { + name: 'SemanticMemory:Services:AzureQueue:ConnectionString' + value: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};AccountKey=${storage.listKeys().keys[1].value}' + } + { + name: 'SemanticMemory:Services:AzureCognitiveSearch:Auth' + value: 'ApiKey' + } + { + name: 'SemanticMemory:Services:AzureCognitiveSearch:Endpoint' + value: memoryStore == 'AzureCognitiveSearch' ? 'https://${azureCognitiveSearch.name}.search.windows.net' : '' + } + { + name: 'SemanticMemory:Services:AzureCognitiveSearch:APIKey' + value: memoryStore == 'AzureCognitiveSearch' ? azureCognitiveSearch.listAdminKeys().primaryKey : '' + } + { + name: 'SemanticMemory:Services:Qdrant:Endpoint' + value: memoryStore == 'Qdrant' ? 'https://${appServiceQdrant.properties.defaultHostName}' : '' + } + { + name: 'SemanticMemory:Services:AzureOpenAIText:Auth' + value: 'ApiKey' + } + { + name: 'SemanticMemory:Services:AzureOpenAIText:Endpoint' + value: deployNewAzureOpenAI ? openAI.properties.endpoint : aiEndpoint + } + { + name: 'SemanticMemory:Services:AzureOpenAIText:APIKey' + value: deployNewAzureOpenAI ? openAI.listKeys().key1 : aiApiKey + } + { + name: 'SemanticMemory:Services:AzureOpenAIText:Deployment' + value: completionModel + } + { + name: 'SemanticMemory:Services:AzureOpenAIEmbedding:Auth' + value: 'ApiKey' + } + { + name: 'SemanticMemory:Services:AzureOpenAIEmbedding:Endpoint' + value: deployNewAzureOpenAI ? openAI.properties.endpoint : aiEndpoint + } + { + name: 'SemanticMemory:Services:AzureOpenAIEmbedding:APIKey' + value: deployNewAzureOpenAI ? openAI.listKeys().key1 : aiApiKey + } + { + name: 'SemanticMemory:Services:AzureOpenAIEmbedding:Deployment' + value: embeddingModel + } + { + name: 'Plugins:0:Name' + value: 'Klarna Shopping' + } + { + name: 'Plugins:0:ManifestDomain' + value: 'https://www.klarna.com' + } + ], + (deployWebSearcherPlugin) ? [ + { + name: 'Plugins:1:Name' + value: 'WebSearcher' + } + { + name: 'Plugins:1:ManifestDomain' + value: 'https://${functionAppWebSearcherPlugin.properties.defaultHostName}' + } + { + name: 'Plugins:1:Key' + value: listkeys('${functionAppWebSearcherPlugin.id}/host/default/', '2022-09-01').functionKeys.default + } + ] : [] + ) } } @@ -594,7 +600,7 @@ resource appServiceMemoryPipelineDeploy 'Microsoft.Web/sites/extensions@2022-09- ] } -resource functionAppWebSearcherPlugin 'Microsoft.Web/sites@2022-09-01' = { +resource functionAppWebSearcherPlugin 'Microsoft.Web/sites@2022-09-01' = if (deployWebSearcherPlugin) { name: 'function-${uniqueName}-websearcher-plugin' location: location kind: 'functionapp' @@ -610,7 +616,7 @@ resource functionAppWebSearcherPlugin 'Microsoft.Web/sites@2022-09-01' = { } } -resource functionAppWebSearcherPluginConfig 'Microsoft.Web/sites/config@2022-09-01' = { +resource functionAppWebSearcherPluginConfig 'Microsoft.Web/sites/config@2022-09-01' = if (deployWebSearcherPlugin) { parent: functionAppWebSearcherPlugin name: 'web' properties: { @@ -634,13 +640,13 @@ resource functionAppWebSearcherPluginConfig 'Microsoft.Web/sites/config@2022-09- } { name: 'PluginConfig:BingApiKey' - value: bingSearchService.listKeys().key1 + value: (deployWebSearcherPlugin) ? bingSearchService.listKeys().key1 : '' } ] } } -resource functionAppWebSearcherDeploy 'Microsoft.Web/sites/extensions@2022-09-01' = if (deployPackages) { +resource functionAppWebSearcherDeploy 'Microsoft.Web/sites/extensions@2022-09-01' = if (deployPackages && deployWebSearcherPlugin) { name: 'MSDeploy' kind: 'string' parent: functionAppWebSearcherPlugin @@ -677,7 +683,7 @@ resource appInsightExtensionMemory 'Microsoft.Web/sites/siteextensions@2022-09-0 dependsOn: [ appServiceMemoryPipelineDeploy ] } -resource appInsightExtensionWebSearchPlugin 'Microsoft.Web/sites/siteextensions@2022-09-01' = { +resource appInsightExtensionWebSearchPlugin 'Microsoft.Web/sites/siteextensions@2022-09-01' = if (deployWebSearcherPlugin) { parent: functionAppWebSearcherPlugin name: 'Microsoft.ApplicationInsights.AzureWebSites' dependsOn: [ functionAppWebSearcherDeploy ] @@ -1101,7 +1107,7 @@ resource ocrAccount 'Microsoft.CognitiveServices/accounts@2022-12-01' = { } } -resource bingSearchService 'Microsoft.Bing/accounts@2020-06-10' = { +resource bingSearchService 'Microsoft.Bing/accounts@2020-06-10' = if (deployWebSearcherPlugin) { name: 'bing-search-${uniqueName}' location: 'global' sku: { @@ -1113,6 +1119,7 @@ resource bingSearchService 'Microsoft.Bing/accounts@2020-06-10' = { output webapiUrl string = appServiceWeb.properties.defaultHostName output webapiName string = appServiceWeb.name output memoryPipelineName string = appServiceMemoryPipeline.name -output pluginNames array = [ - functionAppWebSearcherPlugin.name -] +output pluginNames array = concat( + [], + (deployWebSearcherPlugin) ? [ functionAppWebSearcherPlugin.name ] : [] +) diff --git a/scripts/deploy/main.json b/scripts/deploy/main.json index 475d3a7f9..243b3c1c6 100644 --- a/scripts/deploy/main.json +++ b/scripts/deploy/main.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.22.6.54827", - "templateHash": "9519863138806302085" + "templateHash": "3283711803726471142" } }, "parameters": { @@ -160,6 +160,13 @@ "description": "Whether to deploy Azure Speech Services to enable input by voice" } }, + "deployWebSearcher": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Whether to the web searcher plugin, which requires a Bing resource" + } + }, "deployPackages": { "type": "bool", "defaultValue": true, @@ -301,232 +308,7 @@ "use32BitWorkerProcess": false, "vnetRouteAllEnabled": true, "webSocketsEnabled": true, - "appSettings": [ - { - "name": "Authentication:Type", - "value": "AzureAd" - }, - { - "name": "Authentication:AzureAd:Instance", - "value": "[parameters('azureAdInstance')]" - }, - { - "name": "Authentication:AzureAd:TenantId", - "value": "[parameters('azureAdTenantId')]" - }, - { - "name": "Authentication:AzureAd:ClientId", - "value": "[parameters('webApiClientId')]" - }, - { - "name": "Authentication:AzureAd:Scopes", - "value": "access_as_user" - }, - { - "name": "Planner:Model", - "value": "[parameters('plannerModel')]" - }, - { - "name": "ChatStore:Type", - "value": "[if(parameters('deployCosmosDB'), 'cosmos', 'volatile')]" - }, - { - "name": "ChatStore:Cosmos:Database", - "value": "CopilotChat" - }, - { - "name": "ChatStore:Cosmos:ChatSessionsContainer", - "value": "chatsessions" - }, - { - "name": "ChatStore:Cosmos:ChatMessagesContainer", - "value": "chatmessages" - }, - { - "name": "ChatStore:Cosmos:ChatMemorySourcesContainer", - "value": "chatmemorysources" - }, - { - "name": "ChatStore:Cosmos:ChatParticipantsContainer", - "value": "chatparticipants" - }, - { - "name": "ChatStore:Cosmos:ConnectionString", - "value": "[if(parameters('deployCosmosDB'), listConnectionStrings(resourceId('Microsoft.DocumentDB/databaseAccounts', toLower(format('cosmos-{0}', variables('uniqueName')))), '2023-04-15').connectionStrings[0].connectionString, '')]" - }, - { - "name": "AzureSpeech:Region", - "value": "[parameters('location')]" - }, - { - "name": "AzureSpeech:Key", - "value": "[if(parameters('deploySpeechServices'), listKeys(resourceId('Microsoft.CognitiveServices/accounts', format('cog-speech-{0}', variables('uniqueName'))), '2022-12-01').key1, '')]" - }, - { - "name": "AllowedOrigins", - "value": "[[*]" - }, - { - "name": "Kestrel:Endpoints:Https:Url", - "value": "https://localhost:443" - }, - { - "name": "Frontend:AadClientId", - "value": "[parameters('frontendClientId')]" - }, - { - "name": "Logging:LogLevel:Default", - "value": "Warning" - }, - { - "name": "Logging:LogLevel:CopilotChat.WebApi", - "value": "Warning" - }, - { - "name": "Logging:LogLevel:Microsoft.SemanticKernel", - "value": "Warning" - }, - { - "name": "Logging:LogLevel:Microsoft.AspNetCore.Hosting", - "value": "Warning" - }, - { - "name": "Logging:LogLevel:Microsoft.Hosting.Lifetimel", - "value": "Warning" - }, - { - "name": "Logging:ApplicationInsights:LogLevel:Default", - "value": "Warning" - }, - { - "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[reference(resourceId('Microsoft.Insights/components', format('appins-{0}', variables('uniqueName'))), '2020-02-02').ConnectionString]" - }, - { - "name": "ApplicationInsightsAgent_EXTENSION_VERSION", - "value": "~2" - }, - { - "name": "SemanticMemory:ContentStorageType", - "value": "AzureBlobs" - }, - { - "name": "SemanticMemory:TextGeneratorType", - "value": "[parameters('aiService')]" - }, - { - "name": "SemanticMemory:DataIngestion:OrchestrationType", - "value": "Distributed" - }, - { - "name": "SemanticMemory:DataIngestion:DistributedOrchestration:QueueType", - "value": "AzureQueue" - }, - { - "name": "SemanticMemory:DataIngestion:EmbeddingGeneratorTypes:0", - "value": "[parameters('aiService')]" - }, - { - "name": "SemanticMemory:DataIngestion:VectorDbTypes:0", - "value": "[parameters('memoryStore')]" - }, - { - "name": "SemanticMemory:Retrieval:VectorDbType", - "value": "[parameters('memoryStore')]" - }, - { - "name": "SemanticMemory:Retrieval:EmbeddingGeneratorType", - "value": "[parameters('aiService')]" - }, - { - "name": "SemanticMemory:Services:AzureBlobs:Auth", - "value": "ConnectionString" - }, - { - "name": "SemanticMemory:Services:AzureBlobs:ConnectionString", - "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}', format('st{0}', variables('rgIdHash')), listKeys(resourceId('Microsoft.Storage/storageAccounts', format('st{0}', variables('rgIdHash'))), '2022-09-01').keys[1].value)]" - }, - { - "name": "SemanticMemory:Services:AzureBlobs:Container", - "value": "chatmemory" - }, - { - "name": "SemanticMemory:Services:AzureQueue:Auth", - "value": "ConnectionString" - }, - { - "name": "SemanticMemory:Services:AzureQueue:ConnectionString", - "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}', format('st{0}', variables('rgIdHash')), listKeys(resourceId('Microsoft.Storage/storageAccounts', format('st{0}', variables('rgIdHash'))), '2022-09-01').keys[1].value)]" - }, - { - "name": "SemanticMemory:Services:AzureCognitiveSearch:Auth", - "value": "ApiKey" - }, - { - "name": "SemanticMemory:Services:AzureCognitiveSearch:Endpoint", - "value": "[if(equals(parameters('memoryStore'), 'AzureCognitiveSearch'), format('https://{0}.search.windows.net', format('acs-{0}', variables('uniqueName'))), '')]" - }, - { - "name": "SemanticMemory:Services:AzureCognitiveSearch:APIKey", - "value": "[if(equals(parameters('memoryStore'), 'AzureCognitiveSearch'), listAdminKeys(resourceId('Microsoft.Search/searchServices', format('acs-{0}', variables('uniqueName'))), '2022-09-01').primaryKey, '')]" - }, - { - "name": "SemanticMemory:Services:Qdrant:Endpoint", - "value": "[if(equals(parameters('memoryStore'), 'Qdrant'), format('https://{0}', reference(resourceId('Microsoft.Web/sites', format('app-{0}-qdrant', variables('uniqueName'))), '2022-09-01').defaultHostName), '')]" - }, - { - "name": "SemanticMemory:Services:AzureOpenAIText:Auth", - "value": "ApiKey" - }, - { - "name": "SemanticMemory:Services:AzureOpenAIText:Endpoint", - "value": "[if(parameters('deployNewAzureOpenAI'), reference(resourceId('Microsoft.CognitiveServices/accounts', format('ai-{0}', variables('uniqueName'))), '2022-12-01').endpoint, parameters('aiEndpoint'))]" - }, - { - "name": "SemanticMemory:Services:AzureOpenAIText:APIKey", - "value": "[if(parameters('deployNewAzureOpenAI'), listKeys(resourceId('Microsoft.CognitiveServices/accounts', format('ai-{0}', variables('uniqueName'))), '2022-12-01').key1, parameters('aiApiKey'))]" - }, - { - "name": "SemanticMemory:Services:AzureOpenAIText:Deployment", - "value": "[parameters('completionModel')]" - }, - { - "name": "SemanticMemory:Services:AzureOpenAIEmbedding:Auth", - "value": "ApiKey" - }, - { - "name": "SemanticMemory:Services:AzureOpenAIEmbedding:Endpoint", - "value": "[if(parameters('deployNewAzureOpenAI'), reference(resourceId('Microsoft.CognitiveServices/accounts', format('ai-{0}', variables('uniqueName'))), '2022-12-01').endpoint, parameters('aiEndpoint'))]" - }, - { - "name": "SemanticMemory:Services:AzureOpenAIEmbedding:APIKey", - "value": "[if(parameters('deployNewAzureOpenAI'), listKeys(resourceId('Microsoft.CognitiveServices/accounts', format('ai-{0}', variables('uniqueName'))), '2022-12-01').key1, parameters('aiApiKey'))]" - }, - { - "name": "SemanticMemory:Services:AzureOpenAIEmbedding:Deployment", - "value": "[parameters('embeddingModel')]" - }, - { - "name": "Plugins:0:Name", - "value": "Klarna Shopping" - }, - { - "name": "Plugins:0:ManifestDomain", - "value": "https://www.klarna.com" - }, - { - "name": "Plugins:1:Name", - "value": "WebSearcher" - }, - { - "name": "Plugins:1:ManifestDomain", - "value": "[format('https://{0}', reference(resourceId('Microsoft.Web/sites', format('function-{0}-websearcher-plugin', variables('uniqueName'))), '2022-09-01').defaultHostName)]" - }, - { - "name": "Plugins:1:Key", - "value": "[listkeys(format('{0}/host/default/', resourceId('Microsoft.Web/sites', format('function-{0}-websearcher-plugin', variables('uniqueName')))), '2022-09-01').functionKeys.default]" - } - ] + "appSettings": "[concat(createArray(createObject('name', 'Authentication:Type', 'value', 'AzureAd'), createObject('name', 'Authentication:AzureAd:Instance', 'value', parameters('azureAdInstance')), createObject('name', 'Authentication:AzureAd:TenantId', 'value', parameters('azureAdTenantId')), createObject('name', 'Authentication:AzureAd:ClientId', 'value', parameters('webApiClientId')), createObject('name', 'Authentication:AzureAd:Scopes', 'value', 'access_as_user'), createObject('name', 'Planner:Model', 'value', parameters('plannerModel')), createObject('name', 'ChatStore:Type', 'value', if(parameters('deployCosmosDB'), 'cosmos', 'volatile')), createObject('name', 'ChatStore:Cosmos:Database', 'value', 'CopilotChat'), createObject('name', 'ChatStore:Cosmos:ChatSessionsContainer', 'value', 'chatsessions'), createObject('name', 'ChatStore:Cosmos:ChatMessagesContainer', 'value', 'chatmessages'), createObject('name', 'ChatStore:Cosmos:ChatMemorySourcesContainer', 'value', 'chatmemorysources'), createObject('name', 'ChatStore:Cosmos:ChatParticipantsContainer', 'value', 'chatparticipants'), createObject('name', 'ChatStore:Cosmos:ConnectionString', 'value', if(parameters('deployCosmosDB'), listConnectionStrings(resourceId('Microsoft.DocumentDB/databaseAccounts', toLower(format('cosmos-{0}', variables('uniqueName')))), '2023-04-15').connectionStrings[0].connectionString, '')), createObject('name', 'AzureSpeech:Region', 'value', parameters('location')), createObject('name', 'AzureSpeech:Key', 'value', if(parameters('deploySpeechServices'), listKeys(resourceId('Microsoft.CognitiveServices/accounts', format('cog-speech-{0}', variables('uniqueName'))), '2022-12-01').key1, '')), createObject('name', 'AllowedOrigins', 'value', '[*]'), createObject('name', 'Kestrel:Endpoints:Https:Url', 'value', 'https://localhost:443'), createObject('name', 'Frontend:AadClientId', 'value', parameters('frontendClientId')), createObject('name', 'Logging:LogLevel:Default', 'value', 'Warning'), createObject('name', 'Logging:LogLevel:CopilotChat.WebApi', 'value', 'Warning'), createObject('name', 'Logging:LogLevel:Microsoft.SemanticKernel', 'value', 'Warning'), createObject('name', 'Logging:LogLevel:Microsoft.AspNetCore.Hosting', 'value', 'Warning'), createObject('name', 'Logging:LogLevel:Microsoft.Hosting.Lifetimel', 'value', 'Warning'), createObject('name', 'Logging:ApplicationInsights:LogLevel:Default', 'value', 'Warning'), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', reference(resourceId('Microsoft.Insights/components', format('appins-{0}', variables('uniqueName'))), '2020-02-02').ConnectionString), createObject('name', 'ApplicationInsightsAgent_EXTENSION_VERSION', 'value', '~2'), createObject('name', 'SemanticMemory:ContentStorageType', 'value', 'AzureBlobs'), createObject('name', 'SemanticMemory:TextGeneratorType', 'value', parameters('aiService')), createObject('name', 'SemanticMemory:DataIngestion:OrchestrationType', 'value', 'Distributed'), createObject('name', 'SemanticMemory:DataIngestion:DistributedOrchestration:QueueType', 'value', 'AzureQueue'), createObject('name', 'SemanticMemory:DataIngestion:EmbeddingGeneratorTypes:0', 'value', parameters('aiService')), createObject('name', 'SemanticMemory:DataIngestion:VectorDbTypes:0', 'value', parameters('memoryStore')), createObject('name', 'SemanticMemory:Retrieval:VectorDbType', 'value', parameters('memoryStore')), createObject('name', 'SemanticMemory:Retrieval:EmbeddingGeneratorType', 'value', parameters('aiService')), createObject('name', 'SemanticMemory:Services:AzureBlobs:Auth', 'value', 'ConnectionString'), createObject('name', 'SemanticMemory:Services:AzureBlobs:ConnectionString', 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}', format('st{0}', variables('rgIdHash')), listKeys(resourceId('Microsoft.Storage/storageAccounts', format('st{0}', variables('rgIdHash'))), '2022-09-01').keys[1].value)), createObject('name', 'SemanticMemory:Services:AzureBlobs:Container', 'value', 'chatmemory'), createObject('name', 'SemanticMemory:Services:AzureQueue:Auth', 'value', 'ConnectionString'), createObject('name', 'SemanticMemory:Services:AzureQueue:ConnectionString', 'value', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}', format('st{0}', variables('rgIdHash')), listKeys(resourceId('Microsoft.Storage/storageAccounts', format('st{0}', variables('rgIdHash'))), '2022-09-01').keys[1].value)), createObject('name', 'SemanticMemory:Services:AzureCognitiveSearch:Auth', 'value', 'ApiKey'), createObject('name', 'SemanticMemory:Services:AzureCognitiveSearch:Endpoint', 'value', if(equals(parameters('memoryStore'), 'AzureCognitiveSearch'), format('https://{0}.search.windows.net', format('acs-{0}', variables('uniqueName'))), '')), createObject('name', 'SemanticMemory:Services:AzureCognitiveSearch:APIKey', 'value', if(equals(parameters('memoryStore'), 'AzureCognitiveSearch'), listAdminKeys(resourceId('Microsoft.Search/searchServices', format('acs-{0}', variables('uniqueName'))), '2022-09-01').primaryKey, '')), createObject('name', 'SemanticMemory:Services:Qdrant:Endpoint', 'value', if(equals(parameters('memoryStore'), 'Qdrant'), format('https://{0}', reference(resourceId('Microsoft.Web/sites', format('app-{0}-qdrant', variables('uniqueName'))), '2022-09-01').defaultHostName), '')), createObject('name', 'SemanticMemory:Services:AzureOpenAIText:Auth', 'value', 'ApiKey'), createObject('name', 'SemanticMemory:Services:AzureOpenAIText:Endpoint', 'value', if(parameters('deployNewAzureOpenAI'), reference(resourceId('Microsoft.CognitiveServices/accounts', format('ai-{0}', variables('uniqueName'))), '2022-12-01').endpoint, parameters('aiEndpoint'))), createObject('name', 'SemanticMemory:Services:AzureOpenAIText:APIKey', 'value', if(parameters('deployNewAzureOpenAI'), listKeys(resourceId('Microsoft.CognitiveServices/accounts', format('ai-{0}', variables('uniqueName'))), '2022-12-01').key1, parameters('aiApiKey'))), createObject('name', 'SemanticMemory:Services:AzureOpenAIText:Deployment', 'value', parameters('completionModel')), createObject('name', 'SemanticMemory:Services:AzureOpenAIEmbedding:Auth', 'value', 'ApiKey'), createObject('name', 'SemanticMemory:Services:AzureOpenAIEmbedding:Endpoint', 'value', if(parameters('deployNewAzureOpenAI'), reference(resourceId('Microsoft.CognitiveServices/accounts', format('ai-{0}', variables('uniqueName'))), '2022-12-01').endpoint, parameters('aiEndpoint'))), createObject('name', 'SemanticMemory:Services:AzureOpenAIEmbedding:APIKey', 'value', if(parameters('deployNewAzureOpenAI'), listKeys(resourceId('Microsoft.CognitiveServices/accounts', format('ai-{0}', variables('uniqueName'))), '2022-12-01').key1, parameters('aiApiKey'))), createObject('name', 'SemanticMemory:Services:AzureOpenAIEmbedding:Deployment', 'value', parameters('embeddingModel')), createObject('name', 'Plugins:0:Name', 'value', 'Klarna Shopping'), createObject('name', 'Plugins:0:ManifestDomain', 'value', 'https://www.klarna.com')), if(parameters('deployWebSearcher'), createArray(createObject('name', 'Plugins:1:Name', 'value', 'WebSearcher'), createObject('name', 'Plugins:1:ManifestDomain', 'value', format('https://{0}', reference(resourceId('Microsoft.Web/sites', format('function-{0}-websearcher-plugin', variables('uniqueName'))), '2022-09-01').defaultHostName)), createObject('name', 'Plugins:1:Key', 'value', listkeys(format('{0}/host/default/', resourceId('Microsoft.Web/sites', format('function-{0}-websearcher-plugin', variables('uniqueName')))), '2022-09-01').functionKeys.default)), createArray()))]" }, "dependsOn": [ "[resourceId('Microsoft.Insights/components', format('appins-{0}', variables('uniqueName')))]", @@ -748,6 +530,7 @@ ] }, { + "condition": "[parameters('deployWebSearcher')]", "type": "Microsoft.Web/sites", "apiVersion": "2022-09-01", "name": "[format('function-{0}-websearcher-plugin', variables('uniqueName'))]", @@ -768,6 +551,7 @@ ] }, { + "condition": "[parameters('deployWebSearcher')]", "type": "Microsoft.Web/sites/config", "apiVersion": "2022-09-01", "name": "[format('{0}/{1}', format('function-{0}-websearcher-plugin', variables('uniqueName')), 'web')]", @@ -792,7 +576,7 @@ }, { "name": "PluginConfig:BingApiKey", - "value": "[listKeys(resourceId('Microsoft.Bing/accounts', format('bing-search-{0}', variables('uniqueName'))), '2020-06-10').key1]" + "value": "[if(parameters('deployWebSearcher'), listKeys(resourceId('Microsoft.Bing/accounts', format('bing-search-{0}', variables('uniqueName'))), '2020-06-10').key1, '')]" } ] }, @@ -804,7 +588,7 @@ ] }, { - "condition": "[parameters('deployPackages')]", + "condition": "[and(parameters('deployPackages'), parameters('deployWebSearcher'))]", "type": "Microsoft.Web/sites/extensions", "apiVersion": "2022-09-01", "name": "[format('{0}/{1}', format('function-{0}-websearcher-plugin', variables('uniqueName')), 'MSDeploy')]", @@ -853,6 +637,7 @@ ] }, { + "condition": "[parameters('deployWebSearcher')]", "type": "Microsoft.Web/sites/siteextensions", "apiVersion": "2022-09-01", "name": "[format('{0}/{1}', format('function-{0}-websearcher-plugin', variables('uniqueName')), 'Microsoft.ApplicationInsights.AzureWebSites')]", @@ -1331,6 +1116,7 @@ } }, { + "condition": "[parameters('deployWebSearcher')]", "type": "Microsoft.Bing/accounts", "apiVersion": "2020-06-10", "name": "[format('bing-search-{0}', variables('uniqueName'))]", @@ -1356,9 +1142,7 @@ }, "pluginNames": { "type": "array", - "value": [ - "[format('function-{0}-websearcher-plugin', variables('uniqueName'))]" - ] + "value": "[concat(createArray(), if(parameters('deployWebSearcher'), createArray(format('function-{0}-websearcher-plugin', variables('uniqueName'))), createArray()))]" } } } \ No newline at end of file