constructor()

in experimental/adaptive-dialog/javascript_nodejs/08.todo-bot-with-luis-qnamaker/dialogs/rootDialog/rootDialog.js [21:243]


    constructor() {
        super(DIALOG_ID);
        const lgFile = Templates.parseFile(path.join(__dirname, 'rootDialog.lg'));
        this.lgGenerator = new TemplateEngineLanguageGenerator(lgFile);
        const dialog = new AdaptiveDialog(DIALOG_ID).configure({
            generator: this.lgGenerator,
            recognizer: this.createCrossTrainedRecognizer(),
            triggers: [
                new OnConversationUpdateActivity(this.welcomeUserSteps()),

                // Intent rules for the LUIS model. Each intent here corresponds to an intent defined in ./Dialogs/Resources/ToDoBot.lu file
                new OnIntent("Greeting", [], [
                    new SendActivity("${HelpRootDialog()}"),
                ]),
                new OnIntent("AddItem", [], 
                    [
                        new BeginDialog(AddToDoDialog.dialogName),
                    ],
                    // LUIS returns a confidence score with intent classification. 
                    // Conditions are expressions. 
                    // This expression ensures that this trigger only fires if the confidence score for the 
                    // AddToDoDialog intent classification is at least 0.5
                    "#AddItem.Score >= 0.5"                    
                ),
                new OnIntent("ViewItem", [], [
                    new BeginDialog(ViewToDoDialog.dialogName),
                ], "#ViewItem.Score >= 0.5"),
                new OnIntent("GetUserProfile", [], [
                    new BeginDialog(GetUserProfileDialog.dialogName),
                ], "#GetUserProfile.Score >= 0.5"),
                new OnIntent("DeleteItem", [], [
                    new BeginDialog(DeleteToDoDialog.dialogName),
                ], "#DeleteItem.Score >= 0.5"),
                new OnIntent("Cancel", [], [
                    // Ask user for confirmation.
                    // This input will still use the recognizer and specifically the confirm list entity extraction.
                    new ConfirmInput().configure(
                    {
                        prompt: new ActivityTemplate("${Cancel.prompt()}"),
                        property: new StringExpression("turn.confirm"),
                        value: new ValueExpression("=@confirmation"),
                        // Allow user to intrrupt this only if we did not get a value for confirmation.
                        allowInterruptions: new BoolExpression("!@confirmation"),
                    }),
                    new IfCondition().configure(
                    {
                        condition: new BoolExpression("turn.confirm == true"),
                        actions :[
                            // This is the global cancel in case a child dialog did not explicit handle cancel.
                            new SendActivity("Cancelling all dialogs.."),

                            // SendActivity supports full language generation resolution.
                            // See here to learn more about language generation
                            // https://aka.ms/language-generation
                            new SendActivity("${WelcomeActions()}"),
                            new CancelAllDialogs(),
                        ],
                        elseActions: [
                            new SendActivity("${CancelCancelled()}"),
                            new SendActivity("${WelcomeActions()}"),
                        ],
                    }),
                ],"#Cancel.Score >= 0.8"),
                
                // Help and chitchat is handled by qna
                new OnQnAMatch([
                    // Use code action to render QnA response. This is also a demonstration of how to use code actions to light up custom functionality.
                    new CodeAction(this.resolveAndSendQnAAnswer.bind(this))
                ]),

                // This trigger matches if the response from your QnA KB has follow up prompts.
                new OnQnAMatch([
                    new SetProperty().configure({
                        property: new StringExpression("dialog.qnaContext"),
                        value: new ValueExpression("=turn.recognized.answers[0].context.prompts")
                    }),
                    new TextInput().configure({
                        prompt: new ActivityTemplate('${ShowMultiTurnAnswer()}'),
                        property: new StringExpression('turn.qnaMultiTurnResponse'),
                        // We want the user to respond to the follow up prompt. Do not allow interruptions.
                        allowInterruptions: new BoolExpression("false"),
                        // Since we can have multiple instances of follow up prompts within a single turn, set this to always prompt. 
                        // Alternate to doing this is to delete the 'turn.qnaMultiTurnResponse' property before the EmitEvent.
                        alwaysPrompt: new BoolExpression("true")
                    }),
                    new SetProperty().configure({
                        property: new StringExpression("turn.qnaMatchFromContext"),
                        value: new ValueExpression("=where(dialog.qnaContext, item, item.displayText == turn.qnaMultiTurnResponse)")
                    }),
                    new DeleteProperty().configure({
                        property: new StringExpression("dialog.qnaContext")
                    }),
                    new IfCondition().configure({
                        condition: new BoolExpression("turn.qnaMatchFromContext && count(turn.qnaMatchFromContext) > 0"),
                        actions: [
                            new SetProperty().configure({
                                property: new StringExpression("turn.qnaIdFromPrompt"),
                                value: new ValueExpression("=turn.qnaMatchFromContext[0].qnaId")
                            }),
                            new EmitEvent().configure({
                                eventName: new StringExpression(DialogEvents.activityReceived),
                                eventValue: new ValueExpression("=turn.activity")
                            })
                        ]
                    })
                ], "count(turn.recognized.answers[0].context.prompts) > 0"),

                // This trigger fires when the recognizers do not agree on who should win.
                // This enables you to write simple rules to pick a winner or ask the user for disambiguation.
                new OnChooseIntent([
                    new SetProperty().configure(
                    {
                        property: new StringExpression("dialog.luisResult"),
                        value: new ValueExpression(`=jPath(turn.recognized, "$.candidates{.id == 'LUIS_${DIALOG_ID}'}[0]")`)
                    }),
                    new SetProperty().configure(
                    {
                        property: new StringExpression("dialog.qnaResult"),
                        value: new ValueExpression(`=jPath(turn.recognized, "$.candidates{.id == 'QnA_${DIALOG_ID}'}[0]")`)
                    }),

                    // Rules to determine winner before disambiguation
                    // Rule 1: High confidence result from LUIS and Low confidence result from QnA => Pick LUIS result
                    new IfCondition().configure(
                    {
                        condition: new BoolExpression("dialog.luisResult.score >= 0.9 && dialog.qnaResult.score <= 0.5"),
                        actions: [
                            // By Emitting a recognized intent event with the recognition result from LUIS, adaptive dialog
                            // will evaluate all triggers with that recognition result.
                            new EmitEvent().configure(
                            {
                                eventName: new StringExpression(AdaptiveEvents.recognizedIntent),
                                eventValue: new ValueExpression("=dialog.luisResult.result")
                            }),
                            new BreakLoop()
                        ]
                    }),

                    // Rule 2: High confidence result from QnA, Low confidence result from LUIS => Pick QnA result
                    new IfCondition().configure(
                    {
                        condition: new BoolExpression("dialog.luisResult.score <= 0.5 && dialog.qnaResult.score >= 0.9"),
                        actions: [
                            new EmitEvent().configure(
                            {
                                eventName: new StringExpression(AdaptiveEvents.recognizedIntent),
                                eventValue: new ValueExpression("=dialog.qnaResult.result")
                            }),
                            new BreakLoop()
                        ]
                    }),

                    // Rule 3: QnA has exact match (>=0.95) => Pick QnA result
                    new IfCondition().configure(
                    {
                        condition: new BoolExpression("dialog.qnaResult.score >= 0.95"),
                        actions: [
                            new EmitEvent().configure(
                            {
                                eventName: new StringExpression(AdaptiveEvents.recognizedIntent),
                                eventValue: new ValueExpression("=dialog.qnaResult.result")
                            }),
                            new BreakLoop()
                        ]
                    }),

                    // Rule 4: QnA came back with no match => Pick LUIS result
                    new IfCondition().configure(
                    {
                        condition: new BoolExpression("dialog.qnaResult.score <= 0.05"),
                        actions: [
                            new EmitEvent().configure(
                            {
                                eventName: new StringExpression(AdaptiveEvents.recognizedIntent),
                                eventValue: new ValueExpression("=dialog.luisResult.result")
                            }),
                            new BreakLoop()
                        ]
                    }),
    
                    // None of the rules were true. So ask user to disambiguate. 
                    new TextInput().configure(
                    {
                        property: new StringExpression("turn.intentChoice"),
                        prompt: new ActivityTemplate("${chooseIntentResponseWithCard()}"),
                        // Adaptive card 'data' is automatically bound to entities or intent.
                        // You can include 'intent':'value' in your adaptive card's data to pick that up as an intent.
                        value: new ValueExpression("=@userChosenIntent"),
                        alwaysPrompt: new BoolExpression("true"),
                        allowInterruptions: new BoolExpression("false")
                    }),

                    // Decide which recognition result to use based on user response to disambiguation. 
                    new IfCondition().configure(
                    {
                        condition: new BoolExpression("turn.intentChoice != 'none'"),
                        actions: [
                            new EmitEvent().configure(
                            {
                                eventName: new StringExpression(AdaptiveEvents.recognizedIntent),
                                eventValue: new ValueExpression("=dialog[turn.intentChoice].result")
                            })
                        ],
                        elseActions: [
                            new SendActivity("Sure, no worries.")
                        ],
                    }),
                ]),
            ]
        });

        // Add named dialogs to the DialogSet. These names are saved in the dialog state.
        this.addDialog(dialog);

        // Add other dialogs
        this.addDialog(new ViewToDoDialog());
        this.addDialog(new GetUserProfileDialog());
        this.addDialog(new DeleteToDoDialog());
        this.addDialog(new AddToDoDialog());

        // The initial child Dialog to run.
        this.initialDialogId = DIALOG_ID;
    }