Skip to content

Commit 0ca514d

Browse files
committed
replace code include with inline code
1 parent bb41949 commit 0ca514d

File tree

1 file changed

+180
-2
lines changed

1 file changed

+180
-2
lines changed

articles/cognitive-services/LUIS/luis-nodejs-tutorial-bf-v4.md

Lines changed: 180 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,189 @@ In order to develop the web app bot code, download the code and use on your loca
105105

106106
1. Open the **dialogs -> luiHelper.js** file. This is where the user utterance entered into the bot is sent to LUIS. The response from LUIS is returned from the method as a **bookDetails** JSON object. When you create your own bot, you should also create your own object to return the details from LUIS.
107107

108-
[!code-javascript[This is where the user utterance entered into the bot is sent to LUIS.](~/samples-luis/documentation-samples/tutorial-web-app-bot/v4/luis-nodejs-bot-johnsmith-src/dialogs/luisHelper.js)]
108+
```nodejs
109+
// Copyright (c) Microsoft Corporation. All rights reserved.
110+
// Licensed under the MIT License.
111+
112+
const { LuisRecognizer } = require('botbuilder-ai');
113+
114+
class LuisHelper {
115+
/**
116+
* Returns an object with preformatted LUIS results for the bot's dialogs to consume.
117+
* @param {*} logger
118+
* @param {TurnContext} context
119+
*/
120+
static async executeLuisQuery(logger, context) {
121+
const bookingDetails = {};
122+
123+
try {
124+
const recognizer = new LuisRecognizer({
125+
applicationId: process.env.LuisAppId,
126+
endpointKey: process.env.LuisAPIKey,
127+
endpoint: `https://${ process.env.LuisAPIHostName }`
128+
}, {}, true);
129+
130+
const recognizerResult = await recognizer.recognize(context);
131+
132+
const intent = LuisRecognizer.topIntent(recognizerResult);
133+
134+
bookingDetails.intent = intent;
135+
136+
if (intent === 'Book_flight') {
137+
// We need to get the result from the LUIS JSON which at every level returns an array
138+
139+
bookingDetails.destination = LuisHelper.parseCompositeEntity(recognizerResult, 'To', 'Airport');
140+
bookingDetails.origin = LuisHelper.parseCompositeEntity(recognizerResult, 'From', 'Airport');
141+
142+
// This value will be a TIMEX. And we are only interested in a Date so grab the first result and drop the Time part.
143+
// TIMEX is a format that represents DateTime expressions that include some ambiguity. e.g. missing a Year.
144+
bookingDetails.travelDate = LuisHelper.parseDatetimeEntity(recognizerResult);
145+
}
146+
} catch (err) {
147+
logger.warn(`LUIS Exception: ${ err } Check your LUIS configuration`);
148+
}
149+
return bookingDetails;
150+
}
151+
152+
static parseCompositeEntity(result, compositeName, entityName) {
153+
const compositeEntity = result.entities[compositeName];
154+
if (!compositeEntity || !compositeEntity[0]) return undefined;
155+
156+
const entity = compositeEntity[0][entityName];
157+
if (!entity || !entity[0]) return undefined;
158+
159+
const entityValue = entity[0][0];
160+
return entityValue;
161+
}
162+
163+
static parseDatetimeEntity(result) {
164+
const datetimeEntity = result.entities['datetime'];
165+
if (!datetimeEntity || !datetimeEntity[0]) return undefined;
166+
167+
const timex = datetimeEntity[0]['timex'];
168+
if (!timex || !timex[0]) return undefined;
169+
170+
const datetime = timex[0].split('T')[0];
171+
return datetime;
172+
}
173+
}
174+
175+
module.exports.LuisHelper = LuisHelper;
176+
```
109177
110178
1. Open **dialogs -> bookingDialog.js** to understand how the BookingDetails object is used to manage the conversation flow. Travel details are asked in steps, then the entire booking is confirmed and finally repeated back to the user.
111179
112-
[!code-javascript[Understand how the BookingDetails object is used to manage the conversation flow.](~/samples-luis/documentation-samples/tutorial-web-app-bot/v4/luis-nodejs-bot-johnsmith-src/dialogs/bookingDialog.js)]
180+
```nodejs
181+
// Copyright (c) Microsoft Corporation. All rights reserved.
182+
// Licensed under the MIT License.
183+
184+
const { TimexProperty } = require('@microsoft/recognizers-text-data-types-timex-expression');
185+
const { ConfirmPrompt, TextPrompt, WaterfallDialog } = require('botbuilder-dialogs');
186+
const { CancelAndHelpDialog } = require('./cancelAndHelpDialog');
187+
const { DateResolverDialog } = require('./dateResolverDialog');
188+
189+
const CONFIRM_PROMPT = 'confirmPrompt';
190+
const DATE_RESOLVER_DIALOG = 'dateResolverDialog';
191+
const TEXT_PROMPT = 'textPrompt';
192+
const WATERFALL_DIALOG = 'waterfallDialog';
193+
194+
class BookingDialog extends CancelAndHelpDialog {
195+
constructor(id) {
196+
super(id || 'bookingDialog');
197+
198+
this.addDialog(new TextPrompt(TEXT_PROMPT))
199+
.addDialog(new ConfirmPrompt(CONFIRM_PROMPT))
200+
.addDialog(new DateResolverDialog(DATE_RESOLVER_DIALOG))
201+
.addDialog(new WaterfallDialog(WATERFALL_DIALOG, [
202+
this.destinationStep.bind(this),
203+
this.originStep.bind(this),
204+
this.travelDateStep.bind(this),
205+
this.confirmStep.bind(this),
206+
this.finalStep.bind(this)
207+
]));
208+
209+
this.initialDialogId = WATERFALL_DIALOG;
210+
}
211+
212+
/**
213+
* If a destination city has not been provided, prompt for one.
214+
*/
215+
async destinationStep(stepContext) {
216+
const bookingDetails = stepContext.options;
217+
218+
if (!bookingDetails.destination) {
219+
return await stepContext.prompt(TEXT_PROMPT, { prompt: 'To what city would you like to travel?' });
220+
} else {
221+
return await stepContext.next(bookingDetails.destination);
222+
}
223+
}
224+
225+
/**
226+
* If an origin city has not been provided, prompt for one.
227+
*/
228+
async originStep(stepContext) {
229+
const bookingDetails = stepContext.options;
230+
231+
// Capture the response to the previous step's prompt
232+
bookingDetails.destination = stepContext.result;
233+
if (!bookingDetails.origin) {
234+
return await stepContext.prompt(TEXT_PROMPT, { prompt: 'From what city will you be travelling?' });
235+
} else {
236+
return await stepContext.next(bookingDetails.origin);
237+
}
238+
}
239+
240+
/**
241+
* If a travel date has not been provided, prompt for one.
242+
* This will use the DATE_RESOLVER_DIALOG.
243+
*/
244+
async travelDateStep(stepContext) {
245+
const bookingDetails = stepContext.options;
246+
247+
// Capture the results of the previous step
248+
bookingDetails.origin = stepContext.result;
249+
if (!bookingDetails.travelDate || this.isAmbiguous(bookingDetails.travelDate)) {
250+
return await stepContext.beginDialog(DATE_RESOLVER_DIALOG, { date: bookingDetails.travelDate });
251+
} else {
252+
return await stepContext.next(bookingDetails.travelDate);
253+
}
254+
}
255+
256+
/**
257+
* Confirm the information the user has provided.
258+
*/
259+
async confirmStep(stepContext) {
260+
const bookingDetails = stepContext.options;
261+
262+
// Capture the results of the previous step
263+
bookingDetails.travelDate = stepContext.result;
264+
const msg = `Please confirm, I have you traveling to: ${ bookingDetails.destination } from: ${ bookingDetails.origin } on: ${ bookingDetails.travelDate }.`;
265+
266+
// Offer a YES/NO prompt.
267+
return await stepContext.prompt(CONFIRM_PROMPT, { prompt: msg });
268+
}
269+
270+
/**
271+
* Complete the interaction and end the dialog.
272+
*/
273+
async finalStep(stepContext) {
274+
if (stepContext.result === true) {
275+
const bookingDetails = stepContext.options;
276+
277+
return await stepContext.endDialog(bookingDetails);
278+
} else {
279+
return await stepContext.endDialog();
280+
}
281+
}
282+
283+
isAmbiguous(timex) {
284+
const timexPropery = new TimexProperty(timex);
285+
return !timexPropery.types.has('definite');
286+
}
287+
}
288+
289+
module.exports.BookingDialog = BookingDialog;
290+
```
113291
114292
115293
## Install dependencies and start the bot code in Visual Studio

0 commit comments

Comments
 (0)