diff --git a/.github/workflows/copilot-build-backend.yml b/.github/workflows/copilot-build-backend.yml index bbb3fc014..feebfb782 100644 --- a/.github/workflows/copilot-build-backend.yml +++ b/.github/workflows/copilot-build-backend.yml @@ -57,7 +57,7 @@ jobs: - name: Package Copilot Chat WebAPI run: | - scripts\deploy\package-webapi.ps1 -Configuration Release -DotnetFramework net6.0 -TargetRuntime win-x64 -OutputDirectory ${{ github.workspace }}\scripts\deploy -Version ${{ steps.versiontag.outputs.versiontag }} -InformationalVersion "Built from commit ${{ steps.gitversion.outputs.ShortSha }} on $(Get-Date -Format "yyyy-MM-dd")" + scripts\deploy\package-webapi.ps1 -Configuration Release -DotnetFramework net6.0 -TargetRuntime win-x64 -OutputDirectory ${{ github.workspace }}\scripts\deploy -Version ${{ steps.versiontag.outputs.versiontag }} -InformationalVersion "Built from commit ${{ steps.gitversion.outputs.ShortSha }} on $(Get-Date -Format "yyyy-MM-dd")" -SkipFrontendFiles=${{ github.event_name == 'pull_request' }} - name: Upload package to artifacts uses: actions/upload-artifact@v3 diff --git a/.github/workflows/copilot-deploy-backend.yml b/.github/workflows/copilot-deploy-backend.yml index a846ed149..0f450d270 100644 --- a/.github/workflows/copilot-deploy-backend.yml +++ b/.github/workflows/copilot-deploy-backend.yml @@ -43,6 +43,11 @@ jobs: runs-on: ${{ matrix.os }} steps: + - uses: actions/checkout@v4 + with: + sparse-checkout: | + scripts + - uses: actions/download-artifact@v3 with: name: ${{inputs.ARTIFACT_NAME}} @@ -75,7 +80,5 @@ jobs: az webapp config appsettings set --resource-group ${{vars.CC_DEPLOYMENT_GROUP_NAME}} --name ${{ env.AZURE_WEBAPP_NAME }} --settings WEBSITE_RUN_FROM_PACKAGE="1" -o none - name: "Deploy" - uses: azure/webapps-deploy@v2 - with: - app-name: ${{ env.AZURE_WEBAPP_NAME }} - package: "${{ github.workspace }}/${{inputs.ARTIFACT_NAME}}/webapi.zip" + run: | + scripts/deploy/deploy-webapi.sh -p "${{ github.workspace }}/${{inputs.ARTIFACT_NAME}}/webapi.zip" -d ${{inputs.DEPLOYMENT_NAME}} -s ${{secrets.AZURE_SUBSCRIPTION_ID}} -rg ${{vars.CC_DEPLOYMENT_GROUP_NAME}} --register-cors diff --git a/.github/workflows/copilot-deploy-environment.yml b/.github/workflows/copilot-deploy-environment.yml index c3bbc82a4..63cd96a4c 100644 --- a/.github/workflows/copilot-deploy-environment.yml +++ b/.github/workflows/copilot-deploy-environment.yml @@ -79,14 +79,3 @@ jobs: AZURE_CLIENT_ID: ${{secrets.AZURE_CLIENT_ID}} AZURE_TENANT_ID: ${{secrets.AZURE_TENANT_ID}} AZURE_SUBSCRIPTION_ID: ${{secrets.AZURE_SUBSCRIPTION_ID}} - - deploy-frontend: - needs: [deploy-infra] - uses: ./.github/workflows/copilot-deploy-frontend.yml - with: - DEPLOYMENT_NAME: ${{needs.deploy-infra.outputs.deployment-id}} - ENVIRONMENT: ${{inputs.ENVIRONMENT}} - secrets: - AZURE_CLIENT_ID: ${{secrets.AZURE_CLIENT_ID}} - AZURE_TENANT_ID: ${{secrets.AZURE_TENANT_ID}} - AZURE_SUBSCRIPTION_ID: ${{secrets.AZURE_SUBSCRIPTION_ID}} diff --git a/.github/workflows/copilot-deploy-frontend.yml b/.github/workflows/copilot-deploy-frontend.yml deleted file mode 100644 index 691432d52..000000000 --- a/.github/workflows/copilot-deploy-frontend.yml +++ /dev/null @@ -1,91 +0,0 @@ -name: copilot-deploy-frontend - -on: - workflow_call: - inputs: - ENVIRONMENT: - required: true - type: string - DEPLOYMENT_NAME: - required: true - type: string - secrets: - AZURE_CLIENT_ID: - required: true - AZURE_TENANT_ID: - required: true - AZURE_SUBSCRIPTION_ID: - required: true - -permissions: - contents: read - -jobs: - webapp: - environment: ${{inputs.ENVIRONMENT}} - permissions: - id-token: write - strategy: - fail-fast: false - matrix: - include: - - { dotnet: "6.0", configuration: Release, os: ubuntu-latest } - - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v4 - with: - clean: true - fetch-depth: 0 - - - name: Install Azure CLI - run: | - sudo apt update && sudo apt-get install curl -y - curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash - - - name: Install Keyring - run: | - sudo apt-get install gnome-keyring -y - - - name: "Install SWA CLI" - run: npm install -g @azure/static-web-apps-cli - - - name: Azure login - uses: azure/login@v1 - with: - client-id: ${{secrets.AZURE_CLIENT_ID}} - tenant-id: ${{secrets.AZURE_TENANT_ID}} - subscription-id: ${{secrets.AZURE_SUBSCRIPTION_ID}} - enable-AzPSSession: false - - - name: "Get and Mask SWA Deployment Token" - uses: azure/CLI@v1 - with: - azcliversion: 2.30.0 - inlineScript: | - webappName=$(az deployment group show --name ${{inputs.DEPLOYMENT_NAME}} --resource-group ${{vars.CC_DEPLOYMENT_GROUP_NAME}} --output json | jq -r '.properties.outputs.webappName.value') - swaToken=$(az staticwebapp secrets list --name "$webappName" --resource-group ${{vars.CC_DEPLOYMENT_GROUP_NAME}} --query "properties.apiKey" --output json | jq -r) - echo "::add-mask::$swaToken" - echo "SWA_CLI_DEPLOYMENT_TOKEN=$swaToken" >> $GITHUB_ENV - - - name: Install GitVersion - uses: gittools/actions/gitversion/setup@v0 - with: - versionSpec: '5.x' - - - name: Determine version - id: gitversion - uses: gittools/actions/gitversion/execute@v0 - - - name: Set version tag - id: versiontag - run: | - VERSION_TAG="${{ steps.gitversion.outputs.Major }}." - VERSION_TAG+="${{ steps.gitversion.outputs.Minor }}." - VERSION_TAG+="${{ steps.gitversion.outputs.CommitsSinceVersionSource }}" - echo $VERSION_TAG - echo "versiontag=$VERSION_TAG" >> "$GITHUB_OUTPUT" - - - name: Deploy SWA - run: | - scripts/deploy/deploy-webapp.sh --subscription ${{secrets.AZURE_SUBSCRIPTION_ID}} --resource-group ${{vars.CC_DEPLOYMENT_GROUP_NAME}} --deployment-name ${{inputs.DEPLOYMENT_NAME}} --client-id ${{vars.FRONTEND_CLIENT_ID}} --no-redirect --version ${{ steps.versiontag.outputs.versiontag }} --version-info "Built from commit ${{ steps.gitversion.outputs.ShortSha }} on $(date +"%Y-%m-%d")" diff --git a/.github/workflows/copilot-deploy-infra.yml b/.github/workflows/copilot-deploy-infra.yml index c5e2fad4b..8c243fd29 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}} --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 diff --git a/scripts/deploy/README.md b/scripts/deploy/README.md index b6826bc8a..400716a4a 100644 --- a/scripts/deploy/README.md +++ b/scripts/deploy/README.md @@ -21,7 +21,6 @@ Before you get started, make sure you have the following requirements in place: - Azure CLI (i.e., az) (if you already installed Azure CLI, make sure to update your installation to the latest version) - Windows, go to https://aka.ms/installazurecliwindows - Linux, run "`curl -L https://aka.ms/InstallAzureCli | bash`" -- Azure Static Web App CLI (i.e., swa) can be installed by running "`npm install -g @azure/static-web-apps-cli`" - (Linux only) `zip` can be installed by running "`sudo apt install zip`" ## App registrations (identity) @@ -101,7 +100,7 @@ The examples below assume you are using an existing Azure OpenAI resource. See t ## PowerShell ```powershell -./deploy-azure.ps1 -Subscription {YOUR_SUBSCRIPTION_ID} -DeploymentName {YOUR_DEPLOYMENT_NAME} -AIService {AzureOpenAI or OpenAI} -AIApiKey {YOUR_AI_KEY} -AIEndpoint {YOUR_AZURE_OPENAI_ENDPOINT} -BackendClientId {YOUR_BACKEND_APPLICATION_ID} -TenantId {YOUR_TENANT_ID} +./deploy-azure.ps1 -Subscription {YOUR_SUBSCRIPTION_ID} -DeploymentName {YOUR_DEPLOYMENT_NAME} -AIService {AzureOpenAI or OpenAI} -AIApiKey {YOUR_AI_KEY} -AIEndpoint {YOUR_AZURE_OPENAI_ENDPOINT} -BackendClientId {YOUR_BACKEND_APPLICATION_ID} -FrontendClientId {YOUR_FRONTEND_APPLICATION_ID} -TenantId {YOUR_TENANT_ID} ``` - To use an existing Azure OpenAI resource, set `-AIService` to `AzureOpenAI` and include `-AIApiKey` and `-AIEndpoint`. @@ -112,7 +111,7 @@ The examples below assume you are using an existing Azure OpenAI resource. See t ```bash chmod +x ./deploy-azure.sh -./deploy-azure.sh --subscription {YOUR_SUBSCRIPTION_ID} --deployment-name {YOUR_DEPLOYMENT_NAME} --ai-service {AzureOpenAI or OpenAI} --ai-service-key {YOUR_AI_KEY} --ai-endpoint {YOUR_AZURE_OPENAI_ENDPOINT} --client-id {YOUR_BACKEND_APPLICATION_ID} --tenant-id {YOUR_TENANT_ID} +./deploy-azure.sh --subscription {YOUR_SUBSCRIPTION_ID} --deployment-name {YOUR_DEPLOYMENT_NAME} --ai-service {AzureOpenAI or OpenAI} --ai-service-key {YOUR_AI_KEY} --ai-endpoint {YOUR_AZURE_OPENAI_ENDPOINT} --client-id {YOUR_BACKEND_APPLICATION_ID} --frontend-client-id {YOUR_FRONTEND_APPLICATION_ID} --tenant-id {YOUR_TENANT_ID} ``` - To use an existing Azure OpenAI resource, set `--ai-service` to `AzureOpenAI` and include `--ai-service-key` and `--ai-endpoint`. @@ -125,22 +124,20 @@ You can also deploy the infrastructure directly from the Azure Portal by clickin [![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://aka.ms/sk-deploy-existing-azureopenai-portal) -> This will automatically deploy the most recent release of CopilotChat backend binaries ([link](https://github.com/microsoft/chat-copilot/releases)). +> This will automatically deploy the most recent release of Chat Copilot binaries ([link](https://github.com/microsoft/chat-copilot/releases)). > To find the deployment name when using `Deploy to Azure`, look for a deployment in your resource group that starts with `Microsoft.Template`. -# Deploy Backend (WebAPI) +# Deploy Application -> **_NOTE:_** This step can be skipped if the previous Azure Resources creation step succeeded without errors. The `deployWebApiPackage = true` setting in main.bicep ensures that the latest copilot chat api is deployed. - -To deploy the backend, build the deployment package first and deploy it to the Azure resources created above. +To deploy the application, first package it, then deploy it to the Azure resources created above. ## PowerShell ```powershell ./package-webapi.ps1 -./deploy-webapi.ps1 -Subscription {YOUR_SUBSCRIPTION_ID} -ResourceGroupName rg-{YOUR_DEPLOYMENT_NAME} -DeploymentName {YOUR_DEPLOYMENT_NAME} +./deploy-webapi.ps1 -Subscription {YOUR_SUBSCRIPTION_ID} -ResourceGroupName {YOUR_RESOURCE_GROUP_NAME} -DeploymentName {YOUR_DEPLOYMENT_NAME} ``` ## Bash @@ -150,7 +147,7 @@ chmod +x ./package-webapi.sh ./package-webapi.sh chmod +x ./deploy-webapi.sh -./deploy-webapi.sh --subscription {YOUR_SUBSCRIPTION_ID} --resource-group rg-{YOUR_DEPLOYMENT_NAME} --deployment-name {YOUR_DEPLOYMENT_NAME} +./deploy-webapi.sh --subscription {YOUR_SUBSCRIPTION_ID} --resource-group {YOUR_RESOURCE_GROUP_NAME} --deployment-name {YOUR_DEPLOYMENT_NAME} ``` # Deploy Hosted Plugins @@ -178,43 +175,20 @@ chmod +x ./deploy-plugins.sh ./deploy-webapi.sh --subscription {YOUR_SUBSCRIPTION_ID} --resource-group rg-{YOUR_DEPLOYMENT_NAME} --deployment-name {YOUR_DEPLOYMENT_NAME} ``` -# Deploy Frontend (WebApp) - -## Prerequisites - -### Install Azure's Static Web Apps CLI - -```bash -npm install -g @azure/static-web-apps-cli -``` - -## PowerShell - -```powershell - -./deploy-webapp.ps1 -Subscription {YOUR_SUBSCRIPTION_ID} -ResourceGroupName rg-{YOUR_DEPLOYMENT_NAME} -DeploymentName {YOUR_DEPLOYMENT_NAME} -FrontendClientId {YOUR_FRONTEND_APPLICATION_ID} -PackageFilePath .\out\webapi.zip -``` - -## Bash - -```bash -./deploy-webapp.sh --subscription {YOUR_SUBSCRIPTION_ID} --resource-group rg-{YOUR_DEPLOYMENT_NAME} --deployment-name {YOUR_DEPLOYMENT_NAME} --client-id {YOUR_FRONTEND_APPLICATION_ID} -``` - # (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 previous Azure Resources creation step succeeded without errors. The deployMemoryPipelinePackage = true setting in main.bicep ensures that the latest copilot chat memory pipeline is deployed. +> **_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. To deploy the memorypipeline, build the deployment package first and deploy it to the Azure resources created above. ## PowerShell ```powershell -./package-memorypipeline.ps1 +.\package-memorypipeline.ps1 -./deploy-memorypipeline.ps1 -Subscription {YOUR_SUBSCRIPTION_ID} -ResourceGroupName rg-{YOUR_DEPLOYMENT_NAME} -DeploymentName {YOUR_DEPLOYMENT_NAME} +.\deploy-memorypipeline.ps1 -Subscription {YOUR_SUBSCRIPTION_ID} -ResourceGroupName {YOUR_RESOURCE_GROUP_NAME} -DeploymentName {YOUR_DEPLOYMENT_NAME} ``` ## Bash @@ -224,7 +198,7 @@ chmod +x ./package-memorypipeline.sh ./package-memorypipeline.sh chmod +x ./deploy-memorypipeline.sh -./deploy-memorypipeline.sh --subscription {YOUR_SUBSCRIPTION_ID} --resource-group rg-{YOUR_DEPLOYMENT_NAME} --deployment-name {YOUR_DEPLOYMENT_NAME} +./deploy-memorypipeline.sh --subscription {YOUR_SUBSCRIPTION_ID} --resource-group {YOUR_RESOURCE_GROUP_NAME} --deployment-name {YOUR_DEPLOYMENT_NAME} ``` Your Chat Copilot application is now deployed! @@ -241,9 +215,9 @@ This will get you to the CORS page where you can add your allowed hosts. ### PowerShell ```powershell -$webApiName = $(az deployment group show --name {DEPLOYMENT_NAME} --resource-group rg-{DEPLOYMENT_NAME} --output json | ConvertFrom-Json).properties.outputs.webapiName.value +$webApiName = $(az deployment group show --name {DEPLOYMENT_NAME} --resource-group {YOUR_RESOURCE_GROUP_NAME} --output json | ConvertFrom-Json).properties.outputs.webapiName.value -($(az webapp config appsettings list --name $webapiName --resource-group rg-{YOUR_DEPLOYMENT_NAME} | ConvertFrom-JSON) | Where-Object -Property name -EQ -Value Authorization:ApiKey).value +az webapp cors add --name $webapiName --resource-group $ResourceGroupName --subscription $Subscription --allowed-origins YOUR_FRONTEND_URL ``` ### Bash @@ -251,5 +225,5 @@ $webApiName = $(az deployment group show --name {DEPLOYMENT_NAME} --resource-gro ```bash eval WEB_API_NAME=$(az deployment group show --name $DEPLOYMENT_NAME --resource-group $RESOURCE_GROUP --output json) | jq -r '.properties.outputs.webapiName.value' -$(az webapp config appsettings list --name $WEB_API_NAME --resource-group rg-{YOUR_DEPLOYMENT_NAME} | jq '.[] | select(.name=="Authorization:ApiKey").value') +az webapp cors add --name $WEB_API_NAME --resource-group $RESOURCE_GROUP --subscription $SUBSCRIPTION --allowed-origins YOUR_FRONTEND_URL ``` diff --git a/scripts/deploy/deploy-azure.ps1 b/scripts/deploy/deploy-azure.ps1 index 587b4fbcf..eea677665 100644 --- a/scripts/deploy/deploy-azure.ps1 +++ b/scripts/deploy/deploy-azure.ps1 @@ -19,16 +19,20 @@ param( # Azure AD client ID for the Web API backend app registration $BackendClientId, + [Parameter(Mandatory)] + [string] + # Azure AD client ID for the frontend app registration + $FrontendClientId, + [Parameter(Mandatory)] [string] # Azure AD tenant ID for authenticating users $TenantId, - [Parameter(Mandatory)] [ValidateSet("AzureOpenAI", "OpenAI")] [string] # AI service to use - $AIService, + $AIService = "AzureOpenAI", [string] # API key for existing Azure OpenAI resource or OpenAI account @@ -46,10 +50,6 @@ param( # Region to which to make the deployment (ignored when deploying to an existing resource group) $Region = "southcentralus", - [string] - # Region to deploy to the static web app into. This must be a region that supports static web apps. - $WebAppRegion = "westus2", - [string] # SKU for the Azure App Service plan $WebAppServiceSku = "B1", @@ -117,7 +117,6 @@ if ($MemoryStore -eq "Postgres" -and !$SqlAdminPassword) { $jsonConfig = " { `\`"webAppServiceSku`\`": { `\`"value`\`": `\`"$WebAppServiceSku`\`" }, - `\`"webappLocation`\`": { `\`"value`\`": `\`"$WebAppRegion`\`" }, `\`"aiService`\`": { `\`"value`\`": `\`"$AIService`\`" }, `\`"aiApiKey`\`": { `\`"value`\`": `\`"$AIApiKey`\`" }, `\`"aiEndpoint`\`": { `\`"value`\`": `\`"$AIEndpoint`\`" }, @@ -127,6 +126,7 @@ $jsonConfig = " `\`"azureAdInstance`\`": { `\`"value`\`": `\`"$AzureAdInstance`\`" }, `\`"azureAdTenantId`\`": { `\`"value`\`": `\`"$TenantId`\`" }, `\`"webApiClientId`\`": { `\`"value`\`": `\`"$BackendClientId`\`"}, + `\`"frontendClientId`\`": { `\`"value`\`": `\`"$FrontendClientId`\`"}, `\`"deployNewAzureOpenAI`\`": { `\`"value`\`": $(If ($DeployAzureOpenAI) {"true"} Else {"false"}) }, `\`"memoryStore`\`": { `\`"value`\`": `\`"$MemoryStore`\`" }, `\`"deployCosmosDB`\`": { `\`"value`\`": $(If (!($NoCosmosDb)) {"true"} Else {"false"}) }, diff --git a/scripts/deploy/deploy-azure.sh b/scripts/deploy/deploy-azure.sh index e40bff059..3bc0cae50 100755 --- a/scripts/deploy/deploy-azure.sh +++ b/scripts/deploy/deploy-azure.sh @@ -5,19 +5,19 @@ set -e usage() { - echo "Usage: $0 -d DEPLOYMENT_NAME -s SUBSCRIPTION -c BACKEND_CLIENT_ID -t AZURE_AD_TENANT_ID -ai AI_SERVICE_TYPE [OPTIONS]" + echo "Usage: $0 -d DEPLOYMENT_NAME -s SUBSCRIPTION -c BACKEND_CLIENT_ID -fc FRONTEND_CLIENT_ID -t AZURE_AD_TENANT_ID -ai AI_SERVICE_TYPE [OPTIONS]" echo "" echo "Arguments:" echo " -d, --deployment-name DEPLOYMENT_NAME Name for the deployment (mandatory)" echo " -s, --subscription SUBSCRIPTION Subscription to which to make the deployment (mandatory)" echo " -c, --client-id BACKEND_CLIENT_ID Azure AD client ID for the Web API backend app registration (mandatory)" + echo " -fc, --frontend-client-id FE_CLIENT_ID Azure AD client ID for the frontend app registration (mandatory)" echo " -t, --tenant-id AZURE_AD_TENANT_ID Azure AD tenant ID for authenticating users (mandatory)" echo " -ai, --ai-service AI_SERVICE_TYPE Type of AI service to use (i.e., OpenAI or AzureOpenAI) (mandatory)" echo " -aiend, --ai-endpoint AI_ENDPOINT Endpoint for existing Azure OpenAI resource" echo " -aikey, --ai-service-key AI_SERVICE_KEY API key for existing Azure OpenAI resource or OpenAI account" echo " -rg, --resource-group RESOURCE_GROUP Resource group to which to make the deployment (default: \"rg-\$DEPLOYMENT_NAME\")" echo " -r, --region REGION Region to which to make the deployment (default: \"South Central US\")" - echo " -wr, --web-app-region WEB_APP_REGION Region to deploy to the static web app into. This must be a region that supports static web apps. (default: \"West US 2\")" echo " -a, --app-service-sku WEB_APP_SVC_SKU SKU for the Azure App Service plan (default: \"B1\")" echo " -i, --instance AZURE_AD_INSTANCE Azure AD cloud instance for authenticating users" echo " (default: \"https://login.microsoftonline.com\")" @@ -49,6 +49,11 @@ while [[ $# -gt 0 ]]; do shift shift ;; + -fc | --frontend-client-id) + FRONTEND_CLIENT_ID="$2" + shift + shift + ;; -t | --tenant-id) AZURE_AD_TENANT_ID="$2" shift @@ -79,11 +84,6 @@ while [[ $# -gt 0 ]]; do shift shift ;; - -wr | --web-app-region) - WEB_APP_REGION="$2" - shift - shift - ;; -a | --app-service-sku) WEB_APP_SVC_SKU="$2" shift @@ -128,7 +128,7 @@ while [[ $# -gt 0 ]]; do done # Check mandatory arguments -if [[ -z "$DEPLOYMENT_NAME" ]] || [[ -z "$SUBSCRIPTION" ]] || [[ -z "$BACKEND_CLIENT_ID" ]] || [[ -z "$AZURE_AD_TENANT_ID" ]] || [[ -z "$AI_SERVICE_TYPE" ]]; then +if [[ -z "$DEPLOYMENT_NAME" ]] || [[ -z "$SUBSCRIPTION" ]] || [[ -z "$BACKEND_CLIENT_ID" ]] || [[ -z "$FRONTEND_CLIENT_ID" ]] || [[ -z "$AZURE_AD_TENANT_ID" ]] || [[ -z "$AI_SERVICE_TYPE" ]]; then usage exit 1 fi @@ -191,7 +191,6 @@ az account set -s "$SUBSCRIPTION" # Set defaults : "${REGION:="southcentralus"}" : "${WEB_APP_SVC_SKU:="B1"}" -: "${WEB_APP_REGION:="westus2"}" : "${AZURE_AD_INSTANCE:="https://login.microsoftonline.com"}" : "${MEMORY_STORE:="AzureCognitiveSearch"}" : "${NO_COSMOS_DB:=false}" @@ -202,7 +201,6 @@ JSON_CONFIG=$( cat < param( @@ -24,8 +24,15 @@ param( $DeploymentSlot, [string] - # CopilotChat WebApi package to deploy - $PackageFilePath = "$PSScriptRoot/out/webapi.zip" + $PackageFilePath = "$PSScriptRoot/out/webapi.zip", + + [switch] + # Switch to add our URIs in app registration's redirect URIs if missing + $EnsureUriInAppRegistration, + + [switch] + # Switch to add our URIs in CORS origins for our plugins + $RegisterPluginCors ) # Ensure $PackageFilePath exists @@ -46,25 +53,35 @@ if ($LASTEXITCODE -ne 0) { } Write-Host "Getting Azure WebApp resource name..." -$webappName = $(az deployment group show --name $DeploymentName --resource-group $ResourceGroupName --output json | ConvertFrom-Json).properties.outputs.webapiName.value -if ($null -eq $webAppName) { +$deployment=$(az deployment group show --name $DeploymentName --resource-group $ResourceGroupName --output json | ConvertFrom-Json) +$webApiUrl = $deployment.properties.outputs.webapiUrl.value +$webApiName = $deployment.properties.outputs.webapiName.value +$pluginNames = $deployment.properties.outputs.pluginNames.value + +if ($null -eq $webApiName) { Write-Error "Could not get Azure WebApp resource name from deployment output." exit 1 } -Write-Host "Azure WebApp name: $webappName" +Write-Host "Azure WebApp name: $webApiName" Write-Host "Configuring Azure WebApp to run from package..." -az webapp config appsettings set --resource-group $ResourceGroupName --name $webappName --settings WEBSITE_RUN_FROM_PACKAGE="1" | out-null +az webapp config appsettings set --resource-group $ResourceGroupName --name $webApiName --settings WEBSITE_RUN_FROM_PACKAGE="1" --output none if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } +# Set up deployment command as a string +$azWebAppCommand = "az webapp deployment source config-zip --resource-group $ResourceGroupName --name $webApiName --src $PackageFilePath" + # Check if DeploymentSlot parameter was passed +$origins = @("$webApiUrl") if ($DeploymentSlot) { - - Write-Host "Checking if slot $DeploymentSlot exists for '$webappName'..." - $availableSlots = az webapp deployment slot list --resource-group $ResourceGroupName --name $webappName | ConvertFrom-JSON | Select-Object -Property Name + Write-Host "Checking if slot $DeploymentSlot exists for '$webApiName'..." + $azWebAppCommand += " --slot $DeploymentSlot" + $slotInfo = az webapp deployment slot list --resource-group $ResourceGroupName --name $webApiName | ConvertFrom-JSON + $availableSlots = $slotInfo | Select-Object -Property Name + $origins = $slotInfo | Select-Object -Property defaultHostName $slotExists = false foreach ($slot in $availableSlots) { @@ -74,25 +91,68 @@ if ($DeploymentSlot) { } } - # Web App DeploymentSlot does not exist, create it + # Web App deployment slot does not exist, create it if (!$slotExists) { - Write-Host "DeploymentSlot $DeploymentSlot does not exist, creating..." - az webapp deployment slot create --slot $DeploymentSlot --resource-group $ResourceGroupName --name $webappName | Out-Null + Write-Host "Deployment slot $DeploymentSlot does not exist, creating..." + az webapp deployment slot create --slot $DeploymentSlot --resource-group $ResourceGroupName --name $webApiName --output none + $origins = az webapp deployment slot list --resource-group $ResourceGroupName --name $webApiName | ConvertFrom-JSON | Select-Object -Property defaultHostName } } -Write-Host "Deploying '$PackageFilePath' to Azure WebApp '$webappName'..." -# Setup the command as a string -$azWebAppCommand = "az webapp deployment source config-zip --resource-group $ResourceGroupName --name $webappName --src $PackageFilePath" - -# Check if DeploymentSlot parameter was passed and append the argument to azwebappcommand -if ($DeploymentSlot) { - $azWebAppCommand += " --slot $DeploymentSlot" -} +Write-Host "Deploying '$PackageFilePath' to Azure WebApp '$webApiName'..." # Invoke the command string Invoke-Expression $azWebAppCommand - if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + +if ($EnsureUriInAppRegistration) { + $webapiSettings = $(az webapp config appsettings list --name $webapiName --resource-group $ResourceGroupName | ConvertFrom-JSON) + $frontendClientId = ($webapiSettings | Where-Object -Property name -EQ -Value Frontend:AadClientId).value + $objectId = (az ad app show --id $frontendClientId | ConvertFrom-Json).id + $redirectUris = (az rest --method GET --uri "https://graph.microsoft.com/v1.0/applications/$objectId" --headers 'Content-Type=application/json' | ConvertFrom-Json).spa.redirectUris + $needToUpdateRegistration = $false + + foreach ($address in $origins) { + $origin = "https://$address" + Write-Host "Ensuring '$origin' is included in AAD app registration's redirect URIs..." + + if ($redirectUris -notcontains "$origin") { + $redirectUris += "$origin" + $needToUpdateRegistration = $true + } + } + + if ($needToUpdateRegistration) { + $body = "{spa:{redirectUris:[" + foreach ($uri in $redirectUris) { + $body += "'$uri'," + } + $body += "]}}" + + az rest ` + --method PATCH ` + --uri "https://graph.microsoft.com/v1.0/applications/$objectId" ` + --headers 'Content-Type=application/json' ` + --body $body + if ($LASTEXITCODE -ne 0) { + exit $LASTEXITCODE + } + } +} + +if ($RegisterPluginCors) { + foreach ($pluginName in $pluginNames) { + $allowedOrigins = $((az webapp cors show --name $pluginName --resource-group $ResourceGroupName --subscription $Subscription | ConvertFrom-Json).allowedOrigins) + foreach ($address in $origins) { + $origin = "https://$address" + Write-Host "Ensuring '$origin' is included in CORS origins for plugin '$pluginName'..." + if (-not $allowedOrigins -contains $origin) { + az webapp cors add --name $pluginName --resource-group $ResourceGroupName --subscription $Subscription --allowed-origins $origin + } + } + } +} + +Write-Host "To verify your deployment, go to 'https://$webApiUrl/' in your browser." \ No newline at end of file diff --git a/scripts/deploy/deploy-webapi.sh b/scripts/deploy/deploy-webapi.sh index 37db3f642..67c563253 100755 --- a/scripts/deploy/deploy-webapi.sh +++ b/scripts/deploy/deploy-webapi.sh @@ -1,8 +1,6 @@ -#!/usr/bin/env bash +#!/bin/bash -# Deploy CopilotChat's WebAPI to Azure. - -set -e +# Deploy Chat Copilot application to Azure usage() { echo "Usage: $0 -d DEPLOYMENT_NAME -s SUBSCRIPTION -rg RESOURCE_GROUP [OPTIONS]" @@ -11,40 +9,50 @@ usage() { echo " -d, --deployment-name DEPLOYMENT_NAME Name of the deployment from a 'deploy-azure.sh' deployment (mandatory)" echo " -s, --subscription SUBSCRIPTION Subscription to which to make the deployment (mandatory)" echo " -rg, --resource-group RESOURCE_GROUP Resource group name from a 'deploy-azure.sh' deployment (mandatory)" - echo " -p, --package PACKAGE_FILE_PATH Path to the WebAPI package file from a 'package-webapi.sh' run (default: \"./out/webapi.zip\")" + echo " -p, --package PACKAGE_FILE_PATH Path to the package file from a 'package-webapi.sh' run (default: \"./out/webapi.zip\")" echo " -o, --slot DEPLOYMENT_SLOT Name of the target web app deployment slot" + echo " -r, --register-app Switch to add our URI in app registration's redirect URIs if missing" + echo " -c, --register-cors Register service with the plugins as allowed CORS origin" } # Parse arguments while [[ $# -gt 0 ]]; do key="$1" case $key in - -d|--deployment-name) + -d|--deployment-name) DEPLOYMENT_NAME="$2" shift shift ;; - -s|--subscription) + -s|--subscription) SUBSCRIPTION="$2" shift shift ;; - -rg|--resource-group) + -rg|--resource-group) RESOURCE_GROUP="$2" shift shift ;; - -p|--package) + -p|--package) PACKAGE_FILE_PATH="$2" shift shift ;; - -o|--slot) + -r|--register-app) + REGISTER_APP=true + shift + ;; + -o|--slot) DEPLOYMENT_SLOT="$2" shift shift ;; - *) + -c|--register-cors) + REGISTER_CORS=true + shift + ;; + *) echo "Unknown option $1" usage exit 1 @@ -76,62 +84,120 @@ fi az account set -s "$SUBSCRIPTION" echo "Getting Azure WebApp resource name..." -eval WEB_APP_NAME=$(az deployment group show --name $DEPLOYMENT_NAME --resource-group $RESOURCE_GROUP --output json | jq -r '.properties.outputs.webapiName.value') -# Ensure $WEB_APP_NAME is set -if [[ -z "$WEB_APP_NAME" ]]; then +DEPLOYMENT_JSON=$(az deployment group show --name $DEPLOYMENT_NAME --resource-group $RESOURCE_GROUP --output json) +WEB_API_URL=$(echo $DEPLOYMENT_JSON | jq -r '.properties.outputs.webapiUrl.value') +echo "WEB_API_URL: $WEB_API_URL" +WEB_API_NAME=$(echo $DEPLOYMENT_JSON | jq -r '.properties.outputs.webapiName.value') +echo "WEB_API_NAME: $WEB_API_NAME" +PLUGIN_NAMES=$(echo $DEPLOYMENT_JSON | jq -r '.properties.outputs.pluginNames.value[]') +# Remove double quotes +PLUGIN_NAMES=${PLUGIN_NAMES//\"/} +echo "PLUGIN_NAMES: $PLUGIN_NAMES" +# Ensure $WEB_API_NAME is set +if [[ -z "$WEB_API_NAME" ]]; then echo "Could not get Azure WebApp resource name from deployment output." exit 1 fi -echo "Azure WebApp name: $WEB_APP_NAME" - echo "Configuring Azure WebApp to run from package..." -az webapp config appsettings set --resource-group $RESOURCE_GROUP --name $WEB_APP_NAME --settings WEBSITE_RUN_FROM_PACKAGE="1" > /dev/null +az webapp config appsettings set --resource-group $RESOURCE_GROUP --name $WEB_API_NAME --settings WEBSITE_RUN_FROM_PACKAGE="1" --output none if [ $? -ne 0 ]; then echo "Could not configure Azure WebApp to run from package." exit 1 fi -if [ -n "$DEPLOYMENT_SLOT" ]; then - - echo "Checking if slot $DEPLOYMENT_SLOT exists for $WEB_APP_NAME..." +# Set up deployment command as a string +AZ_WEB_APP_CMD="az webapp deployment source config-zip --resource-group $RESOURCE_GROUP --name $WEB_API_NAME --src $PACKAGE_FILE_PATH" - # Getting the list of slots - AVAILABLE_SLOTS=$(az webapp deployment slot list --resource-group $RESOURCE_GROUP --name $WEB_APP_NAME | jq -r '.[].name') +ORIGINS="$WEB_API_URL" +if [ -n "$DEPLOYMENT_SLOT" ]; then + AZ_WEB_APP_CMD+=" --slot ${DEPLOYMENT_SLOT}" + echo "Checking whether slot $DEPLOYMENT_SLOT exists for $WEB_APP_NAME..." + SLOT_INFO=$(az webapp deployment slot list --resource-group $RESOURCE_GROUP --name $WEB_API_NAME) + AVAILABLE_SLOTS=$(echo $SLOT_INFO | jq '.[].name') + ORIGINS=$(echo $slotInfo | jq '.[].defaultHostName') SLOT_EXISTS=false # Checking if the slot exists - for SLOT in $AVAILABLE_SLOTS; do - if [ "$SLOT" == "$DEPLOYMENT_SLOT" ]; then + for SLOT in $(echo "$AVAILABLE_SLOTS" | tr '\n' ' '); do + if [[ "$SLOT" == "$DEPLOYMENT_SLOT" ]]; then SLOT_EXISTS=true break fi done - # If slot does not exist, create it - if [ "$SLOT_EXISTS" == "false" ]; then - echo "Slot $DEPLOYMENT_SLOT does not exist, creating..." - az webapp deployment slot create --slot $DEPLOYMENT_SLOT --resource-group $RESOURCE_GROUP --name $WEB_APP_NAME > /dev/null + if [[ "$SLOT_EXISTS" = false ]]; then + echo "Deployment slot ${DEPLOYMENT_SLOT} does not exist, creating..." + + az webapp deployment slot create --slot=$DEPLOYMENT_SLOT --resource-group=$RESOURCE_GROUP --name $WEB_API_NAME + + ORIGINS=$(az webapp deployment slot list --resource-group=$RESOURCE_GROUP --name $WEB_API_NAME | jq '.[].defaultHostName') fi fi - -echo "Deploying '$PACKAGE_FILE_PATH' to Azure WebApp '$WEB_APP_NAME'..." - -azWebAppCommand="az webapp deployment source config-zip --resource-group $RESOURCE_GROUP --name $WEB_APP_NAME --src $PACKAGE_FILE_PATH" - -if [ ! -z "$DEPLOYMENT_SLOT" ]; then - azWebAppCommand+=" --slot $DEPLOYMENT_SLOT" +echo "Deploying '$PACKAGE_FILE_PATH' to Azure WebApp '$WEB_API_NAME'..." +eval "$AZ_WEB_APP_CMD" +if [ $? -ne 0 ]; then + echo "Could not deploy '$PACKAGE_FILE_PATH' to Azure WebApp '$WEB_API_NAME'." + exit 1 fi -eval $azWebAppCommand - +if [[ -n $REGISTER_APP ]]; then + WEBAPI_SETTINGS=$(az webapp config appsettings list --name $WEB_API_NAME --resource-group $RESOURCE_GROUP --output json) + FRONTEND_CLIENT_ID=$(echo $WEBAPI_SETTINGS | jq -r '.[] | select(.name == "Frontend:AadClientId") | .value') + OBJECT_ID=$(az ad app show --id $FRONTEND_CLIENT_ID | jq -r '.id') + REDIRECT_URIS=$(az rest --method GET --uri "https://graph.microsoft.com/v1.0/applications/$OBJECT_ID" --headers 'Content-Type=application/json' | jq -r '.spa.redirectUris[]') + NEED_TO_UPDATE_REG=false + + for ADDRESS in $(echo "$ORIGINS"); do + ORIGIN="https://$ADDRESS" + echo "Ensuring '$ORIGIN' is included in AAD app registration's redirect URIs..." + + if [[ ! "$REDIRECT_URIS" =~ "$ORIGIN" ]]; then + if [[ -n $REDIRECT_URIS ]]; then + REDIRECT_URIS=$(echo "$REDIRECT_URIS,$ORIGIN") + else + REDIRECT_URIS=$(echo "$ORIGIN") + fi + NEED_TO_UPDATE_REG=true + fi + done + + if [ $NEED_TO_UPDATE_REG = true ]; then + BODY="{spa:{redirectUris:['$(echo "$REDIRECT_URIS")']}}" + BODY="${BODY//\,/\',\'}" + + echo "Updating redirects with $BODY" + + az rest \ + --method PATCH \ + --uri "https://graph.microsoft.com/v1.0/applications/$OBJECT_ID" \ + --headers 'Content-Type=application/json' \ + --body $BODY + + if [ $? -ne 0 ]; then + echo "Failed to update app registration $OBJECT_ID with redirect URIs" + exit 1 + fi + fi +fi -if [ $? -ne 0 ]; then - echo "Could not deploy '$PACKAGE_FILE_PATH' to Azure WebApp '$WEB_APP_NAME'." - exit 1 +if [[ -n $REGISTER_CORS ]]; then + for PLUGIN_NAME in $PLUGIN_NAMES; do + ALLOWED_ORIGINS=$(az webapp cors show --name $PLUGIN_NAME --resource-group $RESOURCE_GROUP --subscription $SUBSCRIPTION | jq -r '.allowedOrigins[]') + for ADDRESS in $(echo "$ORIGINS"); do + ORIGIN="https://$ADDRESS" + echo "Ensuring '$ORIGIN' is included in CORS origins for plugin '$PLUGIN_NAME'..." + if [[ ! "$ALLOWED_ORIGINS" =~ "$ORIGIN" ]]; then + az webapp cors add --name $PLUGIN_NAME --resource-group $RESOURCE_GROUP --subscription $SUBSCRIPTION --allowed-origins "$ORIGIN" + if [ $? -ne 0 ]; then + echo "Failed to update CORS origins with $ORIGIN" + exit 1 + fi + fi + done + done fi -eval WEB_APP_URL=$(az deployment group show --name $DEPLOYMENT_NAME --resource-group $RESOURCE_GROUP --output json | jq -r '.properties.outputs.webapiUrl.value') -echo "To verify your deployment, go to 'https://$WEB_APP_URL/healthz' in your browser." +echo "To verify your deployment, go to 'https://$WEB_API_URL/' in your browser." diff --git a/scripts/deploy/deploy-webapp.ps1 b/scripts/deploy/deploy-webapp.ps1 deleted file mode 100644 index 81f61f057..000000000 --- a/scripts/deploy/deploy-webapp.ps1 +++ /dev/null @@ -1,149 +0,0 @@ -<# -.SYNOPSIS -Deploy CopilotChat's WebApp to Azure -#> - -param( - [Parameter(Mandatory)] - [string] - # Subscription to which to make the deployment - $Subscription, - - [Parameter(Mandatory)] - [string] - # Resource group to which to make the deployment - $ResourceGroupName, - - [Parameter(Mandatory)] - [string] - # Name of the previously deployed Azure deployment - $DeploymentName, - - [Parameter(Mandatory)] - [string] - # Client application id for the frontend web app - $FrontendClientId, - - [string] - # SWA Environment webapp will be deployed to - $Environment = "Production", - - [string] - # Version to display in UI. - $Version = "", - - [string] - # Additional information given in version info. (Ex: commit SHA) - $VersionInfo = "" -) - -Write-Host "Setting up Azure credentials..." -az account show --output none -if ($LASTEXITCODE -ne 0) { - Write-Host "Log into your Azure account" - az login --output none -} - -Write-Host "Setting subscription to '$Subscription'..." -az account set -s $Subscription -if ($LASTEXITCODE -ne 0) { - exit $LASTEXITCODE -} - -Write-Host "Getting deployment outputs..." -$deployment = $(az deployment group show --name $DeploymentName --resource-group $ResourceGroupName --output json | ConvertFrom-Json) -$webappUrl = $deployment.properties.outputs.webappUrl.value -$webappName = $deployment.properties.outputs.webappName.value -$webapiUrl = $deployment.properties.outputs.webapiUrl.value -$webapiName = $deployment.properties.outputs.webapiName.value -$pluginNames = $deployment.properties.outputs.pluginNames.value -Write-Host "webappUrl: $webappUrl" -Write-Host "webappName: $webappName" -Write-Host "webapiName: $webapiName" -Write-Host "webapiUrl: $webapiUrl" -foreach ($pluginName in $pluginNames) { - Write-Host "pluginName: $pluginName" -} - -# Set ASCII as default encoding for Out-File -$PSDefaultParameterValues['Out-File:Encoding'] = 'ascii' - -$envFilePath = "$PSScriptRoot/../../webapp/.env" -Write-Host "Writing environment variables to '$envFilePath'..." -"REACT_APP_BACKEND_URI=https://$webapiUrl/" | Out-File -FilePath $envFilePath -"REACT_APP_SK_VERSION=$Version" | Out-File -FilePath $envFilePath -Append -"REACT_APP_SK_BUILD_INFO=$VersionInfo" | Out-File -FilePath $envFilePath -Append - -Write-Host "Generating SWA config..." -$swaConfig = $(Get-Content "$PSScriptRoot/../../webapp/template.swa-cli.config.json" -Raw) -$swaConfig = $swaConfig.Replace("{{appDevserverUrl}}", "https://$webappUrl") -$swaConfig = $swaConfig.Replace("{{appName}}", "$webappName") -$swaConfig = $swaConfig.Replace("{{resourceGroup}}", "$ResourceGroupName") -$swaConfig = $swaConfig.Replace("{{subscription-id}}", "$Subscription") - -$swaConfig | Out-File -FilePath "$PSScriptRoot/../../webapp/swa-cli.config.json" -Write-Host $(Get-Content "$PSScriptRoot/../../webapp/swa-cli.config.json" -Raw) - -Push-Location -Path "$PSScriptRoot/../../webapp" -Write-Host "Installing yarn dependencies..." -yarn install -if ($LASTEXITCODE -ne 0) { - exit $LASTEXITCODE -} - -Write-Host "Building webapp..." -swa build -if ($LASTEXITCODE -ne 0) { - exit $LASTEXITCODE -} - -Write-Host "Deploying webapp..." -swa deploy --subscription-id $Subscription --app-name $webappName --env $Environment -if ($LASTEXITCODE -ne 0) { - exit $LASTEXITCODE -} - -Pop-Location - -foreach ($env in (az staticwebapp environment list --name $webappName | ConvertFrom-JSON)) { - $hostname = $env.hostname - $origin = "https://$hostname" - - Write-Host "Ensuring '$origin' is included in CORS origins for webapi '$webapiName'..." - if (-not ((az webapp cors show --name $webapiName --resource-group $ResourceGroupName --subscription $Subscription | ConvertFrom-Json).allowedOrigins -contains $origin)) { - az webapp cors add --name $webapiName --resource-group $ResourceGroupName --subscription $Subscription --allowed-origins $origin - } - - foreach ($pluginName in $pluginNames) { - Write-Host "Ensuring '$origin' is included in CORS origins for plugin '$pluginName'..." - if (-not ((az webapp cors show --name $pluginName --resource-group $ResourceGroupName --subscription $Subscription | ConvertFrom-Json).allowedOrigins -contains $origin)) { - az webapp cors add --name $pluginName --resource-group $ResourceGroupName --subscription $Subscription --allowed-origins $origin - } - } - - Write-Host "Ensuring '$origin' is included in AAD app registration's redirect URIs..." - $objectId = (az ad app show --id $FrontendClientId | ConvertFrom-Json).id - $redirectUris = (az rest --method GET --uri "https://graph.microsoft.com/v1.0/applications/$objectId" --headers 'Content-Type=application/json' | ConvertFrom-Json).spa.redirectUris - if ($redirectUris -notcontains "$origin") { - $redirectUris += "$origin" - - $body = "{spa:{redirectUris:[" - foreach ($uri in $redirectUris) { - $body += "'$uri'," - } - $body += "]}}" - - az rest ` - --method PATCH ` - --uri "https://graph.microsoft.com/v1.0/applications/$objectId" ` - --headers 'Content-Type=application/json' ` - --body $body - } - if ($LASTEXITCODE -ne 0) { - exit $LASTEXITCODE - } - - - Write-Host "To verify your deployment, go to 'https://$webappUrl' in your browser." -} - diff --git a/scripts/deploy/deploy-webapp.sh b/scripts/deploy/deploy-webapp.sh deleted file mode 100755 index 324fc3f8f..000000000 --- a/scripts/deploy/deploy-webapp.sh +++ /dev/null @@ -1,191 +0,0 @@ -#!/usr/bin/env bash - -# Deploy CopilotChat's WebApp to Azure - -set -e - -SCRIPT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - -usage() { - echo "Usage: $0 -d DEPLOYMENT_NAME -s SUBSCRIPTION -rg RESOURCE_GROUP -c FRONTEND_CLIENT_ID [OPTIONS]" - echo "" - echo "Arguments:" - echo " -d, --deployment-name DEPLOYMENT_NAME Name of the deployment from a 'deploy-azure.sh' deployment (mandatory)" - echo " -s, --subscription SUBSCRIPTION Subscription to which to make the deployment (mandatory)" - echo " -rg, --resource-group RESOURCE_GROUP Resource group name from a 'deploy-azure.sh' deployment (mandatory)" - echo " -c, --client-id FRONTEND_CLIENT_ID Client application ID for the frontend web app (mandatory)" - echo " -v --version VERSION Version to display in UI (default: 1.0.0)" - echo " -i --version-info INFO Additional info to put in version details" - echo " -nr, --no-redirect Do not attempt to register redirect URIs with the client application" - echo " -env --environment Specify a SWA environment" -} - -# Default the environment variable to Production -ENVIRONMENT="Production" - -# Parse arguments -while [[ $# -gt 0 ]]; do - key="$1" - case $key in - -d | --deployment-name) - DEPLOYMENT_NAME="$2" - shift - shift - ;; - -s | --subscription) - SUBSCRIPTION="$2" - shift - shift - ;; - -rg | --resource-group) - RESOURCE_GROUP="$2" - shift - shift - ;; - -c | --client-id) - FRONTEND_CLIENT_ID="$2" - shift - shift - ;; - -v | --version) - VERSION="$2" - shift - shift - ;; - -i | --version-info) - VERSION_INFO="$2" - shift - shift - ;; - -nr | --no-redirect) - NO_REDIRECT=true - shift - ;; - -env|--environment) - ENVIRONMENT="$2" # Overwrite the default value if the option is provided - shift - shift - ;; - *) - echo "Unknown option $1" - usage - exit 1 - ;; - esac -done - -# Check mandatory arguments -if [[ -z "$DEPLOYMENT_NAME" ]] || [[ -z "$SUBSCRIPTION" ]] || [[ -z "$RESOURCE_GROUP" ]] || [[ -z "$FRONTEND_CLIENT_ID" ]]; then - usage - exit 1 -fi - -az account show --output none -if [ $? -ne 0 ]; then - echo "Log into your Azure account" - az login --use-device-code -fi - -az account set -s "$SUBSCRIPTION" - -echo "Getting deployment outputs..." -DEPLOYMENT_JSON=$(az deployment group show --name $DEPLOYMENT_NAME --resource-group $RESOURCE_GROUP --output json) -# get the webapiUrl from the deployment outputs -eval WEB_APP_URL=$(echo $DEPLOYMENT_JSON | jq -r '.properties.outputs.webappUrl.value') -echo "WEB_APP_URL: $WEB_APP_URL" -eval WEB_APP_NAME=$(echo $DEPLOYMENT_JSON | jq -r '.properties.outputs.webappName.value') -echo "WEB_APP_NAME: $WEB_APP_NAME" -eval WEB_API_URL=$(echo $DEPLOYMENT_JSON | jq -r '.properties.outputs.webapiUrl.value') -echo "WEB_API_URL: $WEB_API_URL" -eval WEB_API_NAME=$(echo $DEPLOYMENT_JSON | jq -r '.properties.outputs.webapiName.value') -echo "WEB_API_NAME: $WEB_API_NAME" -eval PLUGIN_NAMES=$(echo $DEPLOYMENT_JSON | jq -r '.properties.outputs.pluginNames.value[]') -echo "PLUGIN_NAMES: $PLUGIN_NAMES" - -ENV_FILE_PATH="$SCRIPT_ROOT/../../webapp/.env" -echo "Writing environment variables to '$ENV_FILE_PATH'..." -echo "REACT_APP_BACKEND_URI=https://$WEB_API_URL/" > $ENV_FILE_PATH -echo "REACT_APP_SK_VERSION=$VERSION" >> $ENV_FILE_PATH -echo "REACT_APP_SK_BUILD_INFO=$VERSION_INFO" >> $ENV_FILE_PATH - -echo "Writing swa-cli.config.json..." -SWA_CONFIG_FILE_PATH="$SCRIPT_ROOT/../../webapp/swa-cli.config.json" -SWA_CONFIG_TEMPLATE_FILE_PATH="$SCRIPT_ROOT/../../webapp/template.swa-cli.config.json" -swaConfig=$(cat $SWA_CONFIG_TEMPLATE_FILE_PATH) -swaConfig=$(echo $swaConfig | sed "s/{{appDevserverUrl}}/https:\/\/${WEB_APP_URL}/") -swaConfig=$(echo $swaConfig | sed "s/{{appName}}/$WEB_API_NAME/") -swaConfig=$(echo $swaConfig | sed "s/{{resourceGroup}}/$RESOURCE_GROUP/") -swaConfig=$(echo $swaConfig | sed "s/{{subscription-id}}/$SUBSCRIPTION/") -echo $swaConfig >$SWA_CONFIG_FILE_PATH - -pushd "$SCRIPT_ROOT/../../webapp" - -echo "Installing yarn dependencies..." -yarn install -if [ $? -ne 0 ]; then - echo "Failed to install yarn dependencies" - exit 1 -fi - -echo "Building webapp..." -swa build -if [ $? -ne 0 ]; then - echo "Failed to build webapp" - exit 1 -fi - -echo "Deploying webapp..." -swa deploy --subscription-id $SUBSCRIPTION --app-name $WEB_APP_NAME --env $ENVIRONMENT -if [ $? -ne 0 ]; then - echo "Failed to deploy webapp" - exit 1 -fi - -popd - -ENVIRONMENTS=$(az staticwebapp environment list --name "$WEB_APP_NAME") - -for env in $(echo "${ENVIRONMENTS}" | jq -r '.[] | @base64'); do - HOSTNAME=$(echo "$env" | base64 --decode | jq -r '.hostname') - ORIGIN="https://$HOSTNAME" - - echo "Ensuring origin '$ORIGIN' is included in CORS origins for webapi '$WEB_API_NAME'..." - CORS_RESULT=$(az webapp cors show --name $WEB_API_NAME --resource-group $RESOURCE_GROUP --subscription $SUBSCRIPTION | jq '.allowedOrigins | index("$ORIGIN")') - if [[ "$CORS_RESULT" == "null" ]]; then - echo "Adding CORS origin '$ORIGIN' to webapi '$WEB_API_NAME'..." - az webapp cors add --name $WEB_API_NAME --resource-group $RESOURCE_GROUP --subscription $SUBSCRIPTION --allowed-origins $ORIGIN - fi - - for PLUGIN_NAME in $PLUGIN_NAMES; do - echo "Ensuring origin '$ORIGIN' is included in CORS origins for plugin '$PLUGIN_NAME'..." - CORS_RESULT=$(az webapp cors show --name $PLUGIN_NAME --resource-group $RESOURCE_GROUP --subscription $SUBSCRIPTION | jq '.allowedOrigins | index("$ORIGIN")') - if [[ "$CORS_RESULT" == "null" ]]; then - echo "Adding CORS origin '$ORIGIN' to plugin '$PLUGIN_NAME'..." - az webapp cors add --name $PLUGIN_NAME --resource-group $RESOURCE_GROUP --subscription $SUBSCRIPTION --allowed-origins $ORIGIN - fi - done - - echo "Ensuring '$ORIGIN' is included in AAD app registration's redirect URIs..." - eval OBJECT_ID=$(az ad app show --id $FRONTEND_CLIENT_ID | jq -r '.id') - - if [ "$NO_REDIRECT" != true ]; then - REDIRECT_URIS=$(az rest --method GET --uri "https://graph.microsoft.com/v1.0/applications/$OBJECT_ID" --headers 'Content-Type=application/json' | jq -r '.spa.redirectUris') - if [[ ! "$REDIRECT_URIS" =~ "$ORIGIN" ]]; then - BODY="{spa:{redirectUris:['" - eval BODY+=$(echo $REDIRECT_URIS | jq $'join("\',\'")') - BODY+="','$ORIGIN']}}" - - az rest \ - --method PATCH \ - --uri "https://graph.microsoft.com/v1.0/applications/$OBJECT_ID" \ - --headers 'Content-Type=application/json' \ - --body $BODY - fi - if [ $? -ne 0 ]; then - echo "Failed to update app registration" - exit 1 - fi - fi - - echo "To verify your deployment, go to 'https://$WEB_APP_URL' in your browser." -done diff --git a/scripts/deploy/main.bicep b/scripts/deploy/main.bicep index 9d37f0774..4d2c51cdc 100644 --- a/scripts/deploy/main.bicep +++ b/scripts/deploy/main.bicep @@ -50,6 +50,9 @@ param aiApiKey string = '' @description('Azure AD client ID for the backend web API') param webApiClientId string = '' +@description('Azure AD client ID for the frontend') +param frontendClientId string = '' + @description('Azure AD tenant ID for authenticating users') param azureAdTenantId string = '' @@ -86,9 +89,6 @@ param deployWebSearcherPackage bool = true @description('Region for the resources') param location string = resourceGroup().location -@description('Region for the webapp frontend') -param webappLocation string = 'westus2' - @description('Hash of the resource group ID') var rgIdHash = uniqueString(resourceGroup().id) @@ -254,10 +254,6 @@ resource appServiceWebConfig 'Microsoft.Web/sites/config@2022-09-01' = { name: 'MemoryStore:Qdrant:Port' value: '443' } - { - name: 'MemoryStore:AzureCognitiveSearch:UseVectorSearch' - value: 'true' - } { name: 'MemoryStore:AzureCognitiveSearch:Endpoint' value: memoryStore == 'AzureCognitiveSearch' ? 'https://${azureCognitiveSearch.name}.search.windows.net' : '' @@ -286,6 +282,10 @@ resource appServiceWebConfig 'Microsoft.Web/sites/config@2022-09-01' = { name: 'Kestrel:Endpoints:Https:Url' value: 'https://localhost:443' } + { + name: 'Frontend:AadClientId' + value: frontendClientId + } { name: 'Logging:LogLevel:Default' value: 'Warning' @@ -310,10 +310,6 @@ resource appServiceWebConfig 'Microsoft.Web/sites/config@2022-09-01' = { name: 'Logging:ApplicationInsights:LogLevel:Default' value: 'Warning' } - { - name: 'ApplicationInsights:ConnectionString' - value: appInsightsWeb.properties.ConnectionString - } { name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' value: appInsightsWeb.properties.ConnectionString @@ -1135,7 +1131,7 @@ resource postgresDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = if (me location: 'global' } -resource postgresPrivateEndpoint 'Microsoft.Network/privateEndpoints@2023-04-01' = if (memoryStore == 'Postgres') { +resource postgresPrivateEndpoint 'Microsoft.Network/privateEndpoints@2023-05-01' = if (memoryStore == 'Postgres') { name: 'pg-${uniqueName}-pe' location: location properties: { @@ -1230,20 +1226,6 @@ resource bingSearchService 'Microsoft.Bing/accounts@2020-06-10' = { kind: 'Bing.Search.v7' } -resource staticWebApp 'Microsoft.Web/staticSites@2022-09-01' = { - name: 'swa-${uniqueName}' - location: webappLocation - properties: { - provider: 'None' - } - sku: { - name: 'Free' - tier: 'Free' - } -} - -output webappUrl string = staticWebApp.properties.defaultHostname -output webappName string = staticWebApp.name output webapiUrl string = appServiceWeb.properties.defaultHostName output webapiName string = appServiceWeb.name output memoryPipelineName string = appServiceMemoryPipeline.name diff --git a/scripts/deploy/main.json b/scripts/deploy/main.json index f6dcdcbdf..b89754164 100644 --- a/scripts/deploy/main.json +++ b/scripts/deploy/main.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.21.1.54444", - "templateHash": "11704216743072254394" + "templateHash": "4239752954578942550" } }, "parameters": { @@ -107,6 +107,13 @@ "description": "Azure AD client ID for the backend web API" } }, + "frontendClientId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Azure AD client ID for the frontend" + } + }, "azureAdTenantId": { "type": "string", "defaultValue": "", @@ -183,13 +190,6 @@ "description": "Region for the resources" } }, - "webappLocation": { - "type": "string", - "defaultValue": "westus2", - "metadata": { - "description": "Region for the webapp frontend" - } - }, "sqlAdminPassword": { "type": "securestring", "defaultValue": "[newGuid()]", @@ -389,10 +389,6 @@ "name": "MemoryStore:Qdrant:Port", "value": "443" }, - { - "name": "MemoryStore:AzureCognitiveSearch:UseVectorSearch", - "value": "true" - }, { "name": "MemoryStore:AzureCognitiveSearch:Endpoint", "value": "[if(equals(parameters('memoryStore'), 'AzureCognitiveSearch'), format('https://{0}.search.windows.net', format('acs-{0}', variables('uniqueName'))), '')]" @@ -421,6 +417,10 @@ "name": "Kestrel:Endpoints:Https:Url", "value": "https://localhost:443" }, + { + "name": "Frontend:AadClientId", + "value": "[parameters('frontendClientId')]" + }, { "name": "Logging:LogLevel:Default", "value": "Warning" @@ -445,10 +445,6 @@ "name": "Logging:ApplicationInsights:LogLevel:Default", "value": "Warning" }, - { - "name": "ApplicationInsights:ConnectionString", - "value": "[reference(resourceId('Microsoft.Insights/components', format('appins-{0}-webapi', variables('uniqueName'))), '2020-02-02').ConnectionString]" - }, { "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", "value": "[reference(resourceId('Microsoft.Insights/components', format('appins-{0}-webapi', variables('uniqueName'))), '2020-02-02').ConnectionString]" @@ -1382,7 +1378,7 @@ { "condition": "[equals(parameters('memoryStore'), 'Postgres')]", "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2023-04-01", + "apiVersion": "2023-05-01", "name": "[format('pg-{0}-pe', variables('uniqueName'))]", "location": "[parameters('location')]", "properties": { @@ -1493,30 +1489,9 @@ "name": "S1" }, "kind": "Bing.Search.v7" - }, - { - "type": "Microsoft.Web/staticSites", - "apiVersion": "2022-09-01", - "name": "[format('swa-{0}', variables('uniqueName'))]", - "location": "[parameters('webappLocation')]", - "properties": { - "provider": "None" - }, - "sku": { - "name": "Free", - "tier": "Free" - } } ], "outputs": { - "webappUrl": { - "type": "string", - "value": "[reference(resourceId('Microsoft.Web/staticSites', format('swa-{0}', variables('uniqueName'))), '2022-09-01').defaultHostname]" - }, - "webappName": { - "type": "string", - "value": "[format('swa-{0}', variables('uniqueName'))]" - }, "webapiUrl": { "type": "string", "value": "[reference(resourceId('Microsoft.Web/sites', format('app-{0}-webapi', variables('uniqueName'))), '2022-09-01').defaultHostName]" diff --git a/scripts/deploy/object.txt b/scripts/deploy/object.txt new file mode 100644 index 000000000..200334167 --- /dev/null +++ b/scripts/deploy/object.txt @@ -0,0 +1,94 @@ +{ + "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#applications/$entity", + "addIns": [], + "api": { + "acceptMappedClaims": null, + "knownClientApplications": [], + "oauth2PermissionScopes": [], + "preAuthorizedApplications": [], + "requestedAccessTokenVersion": null + }, + "appId": "2e7a7e36-d840-41e2-9cd2-4a7c1c6e2d6d", + "appRoles": [], + "applicationTemplateId": null, + "certification": null, + "createdDateTime": "2023-07-21T17:08:33Z", + "defaultRedirectUri": null, + "deletedDateTime": null, + "description": null, + "disabledByMicrosoftStatus": null, + "displayName": "SemanticKernel-Copilot-Staging", + "groupMembershipClaims": null, + "id": "04a67174-c17f-4f3a-996c-b22517454c71", + "identifierUris": [], + "info": { + "logoUrl": null, + "marketingUrl": null, + "privacyStatementUrl": null, + "supportUrl": null, + "termsOfServiceUrl": null + }, + "isDeviceOnlyAuthSupported": null, + "isFallbackPublicClient": null, + "keyCredentials": [], + "notes": null, + "optionalClaims": null, + "parentalControlSettings": { + "countriesBlockedForMinors": [], + "legalAgeGroupRule": "Allow" + }, + "passwordCredentials": [], + "publicClient": { + "redirectUris": [] + }, + "publisherDomain": "microsoft.onmicrosoft.com", + "requestSignatureVerification": null, + "requiredResourceAccess": [ + { + "resourceAccess": [ + { + "id": "c71f7111-8e3e-4eb7-b56a-0ce6c2fdfd30", + "type": "Scope" + } + ], + "resourceAppId": "82ee9347-fcb3-49d0-9823-90c173e19952" + }, + { + "resourceAccess": [ + { + "id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d", + "type": "Scope" + } + ], + "resourceAppId": "00000003-0000-0000-c000-000000000000" + } + ], + "samlMetadataUrl": null, + "serviceManagementReference": "05b809ac-318a-4d52-85ff-281458cb5348", + "servicePrincipalLockConfiguration": null, + "signInAudience": "AzureADMyOrg", + "spa": { + "redirectUris": [ + "https://app-copichat-rlvquxqizayf2-webapi.azurewebsites.net", + "https://localhost:40443", + "https://nice-smoke-05abf441e.3.azurestaticapps.net" + ] + }, + "tags": [], + "tokenEncryptionKeyId": null, + "verifiedPublisher": { + "addedDateTime": null, + "displayName": null, + "verifiedPublisherId": null + }, + "web": { + "homePageUrl": null, + "implicitGrantSettings": { + "enableAccessTokenIssuance": true, + "enableIdTokenIssuance": true + }, + "logoutUrl": null, + "redirectUriSettings": [], + "redirectUris": [] + } +} diff --git a/scripts/deploy/package-webapi.ps1 b/scripts/deploy/package-webapi.ps1 index 586570751..acb0d0f87 100755 --- a/scripts/deploy/package-webapi.ps1 +++ b/scripts/deploy/package-webapi.ps1 @@ -1,6 +1,6 @@ <# .SYNOPSIS -Package CopilotChat's WebAPI for deployment to Azure +Package Chat Copilot application for deployment to Azure #> param( @@ -22,13 +22,19 @@ param( [string] # Version to give to assemblies and files. - $Version = "1.0.0", + $Version = "0.0.0", [string] # Additional information given in version info. - $InformationalVersion = "" + $InformationalVersion = "", + + [bool] + # Whether to skip building frontend files (false by default) + $SkipFrontendFiles = $false ) +Write-Host "Building backend executables..." + Write-Host "BuildConfiguration: $BuildConfiguration" Write-Host "DotNetFramework: $DotNetFramework" Write-Host "TargetRuntime: $TargetRuntime" @@ -50,7 +56,30 @@ if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } -Write-Host "Compressing to $publishedZipFilePath" +if (-Not $SkipFrontendFiles) { + Write-Host "Building static frontend files..." + + Push-Location -Path "$PSScriptRoot/../../webapp" + + Write-Host "Installing yarn dependencies..." + yarn install + if ($LASTEXITCODE -ne 0) { + exit $LASTEXITCODE + } + + Write-Host "Building webapp..." + yarn build + if ($LASTEXITCODE -ne 0) { + exit $LASTEXITCODE + } + + Pop-Location + + Write-Host "Copying frontend files to package" + Copy-Item -Path "$PSScriptRoot/../../webapp/build" -Destination "$publishOutputDirectory\wwwroot" -Recurse -Force +} + +Write-Host "Compressing package to $publishedZipFilePath" Compress-Archive -Path $publishOutputDirectory\* -DestinationPath $publishedZipFilePath -Force -Write-Host "Published webapi package to '$publishedZipFilePath'" \ No newline at end of file +Write-Host "Published package to '$publishedZipFilePath'" \ No newline at end of file diff --git a/scripts/deploy/package-webapi.sh b/scripts/deploy/package-webapi.sh old mode 100755 new mode 100644 index 294a7431f..ef5356ad6 --- a/scripts/deploy/package-webapi.sh +++ b/scripts/deploy/package-webapi.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Package CiopilotChat's WebAPI for deployment to Azure +# Package Chat Copilot application for deployment to Azure set -e @@ -18,6 +18,7 @@ usage() { echo " -v --version VERSION Version to set files to (default: 1.0.0)" echo " -i --info INFO Additional info to put in version details" echo " -nz, --no-zip Do not zip package (default: false)" + echo " -s, --skip-frontend Do not build frontend files" } # Parse arguments @@ -58,7 +59,11 @@ while [[ $# -gt 0 ]]; do NO_ZIP=true shift ;; - *) + -s|--skip-frontend) + SKIP_FRONTEND=true + shift + ;; + *) echo "Unknown option $1" usage exit 1 @@ -66,11 +71,13 @@ while [[ $# -gt 0 ]]; do esac done +echo "Building backend executables..." + # Set defaults : "${CONFIGURATION:="Release"}" : "${DOTNET:="net6.0"}" : "${RUNTIME:="linux-x64"}" -: "${VERSION:="1.0.0"}" +: "${VERSION:="0.0.0"}" : "${INFO:=""}" : "${OUTPUT_DIRECTORY:="$SCRIPT_ROOT"}" @@ -100,6 +107,31 @@ if [ $? -ne 0 ]; then exit 1 fi +if [[ -z "$SKIP_FRONTEND" ]]; then + echo "Building static frontend files..." + + pushd "$SCRIPT_ROOT/../../webapp" + + echo "Installing yarn dependencies..." + yarn install + if [ $? -ne 0 ]; then + echo "Failed to install yarn dependencies" + exit 1 + fi + + echo "Building webapp..." + yarn build + if [ $? -ne 0 ]; then + echo "Failed to build webapp" + exit 1 + fi + + popd + + echo "Copying frontend files to package" + cp -R "$SCRIPT_ROOT/../../webapp/build" "$PUBLISH_OUTPUT_DIRECTORY/wwwroot" +fi + # if not NO_ZIP then zip the package if [[ -z "$NO_ZIP" ]]; then pushd "$PUBLISH_OUTPUT_DIRECTORY" diff --git a/webapi/Controllers/MaintenanceController.cs b/webapi/Controllers/MaintenanceController.cs index 861ebbcbf..17f67e085 100644 --- a/webapi/Controllers/MaintenanceController.cs +++ b/webapi/Controllers/MaintenanceController.cs @@ -49,7 +49,7 @@ public MaintenanceController( var migrationStatus = await migrationMonitor.GetCurrentStatusAsync(cancellationToken); - if (migrationStatus == ChatMigrationStatus.Upgrading) + if (migrationStatus != ChatMigrationStatus.None) { result = new MaintenanceResult diff --git a/webapi/Services/MemoryMigration/ChatMigrationMonitor.cs b/webapi/Services/MemoryMigration/ChatMigrationMonitor.cs index af5871de6..8d5e3f119 100644 --- a/webapi/Services/MemoryMigration/ChatMigrationMonitor.cs +++ b/webapi/Services/MemoryMigration/ChatMigrationMonitor.cs @@ -114,15 +114,11 @@ async Task QueryStatusAsync() try { var result = - await this._memory.SearchAsync( + await this._memory.GetAsync( this._indexNameGlobalDocs, MigrationKey, - limit: 1, - minRelevanceScore: -1, - withEmbeddings: false, - cancellationToken) - .SingleOrDefaultAsync(cancellationToken) - ; + withEmbedding: false, + cancellationToken); if (result == null) { diff --git a/webapi/Services/SemanticKernelProvider.cs b/webapi/Services/SemanticKernelProvider.cs index be4dc682d..0bbb39737 100644 --- a/webapi/Services/SemanticKernelProvider.cs +++ b/webapi/Services/SemanticKernelProvider.cs @@ -2,6 +2,7 @@ using System; using System.Net.Http; +using System.Threading; using CopilotChat.WebApi.Options; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -22,6 +23,8 @@ namespace CopilotChat.WebApi.Services; /// public sealed class SemanticKernelProvider { + private static IMemoryStore? _volatileMemoryStore; + private readonly IServiceProvider _serviceProvider; private readonly IConfiguration _configuration; @@ -159,7 +162,9 @@ IMemoryStore CreateMemoryStore() switch (memoryOptions.Retrieval.VectorDbType) { case string x when x.Equals("SimpleVectorDb", StringComparison.OrdinalIgnoreCase): - return new VolatileMemoryStore(); + // Maintain single instance of volatile memory. + Interlocked.CompareExchange(ref _volatileMemoryStore, new VolatileMemoryStore(), null); + return _volatileMemoryStore; case string x when x.Equals("Qdrant", StringComparison.OrdinalIgnoreCase): var qdrantConfig = memoryOptions.GetServiceConfig(this._configuration, "Qdrant"); diff --git a/webapp/src/components/views/BackendProbe.tsx b/webapp/src/components/views/BackendProbe.tsx index 2e4f144c1..e4911e202 100644 --- a/webapp/src/components/views/BackendProbe.tsx +++ b/webapp/src/components/views/BackendProbe.tsx @@ -55,8 +55,7 @@ export const BackendProbe: FC = ({ onBackendFound }) => { .then((data) => { // Body has payload. This means the app is in maintenance setModel(data as IMaintenance); - clearInterval(timer); - return false; + return true; }) .catch((e: any) => { if (e instanceof TypeError) { diff --git a/webapp/template.swa-cli.config.json b/webapp/template.swa-cli.config.json deleted file mode 100644 index cd328d776..000000000 --- a/webapp/template.swa-cli.config.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "$schema": "https://aka.ms/azure/static-web-apps-cli/schema", - "configurations": { - "webapp": { - "appLocation": ".", - "outputLocation": "./build", - "appBuildCommand": "yarn build", - "run": "yarn start", - "appDevserverUrl": "{{appDevserverUrl}}", - "appName": "{{appName}}", - "resourceGroup": "{{resourceGroup}}", - "subscription-id": "{{subscription-id}}", - "env": "production" - } - } -} \ No newline at end of file