Skip to content
This repository was archived by the owner on Jan 15, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 31 additions & 13 deletions packages/lu/src/parser/cross-train/crossTrainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,19 +93,32 @@ const constructResoureTree = function (fileIdToLuResourceMap, triggerRules) {
}
}

const destLuFileToIntent = triggerRules[fileId]
for (const destLuFile of Object.keys(destLuFileToIntent)) {
if (destLuFile !== '' && !fileIdsFromInput.includes(destLuFile)) continue

const triggerIntentName = destLuFileToIntent[destLuFile]
if (triggerIntentName !== '' && !intents.some(i => i.Name === triggerIntentName)) {
throw (new exception(retCode.errorCode.INVALID_INPUT, `Sorry, trigger intent '${triggerIntentName}' is not found in lu file: ${fileId}`))
const intentToDestLuFiles = triggerRules[fileId]
for (const triggerIntent of Object.keys(intentToDestLuFiles)) {
if (triggerIntent !== '' && !intents.some(i => i.Name === triggerIntent)) {
throw (new exception(retCode.errorCode.INVALID_INPUT, `Sorry, trigger intent '${triggerIntent}' is not found in lu file: ${fileId}`))
}

resource.children.push({
target: destLuFile,
intent: triggerIntentName
})
let destLuFiles = intentToDestLuFiles[triggerIntent]
if (typeof destLuFiles === 'string') destLuFiles = [destLuFiles]

if (destLuFiles.length > 0) {
destLuFiles.forEach(destLuFile => {
if (destLuFile !== '' && !fileIdsFromInput.includes(destLuFile)) {
throw (new exception(retCode.errorCode.INVALID_INPUT, `Sorry, lu file '${destLuFile}' is not found`))
} else {
resource.children.push({
target: destLuFile,
intent: triggerIntent
})
}
})
} else {
resource.children.push({
target: '',
intent: triggerIntent
})
}
}

resources.push(resource)
Expand Down Expand Up @@ -158,11 +171,16 @@ const mergeRootInterruptionToLeaves = function (rootResource, result, qnaFileToR
const mergeBrothersInterruption = function (resource, result, intentName) {
let children = resource.children
for (const child of children) {
let triggerIntent = child.intent
const triggerIntent = child.intent
const destLuFile = child.target
let intentsWithSameTarget = []
if (destLuFile !== '') intentsWithSameTarget = children.filter(c => c.target === destLuFile && c.intent !== '').map(x => x.intent)

const brotherSections = resource.content.Sections.filter(s => s.Name !== triggerIntent
&& s.Name !== intentName
&& (s.SectionType === LUSectionTypes.SIMPLEINTENTSECTION || s.SectionType === LUSectionTypes.NESTEDINTENTSECTION)
&& children.some(brotherChild => brotherChild.intent === s.Name))
&& children.some(brotherChild => brotherChild.intent === s.Name)
&& !intentsWithSameTarget.some(intent => intent === s.Name))

let brotherUtterances = []
brotherSections.forEach(s => {
Expand Down
16 changes: 10 additions & 6 deletions packages/lu/src/utils/filehelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,14 +239,18 @@ export function getConfigObject(configContent: any, intentName: string) {
for (const triggerKey of Object.keys(triggers)) {
const destLuFiles = triggers[triggerKey] instanceof Array ? triggers[triggerKey] : [triggers[triggerKey]]
for (const destLuFile of destLuFiles) {
const destLuFileFullPath = path.resolve(configFileDir, destLuFile)
const destLuFileFullPath = destLuFile && destLuFile !== '' ? path.resolve(configFileDir, destLuFile) : destLuFile
if (rootLuFileFullPath in finalLuConfigObj) {
const finalDestLuFileToIntent = finalLuConfigObj[rootLuFileFullPath]
finalDestLuFileToIntent[destLuFileFullPath] = triggerKey
const finalIntentToDestLuFiles = finalLuConfigObj[rootLuFileFullPath]
if (finalIntentToDestLuFiles[triggerKey]) {
finalIntentToDestLuFiles[triggerKey].push(destLuFileFullPath)
} else {
finalIntentToDestLuFiles[triggerKey] = [destLuFileFullPath]
}
} else {
let finalDestLuFileToIntent = Object.create(null)
finalDestLuFileToIntent[destLuFileFullPath] = triggerKey
finalLuConfigObj[rootLuFileFullPath] = finalDestLuFileToIntent
let finalIntentToDestLuFiles = Object.create(null)
finalIntentToDestLuFiles[triggerKey] = [destLuFileFullPath]
finalLuConfigObj[rootLuFileFullPath] = finalIntentToDestLuFiles
}
}
}
Expand Down
91 changes: 75 additions & 16 deletions packages/lu/test/parser/cross-train/crossTrainer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,15 +170,15 @@ describe('luis:cross training tests among lu and qna contents', () => {
],
triggerRules: {
'main.lu': {
'dia1.lu': 'dia1_trigger',
'dia2.lu': 'dia2_trigger'
'dia1_trigger': 'dia1.lu',
'dia2_trigger': 'dia2.lu'
},
'dia2.lu': {
'dia3.lu': 'dia3_trigger',
'dia4.lu': 'dia4_trigger'
'dia3_trigger': 'dia3.lu',
'dia4_trigger': 'dia4.lu'
},
'main.fr-fr.lu': {
'dia1.fr-fr.lu': 'dia1_trigger'
'dia1_trigger': 'dia1.fr-fr.lu'
}
},
intentName: '_Interruption',
Expand Down Expand Up @@ -284,8 +284,8 @@ describe('luis:cross training tests among lu and qna contents', () => {
],
triggerRules: {
'./main/main.lu': {
'./dia1/dia1.lu': 'dia1_trigger',
'./dia2/dia2.lu': 'dia2_trigger'
'dia1_trigger': './dia1/dia1.lu',
'dia2_trigger': './dia2/dia2.lu'
}
},
intentName: '_Interruption',
Expand Down Expand Up @@ -339,9 +339,8 @@ describe('luis:cross training tests among lu and qna contents', () => {
],
triggerRules: {
'./main/main.lu': {
'./dia1/dia1.lu': 'dia1_trigger',
'./dia2/dia2.lu': 'dia1_trigger',
'./dia3/dia3.lu': 'dia2_trigger'
'dia1_trigger': ['./dia1/dia1.lu', './dia2/dia2.lu'],
'dia2_trigger': './dia3/dia3.lu'
}
},
intentName: '_Interruption',
Expand Down Expand Up @@ -398,8 +397,8 @@ describe('luis:cross training tests among lu and qna contents', () => {
],
triggerRules: {
'./main/main.lu': {
'./dia1/dia1.lu': 'dia1_trigger',
'./dia2/dia2.lu': 'dia2_trigger'
'dia1_trigger': './dia1/dia1.lu',
'dia2_trigger': './dia2/dia2.lu'
}
},
intentName: '_Interruption',
Expand Down Expand Up @@ -460,10 +459,10 @@ describe('luis:cross training tests among lu and qna contents', () => {
],
triggerRules: {
'./main/main.lu': {
'./dia1/dia1.lu': 'dia1_trigger',
'./dia2/dia2.lu': 'dia2_trigger',
'': 'dia3_trigger',
'./dia3/dia3.lu': ''
'dia1_trigger': './dia1/dia1.lu',
'dia2_trigger': './dia2/dia2.lu',
'dia3_trigger': '',
'': './dia3/dia3.lu'
}
},
intentName: '_Interruption',
Expand All @@ -482,4 +481,64 @@ describe('luis:cross training tests among lu and qna contents', () => {
assert.equal(luResult.get('./dia3/dia3.lu').Sections[1].Name, '_Interruption')
assert.equal(luResult.get('./dia3/dia3.lu').Sections[1].Body, `- I want to travel to Seattle${NEWLINE}- book a hotel for me${NEWLINE}- cancel`)
})

it('luis:cross training can get expected result when multi trigger intents point to same lu file', () => {
let luContentArray = []

luContentArray.push({
content:
`# dia1_trigger
- I want to travel to Seattle

# dia2_trigger
- book a hotel for me

# dia3_trigger
- cancel`,
id: './main/main.lu'}
)

luContentArray.push({
content:
`# bookTicket
- book a flight for me
- book a train ticket for me

# hotelLevel
- I prefer 4 stars hotel`,
id: './dia1/dia1.lu'}
)

luContentArray.push({
content:
`# cancelTask
- cancel that task`,
id: './dia2/dia2.lu'}
)

let crossTrainConfig = {
rootIds: [
'./main/main.lu'
],
triggerRules: {
'./main/main.lu': {
'dia1_trigger': './dia1/dia1.lu',
'dia2_trigger': './dia1/dia1.lu',
'dia3_trigger': './dia2/dia2.lu',
'': './dia2/dia2.lu'
}
},
intentName: '_Interruption',
verbose: true
}

const trainedResult = crossTrainer.crossTrain(luContentArray, [], crossTrainConfig)
const luResult = trainedResult.luResult

assert.equal(luResult.get('./dia1/dia1.lu').Sections[2].Name, '_Interruption')
assert.equal(luResult.get('./dia1/dia1.lu').Sections[2].Body, `- cancel`)

assert.equal(luResult.get('./dia2/dia2.lu').Sections[1].Name, '_Interruption')
assert.equal(luResult.get('./dia2/dia2.lu').Sections[1].Body, `- I want to travel to Seattle${NEWLINE}- book a hotel for me`)
})
})
44 changes: 44 additions & 0 deletions packages/lu/test/utils/filehelper.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {readTextFile} from './../../src/utils/textfilereader'
const expect = require('chai').expect;
const assert = require('chai').assert
const fileHelper = require('./../../src/utils/filehelper')
const luObject = require('./../../src/parser/lu/lu')
const luOptions = require('./../../src/parser/lu/luOptions')
Expand Down Expand Up @@ -28,4 +29,47 @@ describe('utils/filehelper test', () => {
expected.push(new luObject(content, new luOptions('stdin')))
expect(luObjArray).to.deep.equal(expected)
})

it('File helper correctly build cross train config object', function () {
const configContent = {
"./main/main.lu": {
"rootDialog": true,
"triggers": {
"dia1_trigger": ["./dia1/dia1.lu", "./dia2/dia2.lu"]
}
},
"./dia2/dia2.lu": {
"triggers": {
"dia3_trigger": "",
"": "./dia4/dia4.lu"
}
},
"./main/main.fr-fr.lu": {
"rootDialog": true,
"triggers": {
"dia1_trigger": "./dia1/dia1.fr-fr.lu"
}
}
}

let configObject = fileHelper.getConfigObject({ id: path.join(__dirname, 'config.json'), content: JSON.stringify(configContent) }, '_Interruption')
assert.equal(configObject.rootIds[0].includes('main.lu'), true)
assert.equal(configObject.rootIds[1].includes('main.fr-fr.lu'), true)

const triggerRuleKeys = [...Object.keys(configObject.triggerRules)]
assert.equal(triggerRuleKeys[0].includes('main.lu'), true)
assert.equal(triggerRuleKeys[1].includes('dia2.lu'), true)
assert.equal(triggerRuleKeys[2].includes('main.fr-fr.lu'), true)

const triggerRuleValues = [...Object.values(configObject.triggerRules)]
assert.equal(triggerRuleValues[0]['dia1_trigger'][0].includes('dia1.lu'), true)
assert.equal(triggerRuleValues[0]['dia1_trigger'][1].includes('dia2.lu'), true)
assert.equal(triggerRuleValues[1]['dia3_trigger'][0], '')
assert.equal(triggerRuleValues[1][''][0].includes('dia4.lu'), true)
assert.equal(triggerRuleValues[2]['dia1_trigger'][0].includes('dia1.fr-fr.lu'), true)

assert.equal(configObject.intentName, '_Interruption')

assert.equal(configObject.verbose, true)
})
})