UNPKG

asksuite-core

Version:
286 lines (225 loc) 8.34 kB
const Util = require('./util'); const RequestPreprocessor = require('./util/RequestPreprocessor'); const _ = require('lodash'); const IntentResolver = require('./util/IntentResolver'); const AsksuiteTranslator = require('./util/Translator'); const StringUtils = require('./util/StringUtils'); const AsksuiteUtil = require('./asksuite.util')({}); const DEFAULT_LANGUAGE = 'pt-br'; class AsksuiteProcessingNaturalUtils { static get EXPIRATION_TIME() { return 60 * 60 * 24; } // 24 hrs constructor(config) { this.config = config; if (!_.isEmpty(_.get(this.config, 'redis'))) { this.redis = this.config.redis; } } withRedis() { return !_.isEmpty(_.get(this.config, 'redis')); } resolveLanguage(paramLanguage, languages) { let language; if (languages) { language = _.find(languages, _.matchesProperty('formatIso', paramLanguage)); if (language) { return language.formatIso; } language = _.find( languages, _.matchesProperty('parentLanguage', paramLanguage.substring(0, 2)), ); if (language) { return language.formatIso; } } language = paramLanguage.toLowerCase(); if (language.startsWith('pt')) { return DEFAULT_LANGUAGE; } else if (language.startsWith('en')) { return 'en-us'; } else if (language.startsWith('es')) { return 'es-es'; } else { return language; } } async getInCacheDialogflow(request) { if (!this.withRedis()) { return Promise.resolve(null); } const hash = StringUtils.generateHash(request.text); const language = this.resolveLanguage(request.language, request.languages); const data = await this.getInCache(`dialogflow:${language}:${hash}`); if (!data) { return Promise.resolve(null); } const { intent, extractedData, processingStep, parameterFields } = data; console.log(`OBTAINED BY CACHE ${intent}`); return { intent, extractedData, processingStep, parameterFields }; } findDialogByIntent(request, intent) { const { intents, companyId, text } = request; const intentResolver = new IntentResolver(intents, companyId, text); return intentResolver.findDialogByIntent(intent); } async saveInCacheDialogflow(intent, request) { if (!this.withRedis()) { return Promise.resolve(null); } if (Util.isNaoentendi(intent.intent)) { return Promise.resolve(null); } const { text } = request; const hash = StringUtils.generateHash(text); const language = this.resolveLanguage(request.language, request.languages); return this.setInCache(`dialogflow:${language}:${hash}`, { intent: intent.intent, extractedData: intent.extractedData, processingStep: intent.processingStep, text, hash, }); } async removeInCacheDialogflow({ text, language }) { if (!this.withRedis()) { return Promise.resolve(null); } const normalizedLanguage = this.resolveLanguage(language); const hash = StringUtils.generateHash(text); const key = `dialogflow:${normalizedLanguage}:${hash}`; return this.removeInCache(key); } async removeInCache(key) { return this.redis.remove(`${key}`); } async getInCache(key) { return this.redis.getValue(`${key}`); } async setInCache(key, intent) { return this.redis.setValueWithExpirationTime( `${key}`, intent, true, AsksuiteProcessingNaturalUtils.EXPIRATION_TIME, ); } async translateRequest(request) { if ( AsksuiteUtil.resolveLanguageGoogle(request.language, request.languages, 'formatGoogle') !== AsksuiteUtil.resolveLanguageGoogle(DEFAULT_LANGUAGE, request.languages, 'formatGoogle') && !request.translation ) { request.translated = true; const asksuiteTranslator = new AsksuiteTranslator( request.config.INFOCHAT_DATA_SERVER, request.config.GOOGLE_TRANSLATE_KEY, request.config.TRANSLATION_API_URL ); const { translation } = await asksuiteTranslator.translateByTranslationApi(request.text, request.language, 'pt-br', request.languages); request.translation = translation; } } defineRegexLanguages(languages) { if (!languages || _.isEmpty(languages)) { return new RegExp('(pt|en|es|fr)', 'i'); } const joinedLanguages = _.chain(languages) .map(formatIso => formatIso.split('-')[0]) .uniq() .join('|') .value(); return new RegExp(`(${joinedLanguages})`, 'i'); } async detectLanguage(request) { const { GOOGLE_TRANSLATE_KEY } = request.config; const [detection] = await AsksuiteTranslator.detectLanguage(GOOGLE_TRANSLATE_KEY, request.text); const detectedLanguageCode = detection.language; const companyLanguagesRegex = this.defineRegexLanguages(request.companyLanguages); const isSupportedByCompany = companyLanguagesRegex.test(detectedLanguageCode); const fallbackLanguageCode = request.defaultLanguage; const outputLanguageCode = isSupportedByCompany ? detectedLanguageCode : fallbackLanguageCode; const googleOutputLanguageCode = AsksuiteUtil.resolveLanguageGoogle( outputLanguageCode, request.languages, 'formatGoogle', ); const language = await AsksuiteTranslator.getLanguageByCode( GOOGLE_TRANSLATE_KEY, detectedLanguageCode, googleOutputLanguageCode, ); const fallbackLanguage = await AsksuiteTranslator.getLanguageByCode( GOOGLE_TRANSLATE_KEY, fallbackLanguageCode, googleOutputLanguageCode, ); return Object.assign(detection, { isSupported: isSupportedByCompany, language, fallbackLanguage, }); } async detectLanguageByTranslationsApi(request) { const asksuiteTranslator = new AsksuiteTranslator( request.config.INFOCHAT_DATA_SERVER, request.config.GOOGLE_TRANSLATE_KEY, request.config.TRANSLATION_API_URL ); const detectedLanguageCode = await asksuiteTranslator.detectLanguageByTranslationsApi(request.text); const detectedLanguage = { code: detectedLanguageCode.code, name: detectedLanguageCode.name } const companyLanguagesRegex = this.defineRegexLanguages(request.companyLanguages); const isSupportedByCompany = companyLanguagesRegex.test(detectedLanguage.code); const fallbackLanguage = { code: request.defaultLanguage }; const language = isSupportedByCompany ? detectedLanguage : fallbackLanguage; return { isSupported: isSupportedByCompany, language, fallbackLanguage, }; } isLanguageSupportedByCompany(request, languageCode) { const companyLanguagesRegex = this.defineRegexLanguages(request.companyLanguages); const isSupportedByCompany = companyLanguagesRegex.test(languageCode); return isSupportedByCompany; } async copyRequestToDefaultLanguage(request) { await this.translateRequest(request); const toSend = _.clone(request); toSend.text = toSend.translation || toSend.text; toSend.language = this.resolveLanguage(DEFAULT_LANGUAGE, request.languages); return RequestPreprocessor.process(toSend); } async findIntentDialogFlow(dialogFlowAccessor, request, toDefaultLanguage) { if (toDefaultLanguage) { await this.translateRequest(request); } let fromCache = false; let toSend = _.cloneDeep(request); if (toDefaultLanguage) { toSend = await this.copyRequestToDefaultLanguage(request); } let intent = await this.getInCacheDialogflow(toSend); if (!intent) { intent = await dialogFlowAccessor.resolveText(toSend); await this.saveInCacheDialogflow(intent, toSend); } else { fromCache = true; } const extractedData = intent.extractedData; const processingStep = intent.processingStep; const parameterFields = intent.parameterFields; intent = this.findDialogByIntent(toSend, intent.intent); const translatedFrom = 'translation_api'; intent.fromCache = fromCache; intent.extractedData = extractedData; intent.processingStep = { ...processingStep, translatedFrom: request.translated ? translatedFrom : null }; intent.parameterFields = parameterFields; return intent; } } module.exports = AsksuiteProcessingNaturalUtils;