UNPKG

8.23 kBJavaScriptView Raw
1const AWSLambdaCaller = require('./services/AWSLambdaCaller');
2const Util = require('./util');
3const MediaResolver = require('./util/MediaResolver');
4const DialogFlowAccessor = require('./services/DialogFlowAccessor');
5const QuoteDataAccessor = require('./services/QuoteDataAccessor');
6const KeyMatcherAccessor = require('./services/KeyMatcherAccessor');
7const RasaAccessor = require('./services/RasaAccessor');
8const RasaLayersAccessor = require('./services/RasaLayersAccessor');
9const RasaLayersRedisService = require('./services/RasaLayersRedisService');
10const defaultFallbackIntent = require('./util/defaultFallbackIntent');
11const RequestPreprocessor = require('./util/RequestPreprocessor');
12const AsksuiteProcessingNaturalUtils = require('./AsksuiteProcessingNaturalUtils');
13const NodeCache = require('node-cache');
14
15const DEFAULT_LANGUAGE = 'pt-br';
16
17const intentsNotFoundCache = new NodeCache({ stdTTL: 300, checkperiod: 120 });
18
19class AsksuiteProcessingNatural {
20 static get ORDERED_ACCESSORS() {
21 return ['RASA_LAYERS', 'DIALOG_FLOW', 'RASA', 'KEY_MATCHER'];
22 } // Robot will search for intents in this order default
23 static get RASA_FIRST_ORDERED_ACCESSORS() {
24 return ['RASA', 'RASA_LAYERS', 'DIALOG_FLOW', 'KEY_MATCHER'];
25 } // Robot will search for intents in this order if tryRasaFirst option is set to true
26
27 constructor(config) {
28 this.config = config;
29 this.utils = new AsksuiteProcessingNaturalUtils(this.config);
30 this.rasaLayersRedisService = new RasaLayersRedisService({
31 config: config.config,
32 redis: config.redis,
33 });
34 }
35
36 findIntent(request) {
37 return new Promise((resolve, reject) => {
38 const executor = async request => {
39 let intent = {
40 fromCache: false,
41 };
42
43 request = await RequestPreprocessor.process(request);
44
45 const awsLambdaCaller = new AWSLambdaCaller(request.config.CORE_LAMBDA_AWS);
46 const dialogFlowAccessor = new DialogFlowAccessor(awsLambdaCaller);
47 const keyMatcherAccessor = new KeyMatcherAccessor(awsLambdaCaller);
48 const rasaAccessor = new RasaAccessor(
49 request.config.RASA_URL,
50 request.config.RASA_CONFIDENCE_THRESHOLD,
51 );
52 const rasaLayersAccessor = new RasaLayersAccessor(awsLambdaCaller);
53
54 let orderOption = AsksuiteProcessingNatural.ORDERED_ACCESSORS;
55 if (request.tryRasaFirst) {
56 orderOption = AsksuiteProcessingNatural.RASA_FIRST_ORDERED_ACCESSORS;
57 }
58
59 request.findIntent = defaultFallbackIntent(request.companyId);
60 request.translated = false;
61 request.translation = null;
62
63 for (const accessorName of orderOption) {
64 switch (accessorName) {
65 case 'DIALOG_FLOW':
66 intent = await this.utils.findIntentDialogFlow(dialogFlowAccessor, request, false);
67
68 if (
69 Util.isNaoentendi(intent.intent) &&
70 this.utils.resolveLanguage(request.language, request.languages) !== DEFAULT_LANGUAGE
71 ) {
72 intent = await this.utils.findIntentDialogFlow(dialogFlowAccessor, request, true);
73 }
74
75 break;
76 case 'KEY_MATCHER':
77 intent = await keyMatcherAccessor.resolveText(request);
78
79 if (
80 Util.isNaoentendi(intent.intent) &&
81 this.utils.resolveLanguage(request.language, request.languages) !== DEFAULT_LANGUAGE
82 ) {
83 const toSend = await this.utils.copyRequestToDefaultLanguage(request);
84 intent = await keyMatcherAccessor.resolveText(toSend);
85 }
86
87 intent.keywordTry = { try: true };
88 break;
89 case 'RASA':
90 intent = await rasaAccessor.resolveText(request, request.needsRasaEntityConfident);
91 break;
92 case 'RASA_LAYERS':
93 if (request.order && request.order.length) {
94 let cached = null;
95 try {
96 cached = await this.rasaLayersRedisService.resolveText(
97 request.text,
98 request.language,
99 request.order,
100 request.languages,
101 );
102 } catch (e) {
103 console.error(e);
104 }
105
106 intent = cached ? cached : await rasaLayersAccessor.resolveText(request);
107 }
108 break;
109 }
110
111 request.findIntent = intent;
112
113 if (intent.intent && !Util.isNaoentendi(intent.intent)) {
114 intent.resolver = accessorName;
115
116 if (intent.resolver === 'KEY_MATCHER') {
117 intent.keywordTry.match = intent.intent;
118 intent.keywordTry.intent = intent.intent;
119 } else if (intent.resolver === 'RASA_LAYERS') {
120 await this.rasaLayersRedisService
121 .saveToCache(
122 intent,
123 request.text,
124 request.language,
125 intent.order,
126 request.languages,
127 )
128 .catch(console.error);
129 }
130
131 //FOR exit condition
132 break;
133 }
134 }
135
136 const language = this.utils.resolveLanguage(request.language, request.languages);
137 const key = `${request.companyId}.${request.userId}.${language}`;
138
139 if (Util.isNaoentendi(intent.intent)) {
140 let count = intentsNotFoundCache.get(key) || 0;
141 intentsNotFoundCache.set(key, ++count);
142
143 const {
144 ATTEMPTS_BEFORE_DETECTING_LANGUAGE,
145 LANGUAGE_DETECTION_CONFIDENCE,
146 } = request.config;
147
148 if (count === ATTEMPTS_BEFORE_DETECTING_LANGUAGE) {
149 const detection = await this.utils.detectLanguage(request);
150
151 if (detection.confidence >= LANGUAGE_DETECTION_CONFIDENCE) {
152 const languageCode = detection.isSupported
153 ? detection.language.code
154 : detection.fallbackLanguage;
155
156 if (request.language.substring(0, 2) !== languageCode.substring(0, 2)) {
157 intent.languageDetected = detection;
158 intentsNotFoundCache.del(key);
159 }
160 }
161 }
162
163 if (count > 1 && !intent.languageDetected) {
164 const fallbackIntent = defaultFallbackIntent(request.companyId, count);
165 intent = this.utils.findDialogByIntent(request, fallbackIntent.intent);
166 }
167 } else {
168 intentsNotFoundCache.del(key);
169 }
170
171 intent.translated = request.translated;
172 intent.translation = request.translation;
173
174 return intent;
175 };
176
177 executor(request)
178 .then(resolve)
179 .catch(reject);
180 });
181 }
182
183 resolveMedia(request) {
184 return new Promise((resolve, reject) => {
185 try {
186 const mediaResolver = new MediaResolver(request.companyId);
187 mediaResolver
188 .resolve(request.media, request.intents)
189 .then(resolve)
190 .catch(reject);
191 } catch (e) {
192 reject(e);
193 }
194 });
195 }
196
197 async extractQuoteData(request) {
198 request = await RequestPreprocessor.process(request);
199
200 const awsLambdaCaller = new AWSLambdaCaller(request.config.CORE_LAMBDA_AWS);
201 const quoteDataAccessor = new QuoteDataAccessor(awsLambdaCaller);
202
203 return await quoteDataAccessor.resolveText(request);
204 }
205
206 async extractTextNumbers(request) {
207 request = await RequestPreprocessor.process(request);
208
209 const awsLambdaCaller = new AWSLambdaCaller(request.config.CORE_LAMBDA_AWS);
210 const quoteDataAccessor = new QuoteDataAccessor(awsLambdaCaller);
211
212 return await quoteDataAccessor.resolveTextNumbers(request);
213 }
214
215 async findRasaIntent(request) {
216 let intent = {};
217
218 intent = defaultFallbackIntent(request.companyId);
219 request.findIntent = intent;
220
221 request = await this.utils.copyRequestToDefaultLanguage(request);
222 const rasaAccessor = new RasaAccessor(
223 request.config.RASA_URL,
224 request.config.RASA_CONFIDENCE_THRESHOLD,
225 );
226
227 return await rasaAccessor.resolveText(request, request.needsRasaEntityConfident);
228 }
229}
230
231module.exports = AsksuiteProcessingNatural;