BotFramework:永远不会填充DialogState / DialogStack

时间:2019-02-04 17:29:05

标签: typescript azure botframework azure-cosmosdb azure-bot-service

我们有一个使用对话框的简单机器人,它可以正常工作,但是我最近将其更改为使用CosmosDB进行状态存储,现在我们注意到dialogStack为空。

该机器人的大部分代码都来自samples repo中的BotFramework示例。

每个消息的用户状态正在准确更新,初始化代码如下:

this.dialogState = conversationState.createProperty(DIALOG_STATE_PROPERTY);
this.dialogAccessor = userState.createProperty(DIALOG_PROPERTY);

this.dialogs = new DialogSet(this.dialogState);
this.dialogs.add(new GreetingDialog(GREETING_DIALOG, this.dialogAccessor));
this.dialogs.add(new PharmacyOrderDialog(PHARMACY_DIALOG, this.dialogAccessor));

this.conversationState = conversationState;
this.userState = userState;

我们在onTurn结束时调用saveChanges函数:

await this.conversationState.saveChanges(context);

我什至找不到关于dialogStack对象中应该包含的内容的任何信息,也没想到我认为是我们代码中的错误的解决方案。

感谢您的帮助。

编辑,添加了onTurn函数以提高清晰度:

public onTurn = async (context: TurnContext) => {
if (context.activity.type === ActivityTypes.Message) {
  if (context.activity.value) {
    let useridFromCard = context.activity.value.useridList;
    if (context.activity.value.useridList) {
      useridFromCard = context.activity.value.useridList;
    }
    await this.dialogAccessor.set(context, new DialogDetails(useridFromCard));
  }

  let dialogResult: DialogTurnResult;
  const dc = await this.dialogs.createContext(context);
  const results = await this.luisRecognizer.recognize(context);
  const topIntent = LuisRecognizer.topIntent(results);

  const dialogDetails: DialogDetails = await this.dialogAccessor.get(context);
  if (!dialogDetails) {
    await this.dialogAccessor.set(context, new DialogDetails(ENVIRONMENT.USERID, results));
  } else {
    dialogDetails.luisResults = results;
    await this.dialogAccessor.set(context, dialogDetails);
  }
  const interrupted = await this.isTurnInterrupted(dc, results);
  if (interrupted) {
    if (dc.activeDialog !== undefined) {
      await dc.repromptDialog();
    }
  } else {
    dialogResult = await dc.continueDialog();
  }

  if (!dc.context.responded) {
    switch (dialogResult.status) {
      case DialogTurnStatus.empty:
        switch (topIntent) {
          case GREETING_INTENT:
            await dc.beginDialog(GREETING_DIALOG);
            break;
          case PHARMACY_INTENT:
            await dc.beginDialog(PHARMACY_DIALOG);
            break;
          case NONE_INTENT:
            await context.sendActivities(ResponseRandomizer.getRandomResponse(RANDOM_PHRASE_PATH, POST_GREETING_MESSAGE_PHRASE_KEY));
            break;
          default:
            await dc.context.sendActivity("I didn't understand what you just said to me.");
            break;
        }
        break;
      case DialogTurnStatus.waiting:
        // The active dialog is waiting for a response from the user, so do nothing.
        break;
      case DialogTurnStatus.complete:
        // All child dialogs have ended. so do nothing.
        break;
      default:
        // Unrecognized status from child dialog. Cancel all dialogs.
        await dc.cancelAllDialogs();
        break;
    }
  }
} else if (context.activity.type === ActivityTypes.ConversationUpdate) {
  if (context.activity.membersAdded.length !== 0) {
    for (const idx in context.activity.membersAdded) {
      if (context.activity.membersAdded[idx].id !== context.activity.recipient.id) {
        const welcomeCard = CardFactory.adaptiveCard(WelcomeCard);
        await context.sendActivity({ attachments: [welcomeCard] });

        await context.sendActivities(ResponseRandomizer.getRandomResponse
          (RANDOM_PHRASE_PATH, WELCOME_MESSAGE_PHRASE_KEY));
        const useridCard = CardFactory.adaptiveCard(USERIDCard);
        await context.sendActivity({ attachments: [useridCard] });

      }
    }
  }
}
await this.conversationState.saveChanges(context);
await this.userState.saveChanges(context);
}

感谢所有帮助。可能永远不需要在其中存储任何有关我们的机器人当前设置方式的信息,但我只想确保这对我们而言不是错误。

2 个答案:

答案 0 :(得分:0)

首先,就您自己的代码而言,对话框状态(其堆栈等)实际上只是一个黑匣子。所有您需要做的就是确保保存了为对话框状态创建属性的状态容器,根据上述内容,对话框状态即为您(即this.conversationState.saveChanges(context))。

我需要查看您实际上是如何调用对话框的。至少在调用对话框方面,您可以使用onTurn方法是什么样的来更新您的问题吗?

答案 1 :(得分:0)

如果您使用的是dialogStackDialogSet,则肯定应该有一个WaterfallDialog。这是关于对话框和conceptual informationSDK referenceSample 19dialogStack如下所示:

enter image description here

尽管您的初始化/构造函数代码使用了dialogState dialogAccessor,但在常规代码方面还是有点不合常规,我认为这没什么错。但是,这不应该成为问题。

据我所知,您的onTurn代码也不错。

这使我相信以下两件事之一:

  1. 没有任何活动对话框时,您正在查看dialogStackdialogStack仅在向用户显示对话框时填充,然后在对话框末尾将其清除。听起来好像您的机器人没有问题,所以我想是这种情况。

  2. 哪个对话框给您问题(GreetingDialog或PharmacyOrderDialog)均未正确调用提示。

上面#2的可能修补程序:

  1. 您要将dialogDetails添加到userState中,然后将userState传递到每个对话框中。您不是从dialogDetails调用userState的提示,对吗?如果是这样,那可能是一个问题。如果您正在执行 操作,则您的dialogStack可能会出现在userState中,而不是conversationState中,这不是最佳选择。对话框/提示/瀑布对话框应该使用的唯一上下文是从conversationState派生的上下文,就像在this.dialogState = conversationState.createProperty(DIALOG_STATE_PROPERTY);中一样。因为您使用this.dialogs = new DialogSet(this.dialogState);定义了对话框,所以addthis.dialogs的每个对话框都已经获得了正确的上下文和dialogState,这是应该的,您只需要在对话框中使用它即可。

  2. 也可能是您对话框中的某个地方,您在过早呼叫endDialogcancelAllDialogs

如果这不能解决您的问题,请发布其中一个对话框的代码,给您带来麻烦,我可以帮助您进一步解决问题。