UNPKG

6.3 kBJavaScriptView Raw
1const Util = require('./util');
2const RequestPreprocessor = require('./util/RequestPreprocessor');
3const _ = require('lodash');
4const md5 = require('md5');
5const IntentResolver = require('./util/IntentResolver');
6const AsksuiteTranslator = require('./util/Translator');
7const AsksuiteUtil = require('./asksuite.util')({});
8const DEFAULT_LANGUAGE = 'pt-br';
9
10class AsksuiteProcessingNaturalUtils {
11 static get EXPIRATION_TIME() {
12 return 60 * 60 * 24;
13 } // 24 hrs
14
15 constructor(config) {
16 this.config = config;
17
18 if (!_.isEmpty(_.get(this.config, 'redis'))) {
19 this.redis = this.config.redis;
20 }
21 }
22
23 withRedis() {
24 return !_.isEmpty(_.get(this.config, 'redis'));
25 }
26
27 resolveLanguage(paramLanguage, languages) {
28 let language;
29 if (languages) {
30 language = _.find(languages, _.matchesProperty('formatIso', paramLanguage));
31 if (language) {
32 return language.formatIso;
33 }
34
35 language = _.find(
36 languages,
37 _.matchesProperty('parentLanguage', paramLanguage.substring(0, 2)),
38 );
39 if (language) {
40 return language.formatIso;
41 }
42 }
43
44 language = paramLanguage.toLowerCase();
45
46 if (language.startsWith('pt')) {
47 return DEFAULT_LANGUAGE;
48 } else if (language.startsWith('en')) {
49 return 'en-us';
50 } else if (language.startsWith('es')) {
51 return 'es-es';
52 } else {
53 return language;
54 }
55 }
56
57 async getInCacheDialogflow(request) {
58 if (!this.withRedis()) {
59 return Promise.resolve(null);
60 }
61
62 const hash = this.generateHash(request);
63
64 const language = this.resolveLanguage(request.language, request.languages);
65
66 const data = await this.getInCache(`dialogflow:${language}:${hash}`);
67
68 if (!data) {
69 return Promise.resolve(null);
70 }
71
72 const { intent, extractedData } = data;
73 console.log(`OBTAINED BY CACHE ${intent}`);
74
75 return { intent, extractedData };
76 }
77
78 findDialogByIntent(request, intent) {
79 const { intents, companyId, text } = request;
80
81 const intentResolver = new IntentResolver(intents, companyId, text);
82 return intentResolver.findDialogByIntent(intent);
83 }
84
85 generateHash(request) {
86 const { text } = request;
87
88 const plainText = _.chain(text)
89 .deburr() // special characters
90 .toLower() // lowercase
91 .value() // get value from chain
92 .replace(/\s{2,}/g, ' ') // remove duplicate spaces
93 .replace(/[^\w\/@ ]/g, ''); // remove all characters dont in (word, /, @, space)
94
95 return md5(plainText || text);
96 }
97
98 async saveInCacheDialogflow(intent, request) {
99 if (!this.withRedis()) {
100 return Promise.resolve(null);
101 }
102
103 if (Util.isNaoentendi(intent.intent)) {
104 return Promise.resolve(null);
105 }
106
107 const { text } = request;
108 const hash = this.generateHash(request);
109
110 const language = this.resolveLanguage(request.language, request.languages);
111
112 return this.setInCache(`dialogflow:${language}:${hash}`, {
113 intent: intent.intent,
114 extractedData: intent.extractedData,
115 text,
116 hash,
117 });
118 }
119
120 async removeInCacheDialogflow({ text, language }) {
121 if (!this.withRedis()) {
122 return Promise.resolve(null);
123 }
124
125 const normalizedLanguage = this.resolveLanguage(language);
126
127 const hash = this.generateHash({ text });
128
129 const key = `dialogflow:${normalizedLanguage}:${hash}`;
130 return this.removeInCache(key);
131 }
132
133 async removeInCache(key) {
134 return this.redis.remove(`${key}`);
135 }
136
137 async getInCache(key) {
138 return this.redis.getValue(`${key}`);
139 }
140
141 async setInCache(key, intent) {
142 return this.redis.setValueWithExpirationTime(
143 `${key}`,
144 intent,
145 true,
146 AsksuiteProcessingNaturalUtils.EXPIRATION_TIME,
147 );
148 }
149
150 async translateRequest(request) {
151 if (
152 this.resolveLanguage(request.language, request.languages) !== DEFAULT_LANGUAGE &&
153 !request.translation
154 ) {
155 request.translated = true;
156
157 const asksuiteTranslator = new AsksuiteTranslator(
158 request.config.INFOCHAT_DATA_SERVER,
159 request.config.GOOGLE_TRANSLATE_KEY,
160 );
161 const { translation } = await asksuiteTranslator.googleTranslateIfNeeded(
162 request.text,
163 request.language,
164 request.languages,
165 );
166
167 request.translation = translation;
168 }
169 }
170
171 async detectLanguage(request) {
172 const { GOOGLE_TRANSLATE_KEY } = request.config;
173
174 const [detection] = await AsksuiteTranslator.detectLanguage(GOOGLE_TRANSLATE_KEY, request.text);
175
176 const re = /(pt|en|es|fr)/i;
177 const fallbackLanguage = 'en';
178 const languageCode = detection.language;
179 const isSupported = re.test(languageCode);
180 const outputLanguageCode = isSupported
181 ? this.resolveLanguage(languageCode, request.languages)
182 : fallbackLanguage;
183
184 const language = await AsksuiteTranslator.getLanguageByCode(
185 GOOGLE_TRANSLATE_KEY,
186 AsksuiteUtil.resolveLanguageGoogle(languageCode, request.languages, 'formatGoogle'),
187 AsksuiteUtil.resolveLanguageGoogle(outputLanguageCode, request.languages, 'formatGoogle'),
188 );
189
190 return Object.assign(detection, {
191 isSupported,
192 language,
193 fallbackLanguage,
194 });
195 }
196
197 async copyRequestToDefaultLanguage(request) {
198 await this.translateRequest(request);
199
200 const toSend = _.clone(request);
201 toSend.text = toSend.translation || toSend.text;
202 toSend.language = DEFAULT_LANGUAGE;
203
204 return RequestPreprocessor.process(toSend);
205 }
206
207 async findIntentDialogFlow(dialogFlowAccessor, request, toDefaultLanguage) {
208 if (toDefaultLanguage) {
209 await this.translateRequest(request);
210 }
211
212 let fromCache = false;
213
214 let toSend = request;
215 if (toDefaultLanguage) {
216 toSend = await this.copyRequestToDefaultLanguage(request);
217 }
218
219 let intent = await this.getInCacheDialogflow(toSend);
220 if (!intent) {
221 intent = await dialogFlowAccessor.resolveText(toSend);
222 await this.saveInCacheDialogflow(intent, toSend);
223 } else {
224 fromCache = true;
225 }
226 const extractedData = intent.extractedData;
227 intent = this.findDialogByIntent(toSend, intent.intent);
228
229 intent.fromCache = fromCache;
230 intent.extractedData = extractedData;
231
232 return intent;
233 }
234}
235
236module.exports = AsksuiteProcessingNaturalUtils;