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
2 changes: 2 additions & 0 deletions packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -891,6 +891,8 @@ OPTIONS
--[no-]intra-dialog Only do intra dialog cross train

--log Writes out log messages to console

--exclude Excludes given folders under the input directory, for example, --exclude bin,obj,lib, this will ignore the /bin, /obj, /lib folders under the input path
```

_See code: [@microsoft/bf-luis-cli](https://github.com/microsoft/botframework-cli/tree/master/packages/luis/src/commands/luis/cross-train.ts)_
Expand Down
28 changes: 23 additions & 5 deletions packages/lu/src/parser/cross-train/cross-train.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,23 @@ module.exports = {
* @param {inner: boolean, intra: boolean} trainingOpt trainingOpt indicates whether you want to control do the inner or intra dialog training seperately
* @returns {luResult: any, qnaResult: any} trainedResult of luResult and qnaResult or undefined if no results.
*/
train: async function (input, intentName, config, verbose, trainingOpt) {
train: async function (input, intentName, config, verbose, trainingOpt, exclude) {
// get excluded foleders
let excludedFolders = undefined
if (exclude) {
excludedFolders = exclude.split(',').map(e => e.trim())
}

// Get all related file content.
const luContents = await filehelper.getFilesContent(input, fileExtEnum.LUFile)
const qnaContents = await filehelper.getFilesContent(input, fileExtEnum.QnAFile)
const luContents = await filehelper.getFilesContent(input, fileExtEnum.LUFile, excludedFolders)
const qnaContents = await filehelper.getFilesContent(input, fileExtEnum.QnAFile, excludedFolders)
const configContent = await filehelper.getConfigContent(config)
const defaultLocale = 'en-us'

let importResolver = async function (id, idsToFind) {
let importedContents = []
const idWithoutExt = path.basename(id, path.extname(id))
const locale = /\w\.\w/.test(idWithoutExt) ? idWithoutExt.split('.').pop() : defaultLocale;
for (let idx = 0; idx < idsToFind.length; idx++) {
let file = idsToFind[idx]
if (path.isAbsolute(file.filePath)) {
Expand All @@ -38,7 +47,16 @@ module.exports = {
} else {
const fileName = path.basename(file.filePath)
const updateImportedContents = async function(typedContents, fileExt) {
const found = typedContents.filter(content => content.id === path.basename(fileName, fileExt))
let found = []
// import resolver should be capable to find implicit import files with locale, for example '[import](b.lu)' is defined in a.en-us.lu, the resolver should find b.en-us.lu
const foundWithLocale = typedContents.filter(content => content.id === `${path.basename(fileName, fileExt)}.${locale}`)
if (foundWithLocale.length > 0) {
found = foundWithLocale
} else {
//if no locale specified file is found, just to check whether there is file without locale matched
found = typedContents.filter(content => content.id === path.basename(fileName, fileExt))
}

if(found.length > 0) {
importedContents.push(...found)
} else {
Expand All @@ -57,7 +75,7 @@ module.exports = {
if (fileName.endsWith(fileExtEnum.LUFile)) {
await updateImportedContents(luContents, fileExtEnum.LUFile)
} else if (fileName.endsWith(fileExtEnum.QnAFile)) {
await updateImportedContents(qnaContents, fileExtEnum.LUFile)
await updateImportedContents(qnaContents, fileExtEnum.QnAFile)
}
}
}
Expand Down
17 changes: 15 additions & 2 deletions packages/lu/src/utils/filehelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ export async function detectLuContent(stdin: string, input: string) {
return false
}

export async function getFilesContent(input: string, extType: string) {
export async function getFilesContent(input: string, extType: string, ignoredFolders?: string[]) {
let fileStat = await fs.stat(input)
if (fileStat.isFile()) {
const filePath = path.resolve(input)
Expand All @@ -182,7 +182,20 @@ export async function getFilesContent(input: string, extType: string) {
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})

const allPaths = (await globby([`**/*${extType}` ], {cwd: input, dot: true}))
let paths: string[] = []
if (ignoredFolders) {
for (const path of allPaths) {
const isIgnored = ignoredFolders.filter(e => path.startsWith(e)).length > 0
if (!isIgnored) {
paths.push(path)
}
}
} else {
paths = allPaths
}

return Promise.all(paths.map(async (item: string) => {
const itemPath = path.resolve(path.join(input, item))
const content = await getContentFromFile(itemPath)
Expand Down
2 changes: 2 additions & 0 deletions packages/luis/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,8 @@ OPTIONS
--[no-]intra-dialog Only do intra dialog cross train

--log Writes out log messages to console

--exclude Excludes given folders under the input directory, for example, --exclude bin,obj,lib, this will ignore the /bin, /obj, /lib folders under the input path
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI This will be overriden by the doc script.

```

_See code: [src/commands/luis/cross-train.ts](https://github.com/microsoft/botframework-cli/tree/master/packages/luis/src/commands/luis/cross-train.ts)_
Expand Down
5 changes: 3 additions & 2 deletions packages/luis/src/commands/luis/cross-train.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ export default class LuisCrossTrain extends Command {
force: flags.boolean({char: 'f', description: 'If --out flag is provided with the path to an existing file, overwrites that file', default: false}),
log: flags.boolean({description: 'Writes out log messages to console', default: false}),
'inner-dialog': flags.boolean({description: 'Only do inner dialog cross train', default: true, allowNo: true}),
'intra-dialog': flags.boolean({description: 'Only do intra dialog cross train', default: true, allowNo: true})
'intra-dialog': flags.boolean({description: 'Only do intra dialog cross train', default: true, allowNo: true}),
exclude: flags.string({description: 'Excludes folders under the input directory, separated by ",". If not specified, all luis and qna files will be included in the cross-train'})
}

async run() {
Expand All @@ -46,7 +47,7 @@ export default class LuisCrossTrain extends Command {
intra: flags['intra-dialog']
}

const trainedResult = await crossTrain.train(flags.in, flags.intentName, flags.config, flags.log, trainingOpt)
const trainedResult = await crossTrain.train(flags.in, flags.intentName, flags.config, flags.log, trainingOpt, flags.exclude)

if (flags.out === undefined) {
flags.out = path.join(process.cwd(), 'cross-trained')
Expand Down
14 changes: 14 additions & 0 deletions packages/luis/test/commands/luis/crossTrain.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,18 @@ describe('luis:cross-train tests for lu and qna contents', () => {
expect(await compareLuFiles('./../../../interruptionGen/application.lu', './../../fixtures/verified/interruption8/application.lu')).to.be.true
expect(await compareLuFiles('./../../../interruptionGen/application.qna', './../../fixtures/verified/interruption8/application.qna')).to.be.true
})

test
.stdout()
.command(['luis:cross-train',
'--in', `${path.join(__dirname, './../../fixtures/testcases/testImportWithLocale')}`,
'--config', `${path.join(__dirname, './../../fixtures/testcases/testImportWithLocale/cross-train.config')}`,
'--out', './interruptionGen',
'--exclude', 'bin',
'--force'])
.it('luis:cross training should able to import files with locale and ignore files under the directory specified', async () => {
expect(await compareLuFiles('./../../../interruptionGen/ChitchatDialog.en-us.lu', './../../fixtures/verified/interruption9/ChitchatDialog.en-us.lu')).to.be.true
expect(await compareLuFiles('./../../../interruptionGen/ChitchatDialog.en-us.qna', './../../fixtures/verified/interruption9/ChitchatDialog.en-us.qna')).to.be.true
expect(fs.existsSync('./../../../interruptionGen/extra.en-us.lu')).to.be.false
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[import](chitchat_professional.source.qna)
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# BotTour
- bot tour
- onboarding
- get started
- start the tour
- what can you do
- what can i ask you

# Cancel
- cancel
- quit
- abort
- exit
- never mind
- forget about it
- just stop already
- end this now

# Help
- help
- im stuck
- how do you work
- what can you do
- what can you help me with
- i need help
- i need some assistance

# Feedback
- i want to give feedback
- i have a problem
- something is broken
- this is a bad experience
- fill out survey

# None
- where is my car?
- I want to order a pizza
- place an item on hold
- Is it going to rain?
- turn on the lights
- check my account balance
- do unicorns really exist
- duck
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Why
- help
- what can I say
- why do you need my name?
- why age?
- what do you need my profile for?
- why do you ask?
- why do you need that information?

@ phraselist Test1
- t1
- q1

@ phraselist Test2
- t2
- q2

@ phraselist Test3
- t3
- q3

@ phraselist Test4
- t4
- q4

@ phraselist Test5
- t5
- q5

@ phraselist Test6
- t6
- q6

@ phraselist Test7
- t7
- q7

@ phraselist Test8
- t8
- q8

@ phraselist Test9
- t9
- q9

@ phraselist Test10
- t10
- q10

@ phraselist Test11
- t11
- q11

@ phraselist Test12
- t12
- q1
Loading