|
| 1 | +--- |
| 2 | +author: jefmarti |
| 3 | +ms.service: azure-app-service |
| 4 | +ms.devlang: node |
| 5 | +ms.custom: linux-related-content |
| 6 | +ms.topic: article |
| 7 | +ms.date: 09/30/2024 |
| 8 | +ms.author: jefmarti |
| 9 | +--- |
| 10 | + |
| 11 | +You can use Azure App Service to create applications using Azure OpenAI and OpenAI. In the following tutorial, we're adding Azure OpenAI Service to an Express application using the Azure SDK. |
| 12 | + |
| 13 | +#### Prerequisites |
| 14 | + |
| 15 | +- An [Azure OpenAI resource](/azure/ai-services/openai/quickstart?pivots=programming-language-csharp&tabs=command-line%2Cpython#set-up) or an [OpenAI account](https://platform.openai.com/overview). |
| 16 | +- A Node.js Express application. Create the sample app using our [quickstart](/azure/app-service/quickstart-nodejs?tabs=linux&pivots=development-environment-vscode). |
| 17 | + |
| 18 | +### Set up web app |
| 19 | + |
| 20 | +For this application, we’re building off the [quickstart](/azure/app-service/quickstart-nodejs?tabs=linux&pivots=development-environment-vscode) Express app and adding an extra feature to make a request to an Azure OpenAI or OpenAI service. |
| 21 | + |
| 22 | +First, copy and replace the `index.ejs` file with the following code: |
| 23 | + |
| 24 | +```html |
| 25 | +<!DOCTYPE html> |
| 26 | +<html> |
| 27 | + <head> |
| 28 | + <title><%= title %></title> |
| 29 | + <link rel='stylesheet' href='/stylesheets/style.css' /> |
| 30 | + </head> |
| 31 | + <body> |
| 32 | + <h1><%= title %></h1> |
| 33 | + <p>Welcome to <%= title %></p> |
| 34 | + <form action="/api/completions" method="post"> |
| 35 | + <label for="prompt"><b>Input query:</b></label> |
| 36 | + <input type="text" id="prompt" name="prompt" style="width: 10%"> |
| 37 | + <input type="submit" value="Submit" id="submitBtn"> |
| 38 | + </form> |
| 39 | + </body> |
| 40 | + |
| 41 | + <script src="./index.js"></script> |
| 42 | +</html> |
| 43 | +``` |
| 44 | + |
| 45 | +The previous code will add an input box to our index page to submit requests to OpenAI. |
| 46 | + |
| 47 | +### API Keys and Endpoints |
| 48 | + |
| 49 | +First, you need to grab the keys and endpoint values from Azure OpenAI, or OpenAI and add them as secrets for use in your application. Retrieve and save the values for later use to build the client. |
| 50 | + |
| 51 | +For Azure OpenAI, see [this documentation](/azure/ai-services/openai/quickstart?pivots=programming-language-csharp&tabs=command-line%2Cpython#retrieve-key-and-endpoint) to retrieve the key and endpoint values. If you’re planning to use managed identity to secure your app you’ll only need the `deploymentName` and `apiVersion` values. |
| 52 | + |
| 53 | +Otherwise, you need each of the following: |
| 54 | + |
| 55 | +For Azure OpenAI, use the following settings: |
| 56 | + |
| 57 | +- `endpoint` |
| 58 | +- `apiKey` |
| 59 | +- `deploymentName` |
| 60 | +- `apiVersion` |
| 61 | + |
| 62 | +For OpenAI, see this documentation to retrieve the API keys. For our application, you need the following values: |
| 63 | + |
| 64 | +- `apiKey` |
| 65 | + |
| 66 | +Since we're deploying to App Service, we can secure these secrets in **Azure Key Vault** for protection. Follow the [Quickstart](/azure/key-vault/secrets/quick-create-cli#create-a-key-vault) to set up your Key Vault and add the secrets you saved from earlier. |
| 67 | + |
| 68 | +Next, we can use Key Vault references as app settings in our App Service resource to reference in our application. Follow the instructions in the [documentation](../../app-service-key-vault-references.md?source=recommendations&tabs=azure-cli) to grant your app access to your Key Vault and to set up Key Vault references. |
| 69 | + |
| 70 | +Then, go to the portal Environment Variables page in your resource and add the following app settings: |
| 71 | + |
| 72 | +For Azure OpenAI, use the following settings: |
| 73 | + |
| 74 | +| Setting name| Value | |
| 75 | +|-|-|-| |
| 76 | +| `DEPOYMENT_NAME` | @Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/mysecret/) | |
| 77 | +| `ENDPOINT` | @Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/mysecret/) | |
| 78 | +| `API_KEY` | @Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/mysecret/) | |
| 79 | +| `API_VERSION` | @Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/mysecret/) | |
| 80 | + |
| 81 | +For OpenAI, use the following settings: |
| 82 | + |
| 83 | +| Setting name| Value | |
| 84 | +|-|-|-| |
| 85 | +| `OPENAI_API_KEY` | @Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/mysecret/) | |
| 86 | + |
| 87 | +Once your app settings are saved, you can access the app settings in your code by referencing them in your application. Add the following to the `app.js` file: |
| 88 | + |
| 89 | +For Azure OpenAI: |
| 90 | + |
| 91 | +```jsx |
| 92 | +// access environment variables |
| 93 | +const endpoint = process.env.ENDPOINT; |
| 94 | +const apiKey = process.env.API_KEY; |
| 95 | +const deployment = process.env.DEPLOYMENT_NAME; |
| 96 | +const apiVersion = process.env.API_VERSION; |
| 97 | +``` |
| 98 | + |
| 99 | +For OpenAI: |
| 100 | + |
| 101 | +```jsx |
| 102 | +const apiKey = process.env.API_KEY; |
| 103 | +``` |
| 104 | + |
| 105 | +### Add the OpenAI package |
| 106 | + |
| 107 | +Before you can create the client, you first need to add the Azure OpenAI package. Add the following OpenAI package by using the node package manager. |
| 108 | + |
| 109 | +For Azure OpenAI: |
| 110 | + |
| 111 | +```powershell |
| 112 | +npm install openai @azure/openai |
| 113 | +``` |
| 114 | + |
| 115 | +For OpenAI: |
| 116 | + |
| 117 | +```powershell |
| 118 | +npm install openai |
| 119 | +``` |
| 120 | + |
| 121 | +### Create OpenAI client |
| 122 | + |
| 123 | +Once the package and environment variables are set up, we can create the client that enables chat completion calls. |
| 124 | + |
| 125 | +Add the following code to create the OpenAI client: |
| 126 | + |
| 127 | +For Azure OpenAI: |
| 128 | + |
| 129 | +```jsx |
| 130 | + const { AzureOpenAI } = require("openai"); |
| 131 | + |
| 132 | + const client = new AzureOpenAI({ |
| 133 | + endpoint: endpoint, |
| 134 | + deployment: deployment, |
| 135 | + apiKey: apiKey, |
| 136 | + apiVersion: apiVersion, |
| 137 | + }); |
| 138 | +``` |
| 139 | + |
| 140 | +For OpenAI: |
| 141 | + |
| 142 | +```jsx |
| 143 | +import OpenAI from 'openai'; |
| 144 | + |
| 145 | + const client = OpenAI({ |
| 146 | + apiKey: apiKey, |
| 147 | + }); |
| 148 | +``` |
| 149 | + |
| 150 | +### Secure your app with managed identity |
| 151 | + |
| 152 | +Although optional, it's highly recommended to secure your application using [managed identity](../../overview-managed-identity.md) to authenticate your app to your Azure OpenAI resource. Skip this step if you are not using Azure OpenAI. This enables your application to access the Azure OpenAI resource without needing to manage API keys. |
| 153 | + |
| 154 | +Follow the steps below to secure your application: |
| 155 | + |
| 156 | +Install the Azure identity package using the Node package manager. |
| 157 | + |
| 158 | +```powershell |
| 159 | +npm install @azure/identity |
| 160 | +``` |
| 161 | + |
| 162 | +Create token provider using the default Azure credential. |
| 163 | + |
| 164 | +```jsx |
| 165 | +const credential = new DefaultAzureCredential(); |
| 166 | +const scope = "https://cognitiveservices.azure.com/.default"; |
| 167 | +const azureADTokenProvider = getBearerTokenProvider(credential, scope); |
| 168 | +``` |
| 169 | + |
| 170 | +Create the Azure OpenAI client with the token provider. |
| 171 | + |
| 172 | +```jsx |
| 173 | + const deployment = deployment; |
| 174 | + const apiVersion = apiVersion; |
| 175 | + const client = new AzureOpenAI({ azureADTokenProvider, deployment, apiVersion }); |
| 176 | +``` |
| 177 | + |
| 178 | +Once the credentials are added to the application, enable managed identity in your application and grant access to the resource: |
| 179 | + |
| 180 | +1. In your web app resource, navigate to the **Identity** blade and turn on **System assigned** and select **Save**. |
| 181 | +2. Once System assigned identity is turned on, it will register the web app with Microsoft Entra ID and the web app can be granted permissions to access protected resources. |
| 182 | +3. Go to your Azure OpenAI resource and navigate to the **Access control (IAM)** page on the left pane. |
| 183 | +4. Find the **Grant access to this resource** card and select **Add role assignment**. |
| 184 | +5. Search for the **Cognitive Services OpenAI User** role and select **Next**. |
| 185 | +6. On the **Members** tab, find **Assign access to** and choose the **Managed identity** option. |
| 186 | +7. Next, select **+Select Members** and find your web app. |
| 187 | +8. Select **Review + assign**. |
| 188 | + |
| 189 | +Your web app is now added as a cognitive service OpenAI user and can communicate to your Azure OpenAI resource. |
| 190 | + |
| 191 | +### Set up prompt and call to OpenAI |
| 192 | + |
| 193 | +Now that our OpenAI service is created we can use chat completions to send our request message to OpenAI and return a response. Here's where we add our chat message prompt to the code to be passed to the chat completions method. Use the following code to set up chat completions: |
| 194 | + |
| 195 | +```jsx |
| 196 | +app.post("/api/completions", async (req, res) => { |
| 197 | + |
| 198 | + // Azure OpenAI client |
| 199 | + const client = new AzureOpenAI({ |
| 200 | + endpoint: endpoint, |
| 201 | + deployment: deployment, |
| 202 | + apiKey: apiKey, |
| 203 | + apiVersion: apiVersion, |
| 204 | + }); |
| 205 | + |
| 206 | + // OpenAI client |
| 207 | + const client = OpenAI({ |
| 208 | + apiKey: apiKey, |
| 209 | + }); |
| 210 | + |
| 211 | + const prompt = req.body.prompt; |
| 212 | + |
| 213 | + const chatCompletions = await client.chat.completions.create({ |
| 214 | + messages: [ |
| 215 | + { role: "system", content: "You are a helpful assistant" }, |
| 216 | + { role: "user", content: prompt }, |
| 217 | + ], |
| 218 | + model: "", |
| 219 | + max_tokens: 128, |
| 220 | + stream: true, |
| 221 | + }); |
| 222 | + |
| 223 | + var response = ""; |
| 224 | + |
| 225 | + for await (const chatCompletion of chatCompletions) { |
| 226 | + for (const choice of chatCompletion.choices) { |
| 227 | + response += choice.delta?.content; |
| 228 | + } |
| 229 | + } |
| 230 | + |
| 231 | + console.log(response); |
| 232 | + |
| 233 | + res.send(response); |
| 234 | +}); |
| 235 | +``` |
| 236 | +
|
| 237 | +This post function will create the OpenAI client and add the message being sent to OpenAI with a returned response. |
| 238 | +
|
| 239 | +Here’s the example in it’s complete form. In this example, use the Azure OpenAI chat completion service OR the OpenAI chat completion service, not both. |
| 240 | +
|
| 241 | +```jsx |
| 242 | +var createError = require('http-errors'); |
| 243 | +var express = require('express'); |
| 244 | +var path = require('path'); |
| 245 | +var cookieParser = require('cookie-parser'); |
| 246 | +var logger = require('morgan'); |
| 247 | +const { AzureOpenAI } = require("openai"); |
| 248 | +//import OpenAI from 'openai'; |
| 249 | + |
| 250 | +var indexRouter = require('./routes/index'); |
| 251 | +var usersRouter = require('./routes/users'); |
| 252 | + |
| 253 | +var app = express(); |
| 254 | + |
| 255 | +// view engine setup |
| 256 | +app.set('views', path.join(__dirname, 'views')); |
| 257 | +app.set('view engine', 'ejs'); |
| 258 | + |
| 259 | +app.use(logger('dev')); |
| 260 | +app.use(express.json()); |
| 261 | +app.use(express.urlencoded({ extended: false })); |
| 262 | +app.use(cookieParser()); |
| 263 | +app.use(express.static(path.join(__dirname, 'public'))); |
| 264 | + |
| 265 | +app.use('/', indexRouter); |
| 266 | +app.use('/users', usersRouter); |
| 267 | + |
| 268 | +// variables |
| 269 | +const endpoint = "your-openai-endpoint"; |
| 270 | +const apiKey = "your-openai-apikey"; |
| 271 | +const deployment = "your-openai-deployment-name"; |
| 272 | +const apiVersion = "your-openai-api-version"; |
| 273 | + |
| 274 | +// chat completion |
| 275 | +app.post("/api/completions", async (req, res) => { |
| 276 | + |
| 277 | + const client = new AzureOpenAI({ |
| 278 | + endpoint: endpoint, |
| 279 | + deployment: deployment, |
| 280 | + apiKey: apiKey, |
| 281 | + apiVersion: apiVersion, |
| 282 | + }); |
| 283 | + |
| 284 | + // OpenAI client |
| 285 | + // const client = OpenAI({ |
| 286 | + // apiKey: apiKey, |
| 287 | + // }); |
| 288 | + |
| 289 | + const prompt = req.body.prompt; |
| 290 | + |
| 291 | + const chatCompletions = await client.chat.completions.create({ |
| 292 | + messages: [ |
| 293 | + { role: "system", content: "You are a helpful assistant" }, |
| 294 | + { role: "user", content: prompt }, |
| 295 | + ], |
| 296 | + model: "", |
| 297 | + max_tokens: 128, |
| 298 | + stream: true, |
| 299 | + }); |
| 300 | + |
| 301 | + var response = ""; |
| 302 | + |
| 303 | + for await (const chatCompletion of chatCompletions) { |
| 304 | + for (const choice of chatCompletion.choices) { |
| 305 | + response += choice.delta?.content; |
| 306 | + } |
| 307 | + } |
| 308 | + |
| 309 | + console.log(response); |
| 310 | + |
| 311 | + res.send(response); |
| 312 | +}); |
| 313 | + |
| 314 | +// catch 404 and forward to error handler |
| 315 | +app.use(function(req, res, next) { |
| 316 | + next(createError(404)); |
| 317 | +}); |
| 318 | + |
| 319 | +// error handler |
| 320 | +app.use(function(err, req, res, next) { |
| 321 | + // set locals, only providing error in development |
| 322 | + res.locals.message = err.message; |
| 323 | + res.locals.error = req.app.get('env') === 'development' ? err : {}; |
| 324 | + |
| 325 | + // render the error page |
| 326 | + res.status(err.status || 500); |
| 327 | + res.render('error'); |
| 328 | +}); |
| 329 | + |
| 330 | +module.exports = app; |
| 331 | + |
| 332 | +``` |
| 333 | +
|
| 334 | +### Deploy to App Service |
| 335 | +
|
| 336 | +If you completed the steps above, you can deploy to App Service as you normally would. If you run into any issues, remember that you need to complete the following steps: grant your app access to your Key Vault, and add the app settings with key vault references as your values. App Service resolves the app settings in your application that match what you added in the portal. |
| 337 | +
|
| 338 | +Once the app is deployed, you can visit your site URL and see the text that contains the response from your chat message prompt. |
| 339 | +
|
| 340 | +### Authentication |
| 341 | +
|
| 342 | +Although optional, it's highly recommended that you also add authentication to your web app when using an Azure OpenAI or OpenAI service. This can add a level of security with no other code. Learn how to enable authentication for your web app [here](../../scenario-secure-app-authentication-app-service.md). |
| 343 | +
|
| 344 | +Once deployed, browse to the web app and navigate to the OpenAI tab. Enter a query to the service and you should see a populated response from the server. The tutorial is now complete and you now know how to use OpenAI services to create intelligent applications. |
0 commit comments