From a9f9b96e396152638d6b3bfd76c5b676ff4ca3fc Mon Sep 17 00:00:00 2001 From: Fei Chen <43032123+feich-ms@users.noreply.github.com> Date: Sat, 31 Oct 2020 04:06:46 +0800 Subject: [PATCH] Fix a regression on multiturn extraction functionality of qna url or file import api (#1042) (#1043) * fix regression on file and url import api * add unit tests for multiturn extraction" --- packages/lu/src/parser/qnabuild/builder.ts | 32 +++- .../lu/test/parser/qnabuild/qnabuild.test.js | 161 ++++++++++++++++++ 2 files changed, 184 insertions(+), 9 deletions(-) diff --git a/packages/lu/src/parser/qnabuild/builder.ts b/packages/lu/src/parser/qnabuild/builder.ts index 0ebefa17f..d16102d97 100644 --- a/packages/lu/src/parser/qnabuild/builder.ts +++ b/packages/lu/src/parser/qnabuild/builder.ts @@ -301,7 +301,9 @@ export class Builder { url: string, subscriptionkey: string, endpoint: string, - kbName: string) { + kbName: string, + enableHierarchicalExtraction: boolean = false, + defaultAnswerUsedForExtraction: string = 'More Answers') { const qnaBuildCore = new QnaBuildCore(subscriptionkey, endpoint) const kbs = (await qnaBuildCore.getKBList()).knowledgebases @@ -320,7 +322,7 @@ export class Builder { } // create a new kb - kbId = await this.createUrlKB(qnaBuildCore, url, kbName) + kbId = await this.createUrlKB(qnaBuildCore, url, kbName, enableHierarchicalExtraction, defaultAnswerUsedForExtraction) const kbJson = await qnaBuildCore.exportKB(kbId, 'Test') const kb = new KB(kbJson) @@ -335,7 +337,9 @@ export class Builder { fileUri: string, subscriptionkey: string, endpoint: string, - kbName: string) { + kbName: string, + enableHierarchicalExtraction: boolean = false, + defaultAnswerUsedForExtraction: string = 'More Answers') { const qnaBuildCore = new QnaBuildCore(subscriptionkey, endpoint) const kbs = (await qnaBuildCore.getKBList()).knowledgebases @@ -354,7 +358,7 @@ export class Builder { } // create a new kb - kbId = await this.createFileKB(qnaBuildCore, fileName, fileUri, kbName) + kbId = await this.createFileKB(qnaBuildCore, fileName, fileUri, kbName, enableHierarchicalExtraction, defaultAnswerUsedForExtraction) const kbJson = await qnaBuildCore.exportKB(kbId, 'Test') const kb = new KB(kbJson) @@ -465,12 +469,17 @@ export class Builder { return kbId } - async createUrlKB(qnaBuildCore: QnaBuildCore, url: string, kbName: string) { - const kbJson = { + async createUrlKB(qnaBuildCore: QnaBuildCore, url: string, kbName: string, enableHierarchicalExtraction: boolean, defaultAnswerUsedForExtraction: string) { + let kbJson: any = { name: kbName, qnaList: [], urls: [url], - files: [] + files: [], + } + + if (enableHierarchicalExtraction) { + kbJson.enableHierarchicalExtraction = true + kbJson.defaultAnswerUsedForExtraction = defaultAnswerUsedForExtraction } let response = await qnaBuildCore.importKB(kbJson) @@ -481,8 +490,8 @@ export class Builder { return kbId } - async createFileKB(qnaBuildCore: QnaBuildCore, fileName: string, fileUri: string, kbName: string) { - let kbJson = { + async createFileKB(qnaBuildCore: QnaBuildCore, fileName: string, fileUri: string, kbName: string, enableHierarchicalExtraction: boolean, defaultAnswerUsedForExtraction: string) { + let kbJson: any = { name: kbName, qnaList: [], urls: [], @@ -492,6 +501,11 @@ export class Builder { }] } + if (enableHierarchicalExtraction) { + kbJson.enableHierarchicalExtraction = true + kbJson.defaultAnswerUsedForExtraction = defaultAnswerUsedForExtraction + } + let response = await qnaBuildCore.importKB(kbJson) let operationId = response.operationId const opResult = await this.getKBOperationStatus(qnaBuildCore, operationId, 1000) diff --git a/packages/lu/test/parser/qnabuild/qnabuild.test.js b/packages/lu/test/parser/qnabuild/qnabuild.test.js index 084923830..bac157fdd 100644 --- a/packages/lu/test/parser/qnabuild/qnabuild.test.js +++ b/packages/lu/test/parser/qnabuild/qnabuild.test.js @@ -134,6 +134,87 @@ describe('builder: importUrlOrFileReference function return lu content from file }) }) +describe('builder: importUrlOrFileReference function return lu content from file sucessfully with multiturn extraction enabled', () => { + before(function () { + nock('https://westus.api.cognitive.microsoft.com') + .get(uri => uri.includes('qnamaker')) + .reply(200, { + knowledgebases: + [{ + name: 'test.en-us.qna', + id: 'f8c64e2a-1111-3a09-8f78-39d7adc76ec5', + hostName: 'https://myqnamakerbot.azurewebsites.net' + }] + }) + + nock('https://westus.api.cognitive.microsoft.com') + .post(uri => uri.includes('createasync')) + .reply(202, { + operationId: 'f8c64e2a-aaaa-3a09-8f78-39d7adc76ec5' + }) + + nock('https://westus.api.cognitive.microsoft.com') + .get(uri => uri.includes('operations')) + .reply(200, { + operationState: 'Succeeded', + resourceLocation: 'a/b/f8c64e2a-2222-3a09-8f78-39d7adc76ec5' + }) + + nock('https://westus.api.cognitive.microsoft.com') + .get(uri => uri.includes('knowledgebases')) + .reply(200, { + qnaDocuments: [{ + id: 1, + source: 'SurfaceManual.pdf', + questions: ['User Guide'], + answer: 'More Answers', + metadata: [], + prompts: [{ + displayOrder: 0, + displayText: 'With Windows 10', + qnaId: 2 + }] + }, + { + id: 2, + source: 'SurfaceManual.pdf', + questions: ['With Windows 10'], + answer: '**With Windows 10**', + metadata: [], + prompts: [] + }] + }) + }) + + nock('https://westus.api.cognitive.microsoft.com') + .delete(uri => uri.includes('knowledgebases')) + .reply(200) + + it('should return lu content from file successfully', async () => { + const builder = new Builder() + const luContent = await builder.importFileReference( + 'SurfaceManual.pdf', + 'https://download.microsoft.com/download/2/9/B/29B20383-302C-4517-A006-B0186F04BE28/surface-pro-4-user-guide-EN.pdf', + uuidv1(), + 'https://westus.api.cognitive.microsoft.com/qnamaker/v4.0', + 'mytest.en-us.qna', + true) + + assert.equal(luContent, + `> # QnA pairs${NEWLINE}${NEWLINE}` + + `> !# @qna.pair.source = SurfaceManual.pdf${NEWLINE}${NEWLINE}` + + `${NEWLINE}${NEWLINE}` + + `# ? User Guide${NEWLINE}${NEWLINE}` + + `\`\`\`markdown${NEWLINE}` + + `More Answers${NEWLINE}\`\`\`${NEWLINE}${NEWLINE}` + + `> !# @qna.pair.source = SurfaceManual.pdf${NEWLINE}${NEWLINE}` + + `${NEWLINE}${NEWLINE}` + + `# ? With Windows 10${NEWLINE}${NEWLINE}` + + `\`\`\`markdown${NEWLINE}` + + `**With Windows 10**${NEWLINE}\`\`\`${NEWLINE}${NEWLINE}`) + }) +}) + describe('builder: importUrlOrFileReference function return lu content from url sucessfully', () => { before(function () { nock('https://westus.api.cognitive.microsoft.com') @@ -193,6 +274,86 @@ describe('builder: importUrlOrFileReference function return lu content from url }) }) +describe('builder: importUrlOrFileReference function return lu content from url sucessfully with multiturn extraction enabled', () => { + before(function () { + nock('https://westus.api.cognitive.microsoft.com') + .get(uri => uri.includes('qnamaker')) + .reply(200, { + knowledgebases: + [{ + name: 'test.en-us.qna', + id: 'f8c64e2a-1111-3a09-8f78-39d7adc76ec5', + hostName: 'https://myqnamakerbot.azurewebsites.net' + }] + }) + + nock('https://westus.api.cognitive.microsoft.com') + .post(uri => uri.includes('createasync')) + .reply(202, { + operationId: 'f8c64e2a-aaaa-3a09-8f78-39d7adc76ec5' + }) + + nock('https://westus.api.cognitive.microsoft.com') + .get(uri => uri.includes('operations')) + .reply(200, { + operationState: 'Succeeded', + resourceLocation: 'a/b/f8c64e2a-2222-3a09-8f78-39d7adc76ec5' + }) + + nock('https://westus.api.cognitive.microsoft.com') + .get(uri => uri.includes('knowledgebases')) + .reply(200, { + qnaDocuments: [{ + id: 1, + source: 'SurfaceManual.pdf', + questions: ['User Guide'], + answer: 'More Answers', + metadata: [], + prompts: [{ + displayOrder: 0, + displayText: 'With Windows 10', + qnaId: 2 + }] + }, + { + id: 2, + source: 'SurfaceManual.pdf', + questions: ['With Windows 10'], + answer: '**With Windows 10**', + metadata: [], + prompts: [] + }] + }) + + nock('https://westus.api.cognitive.microsoft.com') + .delete(uri => uri.includes('knowledgebases')) + .reply(200) + }) + + it('should return lu content from url successfully', async () => { + const builder = new Builder() + const luContent = await builder.importUrlReference( + 'https://docs.microsoft.com/en-in/azure/cognitive-services/qnamaker/faqs', + uuidv1(), + 'https://westus.api.cognitive.microsoft.com/qnamaker/v4.0', + 'mytest.en-us.qna', + true) + + assert.equal(luContent, + `> # QnA pairs${NEWLINE}${NEWLINE}` + + `> !# @qna.pair.source = SurfaceManual.pdf${NEWLINE}${NEWLINE}` + + `${NEWLINE}${NEWLINE}` + + `# ? User Guide${NEWLINE}${NEWLINE}` + + `\`\`\`markdown${NEWLINE}` + + `More Answers${NEWLINE}\`\`\`${NEWLINE}${NEWLINE}` + + `> !# @qna.pair.source = SurfaceManual.pdf${NEWLINE}${NEWLINE}` + + `${NEWLINE}${NEWLINE}` + + `# ? With Windows 10${NEWLINE}${NEWLINE}` + + `\`\`\`markdown${NEWLINE}` + + `**With Windows 10**${NEWLINE}\`\`\`${NEWLINE}${NEWLINE}`) + }) +}) + describe('builder: importUrlOrFileReference function return lu content from url sucessfully when updating kb', () => { before(function () { nock('https://westus.api.cognitive.microsoft.com')