Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Infra code for sample #2

Merged
merged 10 commits into from
Oct 21, 2024
Merged
44 changes: 44 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -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"
// }
// }
}
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
59 changes: 59 additions & 0 deletions .github/workflows/pr-gate.yml
Original file line number Diff line number Diff line change
@@ -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/[email protected]
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<<EOF" >> $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 }}"
27 changes: 27 additions & 0 deletions .github/workflows/template-validation.yml
Original file line number Diff line number Diff line change
@@ -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/[email protected]
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 }}
186 changes: 152 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
@@ -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&regions=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)
12 changes: 12 additions & 0 deletions azure.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Binary file added docs/screenshot_chatapp.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 7 additions & 1 deletion infra/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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
Expand All @@ -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
Loading
Loading