diff --git a/packages/lu/package.json b/packages/lu/package.json index a81e6b31e..1c5dd0bda 100644 --- a/packages/lu/package.json +++ b/packages/lu/package.json @@ -43,6 +43,7 @@ "delay": "^4.3.0", "fs-extra": "^8.1.0", "get-stdin": "^6.0.0", + "globby": "^10.0.1", "intercept-stdout": "^0.1.2", "lodash": "^4.17.15", "node-fetch": "^2.1.2", @@ -57,7 +58,6 @@ "@types/mocha": "^5.2.7", "@types/node": "^10.14.15", "chai": "^4.2.0", - "globby": "^10.0.1", "mocha": "^6.2.2", "nock": "^11.7.0", "nyc": "^14.1.1", diff --git a/packages/lu/src/parser/cross-train/cross-train.js b/packages/lu/src/parser/cross-train/cross-train.js index 31a2865a6..37b85fa02 100644 --- a/packages/lu/src/parser/cross-train/cross-train.js +++ b/packages/lu/src/parser/cross-train/cross-train.js @@ -8,7 +8,7 @@ const path = require('path') const file = require('../../utils/filehelper') const fileExtEnum = require('../utils/helpers').FileExtTypeEnum const exception = require('../utils/exception') -const retCode = require('../utils/enums/CLI-errors'); +const retCode = require('../utils/enums/CLI-errors') const crossTrainer = require('./crossTrainer') module.exports = { @@ -16,36 +16,19 @@ module.exports = { * Cross train lu and qna files. * @param {string} input input lu and qna files folder. * @param {string} intentName interruption intent name. Default value is _Interruption. - * @param {string} configPath path to config of mapping rules. If undefined, it will read config.json from input folder. + * @param {string} config path to config of mapping rules or mapping rules json content itself. If undefined, it will read config.json from input folder. * @returns {luResult: any, qnaResult: any} trainedResult of luResult and qnaResult or undefined if no results. */ - train: async function (input, intentName, configPath) { - let trainedResult + train: async function (input, intentName, config) { + // Get all related file content. + const luContents = await file.getFilesContent(input, fileExtEnum.LUFile) + const qnaContents = await file.getFilesContent(input, fileExtEnum.QnAFile) + const configContent = config && !fs.existsSync(config) ? {id: path.join(input, 'config.json'), content: config} : await file.getConfigContent(config || input) - // Parse lu and qna objects - const luObjects = await file.getLuObjects(undefined, input, true, fileExtEnum.LUFile) - const qnaObjects = await file.getLuObjects(undefined, input, true, fileExtEnum.QnAFile) - - let configObject - if (configPath && configPath !== '') { - configObject = await file.getConfigObject(configPath) - } else { - configObject = await file.getConfigObject(input) - } - - if (configObject.rootIds.length > 0) { - let crossTrainConfig = { - rootIds: configObject.rootIds, - triggerRules: configObject.triggerRules, - intentName: intentName, - verbose: true - } - - trainedResult = crossTrainer.crossTrain(luObjects, qnaObjects, JSON.stringify(crossTrainConfig)) - } else { - throw (new exception(retCode.errorCode.INVALID_INPUT_FILE, 'rootDialog property is required in config file')) - } + const configObject = file.getConfigObject(configContent, intentName) + const trainedResult = crossTrainer.crossTrain(luContents, qnaContents, configObject) + return trainedResult }, diff --git a/packages/lu/src/parser/cross-train/crossTrainer.js b/packages/lu/src/parser/cross-train/crossTrainer.js index 17d640cbe..dccd06d9e 100644 --- a/packages/lu/src/parser/cross-train/crossTrainer.js +++ b/packages/lu/src/parser/cross-train/crossTrainer.js @@ -11,7 +11,7 @@ const LUResource = require('../lufile/luResource') const DiagnosticSeverity = require('../lufile/diagnostic').DiagnosticSeverity const fileHelper = require('../../utils/filehelper') const exception = require('../utils/exception') -const retCode = require('../utils/enums/CLI-errors'); +const retCode = require('../utils/enums/CLI-errors') const NEWLINE = require('os').EOL const path = require('path') const QNA_GENERIC_SOURCE = "custom editorial" @@ -19,19 +19,16 @@ const QNA_GENERIC_SOURCE = "custom editorial" module.exports = { /** * Do cross training among lu files - * @param {luObject[]} luObjectArray the lu object list to be parsed - * @param {luObject[]} qnaObjectArray the qna Object list to be parsed + * @param {any[]} luContents the lu content array whose element includes path and content + * @param {any[]} qnaContents the qna content array whose element includes path and content * @param {any} crossTrainConfig cross train json config * @returns {Map} map of file id and luResource * @throws {exception} throws errors */ - crossTrain: function (luObjectArray, qnaObjectArray, crossTrainConfig) { + crossTrain: function (luContents, qnaContents, crossTrainConfig) { try { - const crossTrainConfigObj = JSON.parse(crossTrainConfig) - const rootObjectIds = crossTrainConfigObj.rootIds - const triggerRules = crossTrainConfigObj.triggerRules - const intentName = crossTrainConfigObj.intentName - const verbose = crossTrainConfigObj.verbose + const {luObjectArray, qnaObjectArray} = pretreatment(luContents, qnaContents) + const {rootIds, triggerRules, intentName, verbose} = crossTrainConfig // parse lu content to LUResource object let luFileIdToResourceMap = parseAndValidateContent(luObjectArray, verbose) @@ -43,7 +40,7 @@ module.exports = { let resources = constructResoureTree(luFileIdToResourceMap, triggerRules) // do lu cross training from roots. One root one core training - for (const rootObjectId of rootObjectIds) { + for (const rootObjectId of rootIds) { if (resources.some(r => r.id === rootObjectId)) { // do cross training for each root at top level const result = luCrossTrain(rootObjectId, resources, qnaFileIdToResourceMap, intentName) @@ -466,3 +463,11 @@ const parseAndValidateContent = function (objectArray, verbose) { return fileIdToResourceMap } + +const pretreatment = function (luContents, qnaContents) { + // Parse lu and qna objects + const luObjectArray = fileHelper.getParsedObjects(luContents) + const qnaObjectArray = fileHelper.getParsedObjects(qnaContents) + + return {luObjectArray, qnaObjectArray} +} \ No newline at end of file diff --git a/packages/lu/src/utils/filehelper.ts b/packages/lu/src/utils/filehelper.ts index afaf418c5..91e954871 100644 --- a/packages/lu/src/utils/filehelper.ts +++ b/packages/lu/src/utils/filehelper.ts @@ -11,6 +11,7 @@ const path = require('path') const helpers = require('./../parser/utils/helpers') const luObject = require('./../parser/lu/lu') const LUOptions = require('./../parser/lu/luOptions') +const globby = require('globby') /* tslint:disable:prefer-for-of no-unused*/ @@ -164,6 +165,31 @@ export async function detectLuContent(stdin: string, input: string) { return false } +export async function getFilesContent(input: string, extType: string) { + let fileStat = await fs.stat(input) + if (fileStat.isFile()) { + const filePath = path.resolve(input) + const content = await getContentFromFile(input) + return [{id: filePath, content}] + } + + if (!fileStat.isDirectory()) { + throw (new exception(retCode.errorCode.INVALID_INPUT_FILE, 'Sorry, ' + input + ' is not a folder or does not exist')) + } + const paths = await globby([`**/*${extType}`], {cwd: input, dot: true}) + return Promise.all(paths.map(async (item: string) => { + const itemPath = path.resolve(path.join(input, item)) + const content = await getContentFromFile(itemPath) + return {id: itemPath, content} + })) +} + +export async function getConfigContent(input: string) { + const luConfigFile = await getConfigFile(input) + const content = await getContentFromFile(luConfigFile) + return {id: luConfigFile, content} +} + async function getConfigFile(input: string): Promise { let fileStat = await fs.stat(input) if (fileStat.isFile()) { @@ -183,13 +209,20 @@ async function getConfigFile(input: string): Promise { return defaultConfigFile } -export async function getConfigObject(input: string) { - const luConfigFile = await getConfigFile(input) +export function getParsedObjects(contents: {id: string, content: string}[]) { + const parsedObjects = contents.map(content => { + const opts = new LUOptions(content.id) + return new luObject(content.content, opts) + }) + + return parsedObjects +} +export function getConfigObject(configContent: any, intentName: string) { let finalLuConfigObj = Object.create(null) let rootLuFiles: string[] = [] - const configFileDir = path.dirname(luConfigFile) - const luConfigContent = await getContentFromFile(luConfigFile) + const configFileDir = path.dirname(configContent.id) + const luConfigContent = configContent.content if (luConfigContent && luConfigContent !== '') { try { const luConfigObj = JSON.parse(luConfigContent) @@ -225,7 +258,18 @@ export async function getConfigObject(input: string) { } } - return {rootIds: rootLuFiles, triggerRules: finalLuConfigObj} + if (rootLuFiles.length > 0) { + let crossTrainConfig = { + rootIds: rootLuFiles, + triggerRules: finalLuConfigObj, + intentName, + verbose: true + } + + return crossTrainConfig + } else { + throw (new exception(retCode.errorCode.INVALID_INPUT_FILE, 'rootDialog property is required in config file')) + } } export function parseJSON(input: string, appType: string) { diff --git a/packages/lu/test/parser/cross-train/crossTrainer.test.js b/packages/lu/test/parser/cross-train/crossTrainer.test.js index 1f4a3f48d..686d814e4 100644 --- a/packages/lu/test/parser/cross-train/crossTrainer.test.js +++ b/packages/lu/test/parser/cross-train/crossTrainer.test.js @@ -5,8 +5,6 @@ const assert = require('chai').assert const crossTrainer = require('../../../src/parser/cross-train/crossTrainer') -const content = require('../../../src/parser/lu/lu') -const luOptions = require('../../../src/parser/lu/luOptions') const NEWLINE = require('os').EOL describe('luis:cross training tests among lu and qna contents', () => { @@ -14,258 +12,271 @@ describe('luis:cross training tests among lu and qna contents', () => { let luContentArray = [] let qnaContentArray = [] - luContentArray.push(new content( - `# dia1_trigger - - book a hotel for me - - # dia2_trigger - - book a flight for me - - book a train ticket for me`, - new luOptions('./main/main.lu')) + luContentArray.push({ + content: + `# dia1_trigger + - book a hotel for me + + # dia2_trigger + - book a flight for me + - book a train ticket for me`, + id: 'main.lu'}) + + qnaContentArray.push({ + content: + `# ?user guide + + **Filters:** + - aa=bb + + \`\`\` + Here is the [user guide](http://contoso.com/userguide.pdf) + \`\`\` + + # ?tell joke + \`\`\` + tell a funny joke + \`\`\``, + id: 'main.qna'} ) - qnaContentArray.push(new content( - `# ?user guide - - **Filters:** - - aa=bb - - \`\`\` - Here is the [user guide](http://contoso.com/userguide.pdf) - \`\`\` - - # ?tell joke - \`\`\` - tell a funny joke - \`\`\``, - new luOptions('./main/main.qna')) + luContentArray.push({ + content: + `# dia1_trigger + - réserver un hôtel`, + id: 'main.fr-fr.lu'} ) - luContentArray.push(new content( - `# dia1_trigger - - réserver un hôtel`, - new luOptions('./main/main.fr-fr.lu')) + qnaContentArray.push({ + content: + `# ?guide de l'utilisateur + + **Filters:** + - aa=bb + + \`\`\` + Voici le [guide de l'utilisateur] (http://contoso.com/userguide.pdf) + \`\`\``, + id: 'main.fr-fr.qna'} ) - qnaContentArray.push(new content( - `# ?guide de l'utilisateur - - **Filters:** - - aa=bb - - \`\`\` - Voici le [guide de l'utilisateur] (http://contoso.com/userguide.pdf) - \`\`\``, - new luOptions('./main/main.fr-fr.qna')) - ) - - luContentArray.push(new content( - `> !# @app.name = my luis application - - # hotelLevel - - I need a four star hotel - - # hotelLocation - - can I book a hotel near space needle`, - new luOptions('./dia1/dia1.lu')) + luContentArray.push({ + content: + `> !# @app.name = my luis application + + # hotelLevel + - I need a four star hotel + + # hotelLocation + - can I book a hotel near space needle`, + id: 'dia1.lu'} ) - qnaContentArray.push(new content( - `> !# @app.desc = description of my luis application - - > !# @qna.pair.source = xyz - - - # ?tell joke - - tell me a joke - - \`\`\` - ha ha ha - \`\`\` - **Prompts:** - - [flight booking](#?-book-flight) \`context-only\` - - # ?can I book a hotel near space needle - \`\`\` - of course you can - \`\`\``, - new luOptions('./dia1/dia1.qna')) + qnaContentArray.push({ + content: + `> !# @app.desc = description of my luis application + + > !# @qna.pair.source = xyz + + + # ?tell joke + - tell me a joke + + \`\`\` + ha ha ha + \`\`\` + **Prompts:** + - [flight booking](#?-book-flight) \`context-only\` + + # ?can I book a hotel near space needle + \`\`\` + of course you can + \`\`\``, + id: 'dia1.qna'} ) - luContentArray.push(new content( - `# hotelLevel - - J'ai besoin d'un hôtel quatre étoiles - - # hotelLocation - - puis-je réserver un hôtel près de l'aiguille spatiale`, - new luOptions('./dia1/dia1.fr-fr.lu')) + luContentArray.push({ + content: + `# hotelLevel + - J'ai besoin d'un hôtel quatre étoiles + + # hotelLocation + - puis-je réserver un hôtel près de l'aiguille spatiale`, + id: 'dia1.fr-fr.lu'} ) - qnaContentArray.push(new content( - `# ?raconter la blague - - \`\`\` - ha ha ha - \`\`\``, - new luOptions('./dia1/dia1.fr-fr.qna')) + qnaContentArray.push({ + content: + `# ?raconter la blague + + \`\`\` + ha ha ha + \`\`\``, + id: 'dia1.fr-fr.qna'} ) - luContentArray.push(new content( - `# dia3_trigger - - book a flight from {fromLocation = Seattle} to {toLocation = Beijing} - - # dia4_trigger - - book a train ticket from Seattle to Portland`, - new luOptions('./dia2/dia2.lu')) + luContentArray.push({ + content: + `# dia3_trigger + - book a flight from {fromLocation = Seattle} to {toLocation = Beijing} + + # dia4_trigger + - book a train ticket from Seattle to Portland`, + id: 'dia2.lu'} ) - qnaContentArray.push(new content( - `# ?sing song - \`\`\` - sure, I can sing song. - \`\`\` - - # ?tell a joke - \`\`\` - ha ha ha - \`\`\``, - new luOptions('./dia2/dia2.qna')) + qnaContentArray.push({ + content: + `# ?sing song + \`\`\` + sure, I can sing song. + \`\`\` + + # ?tell a joke + \`\`\` + ha ha ha + \`\`\``, + id: 'dia2.qna'} ) - luContentArray.push(new content( - `# flightDestination - - book a flight to {toLocation = Beijing} - - # flightTime - - which {flightTime} do you prefer`, - new luOptions('./dia3/dia3.lu')) + luContentArray.push({ + content: + `# flightDestination + - book a flight to {toLocation = Beijing} + + # flightTime + - which {flightTime} do you prefer`, + id: 'dia3.lu'} ) - qnaContentArray.push(new content( - ``, - new luOptions('./dia3/dia3.qna')) - ) + qnaContentArray.push({ + content: ``, + id: 'dia3.qna' + }) - luContentArray.push(new content( - `# railwayStation - - which station will you leave from - - # railwayTime - - when do you want to leave from Seattle train station`, - new luOptions('./dia4/dia4.lu')) - ) + luContentArray.push({ + content: + `# railwayStation + - which station will you leave from + + # railwayTime + - when do you want to leave from Seattle train station`, + id: 'dia4.lu'}) let crossTrainConfig = { rootIds: [ - './main/main.lu', - './main/main.fr-fr.lu' + 'main.lu', + 'main.fr-fr.lu' ], triggerRules: { - './main/main.lu': { - './dia1/dia1.lu': 'dia1_trigger', - './dia2/dia2.lu': 'dia2_trigger' + 'main.lu': { + 'dia1.lu': 'dia1_trigger', + 'dia2.lu': 'dia2_trigger' }, - './dia2/dia2.lu': { - './dia3/dia3.lu': 'dia3_trigger', - './dia4/dia4.lu': 'dia4_trigger' + 'dia2.lu': { + 'dia3.lu': 'dia3_trigger', + 'dia4.lu': 'dia4_trigger' }, - './main/main.fr-fr.lu': { - './dia1/dia1.fr-fr.lu': 'dia1_trigger' + 'main.fr-fr.lu': { + 'dia1.fr-fr.lu': 'dia1_trigger' } }, intentName: '_Interruption', verbose: true } - const trainedResult = crossTrainer.crossTrain(luContentArray, qnaContentArray, JSON.stringify(crossTrainConfig)) + const trainedResult = crossTrainer.crossTrain(luContentArray, qnaContentArray, crossTrainConfig) const luResult = trainedResult.luResult const qnaResult = trainedResult.qnaResult - assert.equal(luResult.get('./main/main.lu').Sections[2].Name, 'DeferToRecognizer_QnA_main') - assert.equal(luResult.get('./main/main.lu').Sections[2].Body, `- user guide${NEWLINE}- tell joke`) + assert.equal(luResult.get('main.lu').Sections[2].Name, 'DeferToRecognizer_QnA_main') + assert.equal(luResult.get('main.lu').Sections[2].Body, `- user guide${NEWLINE}- tell joke`) - assert.equal(qnaResult.get('./main/main.qna').Sections[2].Answer, 'intent=DeferToRecognizer_LUIS_main') - assert.equal(qnaResult.get('./main/main.qna').Sections[2].FilterPairs[0].key, 'dialogName') - assert.equal(qnaResult.get('./main/main.qna').Sections[2].FilterPairs[0].value, 'main') - assert.equal(qnaResult.get('./main/main.qna').Sections[2].Questions[0], 'book a hotel for me') - assert.equal(qnaResult.get('./main/main.qna').Sections[2].Questions[2], 'book a train ticket for me') + assert.equal(qnaResult.get('main.qna').Sections[2].Answer, 'intent=DeferToRecognizer_LUIS_main') + assert.equal(qnaResult.get('main.qna').Sections[2].FilterPairs[0].key, 'dialogName') + assert.equal(qnaResult.get('main.qna').Sections[2].FilterPairs[0].value, 'main') + assert.equal(qnaResult.get('main.qna').Sections[2].Questions[0], 'book a hotel for me') + assert.equal(qnaResult.get('main.qna').Sections[2].Questions[2], 'book a train ticket for me') - assert.equal(luResult.get('./dia1/dia1.lu').Sections[0].ModelInfo, '> !# @app.name = my luis application') - assert.equal(luResult.get('./dia1/dia1.lu').Sections[3].Name, '_Interruption') - assert.equal(luResult.get('./dia1/dia1.lu').Sections[3].Body, `- book a flight for me${NEWLINE}- book a train ticket for me${NEWLINE}- user guide`) - assert.equal(luResult.get('./dia1/dia1.lu').Sections[4].Name, 'DeferToRecognizer_QnA_dia1') - assert.equal(luResult.get('./dia1/dia1.lu').Sections[4].Body, `- tell joke${NEWLINE}- tell me a joke`) + assert.equal(luResult.get('dia1.lu').Sections[0].ModelInfo, '> !# @app.name = my luis application') + assert.equal(luResult.get('dia1.lu').Sections[3].Name, '_Interruption') + assert.equal(luResult.get('dia1.lu').Sections[3].Body, `- book a flight for me${NEWLINE}- book a train ticket for me${NEWLINE}- user guide`) + assert.equal(luResult.get('dia1.lu').Sections[4].Name, 'DeferToRecognizer_QnA_dia1') + assert.equal(luResult.get('dia1.lu').Sections[4].Body, `- tell joke${NEWLINE}- tell me a joke`) - assert.equal(qnaResult.get('./dia1/dia1.qna').Sections[0].ModelInfo, '> !# @app.desc = description of my luis application') - assert.equal(qnaResult.get('./dia1/dia1.qna').Sections[1].FilterPairs[0].key, 'dialogName') - assert.equal(qnaResult.get('./dia1/dia1.qna').Sections[1].FilterPairs[0].value, 'dia1') - assert.equal(qnaResult.get('./dia1/dia1.qna').Sections[1].promptsText[0], '[flight booking](#?-book-flight) `context-only`') - assert.equal(qnaResult.get('./dia1/dia1.qna').Sections[3].Questions.join(', '), 'I need a four star hotel, book a flight for me, book a train ticket for me, user guide') + assert.equal(qnaResult.get('dia1.qna').Sections[0].ModelInfo, '> !# @app.desc = description of my luis application') + assert.equal(qnaResult.get('dia1.qna').Sections[1].FilterPairs[0].key, 'dialogName') + assert.equal(qnaResult.get('dia1.qna').Sections[1].FilterPairs[0].value, 'dia1') + assert.equal(qnaResult.get('dia1.qna').Sections[1].promptsText[0], '[flight booking](#?-book-flight) `context-only`') + assert.equal(qnaResult.get('dia1.qna').Sections[3].Questions.join(', '), 'I need a four star hotel, book a flight for me, book a train ticket for me, user guide') - assert.equal(luResult.get('./dia2/dia2.lu').Sections[2].Name, '_Interruption') - assert.equal(luResult.get('./dia2/dia2.lu').Sections[2].Body, `- book a hotel for me${NEWLINE}- user guide${NEWLINE}- tell joke`) - assert.equal(luResult.get('./dia2/dia2.lu').Sections[3].Name, 'DeferToRecognizer_QnA_dia2') - assert.equal(luResult.get('./dia2/dia2.lu').Sections[3].Body, `- sing song${NEWLINE}- tell a joke`) + assert.equal(luResult.get('dia2.lu').Sections[2].Name, '_Interruption') + assert.equal(luResult.get('dia2.lu').Sections[2].Body, `- book a hotel for me${NEWLINE}- user guide${NEWLINE}- tell joke`) + assert.equal(luResult.get('dia2.lu').Sections[3].Name, 'DeferToRecognizer_QnA_dia2') + assert.equal(luResult.get('dia2.lu').Sections[3].Body, `- sing song${NEWLINE}- tell a joke`) - assert.equal(qnaResult.get('./dia2/dia2.qna').Sections[0].FilterPairs[0].key, 'dialogName') - assert.equal(qnaResult.get('./dia2/dia2.qna').Sections[0].FilterPairs[0].value, 'dia2') - assert.equal(qnaResult.get('./dia2/dia2.qna').Sections[2].Questions.join(', '), 'book a flight from Seattle to Beijing, book a train ticket from Seattle to Portland, book a hotel for me, user guide, tell joke') + assert.equal(qnaResult.get('dia2.qna').Sections[0].FilterPairs[0].key, 'dialogName') + assert.equal(qnaResult.get('dia2.qna').Sections[0].FilterPairs[0].value, 'dia2') + assert.equal(qnaResult.get('dia2.qna').Sections[2].Questions.join(', '), 'book a flight from Seattle to Beijing, book a train ticket from Seattle to Portland, book a hotel for me, user guide, tell joke') - assert.equal(luResult.get('./dia3/dia3.lu').Sections.length, 3) - assert.equal(luResult.get('./dia3/dia3.lu').Sections[2].Name, '_Interruption') - assert.equal(luResult.get('./dia3/dia3.lu').Sections[2].Body, `- book a train ticket from Seattle to Portland${NEWLINE}- book a hotel for me${NEWLINE}- user guide${NEWLINE}- tell joke${NEWLINE}- sing song${NEWLINE}- tell a joke`) + assert.equal(luResult.get('dia3.lu').Sections.length, 3) + assert.equal(luResult.get('dia3.lu').Sections[2].Name, '_Interruption') + assert.equal(luResult.get('dia3.lu').Sections[2].Body, `- book a train ticket from Seattle to Portland${NEWLINE}- book a hotel for me${NEWLINE}- user guide${NEWLINE}- tell joke${NEWLINE}- sing song${NEWLINE}- tell a joke`) - assert.equal(qnaResult.get('./dia3/dia3.qna').Sections.length, 0) + assert.equal(qnaResult.get('dia3.qna').Sections.length, 0) - assert.equal(luResult.get('./dia4/dia4.lu').Sections.length, 3) - assert.equal(luResult.get('./dia4/dia4.lu').Sections[2].Name, '_Interruption') - assert.equal(luResult.get('./dia4/dia4.lu').Sections[2].Body, `- book a flight from Seattle to Beijing${NEWLINE}- book a hotel for me${NEWLINE}- user guide${NEWLINE}- tell joke${NEWLINE}- sing song${NEWLINE}- tell a joke`) + assert.equal(luResult.get('dia4.lu').Sections.length, 3) + assert.equal(luResult.get('dia4.lu').Sections[2].Name, '_Interruption') + assert.equal(luResult.get('dia4.lu').Sections[2].Body, `- book a flight from Seattle to Beijing${NEWLINE}- book a hotel for me${NEWLINE}- user guide${NEWLINE}- tell joke${NEWLINE}- sing song${NEWLINE}- tell a joke`) - assert.equal(luResult.get('./main/main.fr-fr.lu').Sections[1].Name, 'DeferToRecognizer_QnA_main') - assert.equal(luResult.get('./main/main.fr-fr.lu').Sections[1].Body, `- guide de l'utilisateur`) + assert.equal(luResult.get('main.fr-fr.lu').Sections[1].Name, 'DeferToRecognizer_QnA_main') + assert.equal(luResult.get('main.fr-fr.lu').Sections[1].Body, `- guide de l'utilisateur`) - assert.equal(qnaResult.get('./main/main.fr-fr.qna').Sections[1].Answer, 'intent=DeferToRecognizer_LUIS_main') - assert.equal(qnaResult.get('./main/main.fr-fr.qna').Sections[1].FilterPairs[0].key, 'dialogName') - assert.equal(qnaResult.get('./main/main.fr-fr.qna').Sections[1].FilterPairs[0].value, 'main') - assert.equal(qnaResult.get('./main/main.fr-fr.qna').Sections[1].Questions.length, 1) - assert.equal(qnaResult.get('./main/main.fr-fr.qna').Sections[1].Questions[0], 'réserver un hôtel') + assert.equal(qnaResult.get('main.fr-fr.qna').Sections[1].Answer, 'intent=DeferToRecognizer_LUIS_main') + assert.equal(qnaResult.get('main.fr-fr.qna').Sections[1].FilterPairs[0].key, 'dialogName') + assert.equal(qnaResult.get('main.fr-fr.qna').Sections[1].FilterPairs[0].value, 'main') + assert.equal(qnaResult.get('main.fr-fr.qna').Sections[1].Questions.length, 1) + assert.equal(qnaResult.get('main.fr-fr.qna').Sections[1].Questions[0], 'réserver un hôtel') - assert.equal(luResult.get('./dia1/dia1.fr-fr.lu').Sections[2].Name, '_Interruption') - assert.equal(luResult.get('./dia1/dia1.fr-fr.lu').Sections[2].Body, `- guide de l'utilisateur`) - assert.equal(luResult.get('./dia1/dia1.fr-fr.lu').Sections[3].Name, 'DeferToRecognizer_QnA_dia1') - assert.equal(luResult.get('./dia1/dia1.fr-fr.lu').Sections[3].Body, `- raconter la blague`) + assert.equal(luResult.get('dia1.fr-fr.lu').Sections[2].Name, '_Interruption') + assert.equal(luResult.get('dia1.fr-fr.lu').Sections[2].Body, `- guide de l'utilisateur`) + assert.equal(luResult.get('dia1.fr-fr.lu').Sections[3].Name, 'DeferToRecognizer_QnA_dia1') + assert.equal(luResult.get('dia1.fr-fr.lu').Sections[3].Body, `- raconter la blague`) - assert.equal(qnaResult.get('./dia1/dia1.fr-fr.qna').Sections[1].Questions.join(', '), 'J\'ai besoin d\'un hôtel quatre étoiles, puis-je réserver un hôtel près de l\'aiguille spatiale, guide de l\'utilisateur') + assert.equal(qnaResult.get('dia1.fr-fr.qna').Sections[1].Questions.join(', '), 'J\'ai besoin d\'un hôtel quatre étoiles, puis-je réserver un hôtel près de l\'aiguille spatiale, guide de l\'utilisateur') }) it('luis:cross training can get expected result when nestedIntentSection is enabled', () => { let luContentArray = [] - luContentArray.push(new content( - `> !# @enableSections = true - > !# @enableMergeIntents = true - - # dia1_trigger - ## bookFlight - - book a flight for me - - #dia2_trigger - - book a hotel for me`, - new luOptions('./main/main.lu')) + luContentArray.push({ + content: + `> !# @enableSections = true + > !# @enableMergeIntents = true + + # dia1_trigger + ## bookFlight + - book a flight for me + + #dia2_trigger + - book a hotel for me`, + id:'./main/main.lu'} ) - luContentArray.push(new content( - `# FlightTime - - which {flightTime} do you prefer`, - new luOptions('./dia1/dia1.lu')) + luContentArray.push({ + content: + `# FlightTime + - which {flightTime} do you prefer`, + id:'./dia1/dia1.lu'} ) - luContentArray.push(new content( - `# HotelLevel - - which hotel star do you prefer`, - new luOptions('./dia2/dia2.lu')) + luContentArray.push({ + content: + `# HotelLevel + - which hotel star do you prefer`, + id:'./dia2/dia2.lu'} ) let crossTrainConfig = { @@ -282,7 +293,7 @@ describe('luis:cross training tests among lu and qna contents', () => { verbose: true } - const trainedResult = crossTrainer.crossTrain(luContentArray, [], JSON.stringify(crossTrainConfig)) + const trainedResult = crossTrainer.crossTrain(luContentArray, [], crossTrainConfig) const luResult = trainedResult.luResult assert.equal(luResult.get('./dia2/dia2.lu').Sections[1].Name, '_Interruption') @@ -292,31 +303,35 @@ describe('luis:cross training tests among lu and qna contents', () => { it('luis:cross training can get expected result when multiple dialog invocations occur in same trigger', () => { let luContentArray = [] - luContentArray.push(new content( - `# dia1_trigger - - I want to travel to Seattle - - #dia2_trigger - - book a hotel for me`, - new luOptions('./main/main.lu')) + luContentArray.push({ + content: + `# dia1_trigger + - I want to travel to Seattle + + #dia2_trigger + - book a hotel for me`, + id: './main/main.lu'} ) - luContentArray.push(new content( - `# bookFlight - - book a flight for me`, - new luOptions('./dia1/dia1.lu')) + luContentArray.push({ + content: + `# bookFlight + - book a flight for me`, + id: './dia1/dia1.lu'} ) - luContentArray.push(new content( - `# bookTrain - - book a train ticket for me`, - new luOptions('./dia2/dia2.lu')) + luContentArray.push({ + content: + `# bookTrain + - book a train ticket for me`, + id: './dia2/dia2.lu'} ) - luContentArray.push(new content( - `# HotelLevel - - I prefer 4 stars hotel`, - new luOptions('./dia3/dia3.lu')) + luContentArray.push({ + content: + `# HotelLevel + - I prefer 4 stars hotel`, + id: './dia3/dia3.lu'} ) let crossTrainConfig = { @@ -334,7 +349,7 @@ describe('luis:cross training tests among lu and qna contents', () => { verbose: true } - const trainedResult = crossTrainer.crossTrain(luContentArray, [], JSON.stringify(crossTrainConfig)) + const trainedResult = crossTrainer.crossTrain(luContentArray, [], crossTrainConfig) const luResult = trainedResult.luResult assert.equal(luResult.get('./dia1/dia1.lu').Sections[1].Name, '_Interruption')