Skip to content
This repository was archived by the owner on Jan 15, 2025. It is now read-only.

Commit 475cc3d

Browse files
authored
bf-lu: update some function to support load file content directly (#626)
* update some function to support load file content * update some code style * update some ref * optimize config parameter * add fileHelper.ts * fix typo * remove semicolon * add the object * change the value * make all the path the same parttern * optimize * adjust test cases to use file name as id * fix typo * fix config id issue * move globby from dev dependency to dependency Co-authored-by: Fei Chen <[email protected]>
1 parent b27ba8e commit 475cc3d

File tree

5 files changed

+305
-258
lines changed

5 files changed

+305
-258
lines changed

packages/lu/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"delay": "^4.3.0",
4444
"fs-extra": "^8.1.0",
4545
"get-stdin": "^6.0.0",
46+
"globby": "^10.0.1",
4647
"intercept-stdout": "^0.1.2",
4748
"lodash": "^4.17.15",
4849
"node-fetch": "^2.1.2",
@@ -57,7 +58,6 @@
5758
"@types/mocha": "^5.2.7",
5859
"@types/node": "^10.14.15",
5960
"chai": "^4.2.0",
60-
"globby": "^10.0.1",
6161
"mocha": "^6.2.2",
6262
"nock": "^11.7.0",
6363
"nyc": "^14.1.1",

packages/lu/src/parser/cross-train/cross-train.js

Lines changed: 10 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,44 +8,27 @@ const path = require('path')
88
const file = require('../../utils/filehelper')
99
const fileExtEnum = require('../utils/helpers').FileExtTypeEnum
1010
const exception = require('../utils/exception')
11-
const retCode = require('../utils/enums/CLI-errors');
11+
const retCode = require('../utils/enums/CLI-errors')
1212
const crossTrainer = require('./crossTrainer')
1313

1414
module.exports = {
1515
/**
1616
* Cross train lu and qna files.
1717
* @param {string} input input lu and qna files folder.
1818
* @param {string} intentName interruption intent name. Default value is _Interruption.
19-
* @param {string} configPath path to config of mapping rules. If undefined, it will read config.json from input folder.
19+
* @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.
2020
* @returns {luResult: any, qnaResult: any} trainedResult of luResult and qnaResult or undefined if no results.
2121
*/
22-
train: async function (input, intentName, configPath) {
23-
let trainedResult
22+
train: async function (input, intentName, config) {
23+
// Get all related file content.
24+
const luContents = await file.getFilesContent(input, fileExtEnum.LUFile)
25+
const qnaContents = await file.getFilesContent(input, fileExtEnum.QnAFile)
26+
const configContent = config && !fs.existsSync(config) ? {id: path.join(input, 'config.json'), content: config} : await file.getConfigContent(config || input)
2427

25-
// Parse lu and qna objects
26-
const luObjects = await file.getLuObjects(undefined, input, true, fileExtEnum.LUFile)
27-
const qnaObjects = await file.getLuObjects(undefined, input, true, fileExtEnum.QnAFile)
28-
29-
let configObject
30-
if (configPath && configPath !== '') {
31-
configObject = await file.getConfigObject(configPath)
32-
} else {
33-
configObject = await file.getConfigObject(input)
34-
}
35-
36-
if (configObject.rootIds.length > 0) {
37-
let crossTrainConfig = {
38-
rootIds: configObject.rootIds,
39-
triggerRules: configObject.triggerRules,
40-
intentName: intentName,
41-
verbose: true
42-
}
43-
44-
trainedResult = crossTrainer.crossTrain(luObjects, qnaObjects, JSON.stringify(crossTrainConfig))
45-
} else {
46-
throw (new exception(retCode.errorCode.INVALID_INPUT_FILE, 'rootDialog property is required in config file'))
47-
}
28+
const configObject = file.getConfigObject(configContent, intentName)
4829

30+
const trainedResult = crossTrainer.crossTrain(luContents, qnaContents, configObject)
31+
4932
return trainedResult
5033
},
5134

packages/lu/src/parser/cross-train/crossTrainer.js

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,24 @@ const LUResource = require('../lufile/luResource')
1111
const DiagnosticSeverity = require('../lufile/diagnostic').DiagnosticSeverity
1212
const fileHelper = require('../../utils/filehelper')
1313
const exception = require('../utils/exception')
14-
const retCode = require('../utils/enums/CLI-errors');
14+
const retCode = require('../utils/enums/CLI-errors')
1515
const NEWLINE = require('os').EOL
1616
const path = require('path')
1717
const QNA_GENERIC_SOURCE = "custom editorial"
1818

1919
module.exports = {
2020
/**
2121
* Do cross training among lu files
22-
* @param {luObject[]} luObjectArray the lu object list to be parsed
23-
* @param {luObject[]} qnaObjectArray the qna Object list to be parsed
22+
* @param {any[]} luContents the lu content array whose element includes path and content
23+
* @param {any[]} qnaContents the qna content array whose element includes path and content
2424
* @param {any} crossTrainConfig cross train json config
2525
* @returns {Map<string, LUResource>} map of file id and luResource
2626
* @throws {exception} throws errors
2727
*/
28-
crossTrain: function (luObjectArray, qnaObjectArray, crossTrainConfig) {
28+
crossTrain: function (luContents, qnaContents, crossTrainConfig) {
2929
try {
30-
const crossTrainConfigObj = JSON.parse(crossTrainConfig)
31-
const rootObjectIds = crossTrainConfigObj.rootIds
32-
const triggerRules = crossTrainConfigObj.triggerRules
33-
const intentName = crossTrainConfigObj.intentName
34-
const verbose = crossTrainConfigObj.verbose
30+
const {luObjectArray, qnaObjectArray} = pretreatment(luContents, qnaContents)
31+
const {rootIds, triggerRules, intentName, verbose} = crossTrainConfig
3532

3633
// parse lu content to LUResource object
3734
let luFileIdToResourceMap = parseAndValidateContent(luObjectArray, verbose)
@@ -43,7 +40,7 @@ module.exports = {
4340
let resources = constructResoureTree(luFileIdToResourceMap, triggerRules)
4441

4542
// do lu cross training from roots. One root one core training
46-
for (const rootObjectId of rootObjectIds) {
43+
for (const rootObjectId of rootIds) {
4744
if (resources.some(r => r.id === rootObjectId)) {
4845
// do cross training for each root at top level
4946
const result = luCrossTrain(rootObjectId, resources, qnaFileIdToResourceMap, intentName)
@@ -466,3 +463,11 @@ const parseAndValidateContent = function (objectArray, verbose) {
466463

467464
return fileIdToResourceMap
468465
}
466+
467+
const pretreatment = function (luContents, qnaContents) {
468+
// Parse lu and qna objects
469+
const luObjectArray = fileHelper.getParsedObjects(luContents)
470+
const qnaObjectArray = fileHelper.getParsedObjects(qnaContents)
471+
472+
return {luObjectArray, qnaObjectArray}
473+
}

packages/lu/src/utils/filehelper.ts

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const path = require('path')
1111
const helpers = require('./../parser/utils/helpers')
1212
const luObject = require('./../parser/lu/lu')
1313
const LUOptions = require('./../parser/lu/luOptions')
14+
const globby = require('globby')
1415

1516
/* tslint:disable:prefer-for-of no-unused*/
1617

@@ -164,6 +165,31 @@ export async function detectLuContent(stdin: string, input: string) {
164165
return false
165166
}
166167

168+
export async function getFilesContent(input: string, extType: string) {
169+
let fileStat = await fs.stat(input)
170+
if (fileStat.isFile()) {
171+
const filePath = path.resolve(input)
172+
const content = await getContentFromFile(input)
173+
return [{id: filePath, content}]
174+
}
175+
176+
if (!fileStat.isDirectory()) {
177+
throw (new exception(retCode.errorCode.INVALID_INPUT_FILE, 'Sorry, ' + input + ' is not a folder or does not exist'))
178+
}
179+
const paths = await globby([`**/*${extType}`], {cwd: input, dot: true})
180+
return Promise.all(paths.map(async (item: string) => {
181+
const itemPath = path.resolve(path.join(input, item))
182+
const content = await getContentFromFile(itemPath)
183+
return {id: itemPath, content}
184+
}))
185+
}
186+
187+
export async function getConfigContent(input: string) {
188+
const luConfigFile = await getConfigFile(input)
189+
const content = await getContentFromFile(luConfigFile)
190+
return {id: luConfigFile, content}
191+
}
192+
167193
async function getConfigFile(input: string): Promise<string> {
168194
let fileStat = await fs.stat(input)
169195
if (fileStat.isFile()) {
@@ -183,13 +209,20 @@ async function getConfigFile(input: string): Promise<string> {
183209
return defaultConfigFile
184210
}
185211

186-
export async function getConfigObject(input: string) {
187-
const luConfigFile = await getConfigFile(input)
212+
export function getParsedObjects(contents: {id: string, content: string}[]) {
213+
const parsedObjects = contents.map(content => {
214+
const opts = new LUOptions(content.id)
215+
return new luObject(content.content, opts)
216+
})
217+
218+
return parsedObjects
219+
}
188220

221+
export function getConfigObject(configContent: any, intentName: string) {
189222
let finalLuConfigObj = Object.create(null)
190223
let rootLuFiles: string[] = []
191-
const configFileDir = path.dirname(luConfigFile)
192-
const luConfigContent = await getContentFromFile(luConfigFile)
224+
const configFileDir = path.dirname(configContent.id)
225+
const luConfigContent = configContent.content
193226
if (luConfigContent && luConfigContent !== '') {
194227
try {
195228
const luConfigObj = JSON.parse(luConfigContent)
@@ -225,7 +258,18 @@ export async function getConfigObject(input: string) {
225258
}
226259
}
227260

228-
return {rootIds: rootLuFiles, triggerRules: finalLuConfigObj}
261+
if (rootLuFiles.length > 0) {
262+
let crossTrainConfig = {
263+
rootIds: rootLuFiles,
264+
triggerRules: finalLuConfigObj,
265+
intentName,
266+
verbose: true
267+
}
268+
269+
return crossTrainConfig
270+
} else {
271+
throw (new exception(retCode.errorCode.INVALID_INPUT_FILE, 'rootDialog property is required in config file'))
272+
}
229273
}
230274

231275
export function parseJSON(input: string, appType: string) {

0 commit comments

Comments
 (0)