optimize code based on comments
This commit is contained in:
Родитель
8db88f8ebb
Коммит
cd3bb6ea90
|
@ -5,6 +5,7 @@ const luParser = require('./../lufile/luParser');
|
|||
const SectionOperator = require('./../lufile/sectionOperator');
|
||||
const LUSectionTypes = require('./../utils/enums/lusectiontypes');
|
||||
const DiagnosticSeverity = require('./../lufile/diagnostic').DiagnosticSeverity;
|
||||
const NEWLINE = require('os').EOL;
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
|
@ -22,85 +23,11 @@ module.exports = {
|
|||
const intentName = crossTrainConfigObj.intentName;
|
||||
const verbose = crossTrainConfigObj.verbose;
|
||||
|
||||
let fileIdToLuResourceMap = new Map();
|
||||
for (const luObject of luObjectArray) {
|
||||
let luContent = luObject.content;
|
||||
luContent = helpers.sanitizeNewLines(luContent);
|
||||
if (luContent === undefined || luContent === '') {
|
||||
continue;
|
||||
}
|
||||
// parse lu content to LUResource object
|
||||
let fileIdToLuResourceMap = this.parseAndValidateLuContent(luObjectArray, verbose);
|
||||
|
||||
let luResource = luParser.parse(luContent);
|
||||
if (luResource.Errors && luResource.Errors.length > 0) {
|
||||
if (verbose) {
|
||||
var warns = luResource.Errors.filter(error => (error && error.Severity && error.Severity === DiagnosticSeverity.WARN));
|
||||
if (warns.length > 0) {
|
||||
process.stdout.write(warns.map(warn => warn.toString()).join('\n').concat('\n'));
|
||||
}
|
||||
}
|
||||
|
||||
var errors = luResource.Errors.filter(error => (error && error.Severity && error.Severity === DiagnosticSeverity.ERROR));
|
||||
if (errors.length > 0) {
|
||||
throw (new exception(retCode.errorCode.INVALID_LINE, errors.map(error => error.toString()).join('\n')));
|
||||
}
|
||||
}
|
||||
|
||||
fileIdToLuResourceMap.set(luObject.id, luResource);
|
||||
}
|
||||
|
||||
/*
|
||||
resources is array of below object
|
||||
{
|
||||
id: a.lu
|
||||
content: LUResource
|
||||
children: [ {target: "b.lu", intent: "b"} , {target: "c.lu", intent: "c"}]
|
||||
}
|
||||
*/
|
||||
let visitedChildren = new Set();
|
||||
let resources = [];
|
||||
let fileIdsFromInput = Array.from(fileIdToLuResourceMap.keys());
|
||||
for (const fileId of fileIdsFromInput) {
|
||||
let luResource = fileIdToLuResourceMap.get(fileId);
|
||||
let resource = {
|
||||
id: fileId,
|
||||
content: luResource,
|
||||
children: []
|
||||
};
|
||||
|
||||
if (fileId in triggerRules) {
|
||||
let intents = [];
|
||||
for (const section of luResource.Sections) {
|
||||
if (section.SectionType === LUSectionTypes.SIMPLEINTENTSECTION
|
||||
|| section.SectionType === LUSectionTypes.NESTEDINTENTSECTION) {
|
||||
intents.push(section);
|
||||
}
|
||||
}
|
||||
|
||||
const destLuFileToIntent = triggerRules[fileId];
|
||||
for (const destLuFile of Object.keys(destLuFileToIntent)) {
|
||||
if (fileIdsFromInput.includes(destLuFile)) {
|
||||
const triggerIntentName = destLuFileToIntent[destLuFile];
|
||||
if (intents.some(i => i.Name === triggerIntentName)) {
|
||||
if (visitedChildren.has(destLuFile)) {
|
||||
// validate loop in a tree or forest
|
||||
throw (new exception(retCode.errorCode.INVALID_INPUT, `Sorry, dialog call loop detected for lu file ${destLuFile} when doing cross training`));
|
||||
} else {
|
||||
resource.children.push({
|
||||
target: destLuFile,
|
||||
intent: triggerIntentName
|
||||
});
|
||||
|
||||
visitedChildren.add(destLuFile);
|
||||
}
|
||||
} else {
|
||||
throw (new exception(retCode.errorCode.INVALID_INPUT, `Sorry, trigger intent '${triggerIntentName}' is not found in lu file: ${fileId}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resources.push(resource);
|
||||
}
|
||||
// contruct resource tree to build the father-children relationship among lu files
|
||||
let resources = this.constructResoureTree(fileIdToLuResourceMap, triggerRules);
|
||||
|
||||
// do cross training from roots. One root one core training
|
||||
for (const rootObjectId of rootObjectIds) {
|
||||
|
@ -121,6 +48,101 @@ module.exports = {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Parse and validate luObject array to convert to LUResource object dict
|
||||
* @param {luObject[]} luObjectArray the luObject list to be parsed
|
||||
* @param {boolean} verbose indicate to enable log messages or not
|
||||
* @returns {Map<string, LUResource>} Map of file id and luResource
|
||||
* @throws {exception} Throws on errors. exception object includes errCode and text
|
||||
*/
|
||||
parseAndValidateLuContent: function (luObjectArray, verbose) {
|
||||
let fileIdToLuResourceMap = new Map();
|
||||
for (const luObject of luObjectArray) {
|
||||
let luContent = luObject.content;
|
||||
luContent = helpers.sanitizeNewLines(luContent);
|
||||
if (luContent === undefined || luContent === '') continue;
|
||||
|
||||
let luResource = luParser.parse(luContent);
|
||||
if (luResource.Errors && luResource.Errors.length > 0) {
|
||||
if (verbose) {
|
||||
var warns = luResource.Errors.filter(error => (error && error.Severity && error.Severity === DiagnosticSeverity.WARN));
|
||||
if (warns.length > 0) {
|
||||
process.stdout.write(warns.map(warn => warn.toString()).join(NEWLINE).concat(NEWLINE));
|
||||
}
|
||||
}
|
||||
|
||||
var errors = luResource.Errors.filter(error => (error && error.Severity && error.Severity === DiagnosticSeverity.ERROR));
|
||||
if (errors.length > 0) {
|
||||
throw (new exception(retCode.errorCode.INVALID_LINE, errors.map(error => error.toString()).join(NEWLINE)));
|
||||
}
|
||||
}
|
||||
|
||||
fileIdToLuResourceMap.set(luObject.id, luResource);
|
||||
}
|
||||
|
||||
return fileIdToLuResourceMap;
|
||||
},
|
||||
|
||||
/**
|
||||
* Contruct resource tree to build the father-children relationship among lu files
|
||||
* @param {Map<string, LUResource>} fileIdToLuResourceMap Map of file id and luResource
|
||||
* @param {any} triggerRules trigger rules object that indicate the triggering rules from root to dest lu files
|
||||
* @returns {any[]} Object array of LUResource with id and children properties
|
||||
* @throws {exception} Throws on errors. exception object includes errCode and text
|
||||
*/
|
||||
constructResoureTree(fileIdToLuResourceMap, triggerRules) {
|
||||
let visitedChildren = new Set();
|
||||
let resources = [];
|
||||
let fileIdsFromInput = Array.from(fileIdToLuResourceMap.keys());
|
||||
for (const fileId of fileIdsFromInput) {
|
||||
let luResource = fileIdToLuResourceMap.get(fileId);
|
||||
let resource = {
|
||||
id: fileId,
|
||||
content: luResource,
|
||||
children: []
|
||||
};
|
||||
|
||||
if (!(fileId in triggerRules)) {
|
||||
resources.push(resource);
|
||||
continue;
|
||||
}
|
||||
|
||||
let intents = [];
|
||||
for (const section of luResource.Sections) {
|
||||
if (section.SectionType === LUSectionTypes.SIMPLEINTENTSECTION
|
||||
|| section.SectionType === LUSectionTypes.NESTEDINTENTSECTION) {
|
||||
intents.push(section);
|
||||
}
|
||||
}
|
||||
|
||||
const destLuFileToIntent = triggerRules[fileId];
|
||||
for (const destLuFile of Object.keys(destLuFileToIntent)) {
|
||||
if (!fileIdsFromInput.includes(destLuFile)) continue;
|
||||
|
||||
if (visitedChildren.has(destLuFile)) {
|
||||
// validate loop in a tree or forest
|
||||
throw (new exception(retCode.errorCode.INVALID_INPUT, `Sorry, dialog call loop detected for lu file ${destLuFile} when doing cross training`));
|
||||
}
|
||||
|
||||
const triggerIntentName = destLuFileToIntent[destLuFile];
|
||||
if (!intents.some(i => i.Name === triggerIntentName)) {
|
||||
throw (new exception(retCode.errorCode.INVALID_INPUT, `Sorry, trigger intent '${triggerIntentName}' is not found in lu file: ${fileId}`));
|
||||
}
|
||||
|
||||
resource.children.push({
|
||||
target: destLuFile,
|
||||
intent: triggerIntentName
|
||||
});
|
||||
|
||||
visitedChildren.add(destLuFile);
|
||||
}
|
||||
|
||||
resources.push(resource);
|
||||
}
|
||||
|
||||
return resources;
|
||||
},
|
||||
|
||||
/**
|
||||
* Cross training core function. Do cross training from a root to its children once.
|
||||
* @param {string} rootResourceId the root resource object id
|
||||
|
@ -144,16 +166,16 @@ module.exports = {
|
|||
},
|
||||
|
||||
mergeRootInteruptionToLeaves: function (rootResource, result, intentName) {
|
||||
if (rootResource && rootResource.children && rootResource.children.length > 0) {
|
||||
this.mergeBrothersInteruption(rootResource, result, intentName)
|
||||
for (const child of rootResource.children) {
|
||||
let childResource = result.get(child.target);
|
||||
if (childResource.visited === undefined) {
|
||||
const newChildResource = this.mergeFatherInteruptionToChild(rootResource, childResource, intentName);
|
||||
result.set(child.target, newChildResource);
|
||||
newChildResource.visited = true;
|
||||
this.mergeRootInteruptionToLeaves(newChildResource, result, intentName);
|
||||
}
|
||||
if (rootResource.children === undefined || rootResource.length <= 0) return;
|
||||
|
||||
this.mergeBrothersInteruption(rootResource, result, intentName)
|
||||
for (const child of rootResource.children) {
|
||||
let childResource = result.get(child.target);
|
||||
if (childResource.visited === undefined) {
|
||||
const newChildResource = this.mergeFatherInteruptionToChild(rootResource, childResource, intentName);
|
||||
result.set(child.target, newChildResource);
|
||||
newChildResource.visited = true;
|
||||
this.mergeRootInteruptionToLeaves(newChildResource, result, intentName);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -205,34 +227,34 @@ module.exports = {
|
|||
let newFileContent = '';
|
||||
fromUtterances.forEach(utterance => {
|
||||
if (!existingUtterances.includes(utterance)) {
|
||||
newFileContent += '- ' + utterance + '\r\n';
|
||||
newFileContent += '- ' + utterance + NEWLINE;
|
||||
}
|
||||
});
|
||||
|
||||
if (newFileContent !== '') {
|
||||
newFileContent = toInteruption.ParseTree.intentDefinition().getText().trim() + '\r\n' + newFileContent;
|
||||
let lines = newFileContent.split(/\r?\n/);
|
||||
let newLines = [];
|
||||
lines.forEach(line => {
|
||||
if (line.trim().startsWith('-')) {
|
||||
newLines.push('- ' + line.trim().slice(1).trim());
|
||||
} else if (line.trim().startsWith('##')) {
|
||||
newLines.push('## ' + line.trim().slice(2).trim());
|
||||
} else if (line.trim().startsWith('#')) {
|
||||
newLines.push('# ' + line.trim().slice(1).trim());
|
||||
}
|
||||
})
|
||||
if (newFileContent === '') return toResource;
|
||||
|
||||
newFileContent = newLines.join('\r\n');
|
||||
newFileContent = toInteruption.ParseTree.intentDefinition().getText().trim() + NEWLINE + newFileContent;
|
||||
let lines = newFileContent.split(/\r?\n/);
|
||||
let newLines = [];
|
||||
lines.forEach(line => {
|
||||
if (line.trim().startsWith('-')) {
|
||||
newLines.push('- ' + line.trim().slice(1).trim());
|
||||
} else if (line.trim().startsWith('##')) {
|
||||
newLines.push('## ' + line.trim().slice(2).trim());
|
||||
} else if (line.trim().startsWith('#')) {
|
||||
newLines.push('# ' + line.trim().slice(1).trim());
|
||||
}
|
||||
})
|
||||
|
||||
// update section here
|
||||
toResource.content = new SectionOperator(toResource.content).updateSection(toInteruption.Id, newFileContent);
|
||||
}
|
||||
newFileContent = newLines.join(NEWLINE);
|
||||
|
||||
// update section here
|
||||
toResource.content = new SectionOperator(toResource.content).updateSection(toInteruption.Id, newFileContent);
|
||||
} else {
|
||||
// construct new content here
|
||||
if (fromUtterances && fromUtterances.length > 0) {
|
||||
let newFileContent = `\r\n# ${intentName}\r\n`;
|
||||
fromUtterances.forEach(utterance => newFileContent += '- ' + utterance + '\r\n');
|
||||
let newFileContent = NEWLINE + `# ${intentName}` + NEWLINE;
|
||||
fromUtterances.forEach(utterance => newFileContent += '- ' + utterance + NEWLINE);
|
||||
|
||||
// add section here
|
||||
toResource.content = new SectionOperator(toResource.content).addSection(newFileContent);
|
||||
|
|
Загрузка…
Ссылка в новой задаче