├── .deployment ├── .devcontainer └── devcontainer.json ├── .env.SAMPLE ├── .github └── workflows │ ├── main_openai-bot-webapp.yml │ └── node18.yml ├── .gitignore ├── .vscode ├── launch.json └── settings.json ├── README.md ├── deploymentScripts ├── linux │ ├── .deployment │ └── deploy.sh ├── webConfigPrep.js └── windows │ ├── .deployment │ └── deploy.cmd ├── deploymentTemplates ├── deployUseExistResourceGroup │ ├── parameters-for-template-AzureBot-with-rg.json │ ├── parameters-for-template-BotApp-with-rg.json │ ├── readme.md │ ├── template-AzureBot-with-rg.json │ └── template-BotApp-with-rg.json ├── deployWithNewResourceGroup │ ├── parameters-for-template-AzureBot-new-rg.json │ ├── parameters-for-template-BotApp-new-rg.json │ ├── readme.md │ ├── template-AzureBot-new-rg.json │ └── template-BotApp-new-rg.json └── linux │ ├── deployUseExistResourceGroup │ ├── parameters-for-template-AzureBot-with-rg.json │ ├── parameters-for-template-BotApp-with-rg.json │ ├── readme.md │ ├── template-AzureBot-with-rg.json │ └── template-BotApp-with-rg.json │ └── deployWithNewResourceGroup │ ├── parameters-for-template-AzureBot-new-rg.json │ ├── parameters-for-template-BotApp-new-rg.json │ ├── readme.md │ ├── template-AzureBot-new-rg.json │ └── template-BotApp-new-rg.json ├── docs ├── img │ ├── arch.png │ ├── bot-emu1.png │ ├── bot-service-test.png │ ├── bot-service.png │ ├── direct-line.png │ ├── oai-playground.png │ ├── vscode.png │ ├── webapp-final-en.png │ └── webapp-final.png └── index.md ├── index.html ├── lib ├── .tsbuildinfo ├── bot.d.ts ├── bot.js ├── bot.js.map ├── index.d.ts ├── index.js └── index.js.map ├── logo.png ├── package-lock.json ├── package.json ├── src ├── bot.ts └── index.ts ├── teams_package ├── color.png ├── manifest.json └── outline.png ├── tsconfig.json └── tslint.json /.deployment: -------------------------------------------------------------------------------- 1 | [config] 2 | SCM_DO_BUILD_DURING_DEPLOYMENT=true -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node 3 | { 4 | "name": "Node.js & TypeScript", 5 | // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile 6 | "image": "mcr.microsoft.com/devcontainers/typescript-node:1-20-bullseye", 7 | "features": { 8 | "ghcr.io/devcontainers/features/azure-cli:1": {} 9 | }, 10 | "customizations": { 11 | "vscode": { 12 | "extensions": [ 13 | "ms-azuretools.vscode-azureappservice", 14 | "TeamsDevApp.ms-teams-vscode-extension" 15 | ] 16 | } 17 | }, 18 | 19 | // Features to add to the dev container. More info: https://containers.dev/features. 20 | // "features": {}, 21 | 22 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 23 | // "forwardPorts": [], 24 | 25 | // Use 'postCreateCommand' to run commands after the container is created. 26 | // "postCreateCommand": "yarn install" 27 | "postCreateCommand": "npm install" 28 | 29 | // Configure tool-specific properties. 30 | // "customizations": {}, 31 | 32 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. 33 | // "remoteUser": "root" 34 | } 35 | -------------------------------------------------------------------------------- /.env.SAMPLE: -------------------------------------------------------------------------------- 1 | MicrosoftAppPassword= 2 | MicrosoftAppId= 3 | OPENAI_API_KEY= 4 | OPENAI_API_URL=https://.openai.azure.com/openai/deployments//chat/completions?api-version=2023-03-15-preview 5 | -------------------------------------------------------------------------------- /.github/workflows/main_openai-bot-webapp.yml: -------------------------------------------------------------------------------- 1 | # Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy 2 | # More GitHub Actions for Azure: https://github.com/Azure/actions 3 | 4 | name: Build and deploy Node.js app to Azure Web App - openai-bot-webapp 5 | 6 | on: 7 | push: 8 | branches: 9 | - main 10 | workflow_dispatch: 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | 19 | - name: Set up Node.js version 20 | uses: actions/setup-node@v1 21 | with: 22 | node-version: '16.x' 23 | 24 | - name: npm install, build, and test 25 | run: | 26 | npm install 27 | npm run build --if-present 28 | npm run test --if-present 29 | 30 | - name: 'Deploy to Azure Web App' 31 | id: deploy-to-webapp 32 | uses: azure/webapps-deploy@v2 33 | with: 34 | app-name: 'openai-bot-webapp' 35 | slot-name: 'Production' 36 | publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_CDB9A1062AFD49BDB0CC1E437A78B3E2 }} 37 | package: . 38 | 39 | 40 | # - name: Upload artifact for deployment job 41 | # uses: actions/upload-artifact@v2 42 | # with: 43 | # name: node-app 44 | # path: . 45 | 46 | # deploy: 47 | # runs-on: ubuntu-latest 48 | # needs: build 49 | # environment: 50 | # name: 'Production' 51 | # url: ${{ steps.deploy-to-webapp.outputs.webapp-url }} 52 | 53 | # steps: 54 | # - name: Download artifact from build job 55 | # uses: actions/download-artifact@v2 56 | # with: 57 | # name: node-app 58 | 59 | -------------------------------------------------------------------------------- /.github/workflows/node18.yml: -------------------------------------------------------------------------------- 1 | # Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy 2 | # More GitHub Actions for Azure: https://github.com/Azure/actions 3 | 4 | name: Build and deploy Node.js app to Azure Web App - openai-bot-webapp 5 | 6 | on: 7 | push: 8 | branches: 9 | - node_upgrade 10 | workflow_dispatch: 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | 19 | - name: Set up Node.js version 20 | uses: actions/setup-node@v1 21 | with: 22 | node-version: '18.x' 23 | 24 | - name: npm install, build, and test 25 | run: | 26 | npm install 27 | npm run build --if-present 28 | npm run test --if-present 29 | 30 | - name: 'Deploy to Azure Web App' 31 | id: deploy-to-webapp 32 | uses: azure/webapps-deploy@v2 33 | with: 34 | app-name: 'openai-bot-webapp-20' 35 | slot-name: 'Production' 36 | publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_NODE20 }} 37 | package: . 38 | 39 | 40 | # - name: Upload artifact for deployment job 41 | # uses: actions/upload-artifact@v2 42 | # with: 43 | # name: node-app 44 | # path: . 45 | 46 | # deploy: 47 | # runs-on: ubuntu-latest 48 | # needs: build 49 | # environment: 50 | # name: 'Production' 51 | # url: ${{ steps.deploy-to-webapp.outputs.webapp-url }} 52 | 53 | # steps: 54 | # - name: Download artifact from build job 55 | # uses: actions/download-artifact@v2 56 | # with: 57 | # name: node-app 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .tsbuildinfo 3 | .env 4 | 5 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 6 | 7 | # dependencies 8 | /node_modules 9 | /.pnp 10 | .pnp.js 11 | 12 | # testing 13 | /coverage 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | .env.local 21 | .env.development.local 22 | .env.test.local 23 | .env.production.local 24 | 25 | npm-debug.log* 26 | yarn-debug.log* 27 | yarn-error.log* 28 | .eslintcache -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Launch Program", 11 | "skipFiles": [ 12 | "/**" 13 | ], 14 | "program": "${workspaceFolder}/lib/index.js", 15 | "preLaunchTask": "tsc: build - tsconfig.json", 16 | "outFiles": [ 17 | "${workspaceFolder}/lib/**/*.js" 18 | ] 19 | } 20 | ] 21 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "appService.zipIgnorePattern": [ 3 | "node_modules{,/**}", 4 | ".vscode{,/**}" 5 | ] 6 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Simple Chatbot using Azure OpenAI service 2 | 3 | [![Build and deploy Node.js app to Azure Web App - openai-bot-webapp](https://github.com/michalmar/openai-demos-bot-webapp/actions/workflows/main_openai-bot-webapp.yml/badge.svg)](https://github.com/michalmar/openai-demos-bot-webapp/actions/workflows/main_openai-bot-webapp.yml) 4 | 5 | ## UPDATE: 6 | > This repo now uses the `ChatGPT-turbo` model in Azure OpenAI service. 7 | > Added support for Node.js 18.18 (LTS) and 20.09 (LTS) versions. 8 | 9 | > This repo now uses `Chat Completion API`: [Chat Completion documentation and examples](https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/chatgpt?pivots=programming-language-chat-completions) 10 | > You need to change the URL so it accepts the Chat Completion API. 11 | 12 | ## Introduction 13 | Chatbots are computer programs that are used to create interaction between humans and computers. OpenAI `text-davinci` is a modern language model based on neural networks developed to understand human language. This article will focus on how to create an effective chatbot based on the [Azure OpenAI](https://learn.microsoft.com/en-us/azure/cognitive-services/openai/) `text-davinci` model. 14 | 15 | In the OpenAI family, there are many models available today, which differ from each other in their focus (natural language, code, images), but also in complexity and what they can do. You can find a nice introduction and examples on [Azure Documentation ](https://learn.microsoft.com/en-us/azure/cognitive-services/openai/concepts/models). 16 | 17 | ## Target 18 | 19 | The goal is to create a simple chatbot using minimal effort, ie. we will use services and components that are already available with just a slight modification. 20 | 21 | **What components will such a chatbot have?** 22 | 23 | Chat logic - the heart of a chatbot is the ability to respond to user input, questions and requests. It should understand what the user is asking, ask for additional information in case of ambiguity and provide (if possible the correct) answer. Here we will rely on the [Azure OpenAI](https://learn.microsoft.com/en-us/azure/cognitive-services/openai/) service. 24 | 25 | Front-end, or GUI, will most likely be a web application that mediates user communication with its own chatbot. However, often such a chatbot can have more than one such interface: part of the users communicates via the website, part can use a mobile app, and another part can, for example, communicate within the Teams platform. This means that the chatbot uses multiple channels without need to edit the bot for each channel separately. 26 | 27 | Communication through channels will be provided by [Azure Bot Service](https://azure.microsoft.com/en-us/products/bot-services/#features), which can expose and manage communication with different channels (Web/Direct, Teams , but perhaps also Email, SMS, Slack, etc. - more [here](https://learn.microsoft.com/en-us/azure/bot-service/bot-service-channels-reference?view=azure-bot-service-4.0)) 28 | 29 | Services and tools used: 30 | - Azure OpenAI - the heart / logic of the chatbot 31 | - Azure App Service (Web App) - GUI exposure and chatbot hosting 32 | - Azure Bot Service - a service for managing communication through various channels 33 | 34 | ## Architecture / Solution design 35 | 36 | ```mermaid 37 | graph TD; 38 | webapp(Web App/Teams/etc.) -- query --> bot; 39 | fe <--> oai(OpenAI service);bot((Bot Service)) -- response --> webapp; 40 | bot <--> fe(Bot app); 41 | 42 | ``` 43 | 44 | ## Implementation 45 | 46 | The procedure is simple. We will make maximum use of prepared templates and examples. 47 | 48 | ### Creation of OpenAI service 49 | 50 | In the first step, we will create an OpenAI service - for this you need to [fill in the form](https://customervoice.microsoft.com/Pages/ResponsePage.aspx?id=v4j5cvGGr0GRqy180BHbR7en2Ais5pxKtso_Pz4b1_xUOFA5Qk1UWDRBMjg0WFhPMkIzTzhKQ1dWNyQlQCN0PWcu). As part of this service, we have access to the Azure OpenAI studio, where we can start by selecting and deploying the model - `text-davinci-003`, which is a GPT3.5 model. At the same time, it offers the option of a "playground" where you can test models and try your own prompts. 51 | 52 | ![azure openai playground](./docs/img/oai-playground.png) 53 | 54 | ### Creating a chatbot - editing the code 55 | 56 | > Important: this code is tested and working for Node.js 16.20 (LTS), 18.18 (LTS), 20.09 (LTS) 57 | 58 | The second step is to create your own bot within the Bot Framework, or we will start from a template for a simple web chatbot - [echo bot](https://github.com/microsoft/BotBuilder-Samples/tree/main/samples/typescript_nodejs/02.echo-bot). I chose JavaScript/TypeScript, but you can also find an example for Python or C#. 59 | 60 | In the `bot.ts` file you can see the chat application's own logic, we will focus on the `onMessage` method, which reacts to the arrival of a message from the user. 61 | 62 | ```javascript 63 | this.onMessage(async (context, next) => { 64 | const replyText = `Echo: ${ context.activity.text }`; 65 | await context.sendActivity(MessageFactory.text(replyText, replyText)); 66 | // By calling next() you ensure that the next BotHandler is run. 67 | await next(); 68 | }); 69 | ``` 70 | 71 | We modify this method in such a way that we send the user input (query or command) in the variable `context.activity.text` to the OpenAI service to get the answer and subsequently use the answer from OpenAI in the answer to the user (`data.choices[0].message.content `): 72 | 73 | ```javascript 74 | this.onMessage(async (context, next) => { 75 | 76 | let reqBody = JSON.stringify({ 77 | "messages": [{"role":"user","content":context.activity.text}}], 78 | "max_tokens": 1500, 79 | "temperature": 0.7, 80 | "frequency_penalty": 0, 81 | "presence_penalty": 0, 82 | "top_p": 1, 83 | "stop": null 84 | }); 85 | const data = await postDataToEndpoint(url, reqBody, headers); 86 | 87 | const replyText = `${ data.choices[0].message.content }`; 88 | 89 | await context.sendActivity(MessageFactory.text(replyText)); 90 | 91 | // By calling next() you ensure that the next BotHandler is run. 92 | await next(); 93 | }); 94 | ``` 95 | 96 | But this does not make the chatbot we probably would like have - we are missing two basic features: 97 | - chatbot personality - prompt 98 | - preserving the context of the communication 99 | 100 | **How to achieve that?** 101 | 102 | Working with OpenAI text models mainly consists of correct setting and tuning of the prompt (more [here](https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/chatgpt?pivots=programming-language-chat-completions)). We will use this prompt for our chatbot: 103 | 104 | ``` 105 | As an advanced chatbot, your primary goal is to assist users to the best of your ability. This may involve answering questions, providing helpful information, or completing tasks based on user input. In order to effectively assist users, it is important to be detailed and thorough in your responses. Use examples and evidence to support your points and justify your recommendations or solutions. 106 | 107 | 108 | 109 | User: 110 | Chatbot: 111 | ``` 112 | 113 | 114 | > ChatGPT/GPT-4 Chat Completion API version: 115 | > ``` 116 | > {"role":"system","content":"ystem As an advanced chatbot, your primary goal is to assist users to the best of your ability. This may involve answering questions, providing helpful information, or completing tasks based on user input. In order to effectively assist users, it is important to be detailed and thorough in your responses. Use examples and evidence to support your points and justify your recommendations or solutions."}, 117 | > 118 | > 119 | > 120 | > {"role":"user", "content":""} 121 | > ... 122 | > ``` 123 | 124 | 125 | In the first part (system message), there is an instruction on how the model will behave to the entered text - giving answers including examples to support decision-making, completion. This is where personality tuning may appear as well, for example: behave professionally or firendly etc. 126 | 127 | Then the following section `` holds the history of the conversation and we gradually adding the the input and output of the chatbot in form of `{"role": "user", "content": "user query"}, {"role":"assistant","content":"bots anwer"}`. This part is important so that the chat bot correctly understands the context of the communication. 128 | 129 | Next is `User: `, for which we will add the user input. 130 | 131 | 132 | The entire function can then look like this: 133 | 134 | ```javascript 135 | this.onMessage(async (context, next) => { 136 | 137 | 138 | // add the user input to the conversation history 139 | conversation_history_array.push({"role":"user", "content":context.activity.text}); 140 | 141 | 142 | let reqBody = JSON.stringify({ 143 | "messages": conversation_history_array, 144 | "max_tokens": 1500, 145 | "temperature": 0.7, 146 | "frequency_penalty": 0, 147 | "presence_penalty": 0, 148 | "top_p": 1, 149 | "stop": null 150 | }); 151 | 152 | 153 | // send request to openai 154 | const data = await postDataToEndpoint(url, reqBody, headers); 155 | 156 | // add the chatbot response to the conversation history 157 | conversation_history_array.push({"role":data.choices[0].message.role, "content":data.choices[0].message.content}); 158 | 159 | 160 | // send response to user 161 | const replyText = `${ data.choices[0].message.content }`; 162 | 163 | await context.sendActivity(MessageFactory.text(replyText)); 164 | 165 | // By calling next() you ensure that the next BotHandler is run. 166 | await next(); 167 | 168 | } 169 | }); 170 | ``` 171 | 172 | We can test such a chatbot locally in [Bot Framework Emulator](https://github.com/microsoft/BotFramework-Emulator): 173 | 174 | ![bot framework emulator](./docs/img/bot-emu1.png) 175 | 176 | ### Deployment do Azure 177 | 178 | After we have tested that the chatbot listens to us and responds in the local environment, we can proceed to the next step, which is deployment to Azure. We are doing this for two reasons: 179 | 180 | 1. we need the service to be accessible from anywhere 181 | 1. we want to be able to run our chatbot on multiple channels 182 | 183 | In case we use [VS Code](https://code.visualstudio.com/) for development (which I highly recommend), we can use the extension for working with Azure Web App for the (1-click) deployment itself. 184 | 185 | ![vscode](./docs/img/vscode.png) 186 | 187 | This is good for one-time testing, for easier iterative development I recommend using the [automatic deployment to Azure Web App using GitHub Actions](https://learn.microsoft.com/en-us/azure/app-service/deploy-continuous- deployment?tabs=github). 188 | 189 | ### Configure Azure / Bot Service 190 | 191 | The bot itself (the engine) is now already hosted in Azure - all we have to do is expose it using the [Azure Bot Service](https://portal.azure.com/#create/Microsoft.AzureBot) to access multiple channels without the need to change the code. 192 | 193 | Just enter the URL of the web application created in the previous step into the Bot service settings - such a URL is the FQDN of the given application plus `api/messages`, i.e. looks something like this: 194 | 195 | ```url 196 | https://YOUR-WEB-APP.azurewebsites.net/api/messages 197 | ``` 198 | 199 | ![bot service](./docs/img/bot-service.png) 200 | 201 | If everything was correct, we can directly test the service in Web Chat within the bot service directly on the Azure Portal: 202 | 203 | ![web chat test](./docs/img/bot-service-test.png) 204 | 205 | This gave us access to several channels: Web Chat, Microsoft Teams, Facebook Messenger, Slack, Twilio SMS,... (full list [here](https://learn.microsoft.com/en-us/azure/ bot-service/bot-service-channels-reference?view=azure-bot-service-4.0)) 206 | 207 | 208 | ### Front-end / Web application 209 | 210 | Now that the chatbot works for us and is deployed in Azure, we can test the most common integrations into the website. The easiest option is that you can generate an integration using an `iframe` and then just insert this code into your HTML page. 211 | 212 | ```html 213 | 215 | ``` 216 | 217 | Another option is to directly use WebChat integration into the page - more [here](https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-webchat-overview?view=azure-bot-service-4.0) and the source is at: [https://github.com/microsoft/BotFramework-WebChat](https://github.com/microsoft/BotFramework-WebChat/tree/main/samples/01.getting-started/a.full-bundle). 218 | 219 | In short, these are JS libraries that allow simple integration and other customizations: 220 | 221 | ```html 222 | 223 | 224 | 225 |
226 | 227 | 238 | 239 | 240 | ``` 241 | 242 | Where `YOUR_DIRECT_LINE_TOKEN` is the token for direct line communication within the Bot Service and `YOUR_USER_ID` is your chosen identification 243 | 244 | ![direct line token](./docs/img/direct-line.png) 245 | 246 | > Important!: When configuring the Web app it is a best practice (proabaly security must) to not to use your tokens/passwords directly in your code but use them as web application environmental variables / application settings. In fact, we use in our example (in this repo) four such variables you would need to setup / fill to make you application communicate correctly: 247 | > 248 | > `DIRECT_LINE_TOKEN`... setting from the Bot Service channel 249 | > 250 | > `OPENAI_API_KEY`...key for authentication to your Azure OpenAI service 251 | > 252 | > `MicrosoftAppId` and `MicrosoftAppPassword` used when creating Bot Service for autentication to Azure resources (you can use your own Service Principal or leave default - more [here](https://learn.microsoft.com/en-us/azure/bot-service/provision-and-publish-a-bot?view=azure-bot-service-4.0&tabs=userassigned%2Ccsharp#plan-your-deployment)) 253 | 254 | Such a page then contains our just-prepared chatbot. The WebChat framework offers a lot of customization options, so you can change almost anything from colors to the display of chat member indicators - more [here](https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-webchat-customization?view=azure-bot-service-4.0). 255 | 256 | So our chatbot can look like this: 257 | 258 | ![web app chat bot](./docs/img/webapp-final-en.png) 259 | 260 | ## Conclusion 261 | 262 | This was a demonstration of how to create a simple chatbot that knows the answer to almost any question :-) because it uses the powerful model `text-davinci-003` from the Azure OpenAI service. 263 | 264 | You can try it yourself if you want! The full source code is available on my GitHub: [https://github.com/michalmar/openai-demos-bot-webapp](https://github.com/michalmar/openai-demos-bot-webapp). In order to use the Azure OpenAI service, you must first request access - [form](https://customervoice.microsoft.com/Pages/ResponsePage.aspx?id=v4j5cvGGr0GRqy180BHbR7en2Ais5pxKtso_Pz4b1_xUOFA5Qk1UWDRBMjg0WFhPMkIzTzhKQ1dWNyQlQCN0PWcu). -------------------------------------------------------------------------------- /deploymentScripts/linux/.deployment: -------------------------------------------------------------------------------- 1 | [config] 2 | command = ./deploy.sh -------------------------------------------------------------------------------- /deploymentScripts/linux/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # ---------------------- 4 | # KUDU Deployment Script 5 | # Version: 1.0.17 6 | # ---------------------- 7 | 8 | # Helpers 9 | # ------- 10 | 11 | exitWithMessageOnError () { 12 | if [ ! $? -eq 0 ]; then 13 | echo "An error has occurred during web site deployment." 14 | echo $1 15 | exit 1 16 | fi 17 | } 18 | 19 | # Prerequisites 20 | # ------------- 21 | 22 | # Verify node.js installed 23 | hash node 2>/dev/null 24 | exitWithMessageOnError "Missing node.js executable, please install node.js, if already installed make sure it can be reached from current environment." 25 | 26 | # Setup 27 | # ----- 28 | 29 | SCRIPT_DIR="${BASH_SOURCE[0]%\\*}" 30 | SCRIPT_DIR="${SCRIPT_DIR%/*}" 31 | ARTIFACTS=$SCRIPT_DIR/../artifacts 32 | KUDU_SYNC_CMD=${KUDU_SYNC_CMD//\"} 33 | 34 | if [[ ! -n "$DEPLOYMENT_SOURCE" ]]; then 35 | DEPLOYMENT_SOURCE=$SCRIPT_DIR 36 | fi 37 | 38 | if [[ ! -n "$NEXT_MANIFEST_PATH" ]]; then 39 | NEXT_MANIFEST_PATH=$ARTIFACTS/manifest 40 | 41 | if [[ ! -n "$PREVIOUS_MANIFEST_PATH" ]]; then 42 | PREVIOUS_MANIFEST_PATH=$NEXT_MANIFEST_PATH 43 | fi 44 | fi 45 | 46 | if [[ ! -n "$DEPLOYMENT_TARGET" ]]; then 47 | DEPLOYMENT_TARGET=$ARTIFACTS/wwwroot 48 | else 49 | KUDU_SERVICE=true 50 | fi 51 | 52 | if [[ ! -n "$KUDU_SYNC_CMD" ]]; then 53 | # Install kudu sync 54 | echo Installing Kudu Sync 55 | npm install kudusync -g --silent 56 | exitWithMessageOnError "npm failed" 57 | 58 | if [[ ! -n "$KUDU_SERVICE" ]]; then 59 | # In case we are running locally this is the correct location of kuduSync 60 | KUDU_SYNC_CMD=kuduSync 61 | else 62 | # In case we are running on kudu service this is the correct location of kuduSync 63 | KUDU_SYNC_CMD=$APPDATA/npm/node_modules/kuduSync/bin/kuduSync 64 | fi 65 | fi 66 | 67 | # Node Helpers 68 | # ------------ 69 | 70 | selectNodeVersion () { 71 | NPM_CMD=npm 72 | NODE_EXE=node 73 | } 74 | 75 | ################################################################################################################################## 76 | # Deployment 77 | # ---------- 78 | 79 | echo Handling node.js deployment. 80 | 81 | # 1. KuduSync 82 | if [[ "$IN_PLACE_DEPLOYMENT" -ne "1" ]]; then 83 | "$KUDU_SYNC_CMD" -v 50 -f "$DEPLOYMENT_SOURCE" -t "$DEPLOYMENT_TARGET" -n "$NEXT_MANIFEST_PATH" -p "$PREVIOUS_MANIFEST_PATH" -i ".git;.hg;.deployment;deploy.sh" 84 | exitWithMessageOnError "Kudu Sync failed" 85 | fi 86 | 87 | # 2. Select node version 88 | selectNodeVersion 89 | 90 | # 3. Install npm packages 91 | if [ -e "$DEPLOYMENT_TARGET/package.json" ]; then 92 | cd "$DEPLOYMENT_TARGET" 93 | echo "Running $NPM_CMD install --production" 94 | eval $NPM_CMD install --production 95 | exitWithMessageOnError "npm failed" 96 | cd - > /dev/null 97 | fi 98 | 99 | ################################################################################################################################## 100 | echo "Finished successfully." -------------------------------------------------------------------------------- /deploymentScripts/webConfigPrep.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | // DO NOT MODIFY THIS CODE 5 | // This script is run as part of the Post Deploy step when 6 | // deploying the bot to Azure. It ensures the Azure Web App 7 | // is configured correctly to host a TypeScript authored bot. 8 | const fs = require('fs'); 9 | const path = require('path'); 10 | const replace = require('replace'); 11 | const WEB_CONFIG_FILE = './web.config'; 12 | 13 | if (fs.existsSync(path.resolve(WEB_CONFIG_FILE))) { 14 | replace({ 15 | regex: "url=\"index.js\"", 16 | replacement: "url=\"lib/index.js\"", 17 | paths: ['./web.config'], 18 | recursive: false, 19 | silent: true, 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /deploymentScripts/windows/.deployment: -------------------------------------------------------------------------------- 1 | [config] 2 | command = deploy.cmd -------------------------------------------------------------------------------- /deploymentScripts/windows/deploy.cmd: -------------------------------------------------------------------------------- 1 | @if "%SCM_TRACE_LEVEL%" NEQ "4" @echo off 2 | 3 | :: ---------------------- 4 | :: KUDU Deployment Script 5 | :: Version: 1.0.17 6 | :: ---------------------- 7 | 8 | :: Prerequisites 9 | :: ------------- 10 | 11 | :: Verify node.js installed 12 | where node 2>nul >nul 13 | IF %ERRORLEVEL% NEQ 0 ( 14 | echo Missing node.js executable, please install node.js, if already installed make sure it can be reached from current environment. 15 | goto error 16 | ) 17 | 18 | :: Setup 19 | :: ----- 20 | 21 | setlocal enabledelayedexpansion 22 | 23 | SET ARTIFACTS=%~dp0%..\artifacts 24 | 25 | IF NOT DEFINED DEPLOYMENT_SOURCE ( 26 | SET DEPLOYMENT_SOURCE=%~dp0%. 27 | ) 28 | 29 | IF NOT DEFINED DEPLOYMENT_TARGET ( 30 | SET DEPLOYMENT_TARGET=%ARTIFACTS%\wwwroot 31 | ) 32 | 33 | IF NOT DEFINED NEXT_MANIFEST_PATH ( 34 | SET NEXT_MANIFEST_PATH=%ARTIFACTS%\manifest 35 | 36 | IF NOT DEFINED PREVIOUS_MANIFEST_PATH ( 37 | SET PREVIOUS_MANIFEST_PATH=%ARTIFACTS%\manifest 38 | ) 39 | ) 40 | 41 | IF NOT DEFINED KUDU_SYNC_CMD ( 42 | :: Install kudu sync 43 | echo Installing Kudu Sync 44 | call npm install kudusync -g --silent 45 | IF !ERRORLEVEL! NEQ 0 goto error 46 | 47 | :: Locally just running "kuduSync" would also work 48 | SET KUDU_SYNC_CMD=%appdata%\npm\kuduSync.cmd 49 | ) 50 | goto Deployment 51 | 52 | :: Utility Functions 53 | :: ----------------- 54 | 55 | :SelectNodeVersion 56 | 57 | IF DEFINED KUDU_SELECT_NODE_VERSION_CMD ( 58 | :: The following are done only on Windows Azure Websites environment 59 | call %KUDU_SELECT_NODE_VERSION_CMD% "%DEPLOYMENT_SOURCE%" "%DEPLOYMENT_TARGET%" "%DEPLOYMENT_TEMP%" 60 | IF !ERRORLEVEL! NEQ 0 goto error 61 | 62 | IF EXIST "%DEPLOYMENT_TEMP%\__nodeVersion.tmp" ( 63 | SET /p NODE_EXE=<"%DEPLOYMENT_TEMP%\__nodeVersion.tmp" 64 | IF !ERRORLEVEL! NEQ 0 goto error 65 | ) 66 | 67 | IF EXIST "%DEPLOYMENT_TEMP%\__npmVersion.tmp" ( 68 | SET /p NPM_JS_PATH=<"%DEPLOYMENT_TEMP%\__npmVersion.tmp" 69 | IF !ERRORLEVEL! NEQ 0 goto error 70 | ) 71 | 72 | IF NOT DEFINED NODE_EXE ( 73 | SET NODE_EXE=node 74 | ) 75 | 76 | SET NPM_CMD="!NODE_EXE!" "!NPM_JS_PATH!" 77 | ) ELSE ( 78 | SET NPM_CMD=npm 79 | SET NODE_EXE=node 80 | ) 81 | 82 | goto :EOF 83 | 84 | :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 85 | :: Deployment 86 | :: ---------- 87 | 88 | :Deployment 89 | echo Handling node.js deployment. 90 | 91 | :: 1. KuduSync 92 | IF /I "%IN_PLACE_DEPLOYMENT%" NEQ "1" ( 93 | call :ExecuteCmd "%KUDU_SYNC_CMD%" -v 50 -f "%DEPLOYMENT_SOURCE%" -t "%DEPLOYMENT_TARGET%" -n "%NEXT_MANIFEST_PATH%" -p "%PREVIOUS_MANIFEST_PATH%" -i ".git;.hg;.deployment;deploy.cmd" 94 | IF !ERRORLEVEL! NEQ 0 goto error 95 | ) 96 | 97 | :: 2. Select node version 98 | call :SelectNodeVersion 99 | 100 | :: 3. Install npm packages 101 | IF EXIST "%DEPLOYMENT_TARGET%\package.json" ( 102 | pushd "%DEPLOYMENT_TARGET%" 103 | call :ExecuteCmd !NPM_CMD! install --production 104 | IF !ERRORLEVEL! NEQ 0 goto error 105 | popd 106 | ) 107 | 108 | :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 109 | goto end 110 | 111 | :: Execute command routine that will echo out when error 112 | :ExecuteCmd 113 | setlocal 114 | set _CMD_=%* 115 | call %_CMD_% 116 | if "%ERRORLEVEL%" NEQ "0" echo Failed exitCode=%ERRORLEVEL%, command=%_CMD_% 117 | exit /b %ERRORLEVEL% 118 | 119 | :error 120 | endlocal 121 | echo An error has occurred during web site deployment. 122 | call :exitSetErrorLevel 123 | call :exitFromFunction 2>nul 124 | 125 | :exitSetErrorLevel 126 | exit /b 1 127 | 128 | :exitFromFunction 129 | () 130 | 131 | :end 132 | endlocal 133 | echo Finished successfully. 134 | -------------------------------------------------------------------------------- /deploymentTemplates/deployUseExistResourceGroup/parameters-for-template-AzureBot-with-rg.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "azureBotId": { 6 | "value": "" 7 | }, 8 | "azureBotSku": { 9 | "value": "S1" 10 | }, 11 | "azureBotRegion": { 12 | "value": "global" 13 | }, 14 | "botEndpoint": { 15 | "value": "" 16 | }, 17 | "appType": { 18 | "value": "MultiTenant" 19 | }, 20 | "appId": { 21 | "value": "" 22 | }, 23 | "UMSIName": { 24 | "value": "" 25 | }, 26 | "UMSIResourceGroupName": { 27 | "value": "" 28 | }, 29 | "tenantId": { 30 | "value": "" 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /deploymentTemplates/deployUseExistResourceGroup/parameters-for-template-BotApp-with-rg.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "appServiceName": { 6 | "value": "" 7 | }, 8 | "existingAppServicePlanName": { 9 | "value": "" 10 | }, 11 | "existingAppServicePlanLocation": { 12 | "value": "" 13 | }, 14 | "newAppServicePlanName": { 15 | "value": "" 16 | }, 17 | "newAppServicePlanLocation": { 18 | "value": "" 19 | }, 20 | "newAppServicePlanSku": { 21 | "value": { 22 | "name": "S1", 23 | "tier": "Standard", 24 | "size": "S1", 25 | "family": "S", 26 | "capacity": 1 27 | } 28 | }, 29 | "appType": { 30 | "value": "MultiTenant" 31 | }, 32 | "appId": { 33 | "value": "" 34 | }, 35 | "appSecret": { 36 | "value": "" 37 | }, 38 | "UMSIName": { 39 | "value": "" 40 | }, 41 | "UMSIResourceGroupName": { 42 | "value": "" 43 | }, 44 | "tenantId": { 45 | "value": "" 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /deploymentTemplates/deployUseExistResourceGroup/readme.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | BotApp must be deployed prior to AzureBot. 3 | 4 | ### Command line: 5 | `az login`
6 | `az deployment group create --resource-group --template-file --parameters @` 7 | 8 | ## Parameters for template-BotApp-with-rg.json: 9 | 10 | - **appServiceName**: (required) The Name of the Bot App Service. 11 | - (Pick an existing App Service Plan or create a new App Service Plan.) 12 | - **existingAppServicePlanName**: The name of the App Service Plan. 13 | - **existingAppServicePlanLocation**: The location of the App Service Plan. 14 | - **newAppServicePlanName**: The name of the App Service Plan. 15 | - **newAppServicePlanLocation**: The location of the App Service Plan. 16 | - **newAppServicePlanSku**: The SKU of the App Service Plan. Defaults to Standard values. 17 | - **appType**: Type of Bot Authentication. set as MicrosoftAppType in the Web App's Application Settings. **Allowed values are: MultiTenant(default), SingleTenant, UserAssignedMSI.** 18 | - **appId**: (required) Active Directory App ID or User-Assigned Managed Identity Client ID, set as MicrosoftAppId in the Web App's Application Settings. 19 | - **appSecret**: (required for MultiTenant and SingleTenant) Active Directory App Password, set as MicrosoftAppPassword in the Web App's Application Settings. 20 | - **UMSIName**: (required for UserAssignedMSI) The User-Assigned Managed Identity Resource used for the Bot's Authentication. 21 | - **UMSIResourceGroupName**: (required for UserAssignedMSI) The User-Assigned Managed Identity Resource Group used for the Bot's Authentication. 22 | - **tenantId**: The Azure AD Tenant ID to use as part of the Bot's Authentication. Only used for SingleTenant and UserAssignedMSI app types. Defaults to Subscription Tenant ID. 23 | 24 | More info: https://docs.microsoft.com/en-us/azure/bot-service/tutorial-provision-a-bot?view=azure-bot-service-4.0&tabs=userassigned%2Cnewgroup#create-an-identity-resource 25 | 26 | ## Parameters for template-AzureBot-with-rg.json: 27 | 28 | - **azureBotId**: (required) The globally unique and immutable bot ID. 29 | - **azureBotSku**: The pricing tier of the Bot Service Registration. Allowed values are: F0, S1(default). 30 | - **azureBotRegion**: Specifies the location of the new AzureBot. Allowed values are: global(default), westeurope. 31 | - **botEndpoint**: Use to handle client messages, Such as `https://.azurewebsites.net/api/messages`. 32 | - **appType**: Type of Bot Authentication. set as MicrosoftAppType in the Web App's Application Settings. Allowed values are: MultiTenant(default), SingleTenant, UserAssignedMSI. 33 | - **appId**: (required) Active Directory App ID or User-Assigned Managed Identity Client ID, set as MicrosoftAppId in the Web App's Application Settings. 34 | - **UMSIName**: (required for UserAssignedMSI) The User-Assigned Managed Identity Resource used for the Bot's Authentication. 35 | - **UMSIResourceGroupName**: (required for UserAssignedMSI) The User-Assigned Managed Identity Resource Group used for the Bot's Authentication. 36 | - **tenantId**: The Azure AD Tenant ID to use as part of the Bot's Authentication. Only used for SingleTenant and UserAssignedMSI app types. Defaults to Subscription Tenant ID. 37 | 38 | More info: https://docs.microsoft.com/en-us/azure/bot-service/tutorial-provision-a-bot?view=azure-bot-service-4.0&tabs=userassigned%2Cnewgroup#create-an-identity-resource -------------------------------------------------------------------------------- /deploymentTemplates/deployUseExistResourceGroup/template-AzureBot-with-rg.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "azureBotId": { 6 | "type": "string", 7 | "metadata": { 8 | "description": "The globally unique and immutable bot ID." 9 | } 10 | }, 11 | "azureBotSku": { 12 | "type": "string", 13 | "defaultValue": "S1", 14 | "metadata": { 15 | "description": "The pricing tier of the Bot Service Registration. Allowed values are: F0, S1(default)." 16 | } 17 | }, 18 | "azureBotRegion": { 19 | "type": "string", 20 | "defaultValue": "global", 21 | "metadata": { 22 | "description": "Specifies the location of the new AzureBot. Allowed values are: global(default), westeurope." 23 | } 24 | }, 25 | "botEndpoint": { 26 | "type": "string", 27 | "defaultValue": "", 28 | "metadata": { 29 | "description": "Use to handle client messages, Such as https://.azurewebsites.net/api/messages." 30 | } 31 | }, 32 | "appType": { 33 | "type": "string", 34 | "defaultValue": "MultiTenant", 35 | "allowedValues": [ 36 | "MultiTenant", 37 | "SingleTenant", 38 | "UserAssignedMSI" 39 | ], 40 | "metadata": { 41 | "description": "Type of Bot Authentication. set as MicrosoftAppType in the Web App's Application Settings. Allowed values are: MultiTenant, SingleTenant, UserAssignedMSI. Defaults to \"MultiTenant\"." 42 | } 43 | }, 44 | "appId": { 45 | "type": "string", 46 | "metadata": { 47 | "description": "Active Directory App ID or User-Assigned Managed Identity Client ID, set as MicrosoftAppId in the Web App's Application Settings." 48 | } 49 | }, 50 | "UMSIName": { 51 | "type": "string", 52 | "defaultValue": "", 53 | "metadata": { 54 | "description": "The User-Assigned Managed Identity Resource used for the Bot's Authentication." 55 | } 56 | }, 57 | "UMSIResourceGroupName": { 58 | "type": "string", 59 | "defaultValue": "", 60 | "metadata": { 61 | "description": "The User-Assigned Managed Identity Resource Group used for the Bot's Authentication." 62 | } 63 | }, 64 | "tenantId": { 65 | "type": "string", 66 | "defaultValue": "[subscription().tenantId]", 67 | "metadata": { 68 | "description": "The Azure AD Tenant ID to use as part of the Bot's Authentication. Only used for SingleTenant and UserAssignedMSI app types. Defaults to \"Subscription Tenant ID\"." 69 | } 70 | } 71 | }, 72 | "variables": { 73 | "botEndpoint": "[if(empty(parameters('botEndpoint')), concat('https://', parameters('azureBotId'), '.azurewebsites.net/api/messages'), parameters('botEndpoint'))]", 74 | "tenantId": "[if(empty(parameters('tenantId')), subscription().tenantId, parameters('tenantId'))]", 75 | "msiResourceId": "[if(empty(parameters('UMSIName')), '', concat(subscription().id, '/resourceGroups/', parameters('UMSIResourceGroupName'), '/providers/', 'Microsoft.ManagedIdentity/userAssignedIdentities/', parameters('UMSIName')))]", 76 | "appTypeDef": { 77 | "MultiTenant": { 78 | "tenantId": "", 79 | "msiResourceId": "" 80 | }, 81 | "SingleTenant": { 82 | "tenantId": "[variables('tenantId')]", 83 | "msiResourceId": "" 84 | }, 85 | "UserAssignedMSI": { 86 | "tenantId": "[variables('tenantId')]", 87 | "msiResourceId": "[variables('msiResourceId')]" 88 | } 89 | }, 90 | "appType": { 91 | "tenantId": "[variables('appTypeDef')[parameters('appType')].tenantId]", 92 | "msiResourceId": "[variables('appTypeDef')[parameters('appType')].msiResourceId]" 93 | } 94 | }, 95 | "resources": [ 96 | { 97 | "apiVersion": "2021-05-01-preview", 98 | "type": "Microsoft.BotService/botServices", 99 | "name": "[parameters('azureBotId')]", 100 | "location": "[parameters('azureBotRegion')]", 101 | "kind": "azurebot", 102 | "sku": { 103 | "name": "[parameters('azureBotSku')]" 104 | }, 105 | "properties": { 106 | "displayName": "[parameters('azureBotId')]", 107 | "iconUrl": "https://docs.botframework.com/static/devportal/client/images/bot-framework-default.png", 108 | "endpoint": "[variables('botEndpoint')]", 109 | "msaAppId": "[parameters('appId')]", 110 | "msaAppTenantId": "[variables('appType').tenantId]", 111 | "msaAppMSIResourceId": "[variables('appType').msiResourceId]", 112 | "msaAppType": "[parameters('appType')]", 113 | "luisAppIds": [], 114 | "schemaTransformationVersion": "1.3", 115 | "isCmekEnabled": false, 116 | "isIsolated": false 117 | }, 118 | "dependsOn": [] 119 | } 120 | ] 121 | } -------------------------------------------------------------------------------- /deploymentTemplates/deployUseExistResourceGroup/template-BotApp-with-rg.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "appServiceName": { 6 | "type": "string", 7 | "defaultValue": "", 8 | "metadata": { 9 | "description": "The globally unique name of the Web App." 10 | } 11 | }, 12 | "existingAppServicePlanName": { 13 | "type": "string", 14 | "defaultValue": "", 15 | "metadata": { 16 | "description": "Name of the existing App Service Plan used to create the Web App for the bot." 17 | } 18 | }, 19 | "existingAppServicePlanLocation": { 20 | "type": "string", 21 | "defaultValue": "", 22 | "metadata": { 23 | "description": "The location of the App Service Plan." 24 | } 25 | }, 26 | "newAppServicePlanName": { 27 | "type": "string", 28 | "defaultValue": "", 29 | "metadata": { 30 | "description": "The name of the new App Service Plan." 31 | } 32 | }, 33 | "newAppServicePlanLocation": { 34 | "type": "string", 35 | "defaultValue": "", 36 | "metadata": { 37 | "description": "The location of the App Service Plan." 38 | } 39 | }, 40 | "newAppServicePlanSku": { 41 | "type": "object", 42 | "defaultValue": { 43 | "name": "S1", 44 | "tier": "Standard", 45 | "size": "S1", 46 | "family": "S", 47 | "capacity": 1 48 | }, 49 | "metadata": { 50 | "description": "The SKU of the App Service Plan. Defaults to Standard values." 51 | } 52 | }, 53 | "appType": { 54 | "type": "string", 55 | "defaultValue": "MultiTenant", 56 | "allowedValues": [ 57 | "MultiTenant", 58 | "SingleTenant", 59 | "UserAssignedMSI" 60 | ], 61 | "metadata": { 62 | "description": "Type of Bot Authentication. set as MicrosoftAppType in the Web App's Application Settings. Allowed values are: MultiTenant, SingleTenant, UserAssignedMSI. Defaults to \"MultiTenant\"." 63 | } 64 | }, 65 | "appId": { 66 | "type": "string", 67 | "metadata": { 68 | "description": "Active Directory App ID or User-Assigned Managed Identity Client ID, set as MicrosoftAppId in the Web App's Application Settings." 69 | } 70 | }, 71 | "appSecret": { 72 | "type": "string", 73 | "defaultValue": "", 74 | "metadata": { 75 | "description": "Active Directory App Password, set as MicrosoftAppPassword in the Web App's Application Settings. Required for MultiTenant and SingleTenant app types. Defaults to \"\"." 76 | } 77 | }, 78 | "UMSIName": { 79 | "type": "string", 80 | "defaultValue": "", 81 | "metadata": { 82 | "description": "The User-Assigned Managed Identity Resource used for the Bot's Authentication. Defaults to \"\"." 83 | } 84 | }, 85 | "UMSIResourceGroupName": { 86 | "type": "string", 87 | "defaultValue": "", 88 | "metadata": { 89 | "description": "The User-Assigned Managed Identity Resource Group used for the Bot's Authentication. Defaults to \"\"." 90 | } 91 | }, 92 | "tenantId": { 93 | "type": "string", 94 | "defaultValue": "[subscription().tenantId]", 95 | "metadata": { 96 | "description": "The Azure AD Tenant ID to use as part of the Bot's Authentication. Only used for SingleTenant and UserAssignedMSI app types. Defaults to \"Subscription Tenant ID\"." 97 | } 98 | } 99 | }, 100 | "variables": { 101 | "tenantId": "[if(empty(parameters('tenantId')), subscription().tenantId, parameters('tenantId'))]", 102 | "useExistingServicePlan": "[not(empty(parameters('existingAppServicePlanName')))]", 103 | "servicePlanName": "[if(variables('useExistingServicePlan'), parameters('existingAppServicePlanName'), parameters('newAppServicePlanName'))]", 104 | "servicePlanLocation": "[if(variables('useExistingServicePlan'), parameters('existingAppServicePlanLocation'), parameters('newAppServicePlanLocation'))]", 105 | "msiResourceId": "[if(empty(parameters('UMSIName')), '', concat(subscription().id, '/resourceGroups/', parameters('UMSIResourceGroupName'), '/providers/', 'Microsoft.ManagedIdentity/userAssignedIdentities/', parameters('UMSIName')))]", 106 | "appTypeDef": { 107 | "MultiTenant": { 108 | "tenantId": "", 109 | "identity": { "type": "None" } 110 | }, 111 | "SingleTenant": { 112 | "tenantId": "[variables('tenantId')]", 113 | "identity": { "type": "None" } 114 | }, 115 | "UserAssignedMSI": { 116 | "tenantId": "[variables('tenantId')]", 117 | "identity": { 118 | "type": "UserAssigned", 119 | "userAssignedIdentities": { 120 | "[variables('msiResourceId')]": {} 121 | } 122 | } 123 | } 124 | }, 125 | "appType": { 126 | "tenantId": "[variables('appTypeDef')[parameters('appType')].tenantId]", 127 | "identity": "[variables('appTypeDef')[parameters('appType')].identity]" 128 | } 129 | }, 130 | "resources": [ 131 | { 132 | "comments": "Create a new App Service Plan if no existing App Service Plan name was passed in.", 133 | "type": "Microsoft.Web/serverfarms", 134 | "condition": "[not(variables('useExistingServicePlan'))]", 135 | "name": "[variables('servicePlanName')]", 136 | "apiVersion": "2018-02-01", 137 | "location": "[parameters('newAppServicePlanLocation')]", 138 | "sku": "[parameters('newAppServicePlanSku')]", 139 | "properties": { 140 | "name": "[variables('servicePlanName')]" 141 | } 142 | }, 143 | { 144 | "comments": "Create a Web App using an App Service Plan", 145 | "type": "Microsoft.Web/sites", 146 | "apiVersion": "2015-08-01", 147 | "location": "[variables('servicePlanLocation')]", 148 | "kind": "app", 149 | "dependsOn": [ 150 | "[resourceId('Microsoft.Web/serverfarms', variables('servicePlanName'))]" 151 | ], 152 | "name": "[parameters('appServiceName')]", 153 | "identity": "[variables('appType').identity]", 154 | "properties": { 155 | "name": "[parameters('appServiceName')]", 156 | "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('servicePlanName'))]", 157 | "siteConfig": { 158 | "appSettings": [ 159 | { 160 | "name": "WEBSITE_NODE_DEFAULT_VERSION", 161 | "value": "10.14.1" 162 | }, 163 | { 164 | "name": "MicrosoftAppType", 165 | "value": "[parameters('appType')]" 166 | }, 167 | { 168 | "name": "MicrosoftAppId", 169 | "value": "[parameters('appId')]" 170 | }, 171 | { 172 | "name": "MicrosoftAppPassword", 173 | "value": "[parameters('appSecret')]" 174 | }, 175 | { 176 | "name": "MicrosoftAppTenantId", 177 | "value": "[variables('appType').tenantId]" 178 | } 179 | ], 180 | "cors": { 181 | "allowedOrigins": [ 182 | "https://botservice.hosting.portal.azure.net", 183 | "https://hosting.onecloud.azure-test.net/" 184 | ] 185 | }, 186 | "webSocketsEnabled": true 187 | } 188 | } 189 | } 190 | ] 191 | } -------------------------------------------------------------------------------- /deploymentTemplates/deployWithNewResourceGroup/parameters-for-template-AzureBot-new-rg.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "groupName": { 6 | "value": "" 7 | }, 8 | "groupLocation": { 9 | "value": "" 10 | }, 11 | "azureBotId": { 12 | "value": "" 13 | }, 14 | "azureBotSku": { 15 | "value": "S1" 16 | }, 17 | "azureBotRegion": { 18 | "value": "global" 19 | }, 20 | "botEndpoint": { 21 | "value": "" 22 | }, 23 | "appType": { 24 | "value": "MultiTenant" 25 | }, 26 | "appId": { 27 | "value": "" 28 | }, 29 | "UMSIName": { 30 | "value": "" 31 | }, 32 | "UMSIResourceGroupName": { 33 | "value": "" 34 | }, 35 | "tenantId": { 36 | "value": "" 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /deploymentTemplates/deployWithNewResourceGroup/parameters-for-template-BotApp-new-rg.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "groupName": { 6 | "value": "" 7 | }, 8 | "groupLocation": { 9 | "value": "" 10 | }, 11 | "appServiceName": { 12 | "value": "" 13 | }, 14 | "appServicePlanName": { 15 | "value": "" 16 | }, 17 | "appServicePlanLocation": { 18 | "value": "" 19 | }, 20 | "appServicePlanSku": { 21 | "value": { 22 | "name": "S1", 23 | "tier": "Standard", 24 | "size": "S1", 25 | "family": "S", 26 | "capacity": 1 27 | } 28 | }, 29 | "appType": { 30 | "value": "MultiTenant" 31 | }, 32 | "appId": { 33 | "value": "" 34 | }, 35 | "appSecret": { 36 | "value": "" 37 | }, 38 | "UMSIName": { 39 | "value": "" 40 | }, 41 | "UMSIResourceGroupName": { 42 | "value": "" 43 | }, 44 | "tenantId": { 45 | "value": "" 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /deploymentTemplates/deployWithNewResourceGroup/readme.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | BotApp must be deployed prior to AzureBot. 3 | 4 | ### Command line: 5 | `az login`
6 | `az deployment sub create --template-file --location --parameters @` 7 | 8 | ## Parameters for template-BotApp-new-rg.json: 9 | 10 | - **groupName**: (required) The name of the new Resource Group. 11 | - **groupLocation**: (required) The location of the new Resource Group. 12 | 13 | - **appServiceName**: (required) The location of the App Service Plan. 14 | - **appServicePlanName**: (required) The name of the App Service Plan. 15 | - **appServicePlanLocation**: The location of the App Service Plan. Defaults to use groupLocation. 16 | - **appServicePlanSku**: The SKU of the App Service Plan. Defaults to Standard values. 17 | 18 | - **appType**: Type of Bot Authentication. set as MicrosoftAppType in the Web App's Application Settings. Allowed values are: MultiTenant(default), SingleTenant, UserAssignedMSI. 19 | - **appId**: (required) Active Directory App ID or User-Assigned Managed Identity Client ID, set as MicrosoftAppId in the Web App's Application Settings. 20 | - **appSecret**: (required for MultiTenant and SingleTenant) Active Directory App Password, set as MicrosoftAppPassword in the Web App's Application Settings. 21 | - **UMSIName**: (required for UserAssignedMSI) The User-Assigned Managed Identity Resource used for the Bot's Authentication. 22 | - **UMSIResourceGroupName**:(required for UserAssignedMSI) The User-Assigned Managed Identity Resource Group used for the Bot's Authentication. 23 | - **tenantId**: The Azure AD Tenant ID to use as part of the Bot's Authentication. Only used for SingleTenant and UserAssignedMSI app types. Defaults to . 24 | 25 | More info: https://docs.microsoft.com/en-us/azure/bot-service/tutorial-provision-a-bot?view=azure-bot-service-4.0&tabs=userassigned%2Cnewgroup#create-an-identity-resource 26 | 27 | 28 | 29 | ## Parameters for template-AzureBot-new-rg.json: 30 | 31 | - **groupName**: (required) The name of the new Resource Group. 32 | - **groupLocation**: (required) The location of the new Resource Group. 33 | 34 | - **azureBotId**: (required) The globally unique and immutable bot ID. Also used to configure the displayName of the bot, which is mutable. 35 | - **azureBotSku**: The pricing tier of the Bot Service Registration. Allowed values are: F0, S1(default). 36 | - **azureBotRegion**: Specifies the location of the new AzureBot. Allowed values are: global(default), westeurope. 37 | - **botEndpoint**: Use to handle client messages, Such as `https://.azurewebsites.net/api/messages`. 38 | 39 | - **appType**: Type of Bot Authentication. set as MicrosoftAppType in the Web App's Application Settings. Allowed values are: MultiTenant(default), SingleTenant, UserAssignedMSI. 40 | - **appId**: (required) Active Directory App ID or User-Assigned Managed Identity Client ID, set as MicrosoftAppId in the Web App's Application Settings. 41 | - **UMSIName**: (required for UserAssignedMSI) The User-Assigned Managed Identity Resource used for the Bot's Authentication. 42 | - **UMSIResourceGroupName**: (required for UserAssignedMSI) The User-Assigned Managed Identity Resource Group used for the Bot's Authentication. 43 | - **tenantId**: The Azure AD Tenant ID to use as part of the Bot's Authentication. Only used for SingleTenant and UserAssignedMSI app types. Defaults to Subscription Tenant ID. 44 | 45 | More info: https://docs.microsoft.com/en-us/azure/bot-service/tutorial-provision-a-bot?view=azure-bot-service-4.0&tabs=userassigned%2Cnewgroup#create-an-identity-resource -------------------------------------------------------------------------------- /deploymentTemplates/deployWithNewResourceGroup/template-AzureBot-new-rg.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "groupName": { 6 | "type": "string", 7 | "metadata": { 8 | "description": "Specifies the name of the Resource Group." 9 | } 10 | }, 11 | "groupLocation": { 12 | "type": "string", 13 | "metadata": { 14 | "description": "Specifies the location of the Resource Group." 15 | } 16 | }, 17 | "azureBotId": { 18 | "type": "string", 19 | "metadata": { 20 | "description": "The globally unique and immutable bot ID." 21 | } 22 | }, 23 | "azureBotSku": { 24 | "type": "string", 25 | "defaultValue": "S1", 26 | "metadata": { 27 | "description": "The pricing tier of the Bot Service Registration. Acceptable values are F0 and S1." 28 | } 29 | }, 30 | "azureBotRegion": { 31 | "type": "string", 32 | "defaultValue": "global", 33 | "metadata": { 34 | "description": "" 35 | } 36 | }, 37 | "botEndpoint": { 38 | "type": "string", 39 | "defaultValue": "", 40 | "metadata": { 41 | "description": "Use to handle client messages, Such as https://.azurewebsites.net/api/messages." 42 | } 43 | }, 44 | "appType": { 45 | "type": "string", 46 | "defaultValue": "MultiTenant", 47 | "allowedValues": [ 48 | "MultiTenant", 49 | "SingleTenant", 50 | "UserAssignedMSI" 51 | ], 52 | "metadata": { 53 | "description": "Type of Bot Authentication. set as MicrosoftAppType in the Web App's Application Settings. Allowed values are: MultiTenant, SingleTenant, UserAssignedMSI. Defaults to \"MultiTenant\"." 54 | } 55 | }, 56 | "appId": { 57 | "type": "string", 58 | "metadata": { 59 | "description": "Active Directory App ID or User-Assigned Managed Identity Client ID, set as MicrosoftAppId in the Web App's Application Settings." 60 | } 61 | }, 62 | "tenantId": { 63 | "type": "string", 64 | "defaultValue": "[subscription().tenantId]", 65 | "metadata": { 66 | "description": "The Azure AD Tenant ID to use as part of the Bot's Authentication. Only used for SingleTenant and UserAssignedMSI app types. Defaults to \"Subscription Tenant ID\"." 67 | } 68 | }, 69 | "UMSIName": { 70 | "type": "string", 71 | "defaultValue": "", 72 | "metadata": { 73 | "description": "The User-Assigned Managed Identity Resource used for the Bot's Authentication." 74 | } 75 | }, 76 | "UMSIResourceGroupName": { 77 | "type": "string", 78 | "defaultValue": "", 79 | "metadata": { 80 | "description": "The User-Assigned Managed Identity Resource Group used for the Bot's Authentication." 81 | } 82 | } 83 | }, 84 | "variables": { 85 | "botEndpoint": "[if(empty(parameters('botEndpoint')), concat('https://', parameters('azureBotId'), '.azurewebsites.net/api/messages'), parameters('botEndpoint'))]", 86 | "tenantId": "[if(empty(parameters('tenantId')), subscription().tenantId, parameters('tenantId'))]", 87 | "msiResourceId": "[if(empty(parameters('UMSIName')), '', concat(subscription().id, '/resourceGroups/', parameters('UMSIResourceGroupName'), '/providers/', 'Microsoft.ManagedIdentity/userAssignedIdentities/', parameters('UMSIName')))]", 88 | "appTypeDef": { 89 | "MultiTenant": { 90 | "tenantId": "", 91 | "msiResourceId": "" 92 | }, 93 | "SingleTenant": { 94 | "tenantId": "[variables('tenantId')]", 95 | "msiResourceId": "" 96 | }, 97 | "UserAssignedMSI": { 98 | "tenantId": "[variables('tenantId')]", 99 | "msiResourceId": "[variables('msiResourceId')]" 100 | } 101 | }, 102 | "appType": { 103 | "tenantId": "[variables('appTypeDef')[parameters('appType')].tenantId]", 104 | "msiResourceId": "[variables('appTypeDef')[parameters('appType')].msiResourceId]" 105 | } 106 | }, 107 | "resources": [ 108 | { 109 | "name": "[parameters('groupName')]", 110 | "type": "Microsoft.Resources/resourceGroups", 111 | "apiVersion": "2018-05-01", 112 | "location": "[parameters('groupLocation')]", 113 | "properties": {} 114 | }, 115 | { 116 | "type": "Microsoft.Resources/deployments", 117 | "apiVersion": "2018-05-01", 118 | "name": "storageDeployment", 119 | "resourceGroup": "[parameters('groupName')]", 120 | "dependsOn": [ 121 | "[resourceId('Microsoft.Resources/resourceGroups/', parameters('groupName'))]" 122 | ], 123 | "properties": { 124 | "mode": "Incremental", 125 | "template": { 126 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 127 | "contentVersion": "1.0.0.0", 128 | "parameters": {}, 129 | "variables": {}, 130 | "resources": [ 131 | { 132 | "apiVersion": "2021-03-01", 133 | "type": "Microsoft.BotService/botServices", 134 | "name": "[parameters('azureBotId')]", 135 | "location": "[parameters('azureBotRegion')]", 136 | "kind": "azurebot", 137 | "sku": { 138 | "name": "[parameters('azureBotSku')]" 139 | }, 140 | "properties": { 141 | "name": "[parameters('azureBotId')]", 142 | "displayName": "[parameters('azureBotId')]", 143 | "iconUrl": "https://docs.botframework.com/static/devportal/client/images/bot-framework-default.png", 144 | "endpoint": "[variables('botEndpoint')]", 145 | "msaAppId": "[parameters('appId')]", 146 | "msaAppTenantId": "[variables('appType').tenantId]", 147 | "msaAppMSIResourceId": "[variables('appType').msiResourceId]", 148 | "msaAppType": "[parameters('appType')]", 149 | "luisAppIds": [], 150 | "schemaTransformationVersion": "1.3", 151 | "isCmekEnabled": false, 152 | "isIsolated": false 153 | } 154 | } 155 | ] 156 | } 157 | } 158 | } 159 | ] 160 | } -------------------------------------------------------------------------------- /deploymentTemplates/deployWithNewResourceGroup/template-BotApp-new-rg.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "groupName": { 6 | "type": "string", 7 | "metadata": { 8 | "description": "Specifies the name of the Resource Group." 9 | } 10 | }, 11 | "groupLocation": { 12 | "type": "string", 13 | "metadata": { 14 | "description": "Specifies the location of the Resource Group." 15 | } 16 | }, 17 | "appServiceName": { 18 | "type": "string", 19 | "metadata": { 20 | "description": "The globally unique name of the Web App." 21 | } 22 | }, 23 | "appServicePlanName": { 24 | "type": "string", 25 | "metadata": { 26 | "description": "The name of the App Service Plan." 27 | } 28 | }, 29 | "appServicePlanLocation": { 30 | "type": "string", 31 | "metadata": { 32 | "description": "The location of the App Service Plan." 33 | } 34 | }, 35 | "appServicePlanSku": { 36 | "type": "object", 37 | "defaultValue": { 38 | "name": "S1", 39 | "tier": "Standard", 40 | "size": "S1", 41 | "family": "S", 42 | "capacity": 1 43 | }, 44 | "metadata": { 45 | "description": "The SKU of the App Service Plan. Defaults to Standard values." 46 | } 47 | }, 48 | "tenantId": { 49 | "type": "string", 50 | "defaultValue": "[subscription().tenantId]", 51 | "metadata": { 52 | "description": "The Azure AD Tenant ID to use as part of the Bot's Authentication. Only used for SingleTenant and UserAssignedMSI app types. Defaults to \"Subscription Tenant ID\"." 53 | } 54 | }, 55 | "appType": { 56 | "type": "string", 57 | "defaultValue": "MultiTenant", 58 | "allowedValues": [ 59 | "MultiTenant", 60 | "SingleTenant", 61 | "UserAssignedMSI" 62 | ], 63 | "metadata": { 64 | "description": "Type of Bot Authentication. set as MicrosoftAppType in the Web App's Application Settings. Allowed values are: MultiTenant, SingleTenant, UserAssignedMSI. Defaults to \"MultiTenant\"." 65 | } 66 | }, 67 | "appId": { 68 | "type": "string", 69 | "metadata": { 70 | "description": "Active Directory App ID or User-Assigned Managed Identity Client ID, set as MicrosoftAppId in the Web App's Application Settings." 71 | } 72 | }, 73 | "appSecret": { 74 | "type": "string", 75 | "metadata": { 76 | "description": "Active Directory App Password, set as MicrosoftAppPassword in the Web App's Application Settings. Required for MultiTenant and SingleTenant app types." 77 | } 78 | }, 79 | "UMSIName": { 80 | "type": "string", 81 | "defaultValue": "", 82 | "metadata": { 83 | "description": "The User-Assigned Managed Identity Resource used for the Bot's Authentication." 84 | } 85 | }, 86 | "UMSIResourceGroupName": { 87 | "type": "string", 88 | "defaultValue": "", 89 | "metadata": { 90 | "description": "The User-Assigned Managed Identity Resource Group used for the Bot's Authentication." 91 | } 92 | } 93 | }, 94 | "variables": { 95 | "tenantId": "[if(empty(parameters('tenantId')), subscription().tenantId, parameters('tenantId'))]", 96 | "appServicePlanName": "[parameters('appServicePlanName')]", 97 | "resourcesLocation": "[if(empty(parameters('appServicePlanLocation')), parameters('groupLocation'), parameters('appServicePlanLocation'))]", 98 | "appServiceName": "[parameters('appServiceName')]", 99 | "resourceGroupId": "[concat(subscription().id, '/resourceGroups/', parameters('groupName'))]", 100 | "msiResourceId": "[if(empty(parameters('UMSIName')), '', concat(subscription().id, '/resourceGroups/', parameters('UMSIResourceGroupName'), '/providers/', 'Microsoft.ManagedIdentity/userAssignedIdentities/', parameters('UMSIName')))]", 101 | "appTypeDef": { 102 | "MultiTenant": { 103 | "tenantId": "", 104 | "identity": { "type": "None" } 105 | }, 106 | "SingleTenant": { 107 | "tenantId": "[variables('tenantId')]", 108 | "identity": { "type": "None" } 109 | }, 110 | "UserAssignedMSI": { 111 | "tenantId": "[variables('tenantId')]", 112 | "identity": { 113 | "type": "UserAssigned", 114 | "userAssignedIdentities": { 115 | "[variables('msiResourceId')]": {} 116 | } 117 | } 118 | } 119 | }, 120 | "appType": { 121 | "tenantId": "[variables('appTypeDef')[parameters('appType')].tenantId]", 122 | "identity": "[variables('appTypeDef')[parameters('appType')].identity]" 123 | } 124 | }, 125 | "resources": [ 126 | { 127 | "name": "[parameters('groupName')]", 128 | "type": "Microsoft.Resources/resourceGroups", 129 | "apiVersion": "2018-05-01", 130 | "location": "[parameters('groupLocation')]", 131 | "properties": {} 132 | }, 133 | { 134 | "type": "Microsoft.Resources/deployments", 135 | "apiVersion": "2018-05-01", 136 | "name": "storageDeployment", 137 | "resourceGroup": "[parameters('groupName')]", 138 | "dependsOn": [ 139 | "[resourceId('Microsoft.Resources/resourceGroups/', parameters('groupName'))]" 140 | ], 141 | "properties": { 142 | "mode": "Incremental", 143 | "template": { 144 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 145 | "contentVersion": "1.0.0.0", 146 | "parameters": {}, 147 | "variables": {}, 148 | "resources": [ 149 | { 150 | "comments": "Create a new App Service Plan", 151 | "type": "Microsoft.Web/serverfarms", 152 | "name": "[variables('appServicePlanName')]", 153 | "apiVersion": "2018-02-01", 154 | "location": "[variables('resourcesLocation')]", 155 | "sku": "[parameters('appServicePlanSku')]", 156 | "properties": { 157 | "name": "[variables('appServicePlanName')]" 158 | } 159 | }, 160 | { 161 | "comments": "Create a Web App using the new App Service Plan", 162 | "type": "Microsoft.Web/sites", 163 | "apiVersion": "2015-08-01", 164 | "location": "[variables('resourcesLocation')]", 165 | "kind": "app", 166 | "dependsOn": [ 167 | "[concat(variables('resourceGroupId'), '/providers/Microsoft.Web/serverfarms/', variables('appServicePlanName'))]" 168 | ], 169 | "name": "[variables('appServiceName')]", 170 | "identity": "[variables('appType').identity]", 171 | "properties": { 172 | "name": "[variables('appServiceName')]", 173 | "serverFarmId": "[variables('appServicePlanName')]", 174 | "siteConfig": { 175 | "appSettings": [ 176 | { 177 | "name": "WEBSITE_NODE_DEFAULT_VERSION", 178 | "value": "10.14.1" 179 | }, 180 | { 181 | "name": "MicrosoftAppType", 182 | "value": "[parameters('appType')]" 183 | }, 184 | { 185 | "name": "MicrosoftAppId", 186 | "value": "[parameters('appId')]" 187 | }, 188 | { 189 | "name": "MicrosoftAppPassword", 190 | "value": "[parameters('appSecret')]" 191 | }, 192 | { 193 | "name": "MicrosoftAppTenantId", 194 | "value": "[variables('appType').tenantId]" 195 | } 196 | ], 197 | "cors": { 198 | "allowedOrigins": [ 199 | "https://botservice.hosting.portal.azure.net", 200 | "https://hosting.onecloud.azure-test.net/" 201 | ] 202 | }, 203 | "webSocketsEnabled": true 204 | } 205 | } 206 | } 207 | ], 208 | "outputs": {} 209 | } 210 | } 211 | } 212 | ] 213 | } -------------------------------------------------------------------------------- /deploymentTemplates/linux/deployUseExistResourceGroup/parameters-for-template-AzureBot-with-rg.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "azureBotId": { 6 | "value": "" 7 | }, 8 | "azureBotSku": { 9 | "value": "S1" 10 | }, 11 | "azureBotRegion": { 12 | "value": "global" 13 | }, 14 | "botEndpoint": { 15 | "value": "" 16 | }, 17 | "appId": { 18 | "value": "" 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /deploymentTemplates/linux/deployUseExistResourceGroup/parameters-for-template-BotApp-with-rg.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "appServiceName": { 6 | "value": "" 7 | }, 8 | "existingAppServicePlanName": { 9 | "value": "" 10 | }, 11 | "existingAppServicePlanLocation": { 12 | "value": "" 13 | }, 14 | "newAppServicePlanName": { 15 | "value": "" 16 | }, 17 | "newAppServicePlanLocation": { 18 | "value": "West US" 19 | }, 20 | "newAppServicePlanSku": { 21 | "value": { 22 | "name": "S1", 23 | "tier": "Standard", 24 | "size": "S1", 25 | "family": "S", 26 | "capacity": 1 27 | } 28 | }, 29 | "linuxFxVersion": { 30 | "value": "" 31 | }, 32 | "appId": { 33 | "value": "" 34 | }, 35 | "appSecret": { 36 | "value": "" 37 | }, 38 | "appType": { 39 | "value": "" 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /deploymentTemplates/linux/deployUseExistResourceGroup/readme.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | BotApp must be deployed prior to AzureBot. 3 | 4 | ### Command line: 5 | `az login`
6 | `az deployment group create --resource-group --template-file --parameters @` 7 | 8 | ## Parameters for template-BotApp-with-rg.json: 9 | 10 | - **appServiceName**: (required) The Name of the Bot App Service. 11 | - (Pick an existing App Service Plan or create a new App Service Plan.) 12 | - **existingAppServicePlanName**: The name of the App Service Plan. 13 | - **existingAppServicePlanLocation**: The location of the App Service Plan. 14 | - **newAppServicePlanName**: The name of the App Service Plan. 15 | - **newAppServicePlanLocation**: The location of the App Service Plan. 16 | - **newAppServicePlanSku**: The SKU of the App Service Plan. Defaults to Standard values. 17 | - **appId**: (required) Active Directory App ID or User-Assigned Managed Identity Client ID, set as MicrosoftAppId in the Web App's Application Settings. 18 | - **appSecret**: (required) Active Directory App Password, set as MicrosoftAppPassword in the Web App's Application Settings. 19 | 20 | ## Parameters for template-AzureBot-with-rg.json: 21 | 22 | - **azureBotId**: (required) The globally unique and immutable bot ID. 23 | - **azureBotSku**: The pricing tier of the Bot Service Registration. Allowed values are: F0, S1(default). 24 | - **azureBotRegion**: Specifies the location of the new AzureBot. Allowed values are: global(default), westeurope. 25 | - **botEndpoint**: Use to handle client messages, Such as `https://.azurewebsites.net/api/messages`. 26 | - **appId**: (required) Active Directory App ID or User-Assigned Managed Identity Client ID, set as MicrosoftAppId in the Web App's Application Settings. -------------------------------------------------------------------------------- /deploymentTemplates/linux/deployUseExistResourceGroup/template-AzureBot-with-rg.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "azureBotId": { 6 | "type": "string", 7 | "metadata": { 8 | "description": "The globally unique and immutable bot ID." 9 | } 10 | }, 11 | "azureBotSku": { 12 | "type": "string", 13 | "defaultValue": "S1", 14 | "metadata": { 15 | "description": "The pricing tier of the Bot Service Registration. Allowed values are: F0, S1(default)." 16 | } 17 | }, 18 | "azureBotRegion": { 19 | "type": "string", 20 | "defaultValue": "global", 21 | "metadata": { 22 | "description": "Specifies the location of the new AzureBot. Allowed values are: global(default), westeurope." 23 | } 24 | }, 25 | "botEndpoint": { 26 | "type": "string", 27 | "defaultValue": "", 28 | "metadata": { 29 | "description": "Use to handle client messages, Such as https://.azurewebsites.net/api/messages." 30 | } 31 | }, 32 | "appId": { 33 | "type": "string", 34 | "metadata": { 35 | "description": "Active Directory App ID or User-Assigned Managed Identity Client ID, set as MicrosoftAppId in the Web App's Application Settings." 36 | } 37 | } 38 | }, 39 | "variables": { 40 | "botEndpoint": "[if(empty(parameters('botEndpoint')), concat('https://', parameters('azureBotId'), '.azurewebsites.net/api/messages'), parameters('botEndpoint'))]" 41 | }, 42 | "resources": [ 43 | { 44 | "apiVersion": "2021-05-01-preview", 45 | "type": "Microsoft.BotService/botServices", 46 | "name": "[parameters('azureBotId')]", 47 | "location": "[parameters('azureBotRegion')]", 48 | "kind": "azurebot", 49 | "sku": { 50 | "name": "[parameters('azureBotSku')]" 51 | }, 52 | "properties": { 53 | "name": "[parameters('azureBotId')]", 54 | "displayName": "[parameters('azureBotId')]", 55 | "iconUrl": "https://docs.botframework.com/static/devportal/client/images/bot-framework-default.png", 56 | "endpoint": "[variables('botEndpoint')]", 57 | "msaAppId": "[parameters('appId')]", 58 | "luisAppIds": [], 59 | "schemaTransformationVersion": "1.3", 60 | "isCmekEnabled": false, 61 | "isIsolated": false 62 | } 63 | } 64 | ] 65 | } -------------------------------------------------------------------------------- /deploymentTemplates/linux/deployUseExistResourceGroup/template-BotApp-with-rg.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "appServiceName": { 6 | "type": "string", 7 | "metadata": { 8 | "description": "The globally unique name of the Web App." 9 | } 10 | }, 11 | "existingAppServicePlanName": { 12 | "type": "string", 13 | "defaultValue": "", 14 | "metadata": { 15 | "description": "Name of the existing App Service Plan used to create the Web App for the bot." 16 | } 17 | }, 18 | "existingAppServicePlanLocation": { 19 | "type": "string", 20 | "defaultValue": "", 21 | "metadata": { 22 | "description": "The location of the App Service Plan." 23 | } 24 | }, 25 | "newAppServicePlanName": { 26 | "type": "string", 27 | "defaultValue": "", 28 | "metadata": { 29 | "description": "The name of the new App Service Plan." 30 | } 31 | }, 32 | "newAppServicePlanLocation": { 33 | "type": "string", 34 | "defaultValue": "", 35 | "metadata": { 36 | "description": "The location of the App Service Plan." 37 | } 38 | }, 39 | "newAppServicePlanSku": { 40 | "type": "object", 41 | "defaultValue": { 42 | "name": "S1", 43 | "tier": "Standard", 44 | "size": "S1", 45 | "family": "S", 46 | "capacity": 1 47 | }, 48 | "metadata": { 49 | "description": "The SKU of the App Service Plan. Defaults to Standard values." 50 | } 51 | }, 52 | "linuxFxVersion": { 53 | "type": "string", 54 | "defaultValue": "NODE|10.14" 55 | }, 56 | "appId": { 57 | "type": "string", 58 | "metadata": { 59 | "description": "Active Directory App ID or User-Assigned Managed Identity Client ID, set as MicrosoftAppId in the Web App's Application Settings." 60 | } 61 | }, 62 | "appSecret": { 63 | "type": "string", 64 | "defaultValue": "", 65 | "metadata": { 66 | "description": "Active Directory App Password, set as MicrosoftAppPassword in the Web App's Application Settings. Required for MultiTenant and SingleTenant app types. Defaults to \"\"." 67 | } 68 | }, 69 | "appType": { 70 | "defaultValue": "MultiTenant", 71 | "type": "string", 72 | "allowedValues": [ 73 | "MultiTenant", 74 | "SingleTenant", 75 | "UserAssignedMSI" 76 | ] 77 | } 78 | }, 79 | "variables": { 80 | "useExistingServicePlan": "[not(empty(parameters('existingAppServicePlanName')))]", 81 | "servicePlanName": "[if(variables('useExistingServicePlan'), parameters('existingAppServicePlanName'), parameters('newAppServicePlanName'))]", 82 | "servicePlanLocation": "[if(variables('useExistingServicePlan'), parameters('existingAppServicePlanLocation'), parameters('newAppServicePlanLocation'))]" 83 | }, 84 | "resources": [ 85 | { 86 | "comments": "Create a new App Service Plan if no existing App Service Plan name was passed in.", 87 | "type": "Microsoft.Web/serverfarms", 88 | "condition": "[not(variables('useExistingServicePlan'))]", 89 | "name": "[variables('servicePlanName')]", 90 | "apiVersion": "2018-02-01", 91 | "location": "[parameters('newAppServicePlanLocation')]", 92 | "sku": "[parameters('newAppServicePlanSku')]", 93 | "kind": "linux", 94 | "properties": { 95 | "name": "[variables('servicePlanName')]", 96 | "perSiteScaling": false, 97 | "reserved": true, 98 | "targetWorkerCount": 0, 99 | "targetWorkerSizeId": 0 100 | } 101 | }, 102 | { 103 | "comments": "Create a Web App using an App Service Plan", 104 | "type": "Microsoft.Web/sites", 105 | "apiVersion": "2015-08-01", 106 | "name": "[parameters('appServiceName')]", 107 | "location": "[variables('servicePlanLocation')]", 108 | "kind": "app,linux", 109 | "dependsOn": [ 110 | "[resourceId('Microsoft.Web/serverfarms', variables('servicePlanName'))]" 111 | ], 112 | "properties": { 113 | "enabled": true, 114 | "hostNameSslStates": [ 115 | { 116 | "name": "[concat(parameters('appServiceName'), '.azurewebsites.net')]", 117 | "sslState": "Disabled", 118 | "hostType": "Standard" 119 | }, 120 | { 121 | "name": "[concat(parameters('appServiceName'), '.scm.azurewebsites.net')]", 122 | "sslState": "Disabled", 123 | "hostType": "Repository" 124 | } 125 | ], 126 | "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('servicePlanName'))]", 127 | "reserved": true, 128 | "scmSiteAlsoStopped": false, 129 | "clientAffinityEnabled": false, 130 | "clientCertEnabled": false, 131 | "hostNamesDisabled": false, 132 | "containerSize": 0, 133 | "dailyMemoryTimeQuota": 0, 134 | "httpsOnly": false, 135 | "siteConfig": { 136 | "linuxFxVersion": "[parameters('linuxFxVersion')]", 137 | "appSettings": [ 138 | { 139 | "name": "WEBSITE_NODE_DEFAULT_VERSION", 140 | "value": "10.14.1" 141 | }, 142 | { 143 | "name": "MicrosoftAppType", 144 | "value": "[parameters('appType')]" 145 | }, 146 | { 147 | "name": "MicrosoftAppId", 148 | "value": "[parameters('appId')]" 149 | }, 150 | { 151 | "name": "MicrosoftAppPassword", 152 | "value": "[parameters('appSecret')]" 153 | } 154 | ] 155 | } 156 | } 157 | }, 158 | { 159 | "type": "Microsoft.Web/sites/config", 160 | "apiVersion": "2016-08-01", 161 | "name": "[concat(parameters('appServiceName'), '/web')]", 162 | "location": "[variables('servicePlanLocation')]", 163 | "dependsOn": [ 164 | "[resourceId('Microsoft.Web/sites', parameters('appServiceName'))]" 165 | ], 166 | "properties": { 167 | "numberOfWorkers": 1, 168 | "defaultDocuments": [ 169 | "Default.htm", 170 | "Default.html", 171 | "Default.asp", 172 | "index.htm", 173 | "index.html", 174 | "iisstart.htm", 175 | "default.aspx", 176 | "index.php", 177 | "hostingstart.html" 178 | ], 179 | "netFrameworkVersion": "v4.0", 180 | "phpVersion": "", 181 | "pythonVersion": "", 182 | "nodeVersion": "", 183 | "linuxFxVersion": "[parameters('linuxFxVersion')]", 184 | "requestTracingEnabled": false, 185 | "remoteDebuggingEnabled": false, 186 | "httpLoggingEnabled": false, 187 | "logsDirectorySizeLimit": 35, 188 | "detailedErrorLoggingEnabled": false, 189 | "publishingUsername": "[concat('$', parameters('appServiceName'))]", 190 | "scmType": "LocalGit", 191 | "use32BitWorkerProcess": true, 192 | "webSocketsEnabled": false, 193 | "alwaysOn": true, 194 | "appCommandLine": "", 195 | "managedPipelineMode": "Integrated", 196 | "virtualApplications": [ 197 | { 198 | "virtualPath": "/", 199 | "physicalPath": "site\\wwwroot", 200 | "preloadEnabled": true, 201 | "virtualDirectories": null 202 | } 203 | ], 204 | "winAuthAdminState": 0, 205 | "winAuthTenantState": 0, 206 | "customAppPoolIdentityAdminState": false, 207 | "customAppPoolIdentityTenantState": false, 208 | "loadBalancing": "LeastRequests", 209 | "routingRules": [], 210 | "experiments": { 211 | "rampUpRules": [] 212 | }, 213 | "autoHealEnabled": false, 214 | "vnetName": "", 215 | "minTlsVersion": "1.2", 216 | "ftpsState": "AllAllowed", 217 | "reservedInstanceCount": 0 218 | } 219 | } 220 | ] 221 | } -------------------------------------------------------------------------------- /deploymentTemplates/linux/deployWithNewResourceGroup/parameters-for-template-AzureBot-new-rg.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "groupName": { 6 | "value": "" 7 | }, 8 | "groupLocation": { 9 | "value": "" 10 | }, 11 | "azureBotId": { 12 | "value": "" 13 | }, 14 | "azureBotSku": { 15 | "value": "S1" 16 | }, 17 | "azureBotRegion": { 18 | "value": "global" 19 | }, 20 | "botEndpoint": { 21 | "value": "" 22 | }, 23 | "appId": { 24 | "value": "" 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /deploymentTemplates/linux/deployWithNewResourceGroup/parameters-for-template-BotApp-new-rg.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "groupName": { 6 | "value": "" 7 | }, 8 | "groupLocation": { 9 | "value": "" 10 | }, 11 | "appServiceName": { 12 | "value": "" 13 | }, 14 | "appServicePlanName": { 15 | "value": "" 16 | }, 17 | "appServicePlanLocation": { 18 | "value": "" 19 | }, 20 | "appServicePlanSku": { 21 | "value": { 22 | "name": "S1", 23 | "tier": "Standard", 24 | "size": "S1", 25 | "family": "S", 26 | "capacity": 1 27 | } 28 | }, 29 | "linuxFxVersion": { 30 | "value": "" 31 | }, 32 | "appId": { 33 | "value": "" 34 | }, 35 | "appSecret": { 36 | "value": "" 37 | }, 38 | "appType": { 39 | "value": "" 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /deploymentTemplates/linux/deployWithNewResourceGroup/readme.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | BotApp must be deployed prior to AzureBot. 3 | 4 | ### Command line: 5 | `az login`
6 | `az deployment sub create --template-file --location --parameters @` 7 | 8 | ## Parameters for template-BotApp-new-rg.json: 9 | 10 | - **groupName**: (required) The name of the new Resource Group. 11 | - **groupLocation**: (required) The location of the new Resource Group. 12 | - **appServiceName**: (required) The location of the App Service Plan. 13 | - **appServicePlanName**: (required) The name of the App Service Plan. 14 | - **appServicePlanLocation**: The location of the App Service Plan. Defaults to use groupLocation. 15 | - **appServicePlanSku**: The SKU of the App Service Plan. Defaults to Standard values. 16 | - **appId**: (required) Active Directory App ID or User-Assigned Managed Identity Client ID, set as MicrosoftAppId in the Web App's Application Settings. 17 | - **appSecret**: (required for MultiTenant and SingleTenant) Active Directory App Password, set as MicrosoftAppPassword in the Web App's Application Settings. 18 | 19 | ## Parameters for template-AzureBot-new-rg.json: 20 | 21 | - **groupName**: (required) The name of the new Resource Group. 22 | - **groupLocation**: (required) The location of the new Resource Group. 23 | - **azureBotId**: (required) The globally unique and immutable bot ID. Also used to configure the displayName of the bot, which is mutable. 24 | - **azureBotSku**: The pricing tier of the Bot Service Registration. Allowed values are: F0, S1(default). 25 | - **azureBotRegion**: Specifies the location of the new AzureBot. Allowed values are: global(default), westeurope. 26 | - **botEndpoint**: Use to handle client messages, Such as `https://.azurewebsites.net/api/messages`. 27 | - **appId**: (required) Active Directory App ID or User-Assigned Managed Identity Client ID, set as MicrosoftAppId in the Web App's Application Settings. -------------------------------------------------------------------------------- /deploymentTemplates/linux/deployWithNewResourceGroup/template-AzureBot-new-rg.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "groupName": { 6 | "type": "string", 7 | "metadata": { 8 | "description": "Specifies the name of the Resource Group." 9 | } 10 | }, 11 | "groupLocation": { 12 | "type": "string", 13 | "metadata": { 14 | "description": "Specifies the location of the Resource Group." 15 | } 16 | }, 17 | "azureBotId": { 18 | "type": "string", 19 | "metadata": { 20 | "description": "The globally unique and immutable bot ID." 21 | } 22 | }, 23 | "azureBotSku": { 24 | "type": "string", 25 | "defaultValue": "S1", 26 | "metadata": { 27 | "description": "The pricing tier of the Bot Service Registration. Acceptable values are F0 and S1." 28 | } 29 | }, 30 | "azureBotRegion": { 31 | "type": "string", 32 | "defaultValue": "global", 33 | "metadata": { 34 | "description": "" 35 | } 36 | }, 37 | "botEndpoint": { 38 | "type": "string", 39 | "defaultValue": "", 40 | "metadata": { 41 | "description": "Use to handle client messages, Such as https://.azurewebsites.net/api/messages." 42 | } 43 | }, 44 | "appId": { 45 | "type": "string", 46 | "metadata": { 47 | "description": "Active Directory App ID or User-Assigned Managed Identity Client ID, set as MicrosoftAppId in the Web App's Application Settings." 48 | } 49 | } 50 | }, 51 | "variables": { 52 | "botEndpoint": "[if(empty(parameters('botEndpoint')), concat('https://', parameters('azureBotId'), '.azurewebsites.net/api/messages'), parameters('botEndpoint'))]" 53 | }, 54 | "resources": [ 55 | { 56 | "name": "[parameters('groupName')]", 57 | "type": "Microsoft.Resources/resourceGroups", 58 | "apiVersion": "2018-05-01", 59 | "location": "[parameters('groupLocation')]", 60 | "properties": {} 61 | }, 62 | { 63 | "type": "Microsoft.Resources/deployments", 64 | "apiVersion": "2018-05-01", 65 | "name": "storageDeployment", 66 | "resourceGroup": "[parameters('groupName')]", 67 | "dependsOn": [ 68 | "[resourceId('Microsoft.Resources/resourceGroups/', parameters('groupName'))]" 69 | ], 70 | "properties": { 71 | "mode": "Incremental", 72 | "template": { 73 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 74 | "contentVersion": "1.0.0.0", 75 | "parameters": {}, 76 | "variables": {}, 77 | "resources": [ 78 | { 79 | "apiVersion": "2021-03-01", 80 | "type": "Microsoft.BotService/botServices", 81 | "name": "[parameters('azureBotId')]", 82 | "location": "[parameters('azureBotRegion')]", 83 | "kind": "azurebot", 84 | "sku": { 85 | "name": "[parameters('azureBotSku')]" 86 | }, 87 | "properties": { 88 | "name": "[parameters('azureBotId')]", 89 | "displayName": "[parameters('azureBotId')]", 90 | "iconUrl": "https://docs.botframework.com/static/devportal/client/images/bot-framework-default.png", 91 | "endpoint": "[variables('botEndpoint')]", 92 | "msaAppId": "[parameters('appId')]", 93 | "luisAppIds": [], 94 | "schemaTransformationVersion": "1.3", 95 | "isCmekEnabled": false, 96 | "isIsolated": false 97 | } 98 | } 99 | ] 100 | } 101 | } 102 | } 103 | ] 104 | } -------------------------------------------------------------------------------- /deploymentTemplates/linux/deployWithNewResourceGroup/template-BotApp-new-rg.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "groupName": { 6 | "type": "string", 7 | "metadata": { 8 | "description": "Specifies the name of the Resource Group." 9 | } 10 | }, 11 | "groupLocation": { 12 | "type": "string", 13 | "metadata": { 14 | "description": "Specifies the location of the Resource Group." 15 | } 16 | }, 17 | "appServiceName": { 18 | "type": "string", 19 | "metadata": { 20 | "description": "The globally unique name of the Web App." 21 | } 22 | }, 23 | "appServicePlanName": { 24 | "type": "string", 25 | "metadata": { 26 | "description": "The name of the App Service Plan." 27 | } 28 | }, 29 | "appServicePlanLocation": { 30 | "type": "string", 31 | "defaultValue": "", 32 | "metadata": { 33 | "description": "The location of the App Service Plan." 34 | } 35 | }, 36 | "appServicePlanSku": { 37 | "type": "object", 38 | "defaultValue": { 39 | "name": "S1", 40 | "tier": "Standard", 41 | "size": "S1", 42 | "family": "S", 43 | "capacity": 1 44 | }, 45 | "metadata": { 46 | "description": "The SKU of the App Service Plan. Defaults to Standard values." 47 | } 48 | }, 49 | "linuxFxVersion": { 50 | "type": "string", 51 | "defaultValue": "NODE|10.14" 52 | }, 53 | "appId": { 54 | "type": "string", 55 | "metadata": { 56 | "description": "Active Directory App ID or User-Assigned Managed Identity Client ID, set as MicrosoftAppId in the Web App's Application Settings." 57 | } 58 | }, 59 | "appSecret": { 60 | "type": "string", 61 | "metadata": { 62 | "description": "Active Directory App Password, set as MicrosoftAppPassword in the Web App's Application Settings. Required for MultiTenant and SingleTenant app types." 63 | } 64 | }, 65 | "appType": { 66 | "defaultValue": "MultiTenant", 67 | "type": "string", 68 | "allowedValues": [ 69 | "MultiTenant", 70 | "SingleTenant", 71 | "UserAssignedMSI" 72 | ] 73 | } 74 | }, 75 | "variables": { 76 | "appServicePlanName": "[parameters('appServicePlanName')]", 77 | "resourcesLocation": "[if(empty(parameters('appServicePlanLocation')), parameters('groupLocation'), parameters('appServicePlanLocation'))]", 78 | "appServiceName": "[parameters('appServiceName')]", 79 | "resourceGroupId": "[concat(subscription().id, '/resourceGroups/', parameters('groupName'))]" 80 | }, 81 | "resources": [ 82 | { 83 | "name": "[parameters('groupName')]", 84 | "type": "Microsoft.Resources/resourceGroups", 85 | "apiVersion": "2018-05-01", 86 | "location": "[parameters('groupLocation')]", 87 | "properties": {} 88 | }, 89 | { 90 | "type": "Microsoft.Resources/deployments", 91 | "apiVersion": "2018-05-01", 92 | "name": "storageDeployment", 93 | "resourceGroup": "[parameters('groupName')]", 94 | "dependsOn": [ 95 | "[resourceId('Microsoft.Resources/resourceGroups/', parameters('groupName'))]" 96 | ], 97 | "properties": { 98 | "mode": "Incremental", 99 | "template": { 100 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 101 | "contentVersion": "1.0.0.0", 102 | "parameters": {}, 103 | "variables": {}, 104 | "resources": [ 105 | { 106 | "comments": "Create a new App Service Plan", 107 | "type": "Microsoft.Web/serverfarms", 108 | "name": "[variables('appServicePlanName')]", 109 | "apiVersion": "2018-02-01", 110 | "location": "[variables('resourcesLocation')]", 111 | "sku": "[parameters('appServicePlanSku')]", 112 | "kind": "linux", 113 | "properties": { 114 | "name": "[variables('appServicePlanName')]", 115 | "perSiteScaling": false, 116 | "reserved": true, 117 | "targetWorkerCount": 0, 118 | "targetWorkerSizeId": 0 119 | } 120 | }, 121 | { 122 | "comments": "Create a Web App using the new App Service Plan", 123 | "type": "Microsoft.Web/sites", 124 | "apiVersion": "2015-08-01", 125 | "name": "[parameters('appServiceName')]", 126 | "location": "[variables('resourcesLocation')]", 127 | "kind": "app,linux", 128 | "dependsOn": [ 129 | "[concat(variables('resourceGroupId'), '/providers/Microsoft.Web/serverfarms/', variables('appServicePlanName'))]" 130 | ], 131 | "properties": { 132 | "enabled": true, 133 | "hostNameSslStates": [ 134 | { 135 | "name": "[concat(parameters('appServiceName'), '.azurewebsites.net')]", 136 | "sslState": "Disabled", 137 | "hostType": "Standard" 138 | }, 139 | { 140 | "name": "[concat(parameters('appServiceName'), '.scm.azurewebsites.net')]", 141 | "sslState": "Disabled", 142 | "hostType": "Repository" 143 | } 144 | ], 145 | "serverFarmId": "[variables('appServicePlanName')]", 146 | "reserved": true, 147 | "scmSiteAlsoStopped": false, 148 | "clientAffinityEnabled": false, 149 | "clientCertEnabled": false, 150 | "hostNamesDisabled": false, 151 | "containerSize": 0, 152 | "dailyMemoryTimeQuota": 0, 153 | "httpsOnly": false, 154 | "siteConfig": { 155 | "linuxFxVersion": "[parameters('linuxFxVersion')]", 156 | "appSettings": [ 157 | { 158 | "name": "WEBSITE_NODE_DEFAULT_VERSION", 159 | "value": "10.14.1" 160 | }, 161 | { 162 | "name": "MicrosoftAppType", 163 | "value": "[parameters('appType')]" 164 | }, 165 | { 166 | "name": "MicrosoftAppId", 167 | "value": "[parameters('appId')]" 168 | }, 169 | { 170 | "name": "MicrosoftAppPassword", 171 | "value": "[parameters('appSecret')]" 172 | } 173 | ] 174 | } 175 | } 176 | }, 177 | { 178 | "type": "Microsoft.Web/sites/config", 179 | "apiVersion": "2016-08-01", 180 | "name": "[concat(parameters('appServiceName'), '/web')]", 181 | "location": "[variables('resourcesLocation')]", 182 | "dependsOn": [ 183 | "[concat(variables('resourceGroupId'), '/providers/Microsoft.Web/sites/', parameters('appServiceName'))]" 184 | ], 185 | "properties": { 186 | "numberOfWorkers": 1, 187 | "defaultDocuments": [ 188 | "Default.htm", 189 | "Default.html", 190 | "Default.asp", 191 | "index.htm", 192 | "index.html", 193 | "iisstart.htm", 194 | "default.aspx", 195 | "index.php", 196 | "hostingstart.html" 197 | ], 198 | "netFrameworkVersion": "v4.0", 199 | "phpVersion": "", 200 | "pythonVersion": "", 201 | "nodeVersion": "", 202 | "linuxFxVersion": "[parameters('linuxFxVersion')]", 203 | "requestTracingEnabled": false, 204 | "remoteDebuggingEnabled": false, 205 | "httpLoggingEnabled": true, 206 | "logsDirectorySizeLimit": 35, 207 | "detailedErrorLoggingEnabled": false, 208 | "publishingUsername": "[concat('$', parameters('appServiceName'))]", 209 | "scmType": "LocalGit", 210 | "use32BitWorkerProcess": true, 211 | "webSocketsEnabled": false, 212 | "alwaysOn": true, 213 | "appCommandLine": "", 214 | "managedPipelineMode": "Integrated", 215 | "virtualApplications": [ 216 | { 217 | "virtualPath": "/", 218 | "physicalPath": "site\\wwwroot", 219 | "preloadEnabled": true, 220 | "virtualDirectories": null 221 | } 222 | ], 223 | "winAuthAdminState": 0, 224 | "winAuthTenantState": 0, 225 | "customAppPoolIdentityAdminState": false, 226 | "customAppPoolIdentityTenantState": false, 227 | "loadBalancing": "LeastRequests", 228 | "routingRules": [], 229 | "experiments": { 230 | "rampUpRules": [] 231 | }, 232 | "autoHealEnabled": false, 233 | "vnetName": "", 234 | "minTlsVersion": "1.2", 235 | "ftpsState": "AllAllowed", 236 | "reservedInstanceCount": 0 237 | } 238 | } 239 | ] 240 | } 241 | } 242 | } 243 | ] 244 | } -------------------------------------------------------------------------------- /docs/img/arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michalmar/openai-demos-bot-webapp/8810470a7ec8adc6d4dba8bc5c2ba0151cef8038/docs/img/arch.png -------------------------------------------------------------------------------- /docs/img/bot-emu1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michalmar/openai-demos-bot-webapp/8810470a7ec8adc6d4dba8bc5c2ba0151cef8038/docs/img/bot-emu1.png -------------------------------------------------------------------------------- /docs/img/bot-service-test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michalmar/openai-demos-bot-webapp/8810470a7ec8adc6d4dba8bc5c2ba0151cef8038/docs/img/bot-service-test.png -------------------------------------------------------------------------------- /docs/img/bot-service.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michalmar/openai-demos-bot-webapp/8810470a7ec8adc6d4dba8bc5c2ba0151cef8038/docs/img/bot-service.png -------------------------------------------------------------------------------- /docs/img/direct-line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michalmar/openai-demos-bot-webapp/8810470a7ec8adc6d4dba8bc5c2ba0151cef8038/docs/img/direct-line.png -------------------------------------------------------------------------------- /docs/img/oai-playground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michalmar/openai-demos-bot-webapp/8810470a7ec8adc6d4dba8bc5c2ba0151cef8038/docs/img/oai-playground.png -------------------------------------------------------------------------------- /docs/img/vscode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michalmar/openai-demos-bot-webapp/8810470a7ec8adc6d4dba8bc5c2ba0151cef8038/docs/img/vscode.png -------------------------------------------------------------------------------- /docs/img/webapp-final-en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michalmar/openai-demos-bot-webapp/8810470a7ec8adc6d4dba8bc5c2ba0151cef8038/docs/img/webapp-final-en.png -------------------------------------------------------------------------------- /docs/img/webapp-final.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michalmar/openai-demos-bot-webapp/8810470a7ec8adc6d4dba8bc5c2ba0151cef8038/docs/img/webapp-final.png -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Jednoduchý Chatbot s pomocí Azure OpenAI služby 2 | 3 | ## Úvod 4 | Chatboty jsou počítačové programy, které slouží k vytváření interakce mezi lidmi a počítači. OpenAI `text-davinci` je moderní jazykový model založený na neuronových sítích, který byl vyvinut s cílem porozumět lidskému jazyku. Tento článek se zaměří na to, jak vytvořit účinný chatbot založený na [Azure OpenAI](https://learn.microsoft.com/en-us/azure/cognitive-services/openai/) `text-davinci` modelu. 5 | 6 | V rodině OpenAI je dnes k dispozici mnoho modelů, které se navzájem liší svým zaměřením (přirozený jazyk, kód, obrázky), ale také komplexitou a tím co dokážou. Pěkný úvod a ukázka shrnutí (sumarizace) textu můžete najít na [blogu ](https://tomaskubica.cz/post/2023/azure-openai-service-sumarizace-textu-v-cestine/) Tomáše Kubici. 7 | 8 | ## Cíl 9 | 10 | Cílem je vytvořit jednoduchý chatbot s použitím minimálního úsilí, tzn. budeme využívat služby a komponenty, které jsou již v zásadě připravené. 11 | 12 | **Jaké komponenty takový chatbot bude mít?** 13 | 14 | Chatovací logika - srdce chatbota je ve schopnosti reagovat na uživatelské podněty, dotazy a požadavky. Měl by pochopit na co se uživatel ptá, v případě nejasností se doptat na doplňující informace a poskytnout (pokud možno správnou) odpověď. Tady právě budeme spoléhat na Azure OpenAI službu. 15 | 16 | Front-end, resp. GUI, bude nejspíš webová aplikace, která zprostředkuje komunikaci uživatele s vlastním chatbotem. Nicméně, často takový chatbot může mít takových interfaců více: část uživatelů komunikuje přes webové stránky, část může používat aplikaci v mobilu a další část může například komunikovat v rámci Teams platformy. To znamená, že chatbot využívá více kanálů - ideální samozřejmě je, pokud nemusím upravovat bot pro každý kanál zvlášť. 17 | 18 | Komunikaci skrz kanály bude poskytovat [Azure Bot Service](https://azure.microsoft.com/en-us/products/bot-services/#features), které umí vystavit a řídit komunikaci s různými kanály (Web/Direct, Teams, ale třeba taky Email, SMS, Slack atp. - více [zde](https://learn.microsoft.com/en-us/azure/bot-service/bot-service-channels-reference?view=azure-bot-service-4.0)) 19 | 20 | Použité služby a nástroje: 21 | - Azure OpenAI - srdce / logika chatbota 22 | - Azure App Service (Web App) - vystavení GUI a hosting chatbota 23 | - Azure Bot Service - služba pro řízení komunikace přes různé kanály 24 | 25 | ## Architektura / Návrh řešení 26 | 27 | Architektura je velmi jednoduchá, pro hostování bota slouží Azure Web App (App Service), která zároveň hostuje i webový front-end/aplikaci. A ta komunikuje pomocí Bot Service (direct channel). Uživatelské vstupy jsou tedy předávány do Azure OpenAI jako jednouché volání API. 28 | 29 | ![architecture](./img/arch.png) 30 | 31 | Pojďme se teď podívat na implementaci takového řešení. 32 | 33 | ## Implementace 34 | 35 | Postup je jednoduchý. Budeme maximálně využívat připravených template a příkladů, 36 | 37 | ### Vytvoření OpenAI služby 38 | 39 | V prvním kroku vytvoříme OpenAI službu - k té je potřeba [vyplnit formulář](https://customervoice.microsoft.com/Pages/ResponsePage.aspx?id=v4j5cvGGr0GRqy180BHbR7en2Ais5pxKtso_Pz4b1_xUOFA5Qk1UWDRBMjg0WFhPMkIzTzhKQ1dWNyQlQCN0PWcu). V rámci této služby máme přístup na Azure OpenAI studio, kde můžeme začít výběrem a deploymentem modelu - `text-davinci-003`, což je model GPT3.5. Zároveň nabízí možnost "hracího hřiště" (playground), kde můžete modely testovat a zkoušet taky vlastní prompty. 40 | 41 | ![azure openai playground](./img/oai-playground.png) 42 | 43 | ### Vytvoření chatbota - úprava kódu 44 | 45 | > Důležité: tento postup je testován a funkční pro Node.js 16.20 (LTS) 46 | 47 | Druhý krok je tvorba vlastního bota v rámci Bot Frameworku, resp. vyjdeme z template pro jednoduchého web chatbota - [echo bot](https://github.com/microsoft/BotBuilder-Samples/tree/main/samples/typescript_nodejs/02.echo-bot). Já jsem si vybral JavaScript/TypeScript, ale můžete najít i příklad pro Python nebo C#. 48 | 49 | V souboru `bot.ts` je vidět vlastní logika chat aplikace, my se zaměříme na `onMessage` metodu, která reaguje na příchod zprávy od uživatele. 50 | 51 | ```javascript 52 | this.onMessage(async (context, next) => { 53 | const replyText = `Echo: ${ context.activity.text }`; 54 | await context.sendActivity(MessageFactory.text(replyText, replyText)); 55 | // By calling next() you ensure that the next BotHandler is run. 56 | await next(); 57 | }); 58 | ``` 59 | 60 | My tuto metodu upravíme tak, že uživatelský vstup (dotaz nebo povel) v proměnné `context.activity.text`, pošleme pro získání odpovědi do OpenAI služby a následně odpověď z OpenAI použijeme v odpovědi uživateli (`data.choices[0].text`): 61 | 62 | ```javascript 63 | this.onMessage(async (context, next) => { 64 | 65 | const requestBody = { 66 | prompt: context.activity.text 67 | , max_tokens: 500 68 | , temperature: 0.7 69 | }; 70 | const data = await postDataToEndpoint(url, requestBody, headers); 71 | 72 | const replyText = `${ data.choices[0].text }`; 73 | 74 | await context.sendActivity(MessageFactory.text(replyText)); 75 | 76 | // By calling next() you ensure that the next BotHandler is run. 77 | await next(); 78 | }); 79 | ``` 80 | 81 | Tím ale ještě nevznikne chatbot, kterého bychom chtěli - chybí nám dvě základní věci: 82 | - chatbot osobnost - prompt 83 | - uchování kontextu komunikace 84 | 85 | **Jak na to?** 86 | 87 | Práce s OpenAI textovými modely spočívá hlavně ve správném nastavení a vyladění promptu (více [zde](https://learn.microsoft.com/en-us/azure/cognitive-services/openai/how-to/completions)). Pro našeho chatbota použijeme prompt: 88 | 89 | ``` 90 | As an advanced chatbot, your primary goal is to assist users to the best of your ability. This may involve answering questions, providing helpful information, or completing tasks based on user input. In order to effectively assist users, it is important to be detailed and thorough in your responses. Use examples and evidence to support your points and justify your recommendations or solutions. 91 | 92 | 93 | 94 | User: 95 | Chatbot: 96 | ``` 97 | 98 | V první části je instrukce jak se model bude k zadanému textu chovat - dávat odpovědi včetně příkladů na podporu rozhodování, doplňování. Zde se může objevit ladění osobnosti například: "chovej se profesionálně". 99 | 100 | Pak následuje sekce ``, která drží historii konverzace a postupně ji doplňujeme o vstup a výstup chatbota. Tato část je důležitá proto, aby chat bot správně držel kontext komunikace. 101 | 102 | Dále je `User: `, za což doplníme uživatelský vstup. 103 | 104 | 105 | Celá funkce pak může vypadat takto: 106 | 107 | ```javascript 108 | this.onMessage(async (context, next) => { 109 | 110 | // construct prompt 111 | let tmp_prompt = prompt.replace("", conversation_history).replace("", context.activity.text) 112 | 113 | // construct request 114 | const requestBody = { 115 | prompt: tmp_prompt 116 | , max_tokens: 500 117 | , temperature: 0.7 118 | 119 | }; 120 | 121 | // send request to OpenAI 122 | const data = await postDataToEndpoint(url, requestBody, headers); 123 | 124 | 125 | // update converstation historz 126 | conversation_history = conversation_history + "User: " + context.activity.text + "\nChatbot: " + data.choices[0].text + "\n" 127 | 128 | const replyText = `${ data.choices[0].text }`; 129 | 130 | await context.sendActivity(MessageFactory.text(replyText)); 131 | 132 | // By calling next() you ensure that the next BotHandler is run. 133 | await next(); 134 | }); 135 | ``` 136 | 137 | Takového chatbota můžeme vyzkoušet lokálně v [Bot Framework Emulator](https://github.com/microsoft/BotFramework-Emulator): 138 | 139 | ![bot framework emulator](./img/bot-emu1.png) 140 | 141 | ### Deployment do Azure 142 | 143 | Když jsme otestovali, že nás chatbot poslouchá a odpovídá v lokálním prostředí, můžeme přistoupit k dalšímu kroku a to je deployment do Azure. To děláme ze dvou důvodů: 144 | 145 | 1. potřebujeme aby byla služba přístupná odkudkoli 146 | 1. chceme mít možnost pustit našeho chatbota na více kanálech 147 | 148 | V případě, že používáme k vývoji [VS Code](https://code.visualstudio.com/) (což vřele doporučuju), můžeme využít rozšíření pro práci s Azure Web App k samotnému (1-click) deploymentu. 149 | 150 | ![vscode](./img/vscode.png) 151 | 152 | To je dobré pro jednorázové testování, pro jednodušší iterativní vývoj doporučuju využít možnosti [automatického deploymentu do Azure Web App pomocí GitHub Actions](https://learn.microsoft.com/en-us/azure/app-service/deploy-continuous-deployment?tabs=github). 153 | 154 | ### Konfigurace Azure / Bot Service 155 | 156 | Bot jako takový (engine) je nyní již hostovaný v Azure - zbývá nám ještě vystavit jej pomocí [Azure Bot Service](https://portal.azure.com/#create/Microsoft.AzureBot) a získat tak přístup k více kanálů bez nutnosti změny kódu. 157 | 158 | Stačí zadat adresu URL web aplikace vytvořené v minulém kroce do nastavení Bot service - taková URL je FQDN dané aplikace plus `api/messages`, tzn. vypadá nějak takto: 159 | 160 | ```url 161 | https://YOUR-WEB-APP.azurewebsites.net/api/messages 162 | ``` 163 | 164 | ![bot service](./img/bot-service.png) 165 | 166 | Pokud vše bylo správně, můžeme rovnou otestovat v rámci Web Chat v rámci bot service služby přímo na Azure Portále: 167 | 168 | ![web chat test](./img/bot-service-test.png) 169 | 170 | Tímto jsme získali přístupu k použití hned několika kanálů: Web Chat, Microsoft Teams, Facebook Messenger, Slack, Twilio SMS,... (celý seznam [zde](https://learn.microsoft.com/en-us/azure/bot-service/bot-service-channels-reference?view=azure-bot-service-4.0)) 171 | 172 | 173 | ### Front-end / Webová aplikace 174 | 175 | Teď když nám chatbot funguje a je deployovaný v Azure, můžeme vyzkoušet nejčastější integrace do webové stránky. Nejjednodušší možnost je, že můžete si vygenerovat integraci pomocí `iframe` a tento kód pak jen vložit do vaší HTML stránky. 176 | 177 | ```html 178 | 180 | ``` 181 | 182 | Další varianta, je že přímo využijeme integraci WebChat do stránky - více [zde](https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-webchat-overview?view=azure-bot-service-4.0) a zdroj je na: [https://github.com/microsoft/BotFramework-WebChat](https://github.com/microsoft/BotFramework-WebChat/tree/main/samples/01.getting-started/a.full-bundle). 183 | 184 | Ve zkratce se jedná o JS knihovny, které dovolují jednoduchou integraci a další úpravy vzhledu: 185 | 186 | ```html 187 | 188 | 189 | 190 |
191 | 192 | 203 | 204 | 205 | ``` 206 | 207 | Kde `YOUR_DIRECT_LINE_TOKEN` je token pro direct line komunikaci v rámci Bot Service a `YOUR_USER_ID` vámi zvolená identifikace 208 | 209 | ![direct line token](./img/direct-line.png) 210 | 211 | > Důležité: Když konfigurujeme Web appku je zapotřebí (z pohledu bezpečnosti) nepoužívat tokeny/hesla přímo v kódu, ale odkazovat se na proměnné prostředí. V rámci tohoto příkladu používáme následující proměnné, které je potřeba správně nastavit v app settings: 212 | > 213 | > `DIRECT_LINE_TOKEN`... token k Bot Service kanálu 214 | > 215 | > `OPENAI_API_KEY`... klíč pro autentizaci k Azure OpenAI službě 216 | > 217 | > `MicrosoftAppId` a `MicrosoftAppPassword` použité při vytváření Bot Service pro autentizaci k Azure zdrojům (můžete použít vlastního Service Principal nebo nechat vygenerovat jako default - více [zde](https://learn.microsoft.com/en-us/azure/bot-service/provision-and-publish-a-bot?view=azure-bot-service-4.0&tabs=userassigned%2Ccsharp#plan-your-deployment)) 218 | 219 | Taková stránka pak obsahuje našeho právě připraveného chatbota. WebChat framework nabízí spoustu možností s úpravou vzhledu, takže můžete měnit téměř cokoli od barev po zobrazení indikátorů členů konverzace - více [zde](https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-webchat-customization?view=azure-bot-service-4.0). 220 | 221 | Takže náš chatbot může vypadat třeba takto: 222 | 223 | ![web app chat bot](./img/webapp-final.png) 224 | 225 | ## Závěr 226 | 227 | Toto byla ukázka, jak vytvořit jednoduchého chatbota, který ale zná odpověd na téměř jakokoli otázku :-), protože používá výkonný model `text-davinci-003` z Azure OpenAI služby. 228 | 229 | Pokud chcete, můžete si to sami vyzkoušet! Celý zdrojový kód je k dispozici na mém GitHubu: [https://github.com/michalmar/openai-demos-bot-webapp](https://github.com/michalmar/openai-demos-bot-webapp). Abyste mohli používat Azure OpenAI službu, je nutné o přístup nejdříve požádat - [formulář](https://customervoice.microsoft.com/Pages/ResponsePage.aspx?id=v4j5cvGGr0GRqy180BHbR7en2Ais5pxKtso_Pz4b1_xUOFA5Qk1UWDRBMjg0WFhPMkIzTzhKQ1dWNyQlQCN0PWcu). 230 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 36 | 37 | 38 | 39 |

Azure OpenAI service - ChatGPT

40 |
version 20230320 | model: ChatGPT (turbo) | max_tokens: 1500 | temperature: 0.7 | Speech input enabled: true | Speech language: EN
41 |
42 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /lib/bot.d.ts: -------------------------------------------------------------------------------- 1 | import { ActivityHandler } from 'botbuilder'; 2 | export declare class EchoBot extends ActivityHandler { 3 | constructor(); 4 | } 5 | -------------------------------------------------------------------------------- /lib/bot.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License. 4 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 5 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 6 | return new (P || (P = Promise))(function (resolve, reject) { 7 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 8 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 9 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 10 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 11 | }); 12 | }; 13 | Object.defineProperty(exports, "__esModule", { value: true }); 14 | exports.EchoBot = void 0; 15 | const botbuilder_1 = require("botbuilder"); 16 | const axios_1 = require("axios"); 17 | class EchoBot extends botbuilder_1.ActivityHandler { 18 | constructor() { 19 | super(); 20 | let conversation_history_dict = {}; 21 | let messages_init = { "role": "system", "content": "As an advanced chatbot, your primary goal is to assist users to the best of your ability. This may involve answering questions, providing helpful information, or completing tasks based on user input. In order to effectively assist users, it is important to be detailed and thorough in your responses. Use examples and evidence to support your points and justify your recommendations or solutions." }; 22 | // this is the url for the openai api 23 | const url = process.env.OPENAI_API_URL; 24 | // number of turns (user messages) to keep in the conversation history 25 | const history_length = 3; 26 | const headers = { 27 | 'Content-Type': 'application/json', 28 | // 'Authorization': 'Bearer YOUR_TOKEN' 29 | 'api-key': process.env.OPENAI_API_KEY 30 | }; 31 | function postDataToEndpoint(url, requestBody, headers) { 32 | return __awaiter(this, void 0, void 0, function* () { 33 | try { 34 | const response = yield axios_1.default.post(url, requestBody, { headers }); 35 | return response.data; 36 | } 37 | catch (error) { 38 | throw new Error(`Error posting data to ${url}: ${error}`); 39 | } 40 | }); 41 | } 42 | // function that iterates through the conversation history and counts number of occurance "user" messages 43 | function count_user_messages(conversation_history_array) { 44 | let count = 0; 45 | for (let i = 0; i < conversation_history_array.length; i++) { 46 | if (conversation_history_array[i].role == "user") { 47 | count = count + 1; 48 | } 49 | } 50 | return count; 51 | } 52 | // See https://aka.ms/about-bot-activity-message to learn more about the message and other activity types. 53 | this.onMessage((context, next) => __awaiter(this, void 0, void 0, function* () { 54 | var _a; 55 | var _b; 56 | // check if user input is "/reset" 57 | if (context.activity.text == "/reset") { 58 | // reset conversation history 59 | conversation_history_dict[context.activity.conversation.id] = []; 60 | // send response to user 61 | yield context.sendActivity(botbuilder_1.MessageFactory.text("Clearing session. Starting with new context - just ask your question.")); 62 | // By calling next() you ensure that the next BotHandler is run. 63 | yield next(); 64 | } 65 | else { 66 | //construct conversation history from conversation_history_array 67 | // conversation_history_dict structure: 68 | // {conversation_id: [{"role":"system", "content":"..."} 69 | // , {"role":"user", "content":"..."} 70 | // , {"role":"assistant", "content":"..."} 71 | // , ...] 72 | let tmp_conversation_history = ""; 73 | (_a = conversation_history_dict[_b = context.activity.conversation.id]) !== null && _a !== void 0 ? _a : (conversation_history_dict[_b] = [messages_init]); 74 | let conversation_history_array = conversation_history_dict[context.activity.conversation.id]; 75 | // check if conversation history is not larger than history_length, if so remove from begining 76 | if (count_user_messages(conversation_history_array) > history_length) { 77 | console.log("history too long - removing first element"); 78 | let N = 2; // removing two elements (question and answer) 79 | for (let i = 0; i < N; i++) { 80 | conversation_history_array.shift(); // remove the first element from the array 81 | } 82 | // make sure that the first element is always the initial message (system message) 83 | conversation_history_array[0] = messages_init; 84 | } 85 | // add the user input to the conversation history 86 | conversation_history_array.push({ "role": "user", "content": context.activity.text }); 87 | let reqBody = JSON.stringify({ 88 | "messages": conversation_history_array, 89 | "max_tokens": 1500, 90 | "temperature": 0.7, 91 | "frequency_penalty": 0, 92 | "presence_penalty": 0, 93 | "top_p": 1, 94 | "stop": null 95 | }); 96 | try { 97 | // send request to openai 98 | const data = yield postDataToEndpoint(url, reqBody, headers); 99 | // add the chatbot response to the conversation history 100 | conversation_history_array.push({ "role": data.choices[0].message.role, "content": data.choices[0].message.content }); 101 | // update conversation history 102 | conversation_history_dict[context.activity.conversation.id] = conversation_history_array; 103 | // send response to user 104 | const replyText = `${data.choices[0].message.content} \n[~ ${data.usage.total_tokens} tokens in ${conversation_history_array.length} turns]`; 105 | // const replyText = `Echox: ${ context.activity.text } value: ${ context.activity.value }`; 106 | yield context.sendActivity(botbuilder_1.MessageFactory.text(replyText)); 107 | // By calling next() you ensure that the next BotHandler is run. 108 | yield next(); 109 | } 110 | catch (error) { 111 | console.log(error); 112 | yield context.sendActivity(botbuilder_1.MessageFactory.text(`${error} - try again later!`)); 113 | yield next(); 114 | } 115 | } 116 | })); 117 | this.onMembersAdded((context, next) => __awaiter(this, void 0, void 0, function* () { 118 | const membersAdded = context.activity.membersAdded; 119 | const welcomeText = 'Hi, this is ChatGPT model! How can I help you?'; 120 | for (const member of membersAdded) { 121 | if (member.id !== context.activity.recipient.id) { 122 | yield context.sendActivity(botbuilder_1.MessageFactory.text(welcomeText, welcomeText)); 123 | conversation_history_dict[context.activity.conversation.id] = [messages_init]; 124 | } 125 | } 126 | // By calling next() you ensure that the next BotHandler is run. 127 | yield next(); 128 | })); 129 | } 130 | } 131 | exports.EchoBot = EchoBot; 132 | //# sourceMappingURL=bot.js.map -------------------------------------------------------------------------------- /lib/bot.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"bot.js","sourceRoot":"","sources":["../src/bot.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /lib/index.d.ts: -------------------------------------------------------------------------------- 1 | export {}; 2 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License. 4 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 5 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 6 | return new (P || (P = Promise))(function (resolve, reject) { 7 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 8 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 9 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 10 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 11 | }); 12 | }; 13 | Object.defineProperty(exports, "__esModule", { value: true }); 14 | const path = require("path"); 15 | const dotenv_1 = require("dotenv"); 16 | const ENV_FILE = path.join(__dirname, '..', '.env.local'); 17 | dotenv_1.config({ path: ENV_FILE }); 18 | const restify = require("restify"); 19 | // Import required bot services. 20 | // See https://aka.ms/bot-services to learn more about the different parts of a bot. 21 | const botbuilder_1 = require("botbuilder"); 22 | // This bot's main dialog. 23 | const bot_1 = require("./bot"); 24 | // Create HTTP server. 25 | const server = restify.createServer(); 26 | server.use(restify.plugins.bodyParser()); 27 | server.listen(process.env.port || process.env.PORT || 3978, () => { 28 | console.log(`\n${server.name} listening to ${server.url}`); 29 | console.log('\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator'); 30 | console.log('\nTo talk to your bot, open the emulator select "Open Bot"'); 31 | }); 32 | const botFrameworkAuthentication = new botbuilder_1.ConfigurationBotFrameworkAuthentication(process.env); 33 | // Create adapter. 34 | // See https://aka.ms/about-bot-adapter to learn more about how bots work. 35 | const adapter = new botbuilder_1.CloudAdapter(botFrameworkAuthentication); 36 | // Catch-all for errors. 37 | const onTurnErrorHandler = (context, error) => __awaiter(void 0, void 0, void 0, function* () { 38 | // This check writes out errors to console log .vs. app insights. 39 | // NOTE: In production environment, you should consider logging this to Azure 40 | // application insights. 41 | console.error(`\n [onTurnError] unhandled error: ${error}`); 42 | // Send a trace activity, which will be displayed in Bot Framework Emulator 43 | yield context.sendTraceActivity('OnTurnError Trace', `${error}`, 'https://www.botframework.com/schemas/error', 'TurnError'); 44 | // Send a message to the user 45 | yield context.sendActivity('The bot encountered an error or bug.'); 46 | yield context.sendActivity('To continue to run this bot, please fix the bot source code.'); 47 | }); 48 | // Set the onTurnError for the singleton CloudAdapter. 49 | adapter.onTurnError = onTurnErrorHandler; 50 | // Create the main dialog. 51 | const myBot = new bot_1.EchoBot(); 52 | // Listen for incoming requests. 53 | server.post('/api/messages', (req, res, next) => __awaiter(void 0, void 0, void 0, function* () { 54 | // Route received a request to adapter for processing 55 | yield adapter.process(req, res, (context) => myBot.run(context)); 56 | return next(); 57 | })); 58 | // Listen for HTTP request on / 59 | server.get('/', (req, res, next) => { 60 | // res.send('Hello World!'); 61 | // display basic html page 62 | res.writeHead(200, { 'Content-Type': 'text/html' }); 63 | res.write(` 64 | 65 | 66 | 67 | 68 | 72 | 98 | 99 | 100 | 101 |

Azure OpenAI - ChatGPT

102 |
version 20230719 | model: ChatGPT (turbo) | API: Chat Completion API | max_tokens: 1500 | temperature: 0.7 | Speech input enabled: false | Speech language: N/A
103 |
104 | 162 | 163 | 164 | 165 | `); 166 | res.end(); 167 | return next(); 168 | }); 169 | // Listen for Upgrade requests for Streaming. 170 | server.on('upgrade', (req, socket, head) => __awaiter(void 0, void 0, void 0, function* () { 171 | // Create an adapter scoped to this WebSocket connection to allow storing session data. 172 | const streamingAdapter = new botbuilder_1.CloudAdapter(botFrameworkAuthentication); 173 | // Set onTurnError for the CloudAdapter created for each connection. 174 | streamingAdapter.onTurnError = onTurnErrorHandler; 175 | yield streamingAdapter.process(req, socket, head, (context) => myBot.run(context)); 176 | })); 177 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /lib/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michalmar/openai-demos-bot-webapp/8810470a7ec8adc6d4dba8bc5c2ba0151cef8038/logo.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "echobot", 3 | "version": "1.0.0", 4 | "description": "Bot Builder v4 echo bot sample", 5 | "author": "Microsoft", 6 | "license": "MIT", 7 | "main": "./lib/index.js", 8 | "scripts": { 9 | "build": "tsc --build", 10 | "lint": "tslint -c tslint.json 'src/**/*.ts'", 11 | "postinstall": "npm run build && node ./deploymentScripts/webConfigPrep.js", 12 | "start": "tsc --build && node ./lib/index.js", 13 | "test": "echo \"No test specified\"", 14 | "watch": "nodemon --watch ./src -e ts --exec \"npm run start\"" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com" 19 | }, 20 | "dependencies": { 21 | "botbuilder": "~4.21.0", 22 | "dotenv": "^8.2.0", 23 | "replace": "^1.2.0", 24 | "restify": "~10.0.0" 25 | }, 26 | "devDependencies": { 27 | "@types/dotenv": "6.1.1", 28 | "@types/node": "^18.18.2", 29 | "@types/restify": "8.5.9", 30 | "nodemon": "~2.0.4", 31 | "tslint": "~6.1.2", 32 | "typescript": "~4.3.2" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/bot.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | import { ActivityHandler, MessageFactory } from 'botbuilder'; 5 | import axios, { AxiosResponse, AxiosRequestHeaders } from 'axios'; 6 | 7 | export class EchoBot extends ActivityHandler { 8 | constructor() { 9 | super(); 10 | 11 | interface OpenAiResponse { 12 | choices: [ 13 | { 14 | message: { 15 | role: string; 16 | content: string; 17 | }; 18 | } 19 | ], 20 | usage: { 21 | total_tokens: number; 22 | } 23 | } 24 | 25 | let conversation_history_dict = {}; 26 | let messages_init = {"role":"system", "content": "As an advanced chatbot, your primary goal is to assist users to the best of your ability. This may involve answering questions, providing helpful information, or completing tasks based on user input. In order to effectively assist users, it is important to be detailed and thorough in your responses. Use examples and evidence to support your points and justify your recommendations or solutions."}; 27 | 28 | // this is the url for the openai api 29 | const url = process.env.OPENAI_API_URL 30 | 31 | // number of turns (user messages) to keep in the conversation history 32 | const history_length = 3 33 | 34 | const headers = { 35 | 'Content-Type': 'application/json', 36 | // 'Authorization': 'Bearer YOUR_TOKEN' 37 | 'api-key': process.env.OPENAI_API_KEY 38 | } 39 | 40 | 41 | async function postDataToEndpoint(url: string, requestBody: string, headers: AxiosRequestHeaders): Promise { 42 | try { 43 | const response: AxiosResponse = await axios.post(url, requestBody, {headers}); 44 | return response.data; 45 | } catch (error) { 46 | throw new Error(`Error posting data to ${url}: ${error}`); 47 | } 48 | } 49 | 50 | // function that iterates through the conversation history and counts number of occurance "user" messages 51 | function count_user_messages(conversation_history_array: any) { 52 | let count = 0; 53 | for (let i = 0; i < conversation_history_array.length; i++) { 54 | if (conversation_history_array[i].role == "user") { 55 | count = count + 1; 56 | } 57 | } 58 | return count; 59 | } 60 | 61 | 62 | // See https://aka.ms/about-bot-activity-message to learn more about the message and other activity types. 63 | this.onMessage(async (context, next) => { 64 | 65 | // check if user input is "/reset" 66 | if (context.activity.text == "/reset") { 67 | // reset conversation history 68 | conversation_history_dict[context.activity.conversation.id] = [] 69 | // send response to user 70 | await context.sendActivity(MessageFactory.text("Clearing session. Starting with new context - just ask your question.")); 71 | 72 | // By calling next() you ensure that the next BotHandler is run. 73 | await next(); 74 | } else { 75 | //construct conversation history from conversation_history_array 76 | // conversation_history_dict structure: 77 | // {conversation_id: [{"role":"system", "content":"..."} 78 | // , {"role":"user", "content":"..."} 79 | // , {"role":"assistant", "content":"..."} 80 | // , ...] 81 | let tmp_conversation_history = "" 82 | conversation_history_dict[context.activity.conversation.id] ??= [messages_init]; 83 | let conversation_history_array = conversation_history_dict[context.activity.conversation.id]; 84 | 85 | // check if conversation history is not larger than history_length, if so remove from begining 86 | if (count_user_messages(conversation_history_array) > history_length) { 87 | console.log("history too long - removing first element") 88 | let N = 2; // removing two elements (question and answer) 89 | for (let i = 0; i < N; i++) { 90 | conversation_history_array.shift(); // remove the first element from the array 91 | } 92 | // make sure that the first element is always the initial message (system message) 93 | conversation_history_array[0] = messages_init; 94 | } 95 | 96 | // add the user input to the conversation history 97 | conversation_history_array.push({"role":"user", "content":context.activity.text}); 98 | 99 | 100 | let reqBody = JSON.stringify({ 101 | "messages": conversation_history_array, 102 | "max_tokens": 1500, 103 | "temperature": 0.7, 104 | "frequency_penalty": 0, 105 | "presence_penalty": 0, 106 | "top_p": 1, 107 | "stop": null 108 | }); 109 | 110 | try { 111 | // send request to openai 112 | const data = await postDataToEndpoint(url, reqBody, headers); 113 | 114 | // add the chatbot response to the conversation history 115 | conversation_history_array.push({"role":data.choices[0].message.role, "content":data.choices[0].message.content}); 116 | 117 | // update conversation history 118 | conversation_history_dict[context.activity.conversation.id] = conversation_history_array; 119 | 120 | // send response to user 121 | const replyText = `${ data.choices[0].message.content } \n[~ ${data.usage.total_tokens} tokens in ${conversation_history_array.length} turns]`; 122 | // const replyText = `Echox: ${ context.activity.text } value: ${ context.activity.value }`; 123 | await context.sendActivity(MessageFactory.text(replyText)); 124 | 125 | // By calling next() you ensure that the next BotHandler is run. 126 | await next(); 127 | } catch (error) { 128 | console.log(error); 129 | await context.sendActivity(MessageFactory.text(`${error} - try again later!`)); 130 | await next(); 131 | } 132 | } 133 | }); 134 | 135 | this.onMembersAdded(async (context, next) => { 136 | const membersAdded = context.activity.membersAdded; 137 | const welcomeText = 'Hi, this is ChatGPT model! How can I help you?'; 138 | 139 | for (const member of membersAdded) { 140 | if (member.id !== context.activity.recipient.id) { 141 | await context.sendActivity(MessageFactory.text(welcomeText, welcomeText)); 142 | conversation_history_dict[context.activity.conversation.id] = [messages_init]; 143 | } 144 | } 145 | // By calling next() you ensure that the next BotHandler is run. 146 | await next(); 147 | }); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | import * as path from 'path'; 5 | 6 | import { config } from 'dotenv'; 7 | const ENV_FILE = path.join(__dirname, '..', '.env.local'); 8 | config({ path: ENV_FILE }); 9 | 10 | import * as restify from 'restify'; 11 | 12 | import { INodeSocket } from 'botframework-streaming'; 13 | 14 | // Import required bot services. 15 | // See https://aka.ms/bot-services to learn more about the different parts of a bot. 16 | import { 17 | CloudAdapter, 18 | ConfigurationServiceClientCredentialFactory, 19 | ConfigurationBotFrameworkAuthentication, 20 | ConfigurationBotFrameworkAuthenticationOptions 21 | } from 'botbuilder'; 22 | 23 | // This bot's main dialog. 24 | import { EchoBot } from './bot'; 25 | 26 | // Create HTTP server. 27 | const server = restify.createServer(); 28 | server.use(restify.plugins.bodyParser()); 29 | server.listen(process.env.port || process.env.PORT || 3978, () => { 30 | console.log(`\n${server.name} listening to ${server.url}`); 31 | console.log('\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator'); 32 | console.log('\nTo talk to your bot, open the emulator select "Open Bot"'); 33 | }); 34 | 35 | const botFrameworkAuthentication = new ConfigurationBotFrameworkAuthentication(process.env as ConfigurationBotFrameworkAuthenticationOptions); 36 | 37 | // Create adapter. 38 | // See https://aka.ms/about-bot-adapter to learn more about how bots work. 39 | const adapter = new CloudAdapter(botFrameworkAuthentication); 40 | 41 | // Catch-all for errors. 42 | const onTurnErrorHandler = async (context, error) => { 43 | // This check writes out errors to console log .vs. app insights. 44 | // NOTE: In production environment, you should consider logging this to Azure 45 | // application insights. 46 | console.error(`\n [onTurnError] unhandled error: ${ error }`); 47 | 48 | // Send a trace activity, which will be displayed in Bot Framework Emulator 49 | await context.sendTraceActivity( 50 | 'OnTurnError Trace', 51 | `${ error }`, 52 | 'https://www.botframework.com/schemas/error', 53 | 'TurnError' 54 | ); 55 | 56 | // Send a message to the user 57 | await context.sendActivity('The bot encountered an error or bug.'); 58 | await context.sendActivity('To continue to run this bot, please fix the bot source code.'); 59 | }; 60 | 61 | // Set the onTurnError for the singleton CloudAdapter. 62 | adapter.onTurnError = onTurnErrorHandler; 63 | 64 | // Create the main dialog. 65 | const myBot = new EchoBot(); 66 | 67 | // Listen for incoming requests. 68 | server.post('/api/messages', async (req, res, next) => { 69 | // Route received a request to adapter for processing 70 | await adapter.process(req, res, (context) => myBot.run(context)); 71 | return next(); 72 | }); 73 | 74 | // Listen for HTTP request on / 75 | server.get('/', (req, res, next) => { 76 | // res.send('Hello World!'); 77 | 78 | // display basic html page 79 | res.writeHead(200, { 'Content-Type': 'text/html' }); 80 | res.write(` 81 | 82 | 83 | 84 | 85 | 89 | 115 | 116 | 117 | 118 |

Azure OpenAI - ChatGPT

119 |
version 20231030 | model: ChatGPT (turbo) | API: Chat Completion API | max_tokens: 1500 | temperature: 0.7 | Speech input enabled: false | Speech language: N/A
120 |
121 | 179 | 180 | 181 | 182 | `); 183 | res.end(); 184 | return next(); 185 | }); 186 | 187 | // Listen for Upgrade requests for Streaming. 188 | server.on('upgrade', async (req, socket, head) => { 189 | // Create an adapter scoped to this WebSocket connection to allow storing session data. 190 | const streamingAdapter = new CloudAdapter(botFrameworkAuthentication); 191 | 192 | // Set onTurnError for the CloudAdapter created for each connection. 193 | streamingAdapter.onTurnError = onTurnErrorHandler; 194 | 195 | await streamingAdapter.process(req, socket as unknown as INodeSocket, head, (context) => myBot.run(context)); 196 | }); 197 | -------------------------------------------------------------------------------- /teams_package/color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michalmar/openai-demos-bot-webapp/8810470a7ec8adc6d4dba8bc5c2ba0151cef8038/teams_package/color.png -------------------------------------------------------------------------------- /teams_package/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.16/MicrosoftTeams.schema.json", 3 | "manifestVersion": "1.16", 4 | "version": "1.0.0", 5 | "id": "${{TEAMS_APP_ID}}", 6 | "packageName": "com.microsoft.teams.extension", 7 | "developer": { 8 | "name": "Teams App, Inc.", 9 | "websiteUrl": "https://www.example.com", 10 | "privacyUrl": "https://www.example.com/termofuse", 11 | "termsOfUseUrl": "https://www.example.com/privacy" 12 | }, 13 | "icons": { 14 | "color": "color.png", 15 | "outline": "outline.png" 16 | }, 17 | "name": { 18 | "short": "firstapp-${{TEAMSFX_ENV}}", 19 | "full": "full name for firstapp" 20 | }, 21 | "description": { 22 | "short": "short description for firstapp", 23 | "full": "full description for firstapp" 24 | }, 25 | "accentColor": "#FFFFFF", 26 | "bots": [ 27 | { 28 | "botId": "${{BOT_ID}}", 29 | "scopes": [ 30 | "personal", 31 | "team", 32 | "groupchat" 33 | ], 34 | "supportsFiles": false, 35 | "isNotificationOnly": false, 36 | "commandLists": [ 37 | { 38 | "scopes": [ 39 | "personal", 40 | "team", 41 | "groupchat" 42 | ], 43 | "commands": [ 44 | { 45 | "title": "welcome", 46 | "description": "Resend welcome card of this Bot" 47 | }, 48 | { 49 | "title": "learn", 50 | "description": "Learn about Adaptive Card and Bot Command" 51 | } 52 | ] 53 | } 54 | ] 55 | } 56 | ], 57 | "composeExtensions": [], 58 | "configurableTabs": [], 59 | "staticTabs": [], 60 | "permissions": [ 61 | "identity", 62 | "messageTeamMembers" 63 | ], 64 | "validDomains": [] 65 | } -------------------------------------------------------------------------------- /teams_package/outline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michalmar/openai-demos-bot-webapp/8810470a7ec8adc6d4dba8bc5c2ba0151cef8038/teams_package/outline.png -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "target": "es2016", 5 | "module": "commonjs", 6 | "outDir": "./lib", 7 | "rootDir": "./src", 8 | "sourceMap": true, 9 | "incremental": true, 10 | "tsBuildInfoFile": "./lib/.tsbuildinfo" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": [ 4 | "tslint:recommended" 5 | ], 6 | "jsRules": {}, 7 | "rules": { 8 | "interface-name" : [true, "never-prefix"], 9 | "max-line-length": [false], 10 | "no-console": [false, "log", "error"], 11 | "no-var-requires": false, 12 | "quotemark": [true, "single"], 13 | "one-variable-per-declaration": false, 14 | "curly": [true, "ignore-same-line"], 15 | "trailing-comma": [true, {"multiline": "never", "singleline": "never"}] 16 | }, 17 | "rulesDirectory": [] 18 | } 19 | --------------------------------------------------------------------------------