diff --git a/deploy/infrastructure/cli/README.md b/deploy/infrastructure/cli/README.md new file mode 100644 index 00000000..a9b00c21 --- /dev/null +++ b/deploy/infrastructure/cli/README.md @@ -0,0 +1,19 @@ +# CLI scripts for creating the Azure resources needed for the workshop + +## Synopsis +This folder contains a PowerShell script that will create the Azure resources needed for the workshop. The script will create a resource group for each of the workshop participants, and will create the required resources in each resource group. You will need to provide a subscription id, and optionally a resource group prefix, location, and the number of resource groups you want. The script will default to the values below if not provided. +resourceGroupPrefix = "myagi-1-rg-" +location = "eastus" +resourceGroupCount = 1 + + +## Steps +1. Install Azure CLI (https://docs.microsoft.com/en-us/cli/azure/install-azure-cli), min version 2.53.0 +2. Install PowerShell (https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-7.1) +3. Change folder to `infrastructure/cli` +4. Run + ``` + ./deploy.ps1 -resourceGroupPrefix "" -location "" -resourceGroupCount "<1>" -subscriptionId "" + ``` + Note: Only subscriptionId is required, the rest are optional and will default to the values above if not provided. + diff --git a/deploy/infrastructure/cli/bicep/search-service.bicep b/deploy/infrastructure/cli/bicep/search-service.bicep new file mode 100644 index 00000000..8b25ba0c --- /dev/null +++ b/deploy/infrastructure/cli/bicep/search-service.bicep @@ -0,0 +1,20 @@ + +param location string = resourceGroup().location +param searchServiceName string + + +param sku object = { + name: 'standard' +} + +resource searchService 'Microsoft.Search/searchServices@2021-04-01-Preview' = { + name: searchServiceName + location: location + + properties: { + semanticSearch: 'free' + } + sku:sku + +} + diff --git a/deploy/infrastructure/cli/deploy.ps1 b/deploy/infrastructure/cli/deploy.ps1 new file mode 100644 index 00000000..13513e09 --- /dev/null +++ b/deploy/infrastructure/cli/deploy.ps1 @@ -0,0 +1,238 @@ +param ( + [string]$resourceGroupPrefix = "miyagi1", + [string]$location = "eastus", + [string]$resourceGroupCount = 1, + [string]$subscriptionId = "SubscriptionId is required" +) + +# print variables + +Write-Host "resourceGroupPrefix: $resourceGroupPrefix" +Write-Host "location: $location" +Write-Host "resourceGroupCount: $resourceGroupCount" +Write-Host "subscriptionId: $subscriptionId" + +# set rgIndex to resourceGroupCount + +$rgIndex = $resourceGroupCount + +# set all these to false the first time you run this script. After that you can set them to true to skip creating resources that already exist +$skipRg = "false" +$skipOpenAI = "false" +$skipEmbeddingModelDeployment = "false" +$skipCompletionModelDeployment = "false" +$skipcognitiveSearch = "false" +$skipCosmosDB = "false" +$skipBlobStorage = "false" +$skipAzureContainerApps = "false" +$skipAzureContainerRegistry = "false" +$skipAPIM = "false" + +# strip - from resourceGroupPrefix + +$resourceGroupPrefix = $resourceGroupPrefix.Replace("-",""); + +# create resource groups in a loop for rgIndex +# if skipRg is true, skip creating resource group + +if ($skipRg -eq "true") { + Write-Host "Skipping resource group creation" +} +else { + + for ($i = 1; $i -le $rgIndex; $i++) { + Write-Host "Creating resource group $resourceGroupPrefix-rg-$i in $location" + az group create --name "$resourceGroupPrefix-rg-$i" --location $location + } +} + +# create Azure Open AI service resource for each resource group + +for ($i = 1; $i -le $rgIndex; $i++) { + # if skipRg is true, skip creating resource group + if ($skipOpenAI -eq "true") { + Write-Host "Skipping OpenAI resource creation" + } + else { + Write-Host "Creating Azure Open AI service resource named $resourceGroupPrefix-OpenAIService-$i in $resourceGroupPrefix-rg-$i" + + az cognitiveservices account create ` + --name "$resourceGroupPrefix-OpenAIService-$i" ` + --resource-group "$resourceGroupPrefix-rg-$i" ` + --location $location ` + --kind "OpenAI" ` + --sku "s0" ` + --subscription $subscriptionId + } + + # if skipEmbeddingModelDeployment is true, skip embedding model deployment + + if ($skipEmbeddingModelDeployment -eq "true") { + Write-Host "Skipping embedding model deployment" + } + else { + # deploy embedding model + + Write-Host "Deploying embedding model $resourceGroupPrefix-EmbeddingModel-$i" + + az cognitiveservices account deployment create ` + --name "$resourceGroupPrefix-OpenAIService-$i" ` + --resource-group "$resourceGroupPrefix-rg-$i" ` + --deployment-name "$resourceGroupPrefix-EmbeddingModel-$i" ` + --model-name text-embedding-ada-002 ` + --model-version "2" ` + --model-format "OpenAI" ` + --scale-capacity "20" ` + --capacity "20" + + } + + # if skipCompletionModelDeployment is true, skip completion model deployment + + if ($skipCompletionModelDeployment -eq "true") { + Write-Host "Skipping completion model deployment" + } + else { + # deploy completion model + + Write-Host "Deploying completion model $resourceGroupPrefix-CompletionModel-$i" + + az cognitiveservices account deployment create ` + --name "$resourceGroupPrefix-OpenAIService-$i" ` + --resource-group "$resourceGroupPrefix-rg-$i" ` + --deployment-name "$resourceGroupPrefix-CompletionModel-$i" ` + --model-name "gpt-35-turbo" ` + --model-version "0613" ` + --model-format "OpenAI" ` + --capacity "30" + + } + + # if skipCosmosDB is false, create CosmosDB account called miyagi with a container called recommendations + + if ($skipCosmosDB -eq "true") { + Write-Host "Skipping CosmosDB account creation" + } + else { + Write-Host "Creating CosmosDB account $resourceGroupPrefix-cosmos-$i in $resourceGroupPrefix-rg-$i" + + az cosmosdb create ` + --name "$resourceGroupPrefix-cosmos-$i" ` + --resource-group "$resourceGroupPrefix-rg-$i" ` + --kind "GlobalDocumentDB" ` + --subscription $subscriptionId + + Write-Host "Creating CosmosDB database $resourceGroupPrefix-cosmos-$i in $resourceGroupPrefix-rg-$i" + + az cosmosdb sql database create ` + --account-name "$resourceGroupPrefix-cosmos-$i" ` + --name "miyagi" ` + --resource-group "$resourceGroupPrefix-rg-$i" ` + --subscription $subscriptionId + + Write-Host "Creating CosmosDB container $resourceGroupPrefix-cosmos-$i in $resourceGroupPrefix-rg-$i" + + az cosmosdb sql container create ` + --account-name "$resourceGroupPrefix-cosmos-$i" ` + --database-name "miyagi" ` + --name "recommendations" ` + --partition-key-path "/partitionKey" ` + --resource-group "$resourceGroupPrefix-rg-$i" ` + --subscription $subscriptionId + } + + # if skipBlobStorage is false, create blob storage account with a container called miyagi + + if ($skipBlobStorage -eq "true") { + Write-Host "Skipping blob storage account creation" + } + else { + + $storageaccount = -join($resourceGroupPrefix,"blobstorge",$i) + Write-Host "Creating blob storage account $storageaccount in $resourceGroupPrefix-rg-$i" + + az storage account create ` + --name $storageaccount ` + --resource-group "$resourceGroupPrefix-rg-$i" ` + --location $location ` + --sku "Standard_LRS" ` + --subscription $subscriptionId + + Write-Host "Creating blob storage container miyagi in $resourceGroupPrefix-rg-$i" + + az storage container create ` + --name "miyagi" ` + --account-name $storageaccount ` + --subscription $subscriptionId + } + + # if skipAzureContainerRegistry is false, create Azure Container Registry called miyagi + + if ($skipAzureContainerRegistry -eq "true") { + Write-Host "Skipping Azure Container Registry creation" + } + else { + + $containerregistry = -join($resourceGroupPrefix,"acr",$i) + Write-Host "Creating Azure Container Registry $containerregistry in $resourceGroupPrefix-rg-$i" + + az acr create ` + --name $containerregistry ` + --resource-group "$resourceGroupPrefix-rg-$i" ` + --location $location ` + --sku "Basic" ` + --subscription $subscriptionId + } + + # if skipAzureContainerApps is false, create Azure Container Apps with a container called miyagi + + if ($skipAzureContainerApps -eq "true") { + Write-Host "Skipping Azure Container App creation" + } + else { + + $containerapp = -join($resourceGroupPrefix,"miyagi",$i) + Write-Host "Creating Azure Container Apps $containerapp in $resourceGroupPrefix-rg-$i" + + az containerapp up --name $containerapp ` + --resource-group "$resourceGroupPrefix-rg-$i" ` + --location centralus ` + --environment "$resourceGroupPrefix-env" ` + --image mcr.microsoft.com/azuredocs/containerapps-helloworld:latest ` + --target-port 80 ` + --ingress external ` + --query properties.configuration.ingress.fqdn ` + + + + + } + + # if skipcognitiveSearch is false, create cognitive search service with semantic search capability + + if ($skipcognitiveSearch -eq "true") { + Write-Host "Skipping cognitive search service creation" + } + else { + + Write-Host "Creating cognitive search service $resourceGroupPrefix-acs-$i in $resourceGroupPrefix-rg-$i" + + az deployment group create ` + --resource-group "$resourceGroupPrefix-rg-$i" ` + --template-file "bicep/search-service.bicep" ` + --parameters "searchServiceName=$resourceGroupPrefix-acs-$i" + + + } + + + + + + + +} + + + + diff --git a/docs/labs/02-build-your-own-copilot/README.md b/docs/labs/02-build-your-own-copilot/README.md new file mode 100644 index 00000000..617fc3a7 --- /dev/null +++ b/docs/labs/02-build-your-own-copilot/README.md @@ -0,0 +1,205 @@ +# Steps: Build Your Own Copilot workshop + +## 1. Setup Local Environment + +1. Install Visual Studio Code (https://code.visualstudio.com/download) +2. Install the following VSCode extenstions + 1. Azure Tools (https://marketplace.visualstudio.com/items?itemName=ms-vscode.vscode-node-azure-pack) + 2. Polyglot Notebooks (https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.dotnet-interactive-vscode) + 3. Semantic Kernel (https://marketplace.visualstudio.com/items?itemName=ms-semantic-kernel.semantic-kernel) + 4. Prompt flow for VSCode (https://marketplace.visualstudio.com/items?itemName=prompt-flow.prompt-flow) + 5. Azure Container Apps (https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurecontainerapps) + 6. Docker Extension (https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker) + +3. Install Azure CLI (https://docs.microsoft.com/en-us/cli/azure/install-azure-cli), min version 2.53.0 +4. Install PowerShell (https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-7.1) +5. Install Docker Desktop (https://www.docker.com/products/docker-desktop) +6. Install .NET 7.0 SDK (https://dotnet.microsoft.com/download/dotnet/7.0) +7. Install python 3.11 (https://www.python.org/downloads/) +8. Install jq (https://stedolan.github.io/jq/download/) +9. Install Postman (https://www.postman.com/downloads/) + + + +## 2. Clone and run miyagi locally + +1. Create a new folder for the workshop +2. Open Visual Studio Code +3. Open the new folder: File -> Open Folder -> Select the folder you created in step 1 +4. Open a new terminal: Terminal -> New Terminal (or Ctrl + Shift + `) +5. Clone this repo + + ``` + git clone -b ap/docs-and-iaac https://github.com/Azure-Samples/miyagi.git + + ``` + **Note:** the above branch is temporary. Soon you will be using the main branch. + +### 2.1 Provision Azure Services required for the workshop + +1. Change folder to miyagi/deploy/infrastructure/cli + + ``` + cd miyagi/deploy/infrastructure/cli + ``` +2. Login to Azure and select the subscription you want to use for the workshop + + ``` + az login + az account set --subscription "" + + ``` +3. Run the following command to create the Azure resources needed for the workshop. The script will create a resource group for each of the workshop participants, and will create the required resources in each resource group. You will need to provide a subscription id, and optionally a resource group prefix, location, and the number of resource groups you want. The script will default to the values below if not provided. + + ``` + ./deploy.ps1 -resourceGroupPrefix "" -location "" -resourceGroupCount "<1>" -subscriptionId "" + ``` + Note: If you are setting up the workshop just for you, make sure you set the value of resourceGroupCount to 1 +4. Wait until the script completes. It will take less than 10 minutes to complete. + +5. Bump up the capacity for Open AI model deployments + + By default the Open AI model are deployed with 1K Tokens per minute (TPM) capacity. This is not enough for the workshop. You will need to bump up the capacity to 20K Tokens per minute. You can do this by going to Azure Portal -> Resource Groups -> Select the resource group you created in step 3 of the previous section -> Select the Open AI resource -> Overview -> Click Go to Azure OpenAI Studio -> Deployments -> Select the deployment for gpt-35-turbo model -> Click Edit Deployment -> Advanced Options -> Slide the TPM slider to 20K -> Click Save and close. + + Repeat the same steps for the deployment for text-embedding-ada-002 model. + +### 2.2 Setup configuration for miyagi app + +1. Create a new file called .env in miyagi/ui/typescript +2. Copy paste the contents of .env.local.example into .env and save the file +3. You will setup the values for the variables in the workshop [ this will be updated later] +4. Create a new file named appsettings.json in miyagi/services/recommendation-service/dotnet +5. Copy paste the contents of appsettings.json.example into appsettings.json and save the file +6. Update appsettings.json with the values for the variables below. You can get the values from the Azure Portal. + > Go to Azure Portal -> Resource Groups -> Select the resource group you created in step 3 of the previous section -> Select the Open AI resource -> Select Keys and Endpoint + + > Copy the values of the Language API endpoint and the key1 into "endpoint" and "apikey" in the appsettings.json file and save the file + + > Go back to your Open AI resource -> Overview -> Click Go to Azure OpenAI Studio -> Deployments + + > Copy the value of the deployment name for gpt-35-turbo model and paste it into the appsettings.json file as the value of the variable "deploymentOrModelId" + + > Copy the value of the deployment name for text-embedding-ada-002 model and paste it into the appsettings.json file as the value of the variable "embeddingDeploymentOrModelId" + + > Go to Azure Portal -> Resource Groups -> Select the resource group you created in step 3 of the previous section -> Select Azure Cognitive Search resource -> Overview -> Copy the value of the Url and paste it into the appsettings.json file as the value of the variable "azureCognitiveSearchEndpoint" + + > Go to Azure Portal -> Resource Groups -> Select the resource group you created in step 3 of the previous section -> Select Azure Cognitive Search resource -> Keys -> Copy the value of the Primary Admin Key and paste it into the appsettings.json file as the value of the variable "azureCognitiveSearchApiKey" + + > Go to Azure Portal -> Resource Groups -> Select the resource group you created in step 3 of the previous section -> Select the Cosmos DB resource -> Overview -> Copy the value of the Url and paste it into the appsettings.json file as the value of the variable "cosmosDbUri" + + > Leave the cosmosDbName as "miyagi" and the cosmosDbContainer name as "recommendations" + + > Set the blobServiceUri tp https://yourstorageservicename.blob.core.windows.net/ + + +7. Create a new file named .env in miyagi/sandbox/usecases/rag/dotnet +8. Copy paste the contents of rag/.env.local.example into .env and save the file +9. Copy the values from Step 6 into the .env file and save the file + + +### 2.3 Setup .NET secrets + +1. Open a new terminal: Terminal -> New Terminal (or Ctrl + Shift + `) +2. Change folder to miyagi/services/recommendation-service/dotnet +3. Run the following command to set the secrets for the recommendation service. You will need to provide the values for the variables below. + + ``` + dotnet user-secrets set "USE_OPEN_AI" "False" + dotnet user-secrets set "serviceType" "AzureOpenAI" + dotnet user-secrets set "BING_API_KEY" "" + dotnet user-secrets set "MEMORY_COLLECTION" "miyagi-embeddings" + dotnet user-secrets set "deploymentOrModelId" "" + dotnet user-secrets set "embeddingDeploymentOrModelId" "" + dotnet user-secrets set "endpoint" "" + dotnet user-secrets set "apiKey" "" + dotnet user-secrets set "COSMOS_DB_CONNECTION_STRING" "" + + ``` + Use the following instructions to get the values for the arguments to the dotnet user-secrets set command + + > **Bing API Key:** This will be provided to you during the workshop. + + > **Open AI Endpoint:** Go to Azure Portal -> Resource Groups -> Select the resource group you created in step 3 of the previous section -> Select the Open AI resource -> Select Keys and Endpoint -> Copy the value of Endpoint. + + > **Open AI API Key:** Go to Azure Portal -> Resource Groups -> Select the resource group you created in step 3 of the previous section -> Select the Open AI resource -> Select Keys and Endpoint -> Copy the value of key1. + + > **Completions model Deployment Id:** Go to Azure Portal -> Resource Groups -> Select the resource group you created in step 3 of the previous section -> Select the Open AI resource -> Overview -> Click Go to Azure OpenAI Studio -> Deployments -> Copy the value of the deployment name for gpt-35-turbo model. + + > **Embeddings model Deployment Id:** Go to Azure Portal -> Resource Groups -> Select the resource group you created in step 3 of the previous section -> Select the Open AI resource -> Overview -> Click Go to Azure OpenAI Studio -> Deployments -> Copy the value of the deployment name for text-embedding-ada-002 model. + + > **Cosmos DB Connection String:** Go to Azure Portal -> Resource Groups -> Select the resource group you created in step 3 of the previous section -> Select the Cosmos DB resource -> Keys -> Copy the value of the Cosmos DB Connection String. + + + +### 2.4 Understanding implementation of the recommendation service + +Recommendation service implements RAG pattern using Semantic Kernel SDK. The details of the implementation are captured in the Jupyter notebook in the folder miyagi/sandbox/usecases/rag/dotnet. You can open the notebook in VSCode and run the cells to understand step by step details of how the Recommendation Service is implemented. Pay special attention to how RAG pattern is implemented using Semantic Kernel. Select kernel as .NET Interactive in the top right corner of the notebook. + +### 2.5 Run miyagi frontend locally + +1. Open a new terminal: Terminal -> New Terminal (or Ctrl + Shift + `) +2. Change folder to miyagi/ui/typescript +3. Run the following command to install the dependencies + + ``` + npm install --global yarn + yarn install + yarn dev + ``` +4. Open a browser and navigate to + ``` + http://localhost: Default port is 4001 + ``` + Get the port from the logs in the terminal. You should see the miyagi app running locally. + +### 2.6 Run recommendation service locally +1. Open a new terminal: Terminal -> New Terminal (or Ctrl + Shift + `) +2. Change folder to miyagi/services/recommendation-service/dotnet +3. Run the following command to run the recommendation service locally + ``` + dotnet build + dotnet run + ``` +4. Open a browser and navigate to + ``` + http://localhost:/swagger/index.html Default port is 5224 + ``` + Get the port from the logs in the terminal. You should see the swagger page for the recommendation service. + +### 2.7 Vectorize and persist embeddings in Azure Cognitive Search +1. Open Postman -> Click import -> select Files -> select the file miyagi/services/recommendation-service/dotnet/setup/hydate.postman_collection.json +2. Click hydrate -> GET 7288/datasets -> Click Send. You should see the following response + ``` + [ + "resources\\sample-datasets\\common-stocks-uncommon-profits.txt", + "resources\\sample-datasets\\intelligent-investor.txt", + "resources\\sample-datasets\\random-walk-down-wall-street.txt" + ] + ``` +3. Click hydrate -> POST save 7288/datasets -> Click Send. You should see the following response + ``` + { + "metadata": { + "userId": "50", + "riskLevel": "aggressive", + "favoriteSubReddit": "finance", + "favoriteAdvisor": "Jim Cramer" + }, + "dataSetName": "intelligent-investor" + + } + ``` + +### 2.8 Explore the recommendation service + +Go back to the ui -> click personalize button -> select financial advisor. You should see the recommendations from the recommendation service in the Top Stocks widget. + +## 3. TODO: Deploy Apps to Azure Container Apps + +## 4. TODO: Expose Open AI through APIM + + + + + + diff --git a/sandbox/usecases/rag/.env.example b/sandbox/usecases/rag/.env.example index f9870b86..13f5cfbf 100644 --- a/sandbox/usecases/rag/.env.example +++ b/sandbox/usecases/rag/.env.example @@ -3,5 +3,5 @@ AZURE_OPENAI_CHAT_MODEL="gpt-35-turbo" AZURE_OPENAI_EMBEDDING_MODEL="text-embedding-ada-002" AZURE_OPENAI_API_KEY="<...>" -AZURE_SEARCH_ENDPOINT="https://<...>.search.windows.net" -AZURE_SEARCH_API_KEY="<...>" +AZURE_COGNITIVE_SEARCH_ENDPOINT="https://<...>.search.windows.net" +AZURE_COGNITIVE_SEARCH_API_KEY="<...>" diff --git a/services/recommendation-service/dotnet/appsettings.json.example b/services/recommendation-service/dotnet/appsettings.json.example new file mode 100644 index 00000000..1653dbc8 --- /dev/null +++ b/services/recommendation-service/dotnet/appsettings.json.example @@ -0,0 +1,20 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Trace", + "Microsoft.AspNetCore": "Trace" + } + }, + "AllowedHosts": "*", + "deploymentOrModelId": "", + "embeddingDeploymentOrModelId": "", + "endpoint": "", + "apiKey": "", + "azureCognitiveSearchEndpoint": "", + "azureCognitiveSearchApiKey": "", + "cosmosDbUri": "", + "cosmosDbName": "miyagi", + "blobServiceUri": "", + "cosmosDbContainerName": "recommendations", + "logLevel": "Trace" + } \ No newline at end of file diff --git a/ui/typescript/.env.local.example b/ui/typescript/.env.local.example index 050a79c6..5bdae45c 100644 --- a/ui/typescript/.env.local.example +++ b/ui/typescript/.env.local.example @@ -1 +1,8 @@ -NEXT_PUBLIC_REST_API_ENDPOINT \ No newline at end of file +NEXT_PUBLIC_GA_MEASUREMENT_ID= +RECCOMMENDATION_SERVICE_URL= +NEXT_PUBLIC_CHAT_ID= +COPILOT_CHAT_BASE_URL= +NEXT_PUBLIC_COPILOT_CHAT_BASE_URL= +NEXT_PUBLIC_SK_API_KEY= +APIM_API_KEY= +NODE_TLS_REJECT_UNAUTHORIZED=0 \ No newline at end of file