UNPKG

3.4 kBJavaScriptView Raw
1'use strict';
2const _ = require('lodash');
3const bases = require('bases');
4const builtInSlotsMap = require('./built-in-slots-map');
5const builtInIntentsMap = require('./built-in-intents-map');
6const validator = require('./validator');
7
8/**
9 * Creates intent
10 * @param {Object[]} intents - Array of intents. Required for determining taken intent names
11 * @param {string} name - Name of the intent. If null or undefined, automatically generated intent name is used
12 * @param {(string|string[])} richUtterances - Utterance or array of rich utterances
13 * @param {function} handler - Function to be called when intent is invoked
14 */
15module.exports = (intents, name, richUtterances, handler) => {
16 // Convert utterances to array
17 richUtterances = _.isArray(richUtterances) ? richUtterances : [richUtterances];
18
19 // If intent name is not specified, try to generate unique one
20 if(!name) {
21 name = generateIntentName(intents);
22
23 } else if(!validator.isNameValid(name)) {
24 throw Error(`Intent name ${name} is invalid. Only lowercase and uppercase letters are allowed`);
25
26 } else if(builtInIntentsMap[name]) {
27 // If built-in intent name was used map intent name to it
28 name = builtInIntentsMap[name];
29 }
30
31 // Transformed slots and utterances from richUtterances
32 let slots = [];
33 let utterances = [];
34
35 parseRichUtterances(richUtterances, slots, utterances)
36
37 return {
38 name: name,
39 slots: slots,
40 utterances: utterances,
41 handler: handler
42 };
43}
44
45const generateIntentName = (intents) => {
46 let position = 0;
47 let generatedName;
48
49 // While generated name is not already used and generatedName is not built-in intent (just in case)
50 while(intents[(generatedName = bases.toBase52(position++))] && !builtInIntentsMap[generatedName]);
51
52 return generatedName;
53};
54
55const parseRichUtterances = (richUtterances, slots, utterances) => {
56 // Iterate over each rich utterance and transform it by removing slots description
57 _.each(richUtterances, function(utterance) {
58 var matches = findUtteranceMatches(utterance);
59
60 _.each(matches, function(match) {
61
62 // Remember slot type
63 slots.push({
64 name: match[1],
65 type: transformSlotType(match[2])
66 });
67
68 // Replace utterance slot type (there could be multiple slots in utterance)
69 utterance = utterance.replace(match[0], '{' + match[1] + '}');
70 });
71
72 if(validator.isUtteranceValid(utterance)) {
73 // Remember utterance
74 utterances.push(utterance);
75 } else {
76 throw new Error(`Error: Sample utterance: '${utterance}' is not valid. Each sample utterance must consist only of alphabet characters, spaces, dots, hyphens, brackets and single quotes`);
77 }
78
79 });
80};
81
82const transformSlotType = (type) => {
83 const transformedType = builtInSlotsMap[type];
84 return transformedType ? transformedType : type;
85}
86
87const findUtteranceMatches = (utterance) => {
88 // Example: for 'move forward by {value:Number}' we get:
89 // [[ '{value:Number}', 'value', 'Number', index: 16, input: 'move forward by {value:Number}' ]]
90 var myregex = /{(.*?):(.*?)\}/gmi;
91 var result, allMatches = [];
92
93 while((result = myregex.exec(utterance)) != null) {
94 allMatches.push(result);
95 }
96
97 return allMatches;
98}
\No newline at end of file