From 5ab3ea69e4291e32283fa4ca2b860ff23aeaf653 Mon Sep 17 00:00:00 2001 From: Jordan Matthiesen <1333029+jmatthiesen@users.noreply.github.com> Date: Mon, 21 Oct 2024 12:48:28 -0700 Subject: [PATCH] Infra code for sample (#2) * Added support for assigning the current user to the Cognitive Services User role, so that the sample can be run after using azd provision/up. * Continuing work on infra * Refactoring infra to store connection strings in user secrets. Enabling external HTTP endpoints when deployed. * Updates with latest generated code from `azd infra synth` * Setting up CodeSpaces support. * Updated to install aspire workload. * Final edits to CodeSpaces for now (it won't really work until Aspire 9). * Added initial README and actions. --- .devcontainer/devcontainer.json | 44 +++++ .github/ISSUE_TEMPLATE.md | 2 +- .github/workflows/pr-gate.yml | 59 ++++++ .github/workflows/template-validation.yml | 27 +++ README.md | 186 ++++++++++++++---- azure.yaml | 12 ++ docs/screenshot_chatapp.png | Bin 0 -> 51560 bytes infra/main.bicep | 8 +- infra/main.parameters.json | 2 +- infra/openai/openai.module.bicep | 53 +++-- infra/post-script/store-env-variables.ps1 | 20 ++ infra/post-script/store-env-variables.sh | 29 +++ readme_diagram.png | Bin 0 -> 52374 bytes src/AIChatApp.AppHost/Program.cs | 11 +- .../infra/aichatapp-web.tmpl.yaml | 51 +++++ 15 files changed, 443 insertions(+), 61 deletions(-) create mode 100644 .devcontainer/devcontainer.json create mode 100644 .github/workflows/pr-gate.yml create mode 100644 .github/workflows/template-validation.yml create mode 100644 docs/screenshot_chatapp.png create mode 100644 infra/post-script/store-env-variables.ps1 create mode 100644 infra/post-script/store-env-variables.sh create mode 100644 readme_diagram.png create mode 100644 src/AIChatApp.AppHost/infra/aichatapp-web.tmpl.yaml diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..e9862b4 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,44 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/dotnet +{ + "name": "C# (.NET)", + + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "image": "mcr.microsoft.com/devcontainers/dotnet:1-8.0", + + // Features to add to the dev container. More info: https://containers.dev/features. + "features": { + "ghcr.io/devcontainers/features/azure-cli:1": { + "installBicep": true, + "version": "latest" + }, + "ghcr.io/azure/azure-dev/azd:0": { + "version": "stable" + }, + "ghcr.io/devcontainers/features/dotnet:2": { + "workloads": "aspire" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "ms-dotnettools.csdevkit", + "ms-dotnettools.vscode-dotnet-runtime", + "GitHub.vscode-github-actions", + "ms-azuretools.azure-dev", + "ms-azuretools.vscode-bicep", + "ms-azuretools.vscode-docker", + "ms-vscode.js-debug" ] + } + }, + + "postCreateCommand": "dotnet dev-certs https --trust" // Enable HTTPS support + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [5000, 5001], + // "portsAttributes": { + // "17099": { + // "protocol": "https" + // } + // } +} diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 15c7f60..c8eae57 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -30,4 +30,4 @@ IF SUFFICIENT INFORMATION IS NOT PROVIDED VIA THE FOLLOWING TEMPLATE THE ISSUE M ### Mention any other details that might be useful > --------------------------------------------------------------- -> Thanks! We'll be in touch soon. +> Thanks! We'll be in touch soon. \ No newline at end of file diff --git a/.github/workflows/pr-gate.yml b/.github/workflows/pr-gate.yml new file mode 100644 index 0000000..532b93f --- /dev/null +++ b/.github/workflows/pr-gate.yml @@ -0,0 +1,59 @@ +name: AI Gallery Template Gate Validation +on: + workflow_dispatch: + pull_request: + branches: + - main + +permissions: + contents: read + id-token: write + pull-requests: write + security-events: write + +jobs: + validation: + runs-on: ubuntu-latest + env: + AZURE_CLIENT_ID: ${{ vars.AZURE_CLIENT_ID }} + AZURE_TENANT_ID: ${{ vars.AZURE_TENANT_ID }} + AZURE_SUBSCRIPTION_ID: ${{ vars.AZURE_SUBSCRIPTION_ID }} + AZURE_ENV_NAME: ${{ vars.AZURE_ENV_NAME }} + AZURE_LOCATION: ${{ vars.AZURE_LOCATION }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - name: Get PR branch URL + id: get_pr_branch_url + run: | + PR_REPO_URL="https://github.com/${{ github.event.pull_request.head.repo.full_name }}" + PR_BRANCH_NAME=${{ github.event.pull_request.head.ref }} + echo "PR_REPO_URL=${PR_REPO_URL}" >> $GITHUB_ENV + echo "PR_BRANCH_NAME=${PR_BRANCH_NAME}" >> $GITHUB_ENV + + - uses: actions/checkout@v4 + - id: validation + uses: microsoft/template-validation-action@v0.0.2 + with: + repositoryURL: ${{ env.PR_REPO_URL }} + branch: ${{ env.PR_BRANCH_NAME }} + env: + PR_BRANCH_NAME: ${{ env.PR_BRANCH_NAME }} + PR_REPO_URL: ${{ env.PR_REPO_URL }} + + - name: Read file content + if: always() + id: read_validation_result + run: | + cat ${{ steps.validation.outputs.resultFile }} + FILE_CONTENT=$(cat ${{ steps.validation.outputs.resultFile }}) + echo "validation_result<> $GITHUB_ENV + echo "$FILE_CONTENT" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + + - name: Post comment on PR + if: always() + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COMMENT_BODY: ${{ env.validation_result }} + run: | + gh pr comment ${{ github.event.pull_request.number }} --body "${{ env.COMMENT_BODY }}" \ No newline at end of file diff --git a/.github/workflows/template-validation.yml b/.github/workflows/template-validation.yml new file mode 100644 index 0000000..ccc305f --- /dev/null +++ b/.github/workflows/template-validation.yml @@ -0,0 +1,27 @@ +name: Template Validation Workflow +on: + workflow_dispatch: + +permissions: + contents: read + id-token: write + pull-requests: write + +jobs: + template_validation_job: + runs-on: ubuntu-latest + name: template validation + steps: + - uses: actions/checkout@v4 + + - uses: microsoft/template-validation-action@v0.1 + env: + AZURE_CLIENT_ID: ${{ vars.AZURE_CLIENT_ID }} + AZURE_TENANT_ID: ${{ vars.AZURE_TENANT_ID }} + AZURE_SUBSCRIPTION_ID: ${{ vars.AZURE_SUBSCRIPTION_ID }} + AZURE_ENV_NAME: ${{ vars.AZURE_ENV_NAME }} + AZURE_LOCATION: ${{ vars.AZURE_LOCATION }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: print result + run: cat ${{ steps.validation.outputs.resultFile }} diff --git a/README.md b/README.md index 364f052..40d04f9 100644 --- a/README.md +++ b/README.md @@ -1,57 +1,175 @@ -# Project Name +# Chat Application using Azure OpenAI, Semantic Kernel, and .NET Aspire (C#/.NET) -(short, 1-3 sentenced, description of the project) +[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/Azure-Samples/ai-chat-aspire-sk-csharp) +[![Open in Dev Containers](https://img.shields.io/static/v1?style=for-the-badge&label=Dev%20Containers&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/azure-samples/ai-chat-aspire-sk-csharp) + +This repository includes a .NET/C# app that uses Azure OpenAI to generate responses to user messages. + +The project includes all the infrastructure and configuration needed to provision Azure OpenAI resources and deploy the app to [Azure Container Apps](https://learn.microsoft.com/azure/container-apps/overview) using the [Azure Developer CLI](https://learn.microsoft.com/azure/developer/azure-developer-cli/overview). By default, the app will use managed identity to authenticate with Azure OpenAI. + +We recommend first going through the [deploying steps](#deploying) before running this app locally, +since the local app needs credentials for Azure OpenAI to work properly. + +* [Features](#features) +* [Architecture diagram](#architecture-diagram) +* [Getting started](#getting-started) + * [Local Environment - Visual Studio or VS Code](#local-environment) + * [GitHub Codespaces](#github-codespaces) + * [VS Code Dev Containers](#vs-code-dev-containers) +* [Deploying](#deploying) +* [Development server](#development-server) +* [Guidance](#guidance) + * [Costs](#costs) + * [Security Guidelines](#security-guidelines) +* [Resources](#resources) ## Features -This project framework provides the following features: +* An [ASP.NET Core](https://dotnet.microsoft.com/en-us/apps/aspnet) that uses [Semantic Kernel](https://learn.microsoft.com/semantic-kernel/overview/) package to access language models to generate responses to user messages. +* A Blazor frontend that streams responses from the backend. +* [.NET Aspire](https://learn.microsoft.com/dotnet/aspire/get-started/aspire-overview) to orchestrate and build a cloud native application. +* [Bicep files](https://docs.microsoft.com/azure/azure-resource-manager/bicep/) for provisioning Azure resources, including Azure OpenAI, Azure Container Apps, Azure Container Registry, Azure Log Analytics, and RBAC roles. +* Using the OpenAI gpt-4o model through Azure OpenAI. -* Feature 1 -* Feature 2 -* ... +![Screenshot of the chat app](docs/screenshot_chatapp.png) -## Getting Started +## Architecture diagram -### Prerequisites +![Architecture diagram: Azure Container Apps inside Container Apps Environment, connected to Container Registry with Container, connected to Managed Identity for Azure OpenAI](readme_diagram.png) -(ideally very short, if any) +## Getting started -- OS -- Library version -- ... +You have a few options for getting started with this template. -### Installation +### Local Environment -(ideally very short) +If you're not using one of the above options for opening the project, then you'll need to: -- npm install [package name] -- mvn install -- ... +1. Make sure the following tools are installed: -### Quickstart -(Add steps to get up and running quickly) + * [.NET 8](https://dotnet.microsoft.com/downloads/) + * With the [.NET Aspire workload installed](https://learn.microsoft.com/dotnet/aspire/fundamentals/setup-tooling?tabs=windows&pivots=visual-studio#install-net-aspire) using `dotnet workload install aspire` + * [Git](https://git-scm.com/downloads) + * [Azure Developer CLI (azd)](https://aka.ms/install-azd) + * [VS Code](https://code.visualstudio.com/Download) or [Visual Studio](https://visualstudio.microsoft.com/downloads/) + * If using VS Code, install the [C# Dev Kit](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csdevkit) -1. git clone [repository clone url] -2. cd [repository name] -3. ... +2. Download the project code: + ```shell + azd init -t ai-chat-aspire-sk-csharp + ``` -## Demo +3. If you're using Visual Studio, open the src/ai-chat-aspire-sk.sln solution file. If you're using VS Code, open the src folder. -A demo app is included to show how to use the project. +4. Continue with the [deploying steps](#deploying), or if using Visual Studio, you can [deploy the application and dependencies to Azure](https://learn.microsoft.com/dotnet/aspire/deployment/azure/aca-deployment-visual-studio#create-a-net-aspire-project). -To run the demo, follow these steps: +### VS Code Dev Containers -(Add steps to start up the demo) +Visual Stuido Code Dev Containers can also be used locally, which will open the project in your local VS Code using the [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers): -1. -2. -3. +1. Start Docker Desktop (install it if not already installed) +2. Open the project: -## Resources + [![Open in Dev Containers](https://img.shields.io/static/v1?style=for-the-badge&label=Dev%20Containers&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/azure-samples/ai-chat-aspire-sk-csharp) + +3. In the VS Code window that opens, once the project files show up (this may take several minutes), open a terminal window. + +4. Continue with the [deploying steps](#deploying) + +### GitHub Codespaces + +**Coming soon** - GitHub Codespaces support works best with Aspire 9, which is coming soon. For now, you can load the project and build in CodeSpaces, but won't be able to run. + +## Deploying + +Once you've opened the project [locally](#local-environment) or in [Dev Containers](#vs-code-dev-containers), you can deploy it to Azure. + +### Azure account setup + +1. Sign up for a [free Azure account](https://azure.microsoft.com/free/) and create an Azure Subscription. +2. Check that you have the necessary permissions: + + * Your Azure account must have `Microsoft.Authorization/roleAssignments/write` permissions, such as [Role Based Access Control Administrator](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#role-based-access-control-administrator-preview), [User Access Administrator](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#user-access-administrator), or [Owner](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#owner). If you don't have subscription-level permissions, you must be granted [RBAC](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#role-based-access-control-administrator-preview) for an existing resource group and [deploy to that existing group](/docs/deploy_existing.md#resource-group). + * Your Azure account also needs `Microsoft.Resources/deployments/write` permissions on the subscription level. + +### Deploying with azd + +From a Terminal window, open the folder with the clone of this repo and run the following commands. + +1. Login to Azure: + + ```shell + azd auth login + ``` + +2. Provision and deploy all the resources: + + ```shell + azd up + ``` + + It will prompt you to provide an `azd` environment name (like "chat-app"), select a subscription from your Azure account, and select a [location where OpenAI is available](https://azure.microsoft.com/explore/global-infrastructure/products-by-region/?products=cognitive-services®ions=all) (like "francecentral"). Then it will provision the resources in your account and deploy the latest code. If you get an error or timeout with deployment, changing the location can help, as there may be availability constraints for the OpenAI resource. + +3. When `azd` has finished deploying, you'll see an endpoint URI in the command output. Visit that URI, and you should see the chat app! 🎉 -(Any additional resources or related projects) +4. When you've made any changes to the app code, you can just run: + + ```shell + azd deploy + ``` + +## Run the application + +Start the project: + + **If using Visual Studio**, choose the `Debug > Start Debugging` menu. + **If using VS Code or GitHub CodeSpaces***, choose the `Run > Start Debugging` menu. + Finally, if using the command line, run the following from the project directory: + + ```shell + dotnet run + ``` + +## Using an existing deployment + +In order to run this app, you need to have an Azure OpenAI account deployed (from the [deploying steps](#deploying)). After deployment, Azure OpenAI is configured for you using [User Secrets](https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets). If you could not run the deployment steps here, or you want to use an existing Azure OpenAI resource and deployment, open a terminal from the root of this repo and run the following + +```bash +cd ./src/AIChatApp.AppHost +dotnet user-secrets set "ConnectionStrings:openai" "https://{account_name}.openai.azure.com/" +``` + +The value for the connection string can be found in the Keys & Endpoint section when examining your resource from the Azure portal. Alternatively, you can find the value in the Azure OpenAI Studio > Playground > Code View. An example endpoint is: https://docs-test-001.openai.azure.com/. + +## Guidance + +### Costs + +Pricing varies per region and usage, so it isn't possible to predict exact costs for your usage. +The majority of the Azure resources used in this infrastructure are on usage-based pricing tiers. +However, Azure Container Registry has a fixed cost per registry per day. + +You can try the [Azure pricing calculator](https://azure.com/e/2176802ea14941e4959eae8ad335aeb5) for the resources: + +* Azure OpenAI Service: S0 tier, gpt-4o model. Pricing is based on token count. [Pricing](https://azure.microsoft.com/pricing/details/cognitive-services/openai-service/) +* Azure Container App: Consumption tier with 0.5 CPU, 1GiB memory/storage. Pricing is based on resource allocation, and each month allows for a certain amount of free usage. [Pricing](https://azure.microsoft.com/pricing/details/container-apps/) +* Azure Container Registry: Basic tier. [Pricing](https://azure.microsoft.com/pricing/details/container-registry/) +* Log analytics: Pay-as-you-go tier. Costs based on data ingested. [Pricing](https://azure.microsoft.com/pricing/details/monitor/) + +⚠️ To avoid unnecessary costs, remember to take down your app if it's no longer in use, +either by deleting the resource group in the Portal or running `azd down`. + +### Security Guidelines + +This template uses [Managed Identity](https://learn.microsoft.com/entra/identity/managed-identities-azure-resources/overview) for authenticating to the Azure OpenAI service. + +You may want to consider additional security measures, such as: + +* Protecting the Azure Container Apps instance with a [firewall](https://learn.microsoft.com/azure/container-apps/waf-app-gateway) and/or [Virtual Network](https://learn.microsoft.com/azure/container-apps/networking?tabs=workload-profiles-env%2Cazure-cli). + +## Resources -- Link to supporting information -- Link to similar sample -- ... +* [eShopSupport .NET Aspire + AI sample](https://github.com/dotnet/eShopSupport/): A full featured .NET Aspire application using AI +* [Develop .NET Apps with AI Features](https://learn.microsoft.com/dotnet/ai/get-started/dotnet-ai-overview) +* [.NET Aspire Overview](https://learn.microsoft.com/en-us/dotnet/aspire/get-started/aspire-overview) diff --git a/azure.yaml b/azure.yaml index 44c16cb..d2af017 100644 --- a/azure.yaml +++ b/azure.yaml @@ -6,3 +6,15 @@ services: language: dotnet project: ./src/AIChatApp.AppHost/AIChatApp.AppHost.csproj host: containerapp +hooks: + postprovision: + windows: + shell: pwsh + run: ./infra/post-script/store-env-variables.ps1 + interactive: true + continueOnError: true + posix: + shell: sh + run: ./infra/post-script/store-env-variables.sh + interactive: false + continueOnError: true diff --git a/docs/screenshot_chatapp.png b/docs/screenshot_chatapp.png new file mode 100644 index 0000000000000000000000000000000000000000..2060b519156c48fbbcae9305b68784434fd1eb52 GIT binary patch literal 51560 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 R=LQ8nq{QS!%R~(P{}&B72N3`O literal 0 HcmV?d00001 diff --git a/infra/main.bicep b/infra/main.bicep index 31d38b2..4e034df 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -12,6 +12,11 @@ param location string @description('Id of the user or app to assign application roles') param principalId string = '' +@description('Flag to decide where to create OpenAI role for current user') +param createRoleForUser bool = true + +var userId = createRoleForUser ? principalId : '' + var tags = { 'azd-env-name': environmentName } @@ -39,6 +44,7 @@ module openai 'openai/openai.module.bicep' = { location: location principalId: resources.outputs.MANAGED_IDENTITY_PRINCIPAL_ID principalType: 'ServicePrincipal' + userId: userId } } output MANAGED_IDENTITY_CLIENT_ID string = resources.outputs.MANAGED_IDENTITY_CLIENT_ID @@ -49,4 +55,4 @@ output AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID string = resources.outputs.A output AZURE_CONTAINER_APPS_ENVIRONMENT_NAME string = resources.outputs.AZURE_CONTAINER_APPS_ENVIRONMENT_NAME output AZURE_CONTAINER_APPS_ENVIRONMENT_ID string = resources.outputs.AZURE_CONTAINER_APPS_ENVIRONMENT_ID output AZURE_CONTAINER_APPS_ENVIRONMENT_DEFAULT_DOMAIN string = resources.outputs.AZURE_CONTAINER_APPS_ENVIRONMENT_DEFAULT_DOMAIN -output OPENAI_CONNECTIONSTRING string = openai.outputs.connectionString +output CONNECTIONSTRINGS__OPENAI string = openai.outputs.connectionString diff --git a/infra/main.parameters.json b/infra/main.parameters.json index db7cedc..57d6343 100644 --- a/infra/main.parameters.json +++ b/infra/main.parameters.json @@ -9,7 +9,7 @@ "value": "${AZURE_ENV_NAME}" }, "location": { - "value": "${AZURE_LOCATION}" + "value": "${AZURE_LOCATION=eastus}" } } } diff --git a/infra/openai/openai.module.bicep b/infra/openai/openai.module.bicep index 6cde0a3..d56c5a2 100644 --- a/infra/openai/openai.module.bicep +++ b/infra/openai/openai.module.bicep @@ -1,45 +1,51 @@ -targetScope = 'resourceGroup' - -@description('') +@description('The location for the resource(s) to be deployed.') param location string = resourceGroup().location -@description('') param principalId string -@description('') param principalType string -resource cognitiveServicesAccount_wXAGTFUId 'Microsoft.CognitiveServices/accounts@2023-05-01' = { - name: toLower(take('openai${uniqueString(resourceGroup().id)}', 24)) +param userId string + +resource openai 'Microsoft.CognitiveServices/accounts@2024-10-01' = { + name: take('openai-${uniqueString(resourceGroup().id)}', 64) location: location kind: 'OpenAI' - sku: { - name: 'S0' - } properties: { customSubDomainName: toLower(take(concat('openai', uniqueString(resourceGroup().id)), 24)) publicNetworkAccess: 'Enabled' disableLocalAuth: true } + sku: { + name: 'S0' + } + tags: { + 'aspire-resource-name': 'openai' + } } -resource roleAssignment_Hsk8rxWY8 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - scope: cognitiveServicesAccount_wXAGTFUId - name: guid(cognitiveServicesAccount_wXAGTFUId.id, principalId, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')) +resource openai_CognitiveServicesOpenAIContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(openai.id, principalId, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')) // Cognitive Services User role properties: { - roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442') principalId: principalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd') principalType: principalType } + scope: openai } -resource cognitiveServicesAccountDeployment_6E9woetGC 'Microsoft.CognitiveServices/accounts/deployments@2023-05-01' = { - parent: cognitiveServicesAccount_wXAGTFUId - name: 'chat' - sku: { - name: 'GlobalStandard' - capacity: 10 +resource openai_CognitiveServicesOpenAILocalUser 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(userId)) { + name: guid(openai.id, userId, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')) // Cognitive Services User role + properties: { + principalId: userId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd') + principalType: 'user' } + scope: openai +} + +resource chat 'Microsoft.CognitiveServices/accounts/deployments@2024-10-01' = { + name: 'chat' properties: { model: { format: 'OpenAI' @@ -47,6 +53,11 @@ resource cognitiveServicesAccountDeployment_6E9woetGC 'Microsoft.CognitiveServic version: '2024-05-13' } } + sku: { + name: 'Standard' + capacity: 10 + } + parent: openai } -output connectionString string = 'Endpoint=${cognitiveServicesAccount_wXAGTFUId.properties.endpoint}' +output connectionString string = 'Endpoint=${openai.properties.endpoint}' diff --git a/infra/post-script/store-env-variables.ps1 b/infra/post-script/store-env-variables.ps1 new file mode 100644 index 0000000..d659727 --- /dev/null +++ b/infra/post-script/store-env-variables.ps1 @@ -0,0 +1,20 @@ +function Set-DotnetUserSecrets { + param ($path, $lines) + Push-Location $path + + dotnet user-secrets init + dotnet user-secrets clear + foreach ($line in $lines) { + $name, $value = $line -split '=', 2 + $value = $value -replace '"', '' + $name = $name -replace '__', ':' # Replace __ with : to match the format of user secrets + if ($value -ne '') { + dotnet user-secrets set "$name" "$value" | Out-Null + } + } + Pop-Location +} + +# Get all of the generated env variables, and store them as user secrets for the project +$lines = (azd env get-values) -split "`n" +Set-DotnetUserSecrets -path "./src/AIChatApp.AppHost/" -lines $lines \ No newline at end of file diff --git a/infra/post-script/store-env-variables.sh b/infra/post-script/store-env-variables.sh new file mode 100644 index 0000000..3e12eba --- /dev/null +++ b/infra/post-script/store-env-variables.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +function set_dotnet_user_secrets() { + local path="$1" + local lines="$2" + + pushd "$path" >/dev/null + dotnet user-secrets init + dotnet user-secrets clear + + IFS=$'\n' + for line in $lines; do + name="${line%%=*}" + value="${line#*=}" + value="${value%\"}" + value="${value#\"}" + name="${name//__/:}" + + if [[ -n "$value" ]]; then + dotnet user-secrets set "$name" "$value" >/dev/null + fi + done + + popd >/dev/null +} + +# Get all of the generated env variables, and store them as user secrets for the project +lines=$(azd env get-values) +set_dotnet_user_secrets "./src/AIChatApp.AppHost/" "$lines" \ No newline at end of file diff --git a/readme_diagram.png b/readme_diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..3e6b062cf3dda1fcbe7fe11c5ee8a92b230436c5 GIT binary patch literal 52374 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 Udlte)g#Z8m07*qoM6N<$g0i}bF8}}l literal 0 HcmV?d00001 diff --git a/src/AIChatApp.AppHost/Program.cs b/src/AIChatApp.AppHost/Program.cs index 59d7fba..0210eb1 100644 --- a/src/AIChatApp.AppHost/Program.cs +++ b/src/AIChatApp.AppHost/Program.cs @@ -5,15 +5,20 @@ var builder = DistributedApplication.CreateBuilder(args); var chatDeploymentName = "chat"; + +// The connection string may be set in configuration to use a pre-existing deployment; +// it's also set automatically when provisioning this sample using the included bicep code +// (see the README for details) var connectionString = builder.Configuration.GetConnectionString("openai"); -var openai = String.IsNullOrEmpty(connectionString) +var openai = String.IsNullOrEmpty(connectionString) || builder.ExecutionContext.IsPublishMode ? builder.AddAzureOpenAI("openai") - .AddDeployment(new AzureOpenAIDeployment(chatDeploymentName, "gpt-4o", "2024-05-13", "GlobalStandard", 10)) + .AddDeployment(new AzureOpenAIDeployment(chatDeploymentName, "gpt-4o", "2024-05-13", "Standard", 10)) : builder.AddConnectionString("openai"); builder.AddProject("aichatapp-web") .WithReference(openai) - .WithEnvironment("AI_ChatDeploymentName", chatDeploymentName); + .WithEnvironment("AI_ChatDeploymentName", chatDeploymentName) + .WithExternalHttpEndpoints(); builder.Build().Run(); diff --git a/src/AIChatApp.AppHost/infra/aichatapp-web.tmpl.yaml b/src/AIChatApp.AppHost/infra/aichatapp-web.tmpl.yaml new file mode 100644 index 0000000..039e963 --- /dev/null +++ b/src/AIChatApp.AppHost/infra/aichatapp-web.tmpl.yaml @@ -0,0 +1,51 @@ +api-version: 2024-02-02-preview +location: {{ .Env.AZURE_LOCATION }} +identity: + type: UserAssigned + userAssignedIdentities: + ? "{{ .Env.AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID }}" + : {} +properties: + environmentId: {{ .Env.AZURE_CONTAINER_APPS_ENVIRONMENT_ID }} + configuration: + activeRevisionsMode: single + runtime: + dotnet: + autoConfigureDataProtection: true + ingress: + external: true + targetPort: {{ targetPortOrDefault 8080 }} + transport: http + allowInsecure: false + registries: + - server: {{ .Env.AZURE_CONTAINER_REGISTRY_ENDPOINT }} + identity: {{ .Env.AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID }} + secrets: + - name: connectionstrings--openai + value: '{{ .Env.CONNECTIONSTRINGS__OPENAI }}' + template: + containers: + - image: {{ .Image }} + name: aichatapp-web + env: + - name: AZURE_CLIENT_ID + value: {{ .Env.MANAGED_IDENTITY_CLIENT_ID }} + - name: AI_ChatDeploymentName + value: chat + - name: ASPNETCORE_FORWARDEDHEADERS_ENABLED + value: "true" + - name: HTTP_PORTS + value: '{{ targetPortOrDefault 0 }}' + - name: OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES + value: "true" + - name: OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES + value: "true" + - name: OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY + value: in_memory + - name: ConnectionStrings__openai + secretRef: connectionstrings--openai + scale: + minReplicas: 1 +tags: + azd-service-name: aichatapp-web + aspire-resource-name: aichatapp-web