botbuilder-dialogs
Version:
A dialog stack based conversation manager for Microsoft BotBuilder.
103 lines • 4.29 kB
JavaScript
/**
* @module botbuilder-dialogs
*/
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.recognizeChoices = void 0;
const Recognizers = require("@microsoft/recognizers-text-number");
const findChoices_1 = require("./findChoices");
/**
* High level function for recognizing a choice in a users utterance.
*
* @remarks
* This is layered above the `findChoices()` function and adds logic to let the user specify their
* choice by index (they can say "one" to pick `choice[0]`) or ordinal position (they can say "the
* second one" to pick `choice[1]`.) The users utterance is recognized in the following order:
*
* - By name using `findChoices()`.
* - By 1's based ordinal position.
* - By 1's based index position.
*
* ```JavaScript
* const { recognizeChoices } = require('botbuilder-choices');
*
* const choices = ['red', 'green', 'blue'];
* const utterance = context.activity.text;
* const results = recognizeChoices(utterance, choices);
* if (results.length == 1) {
* await context.sendActivity(`I like ${results[0].resolution.value} too!`);
* } else if (results.length > 1) {
* const ambiguous = results.map((r) => r.resolution.value);
* await context.sendActivity(ChoiceFactory.forChannel(context, ambiguous, `Which one?`));
* } else {
* await context.sendActivity(ChoiceFactory.forChannel(context, choices, `I didn't get that... Which color?`));
* }
* ```
* @param utterance The text or user utterance to search over. For an incoming 'message' activity you can simply use `context.activity.text`.
* @param choices List of choices to search over.
* @param options (Optional) options used to tweak the search that's performed.
* @returns A list of found choices, sorted by most relevant first.
*/
function recognizeChoices(utterance, choices, options) {
function matchChoiceByIndex(match) {
try {
const index = parseInt(match.resolution.value, 10) - 1;
if (index >= 0 && index < list.length) {
const choice = list[index];
matched.push({
start: match.start,
end: match.end,
typeName: 'choice',
text: match.text,
resolution: {
value: choice.value,
index: index,
score: 1,
},
});
}
}
catch (_a) {
// noop
// TODO: Should this log an error or do something?
}
}
// Initialize options
options = Object.assign({
locale: 'en-us',
recognizeNumbers: true,
recognizeOrdinals: true,
}, options);
// Normalize choices
const list = (choices || [])
.map((choice) => (typeof choice === 'string' ? { value: choice } : choice))
.filter((choice) => choice // TODO: does this do anything?
);
// Try finding choices by text search first
// - We only want to use a single strategy for returning results to avoid issues where utterances
// like the "the third one" or "the red one" or "the first division book" would miss-recognize as
// a numerical index or ordinal as well.
let matched = findChoices_1.findChoices(utterance, list, options);
if (matched.length === 0) {
// Next try finding by ordinal
if (options.recognizeOrdinals) {
const ordinals = Recognizers.recognizeOrdinal(utterance, options.locale);
ordinals.forEach(matchChoiceByIndex);
}
// Finally try by numerical index
if (matched.length === 0 && options.recognizeNumbers) {
Recognizers.recognizeNumber(utterance, options.locale).forEach(matchChoiceByIndex);
}
// Sort any found matches by their position within the utterance.
// - The results from findChoices() are already properly sorted so we just need this
// for ordinal & numerical lookups.
matched = matched.sort((a, b) => a.start - b.start);
}
return matched;
}
exports.recognizeChoices = recognizeChoices;
//# sourceMappingURL=recognizeChoices.js.map
;