Выполнение вложенных WaterfallDialogs - nodejs - PullRequest
2 голосов
/ 13 января 2020

Я пытаюсь создать систему требований для диалогов заказов в нашем боте, чтобы мы могли повторно использовать основную структуру для различных процедур.


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!);

Запускает WaterfallDialog, объявленный в конструкторе Dialog, и метод route также находится внутри общего waterfallDialog.

Проблема в том, что когда один из дочерних диалоговых окон запрашивает пользователя, код не дождитесь ответа пользователя, и из-за того, как работает маршрут, он снова вызовет тот же диалог (если значение объекта не заполнено, он вызовет указанное диалоговое окно, что и делает менеджер требований).

Если при сохранении возврата из этой строки мы видим, что статус «ждет», как я могу это исправить или я должен создать независимые диалоги для каждого требования, а не только waterfallDialogs?

Спасибо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...