首页 > 解决方案 > 执行嵌套的 WaterfallDialogs - nodejs

问题描述

我正在尝试为我们的机器人中的订单对话框构建一个需求系统,以便我们可以将主要结构重用于不同的程序。


enum DialogIds {
    // Necessary Ids
    oauthPrompt = "oauthPrompt",

    // Requirement dialogs
    itemWaterfallDialog = "itemWaterfallDialog",

    // Reset Dialogs
    summaryWaterfallDialog = "summaryWaterfallDialog",

    // All other prompts
    unrecognizedItemPrompt = "unrecognizedItemPrompt",
    beneficiaryConfirmPrompt = "beneficiaryConfirmPrompt",
    askBeneficiaryPrompt = "askBeneficiaryPrompt",
    reasonPrompt = "reasonPrompt",
    orderConfirm = "orderConfirm"
}

export class OrderDialog extends ComponentDialog {
    private responseManager: ResponseManager;
    private requirementManager: RequirementManager;
    private luisResult: RecognizerResult | undefined = undefined;

    // TODO: get userState and ConversationState
    constructor(
        private service: BotServices,
        telemetryClient: BotTelemetryClient
    ) {
        super(OrderDialog.name);

        this.initialDialogId = OrderDialog.name;

        // Response manager serving OrderResponses.json
        this.responseManager = new ResponseManager(["fr-fr"], [OrderResponses]);

        const routeWaterfallDialog: ((
            sc: WaterfallStepContext
        ) => Promise<DialogTurnResult>)[] = [
            this.route.bind(this)
        ];

        this.telemetryClient = telemetryClient;
        this.addDialog(
            new WaterfallDialog(this.initialDialogId, routeWaterfallDialog)
        );

        /**
         * Order specific dialogs and requirements
         */

        const itemWaterfallDialog: WaterfallDialog = new WaterfallDialog(
            DialogIds.itemWaterfallDialog,
            [this.itemStep.bind(this), this.itemEndStep.bind(this)]
        );
        this.addDialog(itemWaterfallDialog);

        const reqs = [
            new Requirement<string>("claimant", false, undefined),
            new Requirement<string>(
                "item",
                true,
                undefined,
                itemWaterfallDialog,
                DialogIds.itemWaterfallDialog
            ),
        ];

        // Create requirement manager for this dialog
        this.requirementManager = new RequirementManager(reqs);

        // Add all the prompt
        this.addDialog(new ConfirmPrompt(DialogIds.beneficiaryConfirmPrompt));
        this.addDialog(new TextPrompt(DialogIds.unrecognizedItemPrompt));
        this.addDialog(new TextPrompt(DialogIds.askBeneficiaryPrompt));
        this.addDialog(new TextPrompt(DialogIds.reasonPrompt));
        this.addDialog(new ConfirmPrompt(DialogIds.orderConfirm));
    }

    /**
     * We save the token, query graph is necessary and
     * execute the next dialog if any, if not we'll
     * execute the summary waterfallDialog.
     * @param sc context
     */
    async route(sc: WaterfallStepContext): Promise<DialogTurnResult> {
        this.requirementManager.set("claimant", 'nothing');

        let next = this.requirementManager.getNext();
        while (next) {

            await sc.beginDialog(next.dialogId!);

            // Execute summary if there are no elements left
            if (!this.requirementManager.getNextBool()) {
                await sc.beginDialog(DialogIds.summaryWaterfallDialog);
            }
            next = this.requirementManager.getNext();
        }

        return sc.endDialog();
    }

    /**
     * ITEM
     * @param sc
     */

    async itemStep(sc: WaterfallStepContext): Promise<DialogTurnResult> {
        // Couldn't recgonize any item
        if (this.luisResult!.entities.length === 0) {
            await sc.context.sendActivity(
                this.responseManager.getResponse(
                    OrderResponses.itemNotRecognized
                )
            );

            // prompt user for the item again
            return await sc.prompt(
                DialogIds.unrecognizedItemPrompt,
                this.responseManager.getResponse(OrderResponses.rePromptItem)
            );
        }

        const entities = this.luisResult!.entities as generalLuis["entities"];

        if (entities.PhoneItem || entities.ComputerItem) {
            const item = entities.PhoneItem
                ? entities.PhoneItem
                : entities.ComputerItem;

            if (item) {
                this.requirementManager.set("item", item[0][0]);
            }
        }

        return await sc.next();
    }

    async itemEndStep(sc: WaterfallStepContext): Promise<DialogTurnResult> {
        // Save result from itemStep(prompt triggered) if any
        if (sc.result) {
            await sc.context.sendActivity(
                this.responseManager.getResponse(OrderResponses.thanksUser)
            );

            // retrieve item from result and save it
            const item = sc.result as string;
            this.requirementManager.set("item", item);
        }

        return sc.endDialog();
    }

}

线

const result = await sc.beginDialog(next.dialogId!);

是在Dialog的构造函数中声明了一个WaterfallDialog,并且route方法也在一般的waterfallDialog里面。

问题是,当其中一个子对话框提示用户时,代码不会等待用户响应,并且由于路由的工作方式,它会再次调用相同的对话框(如果对象上的值不是填充它将调用指示的对话框,这就是需求管理器所做的)。

如果保存该行的返回,我们可以看到状态为“等待”,我该如何修复它,或者我应该为每个需求创建独立的对话框,而不仅仅是瀑布对话框?

谢谢。

标签: node.jsbotframework

解决方案


推荐阅读