UNPKG

@cognigy/rest-api-client

Version:

Cognigy REST-Client

266 lines 11.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.patternMatcher = void 0; const cognigySlots_1 = require("../../../../interfaces/cognigySlots"); const systemSlots = new Set(cognigySlots_1.cognigySystemSlots); /** * Finds compound slots using pattern inside the user input * @param input Cognigy Input Object * @param patterns The patterns to check for * @param patternGroupName Name for the compound group * @param detailedCompoundSlots Store detailed results for compound slots * @param tagExistingSlots Tag existing slots * @param createNewSlots Create new slots from tags * @param nluResult result from cognigy NLU since there was an alternative input */ const patternMatcher = (params) => { var _a; const { input, patternGroupName, detailedCompoundSlots, tagExistingSlots, createNewSlots, nluResult, useFullSystemslotText } = params; let { patterns } = params; // prune patterns if more than 20 if (patterns.length > 20) { patterns = patterns.slice(0, 20); } // firstly sort array to start with the longest patterns, as those will win patterns.sort((a, b) => { return b.length - a.length; }); // we use let because we strip out found phrases later let inputText = nluResult.text || input.text; // ci.processText let inputSlots = nluResult.slots || input.slots; const detailedSlots = ((_a = input.nlu) === null || _a === void 0 ? void 0 : _a.detailedSlots) || {}; const regexPatterns = []; // go through patterns and create regex versions of each that is not empty string patterns.forEach((pattern) => { if (pattern) { // set parsedPattern to pattern in case there are no slots let parsedPattern = pattern; // match all mentioned slots in the pattern const foundSlots = pattern.match(/\@[\w>]+/g); const tags = []; const slots = []; // if there are slots, process them if (Array.isArray(foundSlots) && foundSlots.length > 0) { foundSlots.forEach((slot) => { // splits tags from slots const split = slot.split(">"); const slotName = split[0].replace("@", ""); slots.push(slotName); // if there is a tag (SLOT>TAG), remember it if (split.length === 2) tags.push(split[1]); else tags.push(""); const slotValues = []; if (inputSlots[slotName]) { if (systemSlots.has(slotName)) { processFoundSystemSlots(useFullSystemslotText, inputSlots, detailedSlots, slotName, slotValues); } else { inputSlots[slotName].forEach((s) => { // it's important to use the synonym, as this is the text that was actually found slotValues.push(s.synonym); }); } const slotRegex = slotValues.join("|"); // replace the slots name with the list of actually found entites for this slot parsedPattern = parsedPattern.replace(new RegExp(`${slot}`, "g"), `(${slotRegex})`); } }); } if (parsedPattern != "()") { regexPatterns.push({ "pattern": pattern, "parsedPattern": parsedPattern, "tags": tags, "slots": slots }); } } }); const compoundGroups = []; // go through all created patterns and test them regexPatterns.forEach((pattern) => { let result; const regExp = new RegExp(pattern.parsedPattern, "gi"); const regexMatches = []; while (result = regExp.exec(inputText)) { regexMatches.push(result); } regexMatches.forEach((m) => { inputText = inputText.replace(m[0], ""); }); if (regexMatches.length > 0) { // we found a match for this pattern! regexMatches.forEach((matches, mi) => { // set up a compoundGroup scaffold, just in case we need it const matchedPatternGroup = { "matchedPhrase": matches[0], "components": [] }; if (!detailedCompoundSlots) delete matchedPatternGroup.components; // iterate through matches, starting at the first group result ([0] is the full match) for (let i = 1; i < matches.length; i++) { let originalSlot = null; const match = matches[i]; const slot = pattern.slots[i - 1]; if (systemSlots.has(slot)) { originalSlot = handleSystemSlotMatches(useFullSystemslotText, match, slot, inputSlots, detailedSlots); } else { originalSlot = inputSlots[pattern.slots[i - 1]].find(e => (e.synonym) ? e.synonym.toLowerCase() === matches[i].toLowerCase() : false); } // create compound groups if (detailedCompoundSlots) { const components = { "slot": pattern.slots[i - 1], "value": originalSlot.keyphrase || originalSlot }; if (pattern.tags[i - 1]) components["tag"] = pattern.tags[i - 1]; else components["tag"] = null; matchedPatternGroup.components.push(components); } else { if (pattern.tags[i - 1]) matchedPatternGroup[pattern.tags[i - 1]] = (originalSlot === null || originalSlot === void 0 ? void 0 : originalSlot.keyphrase) || originalSlot; else matchedPatternGroup[pattern.slots[i - 1]] = originalSlot || originalSlot.keyphrase; } if (pattern.tags[i - 1]) { if (createNewSlots) { if (inputSlots[pattern.tags[i - 1]]) { inputSlots[pattern.tags[i - 1]].push(originalSlot); } else inputSlots[pattern.tags[i - 1]] = [originalSlot]; } if (tagExistingSlots) { inputSlots[pattern.slots[i - 1]].forEach((s) => { var _a, _b; if (((_a = s === null || s === void 0 ? void 0 : s.synonym) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === ((_b = matches[i]) === null || _b === void 0 ? void 0 : _b.toLowerCase())) { s["tags"] = (Array.isArray(s["tags"])) ? s["tags"].push(pattern.tags[i - 1]) : [pattern.tags[i - 1]]; } }); } } } compoundGroups.push(matchedPatternGroup); }); } }); if (!input["matchedPatterns"]) input["matchedPatterns"] = {}; if (compoundGroups && Array.isArray(compoundGroups) && compoundGroups.length > 0) { input["matchedPatterns"][patternGroupName] = compoundGroups; } if (compoundGroups && compoundGroups.length === 0 && (typeof input["matchedPatterns"] !== 'object' || Object.keys(input["matchedPatterns"]).length === 0)) delete input["matchedPatterns"]; return input; }; exports.patternMatcher = patternMatcher; const processFoundSystemSlots = (useFullSystemslotText, inputSlots, detailedSlots, slotName, slotValues) => { var _a; if (useFullSystemslotText) { // we use the detailed system slots to get the text value (_a = detailedSlots[slotName]) === null || _a === void 0 ? void 0 : _a.forEach((s) => { slotValues.push(s.text); }); } else if (inputSlots[slotName]) { switch (slotName) { case "DATE": inputSlots.DATE.forEach((s) => { if (s.start) slotValues.push(s["text"]); }); break; case "NUMBER": inputSlots.NUMBER.forEach((s) => { slotValues.push(s); }); break; case "DURATION": inputSlots.DURATION.forEach((s) => { slotValues.push(s["years"] || s["months"] || s["weeks"] || s["days"] || s["hours"] || s["minutes"] || s["seconds"]); }); break; case "TEMPERATURE": inputSlots.TEMPERATURE.forEach((s) => { slotValues.push(s.value); }); break; case "AGE": inputSlots.AGE.forEach((s) => { slotValues.push(s.value); }); break; case "PERCENTAGE": inputSlots.PERCENTAGE.forEach((s) => { slotValues.push(s + "%"); slotValues.push(s + " percent"); }); break; case "EMAIL": inputSlots.EMAIL.forEach((s) => { slotValues.push(s); }); break; case "URL": inputSlots.URL.forEach((s) => { slotValues.push(s); }); break; case "MONEY": inputSlots.MONEY.forEach((s) => { slotValues.push(s.value); }); break; case "DISTANCE": inputSlots.DISTANCE.forEach((s) => { slotValues.push(s.value); }); break; } } }; const handleSystemSlotMatches = (useFullSystemslotText, match, slotName, inputSlots, detailedSlots) => { if (useFullSystemslotText) { const matchedSlot = detailedSlots[slotName].find(e => (e["text"] === match)); if (!matchedSlot) { return; } switch (slotName) { case "NUMBER": case "PERCENTAGE": return matchedSlot.data.value; case "DATE": return Object.assign(Object.assign({}, matchedSlot.data), { text: matchedSlot.text }); default: return matchedSlot.data; } } else { switch (slotName) { case "PERCENTAGE": return Number(match.replace(new RegExp("[^0-9]", "gi"), "")); case "TEMPERATURE": case "AGE": case "NUMBER": case "MONEY": case "DISTANCE": case "DURATION": return Number(match); case "DATE": // @ts-ignore const dateSlot = inputSlots.DATE.find(e => (e["text"] === match)); // @ts-ignore return (dateSlot === null || dateSlot === void 0 ? void 0 : dateSlot.start) || (dateSlot === null || dateSlot === void 0 ? void 0 : dateSlot.end); default: return match; } } }; //# sourceMappingURL=patternMatcher.js.map