Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: bf-orchestrator lib integration #4384

Merged
merged 27 commits into from
Oct 26, 2020
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
571e4fa
Add bf-orchestrator dependency
taicchoumsft Oct 13, 2020
abd474a
Merge branch 'main' into tachou/orchestratorlib
taicchoumsft Oct 13, 2020
4c8b17f
Basic API and FT
taicchoumsft Oct 14, 2020
d8bcaa9
Merge branch 'main' into tachou/orchestratorlib
taicchoumsft Oct 14, 2020
d98e685
Add test to ignore list for now
taicchoumsft Oct 14, 2020
3a1a2c3
Fix linter issues
taicchoumsft Oct 15, 2020
ff3bfe7
Merge branch 'main' into tachou/orchestratorlib
taicchoumsft Oct 19, 2020
9e53aa8
Update orchestrator-core to pick up Linux fixes
taicchoumsft Oct 21, 2020
af001ea
Merge branch 'main' into tachou/orchestratorlib
taicchoumsft Oct 21, 2020
d337083
Fixes after latest merge
taicchoumsft Oct 21, 2020
2683207
Merge branch 'main' into tachou/orchestratorlib
taicchoumsft Oct 21, 2020
4272952
Attempt to run orchestrator tests on CI
taicchoumsft Oct 21, 2020
1ab34a1
Disable test again local model is available
taicchoumsft Oct 21, 2020
6e21b22
Merge branch 'main' into tachou/orchestratorlib
taicchoumsft Oct 22, 2020
ff119aa
Try to bring glic into alpine-linux
boydc2014 Oct 22, 2020
0770425
Revert "Try to bring glic into alpine-linux"
boydc2014 Oct 22, 2020
6e09c3e
Merge branch 'main' into tachou/orchestratorlib
taicchoumsft Oct 22, 2020
f7ad9b3
Try switching to buster for Orchestrator
taicchoumsft Oct 23, 2020
6227bb5
Merge branch 'tachou/orchestratorlib' of https://github.com/microsoft…
taicchoumsft Oct 23, 2020
7e211b6
Merge branch 'main' into tachou/orchestratorlib
taicchoumsft Oct 23, 2020
d401109
Merge branch 'main' into tachou/orchestratorlib
taicchoumsft Oct 23, 2020
5ccb46c
Merge branch 'main' into tachou/orchestratorlib
taicchoumsft Oct 23, 2020
fe3f33a
Merge branch 'main' into tachou/orchestratorlib
taicchoumsft Oct 23, 2020
1bc00ba
Merge branch 'main' into tachou/orchestratorlib
taicchoumsft Oct 26, 2020
2c372c3
lockdown orchestrator version due to API change
taicchoumsft Oct 26, 2020
37f89b5
Merge branch 'main' into tachou/orchestratorlib
taicchoumsft Oct 26, 2020
4869689
Add libgomp dep for orchestrator
taicchoumsft Oct 26, 2020
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: 1 addition & 1 deletion Composer/packages/server/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ const { createConfig } = require('@botframework-composer/test-utils');

module.exports = createConfig('server', 'node', {
setupFiles: [path.resolve(__dirname, 'src/__tests__/setupEnv.ts')],
testPathIgnorePatterns: ['src/__tests__/setupEnv.ts'],
testPathIgnorePatterns: ['src/__tests__/setupEnv.ts', 'orchestratorBuilder'],
});
1 change: 1 addition & 0 deletions Composer/packages/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
"@microsoft/bf-dispatcher": "^4.11.0-beta.20201016.393c6b2",
"@microsoft/bf-generate-library": "^4.10.0-daily.20201015.174962",
"@microsoft/bf-lu": "^4.11.0-dev.20201013.7ccb128",
"@microsoft/bf-orchestrator": "^4.11.0-beta.20201013.20d7917",
boydc2014 marked this conversation as resolved.
Show resolved Hide resolved
"archiver": "^5.0.2",
"axios": "^0.19.2",
"azure-storage": "^2.10.3",
Expand Down
16 changes: 16 additions & 0 deletions Composer/packages/server/src/models/bot/__mocks__/mockLUInput.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[
{
"name": "emptybot-1.dialog",
"content": "{\n \"$kind\": \"Microsoft.AdaptiveDialog\",\n \"$designer\": {\n \"name\": \"AddItem\",\n \"id\": \"225905\"\n },\n \"autoEndDialog\": true,\n \"defaultResultProperty\": \"dialog.result\",\n \"triggers\": [\n {\n \"$kind\": \"Microsoft.OnBeginDialog\",\n \"$designer\": {\n \"name\": \"BeginDialog\",\n \"id\": \"479346\"\n },\n \"actions\": [\n {\n \"$kind\": \"Microsoft.SetProperties\",\n \"$designer\": {\n \"id\": \"811190\",\n \"name\": \"Set properties\"\n },\n \"assignments\": [\n {\n \"property\": \"dialog.itemTitle\",\n \"value\": \"=coalesce(@itemTitle, $itemTitle)\"\n },\n {\n \"property\": \"dialog.listType\",\n \"value\": \"=coalesce(@listType, $listType)\"\n }\n ]\n },\n {\n \"$kind\": \"Microsoft.TextInput\",\n \"$designer\": {\n \"id\": \"282825\",\n \"name\": \"AskForTitle\"\n },\n \"prompt\": \"${TextInput_Prompt_282825()}\",\n \"maxTurnCount\": \"3\",\n \"property\": \"dialog.itemTitle\",\n \"value\": \"=coalesce(@itemTitle, $itemTitle)\",\n \"allowInterruptions\": \"!@itemTitle && #_Interruption.Score >= 0.9\"\n },\n {\n \"$kind\": \"Microsoft.ChoiceInput\",\n \"$designer\": {\n \"id\": \"878594\",\n \"name\": \"AskForListType\"\n },\n \"prompt\": \"${TextInput_Prompt_878594()}\",\n \"maxTurnCount\": \"3\",\n \"property\": \"dialog.listType\",\n \"value\": \"=@listType\",\n \"allowInterruptions\": \"!@listType\",\n \"outputFormat\": \"value\",\n \"choices\": [\n {\n \"value\": \"todo\",\n \"synonyms\": [\n \"to do\"\n ]\n },\n {\n \"value\": \"grocery\",\n \"synonyms\": [\n \"groceries\"\n ]\n },\n {\n \"value\": \"shopping\",\n \"synonyms\": [\n \"shoppers\"\n ]\n }\n ],\n \"appendChoices\": \"true\",\n \"defaultLocale\": \"en-us\",\n \"style\": \"Auto\",\n \"choiceOptions\": {\n \"inlineSeparator\": \", \",\n \"inlineOr\": \" or \",\n \"inlineOrMore\": \", or \",\n \"includeNumbers\": true\n },\n \"recognizerOptions\": {\n \"noValue\": false\n }\n },\n {\n \"$kind\": \"Microsoft.EditArray\",\n \"$designer\": {\n \"id\": \"733511\",\n \"name\": \"Edit an Array property\"\n },\n \"changeType\": \"push\",\n \"itemsProperty\": \"user.lists[dialog.listType]\",\n \"value\": \"=$itemTitle\"\n },\n {\n \"$kind\": \"Microsoft.SendActivity\",\n \"$designer\": {\n \"id\": \"139532\",\n \"name\": \"Send a response\"\n },\n \"activity\": \"${SendActivity_139532()}\"\n }\n ]\n }\n ],\n \"generator\": \"additem.lg\",\n \"recognizer\": \"additem.lu\"\n}\n",
"path": "/Users/tester/Desktop/EmptyBot-1/additem.dialog",
"relativePath": "",
"lastModified": "Thu Jul 09 2020 10:19:09 GMT-0700 (Pacific Daylight Time)"
},
{
"name": "additem.en-us.lu",
"content": "\n# TextInput_Response_282825\n- Please remind me to {itemTitle=buy milk}\n- Please remember that I need to {itemTitle=buy milk}\n- shoppers",
"path": "/Users/tester/Desktop/EmptyBot-1/dialogs/additem/language-understanding/en-us/additem.en-us.lu",
"relativePath": "dialogs/additem/language-understanding/en-us/additem.en-us.lu",
"lastModified": "Thu Jul 09 2020 10:19:09 GMT-0700 (Pacific Daylight Time)"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import * as path from 'path';

import rimraf from 'rimraf';
import { FileInfo } from '@bfc/types';
import { Utility } from '@microsoft/bf-orchestrator';

import { IFileStorage } from '../../storage/interface';
import { Builder } from '../builder';
import mockLUInput from '../__mocks__/mockLUInput.json';

const nlrId = 'pretrained.20200924.microsoft.dte.00.03.en.onnx';
const nlrPath: string = path.resolve('./orchestrator_ut_model/');
const downloadModelTimeoutMs = 90000;

describe('Orchestrator Tests', () => {
beforeAll(async () => {
// disable Orchestrator Lib console logging across the board - interferes with Jest
Utility.toPrintDebuggingLogToConsole = false;

const progressStatusStub = jest.fn();
const successStatusStub = jest.fn();

const builder = new Builder('', {} as IFileStorage, 'en-us');

// download the UT NLR model once before all tests are run - build tests don't work without a valid model
await builder.runOrchestratorNlrGet(nlrPath, nlrId, progressStatusStub, successStatusStub);
taicchoumsft marked this conversation as resolved.
Show resolved Hide resolved

expect(progressStatusStub).toBeCalled();
expect(successStatusStub).toBeCalledTimes(1);
}, downloadModelTimeoutMs);

afterAll(async () => {
const callbackStub = jest.fn();
rimraf(nlrPath, callbackStub);

expect(callbackStub).toBeCalledWith();
});

it('always lists DTE 3L model for FTs', async () => {
const builder = new Builder('', {} as IFileStorage, 'en-us');

const nlrList = await builder.runOrchestratorNlrList();
expect(Object.getOwnPropertyNames(nlrList.models)).toContain(nlrId);
});

it('throws if input empty', () => {
const builder = new Builder('', {} as IFileStorage, 'en-us');

expect(builder.runOrchestratorBuild([], nlrPath)).rejects.toThrow();
});

it('throws if NLR path invalid', () => {
const builder = new Builder('', {} as IFileStorage, 'en-us');

const data: FileInfo[] = [{ name: 'hello', content: 'test', lastModified: '', path: '', relativePath: '' }];
expect(builder.runOrchestratorBuild(data, 'invalidPath')).rejects.toThrow();
});

it('produces expected snapshot and recognizer shape', async () => {
const builder = new Builder('', {} as IFileStorage, 'en-us');

const buildOutput = await builder.runOrchestratorBuild(mockLUInput, nlrPath);

expect(buildOutput.outputs.map((o) => o.id)).toContain('additem.en-us.lu');

const addItemData = buildOutput.outputs.find((o) => o.id == 'additem.en-us.lu');
expect(addItemData?.snapshot).toBeTruthy();
});

it('produces expected recognizer shape', async () => {
const builder = new Builder('', {} as IFileStorage, 'en-us');
const buildOutput = await builder.runOrchestratorBuild(mockLUInput, nlrPath);

expect(buildOutput.outputs.map((o) => o.id)).toContain('additem.en-us.lu');

const addItemData = buildOutput.outputs.find((o) => o.id == 'additem.en-us.lu');
expect(addItemData?.recognizer).toBeTruthy();

expect(addItemData?.recognizer.orchestratorRecognizer).toBeTruthy();
expect(addItemData?.recognizer.orchestratorRecognizer.$kind).toBe('Microsoft.OrchestratorRecognizer');
});
});
2 changes: 1 addition & 1 deletion Composer/packages/server/src/models/bot/botProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -826,7 +826,7 @@ export class BotProject implements IBotProject {
try {
const defaultBotProjectFile: any = await AssetService.manager.botProjectFileTemplate;

for (const [_, file] of files) {
for (const [, file] of files) {
if (file.name.endsWith(FileExtensions.BotProject)) {
return fileList;
}
Expand Down
57 changes: 57 additions & 0 deletions Composer/packages/server/src/models/bot/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
import { FileInfo, IConfig } from '@bfc/shared';
import { ComposerReservoirSampler } from '@microsoft/bf-dispatcher/lib/mathematics/sampler/ComposerReservoirSampler';
import { ComposerBootstrapSampler } from '@microsoft/bf-dispatcher/lib/mathematics/sampler/ComposerBootstrapSampler';
import { Orchestrator } from '@microsoft/bf-orchestrator';

import { Path } from '../../utility/path';
import { IFileStorage } from '../storage/interface';
import log from '../../logger';

import { IOrchestratorBuildOutput, IOrchestratorNLRList, IOrchestratorProgress } from './interface';

// eslint-disable-next-line @typescript-eslint/no-var-requires
const crossTrainer = require('@microsoft/bf-lu/lib/parser/cross-train/crossTrainer.js');
const luBuild = require('@microsoft/bf-lu/lib/parser/lubuild/builder.js');
const qnaBuild = require('@microsoft/bf-lu/lib/parser/qnabuild/builder.js');
Expand Down Expand Up @@ -98,6 +102,59 @@ export class Builder {
this._locale = v;
}

/**
* Orchestrator: Get available list of NLR models
*/
public async runOrchestratorNlrList(): Promise<IOrchestratorNLRList> {
return JSON.parse(await Orchestrator.nlrListAsync());
}

/**
* Orchestrator: Download an available NLR model.
*
* @remarks Available NLR models and VersionIds are obtained by running runOrchestratorNlrList first.
*
* @param modelPath - Folder path to save NLR model
* @param nlrId - VersionId of the model
* @param onProgress - Callback to notify of D/L progress
* @param onFinish - Callback to notify of D/L completed
*/
public async runOrchestratorNlrGet(
modelPath: string,
nlrId: string,
onProgress: IOrchestratorProgress,
onFinish: IOrchestratorProgress
): Promise<void> {
await Orchestrator.nlrGetAsync(modelPath, nlrId, onProgress, onFinish);
}

/**
* Orchestrator: Build command to compile .lu files into Binary LU (.blu) snapshots.
boydc2014 marked this conversation as resolved.
Show resolved Hide resolved
*
* A snapshot (.blu file) is created per .lu supplied
*
* @param files - Array of FileInfo
* @param modelPath - Path to NLR model folder
* @param isDialog - Flag to toggle creation of Recognizer Dialogs (default: true)
* @param fullEmbedding - Use larger embeddings and skip size optimization (default: false)
* @returns An object containing snapshot bytes and recognizer dialogs for each .lu file
*/
public async runOrchestratorBuild(
files: FileInfo[],
modelPath: string,
isDialog = true,
fullEmbedding = false
): Promise<IOrchestratorBuildOutput> {
const luObjects = files
.filter((fi) => fi.name.endsWith('.lu'))
.map((fi) => ({
id: fi.name,
content: fi.content,
}));

return await Orchestrator.buildAsync(modelPath, luObjects, isDialog, null, fullEmbedding);
}

private async createGeneratedDir() {
// clear previous folder
await this.deleteDir(this.generatedFolderPath);
Expand Down
32 changes: 31 additions & 1 deletion Composer/packages/server/src/models/bot/interface.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { ILuisConfig, IQnAConfig } from '@bfc/shared';
import { BaseSchema, ILuisConfig, IQnAConfig } from '@bfc/shared';

import { CrossTrainConfig } from './builder';
import { RecognizerTypes } from './recognizer';
Expand Down Expand Up @@ -48,3 +48,33 @@ export interface IOperationLUFile {
export interface ILuisStatusOperation {
[key: string]: IOperationLUFile;
}

export interface IOrchestratorNLRList {
version: string;
readonly models: {
[versionId: string]: {
releaseDate: string;
description: string;
};
};
}

export interface IOrchestratorProgress {
(status: string): void;
}

export interface IOrchestratorRecognizer extends BaseSchema {
modelPath: string;
snapshotPath: string;
entityRecognizers: any[];
}

export interface IOrchestratorBuildOutput {
outputs: [{ id: string; snapshot: Uint8Array; recognizer: { [recog: string]: BaseSchema } }];
settings: {
orchestrator: {
modelPath: string;
snapshots: Map<string, string>;
};
};
}
Loading