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/docs/screenshot_chatapp.png b/docs/screenshot_chatapp.png new file mode 100644 index 0000000..2060b51 Binary files /dev/null and b/docs/screenshot_chatapp.png differ diff --git a/readme_diagram.png b/readme_diagram.png new file mode 100644 index 0000000..3e6b062 Binary files /dev/null and b/readme_diagram.png differ