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

Commit bac9de7

Browse files
resolve cross train issues (#814)
* make --config relative to cwd for luis and qnamaker cross train * fix typo * resolve imports and only copy files sepcified in config * support case insensitive config and cross train empty file and adjust tests * adjust test cases for luis:cross-train and qnamaker:cross-train * remove patterns with prebuilt entity from cross-trained _Interruption intent * validate prebuilt entities in pattern having explicit definitions * adjust test cases in luis package * optimize crossTrainer dedup logic to make it compare lower case of utterances and optimize luConverter to make sure there is only one whitespace between words in utterances * split large QA pair into smaller ones to overcome the limit of QnAMaker in cross train and fix error not thrown issue in qnamaker * add unit tests for split large KB pair into smaller ones in cross train * resolve file name lower casing issue when write out Co-authored-by: Vishwac Sena Kannan <[email protected]>
1 parent 32a8a27 commit bac9de7

File tree

90 files changed

+6993
-432
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+6993
-432
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ module.exports = {
3636
// Get all related file content.
3737
const luContents = await file.getFilesContent(input, fileExtEnum.LUFile)
3838
const qnaContents = await file.getFilesContent(input, fileExtEnum.QnAFile)
39-
const configContent = config && !fs.existsSync(config) ? {id: path.join(input, 'config.json'), content: config} : await file.getConfigContent(config || input)
39+
const configContent = config && !fs.existsSync(config) ? {id: path.join(input, 'config.json'), content: config} : await file.getConfigContent(config)
4040

4141
const configObject = file.getConfigObject(configContent, intentName)
4242

43-
const trainedResult = crossTrainer.crossTrain(luContents, qnaContents, configObject)
43+
const trainedResult = await crossTrainer.crossTrain(luContents, qnaContents, configObject)
4444

4545
return trainedResult
4646
},

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

Lines changed: 75 additions & 36 deletions
Large diffs are not rendered by default.

packages/lu/src/parser/lubuild/builder.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ export class Builder {
358358
this.handler(`${recognizer.getLuPath()} training version=${recognizer.versionId}\n`)
359359
await delay(delayDuration)
360360
await luBuildCore.trainApplication(recognizer.getAppId(), recognizer.versionId)
361-
this.handler(`${recognizer.getLuPath()} waiting for training for version=${recognizer.versionId}...`)
361+
this.handler(`${recognizer.getLuPath()} waiting for training for version=${recognizer.versionId}...\n`)
362362
let done = true
363363
do {
364364
await delay(delayDuration)

packages/lu/src/parser/lufile/parseFileContents.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,19 @@ const parseAndHandleSimpleIntentSection = function (parsedContent, luResource) {
791791
throw (new exception(retCode.errorCode.INVALID_INPUT, error.toString(), [error]));
792792
}
793793

794+
let prebuiltEntities = entitiesFound.filter(item => builtInTypes.consolidatedList.includes(item.entity));
795+
prebuiltEntities.forEach(prebuiltEntity => {
796+
if (parsedContent.LUISJsonStructure.prebuiltEntities.findIndex(e => e.name === prebuiltEntity.entity) < 0) {
797+
let errorMsg = `Pattern "${utteranceAndEntities.context.getText()}" has prebuilt entity ${prebuiltEntity.entity}. Please define it explicitly with @ prebuilt ${prebuiltEntity.entity}.`;
798+
let error = BuildDiagnostic({
799+
message: errorMsg,
800+
context: utteranceAndEntities.context
801+
})
802+
803+
throw (new exception(retCode.errorCode.INVALID_INPUT, error.toString(), [error]));
804+
}
805+
})
806+
794807
let newPattern = new helperClass.pattern(utterance, intentName);
795808
if (!hashTable[uttHash]) {
796809
parsedContent.LUISJsonStructure.patterns.push(newPattern);
@@ -1856,8 +1869,8 @@ const parseAndHandleModelInfoSection = function (parsedContent, luResource, log)
18561869
if (kvPair[1] === 'enableSections') continue
18571870

18581871
if (kvPair.length === 4) {
1859-
if (kvPair[1] === 'enableMergeIntents' && kvPair[3] === 'false') {
1860-
enableMergeIntents = false;
1872+
if (kvPair[1] === 'enableMergeIntents') {
1873+
enableMergeIntents = kvPair[3] === 'false' ? false : true;
18611874
continue;
18621875
}
18631876

packages/lu/src/parser/luis/luConverter.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,11 @@ const parseUtterancesToLu = function(utterances, luisJSON){
9999
getEntitiesByPositionList(sortedEntitiesList, tokenizedText);
100100
updatedText = tokenizedText.join('');
101101
}
102-
if(updatedText) fileContent += '- ' + updatedText + NEWLINE;
102+
103+
// remove duplicated whitespaces between words inside utterance to make sure they are aligned with the luis portal
104+
// as luis portal only keeps one whitespace between words even if you type multiple ones
105+
// this will benefit the comparison of lu files that are converted from local and remote luis application
106+
if(updatedText) fileContent += '- ' + updatedText.replace(/\s+/g, ' ') + NEWLINE;
103107
});
104108
return fileContent
105109
}

packages/lu/src/parser/qnabuild/core.ts

Lines changed: 45 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import {Recognizer} from './recognizer'
77
import {MultiLanguageRecognizer} from './multi-language-recognizer'
88
import {Settings} from './settings'
99
import * as path from 'path'
10+
const retCode = require('./../utils/enums/CLI-errors')
11+
const exception = require('./../utils/exception')
1012
const Content = require('./../lu/qna')
1113
const LUOptions = require('./../lu/luOptions')
1214
const {ServiceBase} = require('./serviceBase')
@@ -22,101 +24,102 @@ export class QnaBuildCore {
2224
public async getKBList() {
2325
const response = await this.service.createRequest('/knowledgebases', 'GET')
2426
const text = await response.text()
25-
try {
26-
return JSON.parse(text)
27-
} catch {
28-
return text
27+
const kbList = JSON.parse(text)
28+
if (kbList.error) {
29+
throw (new exception(retCode.errorCode.LUIS_API_CALL_FAILED, text))
2930
}
31+
32+
return kbList
3033
}
3134

3235
public async getKB(kbId: string) {
3336
const response = await this.service.createRequest(`/knowledgebases/${kbId}`, 'GET')
3437
const text = await response.text()
35-
try {
36-
return JSON.parse(text)
37-
} catch {
38-
return text
38+
const kb = JSON.parse(text)
39+
if (kb.error) {
40+
throw (new exception(retCode.errorCode.LUIS_API_CALL_FAILED, text))
3941
}
42+
43+
return kb
4044
}
4145

4246
public async importKB(kbPayload: any) {
4347
const response = await this.service.createRequest('/knowledgebases/createasync', 'POST', kbPayload)
4448
const text = await response.text()
45-
try {
46-
return JSON.parse(text)
47-
} catch {
48-
return text
49+
const status = JSON.parse(text)
50+
if (status.error) {
51+
throw (new exception(retCode.errorCode.LUIS_API_CALL_FAILED, text))
4952
}
53+
54+
return status
5055
}
5156

5257
public async getOperationStatus(operationId: string) {
5358
const response = await this.service.createRequest(`/operations/${operationId}`, 'GET')
5459
const text = await response.text()
55-
try {
56-
return JSON.parse(text)
57-
} catch {
58-
return text
60+
const status = JSON.parse(text)
61+
if (status.error) {
62+
throw (new exception(retCode.errorCode.LUIS_API_CALL_FAILED, text))
5963
}
64+
65+
return status
6066
}
6167

6268
public async exportKB(kbId: string, environment: string) {
6369
const response = await this.service.createRequest(`/knowledgebases/${kbId}/${environment}/qna`, 'GET')
6470
const text = await response.text()
65-
try {
66-
return JSON.parse(text)
67-
} catch {
68-
return text
71+
const kb = JSON.parse(text)
72+
if (kb.error) {
73+
throw (new exception(retCode.errorCode.LUIS_API_CALL_FAILED, text))
6974
}
75+
76+
return kb
7077
}
7178

7279
public async updateKB(kbId: string, replaceKb: any) {
7380
const response = await this.service.createRequest(`/knowledgebases/${kbId}`, 'PATCH', replaceKb)
7481
const text = await response.text()
75-
try {
76-
return JSON.parse(text)
77-
} catch {
78-
return text
82+
const status = JSON.parse(text)
83+
if (status.error) {
84+
throw (new exception(retCode.errorCode.LUIS_API_CALL_FAILED, text))
7985
}
86+
87+
return status
8088
}
8189

8290
public async replaceKB(kbId: string, replaceKb: any) {
8391
const response = await this.service.createRequest(`/knowledgebases/${kbId}`, 'PUT', replaceKb)
8492
const text = await response.text()
85-
try {
86-
return JSON.parse(text)
87-
} catch {
88-
return text
93+
if (text) {
94+
throw (new exception(retCode.errorCode.LUIS_API_CALL_FAILED, text))
8995
}
9096
}
9197

9298
public async publishKB(kbId: string) {
9399
const response = await this.service.createRequest(`/knowledgebases/${kbId}`, 'POST')
94100
const text = await response.text()
95-
try {
96-
return JSON.parse(text)
97-
} catch {
98-
return text
101+
if (text) {
102+
throw (new exception(retCode.errorCode.LUIS_API_CALL_FAILED, text))
99103
}
100104
}
101105

102106
public async replaceAlt(altJson: any) {
103107
const response = await this.service.createRequest('/alterations', 'PUT', altJson)
104108
const text = await response.text()
105-
try {
106-
return JSON.parse(text)
107-
} catch {
108-
return text
109+
if (text) {
110+
throw (new exception(retCode.errorCode.LUIS_API_CALL_FAILED, text))
109111
}
110112
}
111113

112114
public async getEndpointKeys() {
113115
const response = await this.service.createRequest('/endpointkeys', 'GET')
114116
const text = await response.text()
115-
try {
116-
return JSON.parse(text)
117-
} catch {
118-
return text
117+
const endpointKeys = JSON.parse(text)
118+
if (endpointKeys.error) {
119+
throw (new exception(retCode.errorCode.LUIS_API_CALL_FAILED, text))
119120
}
121+
122+
return endpointKeys
120123
}
121124

122125
public generateDeclarativeAssets(recognizers: Array<Recognizer>, multiRecognizer: MultiLanguageRecognizer, settings: Settings)
@@ -148,7 +151,7 @@ export class QnaBuildCore {
148151
answer: qna.answer,
149152
source: qna.source,
150153
questions: qna.questions.slice(),
151-
metadata: qna.metadata,
154+
metadata: qna.metadata.slice(),
152155
context: qna.context
153156
}
154157
})
@@ -190,7 +193,7 @@ export class QnaBuildCore {
190193
fileContent += NEWLINE
191194
if (qnaItem.metadata && qnaItem.metadata.length > 0) {
192195
fileContent += '**Filters:**' + NEWLINE
193-
qnaItem.metadata.forEach((filter: any) => {
196+
qnaItem.metadata.sort((a: any, b: any) => (a.name > b.name) ? 1 : -1).forEach((filter: any) => {
194197
fileContent += '- ' + filter.name + ' = ' + filter.value + NEWLINE
195198
})
196199
fileContent += NEWLINE

packages/lu/test/commands/luis/convert.test.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,19 @@ describe('luis:convert negative tests', () => {
220220
})
221221

222222
})
223+
224+
it('luis:convert should show ERR message when prebuilt entity in pattern is not explicitly defined', (done) => {
225+
loadLuFile('./../../fixtures/testcases/bad4.lu')
226+
.then(res => {
227+
LuisBuilder.fromLUAsync(res)
228+
.then(res => done(res))
229+
.catch(err => {
230+
assert.isTrue(err.text.includes(`[ERROR] line 2:0 - line 2:27: Pattern "- hi {@personName:userName}" has prebuilt entity personName. Please define it explicitly with @ prebuilt personName.`))
231+
done()
232+
})
233+
})
234+
235+
})
223236
})
224237

225238
describe('luis:convert new entity format', () => {
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# greeting
2+
- hi {@personName:userName}

packages/lu/test/fixtures/verified/all.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,18 +175,18 @@
175175
]
176176
},
177177
{
178-
"text": "you can call me vishwac",
178+
"text": "you can call me vishwac",
179179
"intent": "AskForUserName",
180180
"entities": [
181181
{
182182
"entity": "userName",
183-
"startPos": 16,
184-
"endPos": 22
183+
"startPos": 17,
184+
"endPos": 23
185185
}
186186
]
187187
},
188188
{
189-
"text": "create an alarm",
189+
"text": "create an alarm",
190190
"intent": "CreateAlarm",
191191
"entities": []
192192
},

0 commit comments

Comments
 (0)