diff --git a/.github/workflows/copilot-deploy-infra.yml b/.github/workflows/copilot-deploy-infra.yml index 8c243fd2..63a54918 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 400716a4..5b93a17e 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 6fe55ceb..c82787f6 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 dac1f827..81f89d52 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 13f6c34c..a3d2d66b 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 475d3a7f..243b3c1c 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