簡體   English   中英

在 Microsoft Bot Framework v4 中處理自適應卡片 - Nodejs

[英]Handling Adaptive cards in Microsoft Bot Framework v4 - Nodejs

  return new Promise((resolve, reject) => {
                            x = context.sendActivity({
                            text: 'hi',
                             attachments: [CardFactory.adaptiveCard(menuJson)]
                            })

我正在嘗試發送一個自適應卡,其中包含一個 Input.text 字段......現在我的問題是如何使用上下文對象從我的程序中的用戶獲取輸入數據?

即如何使用 node js 在 bot framework v4 中處理自適應卡?

自適應卡片發送的提交結果與常規用戶文本略有不同。 當用戶輸入聊天內容並發送一條普通消息時,它最終會出現在context.activity.text 當用戶在自適應卡片上填寫輸入時,它最終會出現在context.activity.value ,這是一個對象,其中鍵名是menuJson中的id ,值是自適應卡片中的字段值。

例如,json:

{
    "type": "AdaptiveCard",
    "body": [
        {
            "type": "TextBlock",
            "text": "Test Adaptive Card"
        },
        {
            "type": "ColumnSet",
            "columns": [
                {
                    "type": "Column",
                    "items": [
                        {
                            "type": "TextBlock",
                            "text": "Text:"
                        }
                    ],
                    "width": 20
                },
                {
                    "type": "Column",
                    "items": [
                        {
                            "type": "Input.Text",
                            "id": "userText",
                            "placeholder": "Enter Some Text"
                        }
                    ],
                    "width": 80
                }
            ]
        }
    ],
    "actions": [
        {
            "type": "Action.Submit",
            "title": "Submit"
        }
    ],
    "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
    "version": "1.0"
}

.. 創建一張如下所示的卡片:

測試自適應卡

如果用戶在文本框中輸入“Testing Testing 123”並點擊提交, context.activity將類似於:

{ type: 'message',
  value: { userText: 'Testing Testing 123' },
  from: { id: 'xxxxxxxx-05d4-478a-9daa-9b18c79bb66b', name: 'User' },
  locale: '',
  channelData: { postback: true },
  channelId: 'emulator',
  conversation: { id: 'xxxxxxxx-182b-11e9-be61-091ac0e3a4ac|livechat' },
  id: 'xxxxxxxx-182b-11e9-ad8e-63b45e3ebfa7',
  localTimestamp: 2019-01-14T18:39:21.000Z,
  recipient: { id: '1', name: 'Bot', role: 'bot' },
  timestamp: 2019-01-14T18:39:21.773Z,
  serviceUrl: 'http://localhost:58453' }

用戶提交可以在context.activity.value.userText看到。

請注意,自適應卡片提交作為回發發送,這意味着提交數據不會作為對話的一部分出現在聊天窗口中——它保留在自適應卡片上。

瀑布對話框中使用自適應卡片

您的問題與此不太相關,但由於您最終可能會嘗試這樣做,因此我認為將其包含在我的答案中可能很重要。

自適應卡片本身不像提示那樣工作。 使用提示,提示將顯示並等待用戶輸入,然后再繼續。 但是對於自適應卡片(即使它包含一個輸入框和一個提交按鈕),自適應卡片中沒有代碼會導致瀑布對話框在繼續對話框之前等待用戶輸入。

因此,如果您使用的是接受用戶輸入的自適應卡片,您通常希望處理用戶在瀑布對話框上下文之外提交的任何內容。

話雖如此,如果您想將自適應卡片用作瀑布對話框的一部分,則有一種解決方法。 基本上,您:

  1. 顯示自適應卡片
  2. 顯示文本提示
  3. 將用戶的 Adaptive Card 輸入轉換為 Text Prompt 的輸入

在您的瀑布對話框文件中(步驟 1 和 2):

async displayCard(step) {
    // Display the Adaptive Card
    await step.context.sendActivity({
        text: 'Adaptive Card',
        attachments: [yourAdaptiveCard],
});
    // Display a Text Prompt
    return await step.prompt('textPrompt', 'waiting for user input...');
}

async handleResponse(step) {
    // Do something with step.result
    // Adaptive Card submissions are objects, so you likely need to JSON.parse(step.result)
    ...
    return await step.next();

在您的bot.ts文件中(第 3 步):

const activity = dc.context.activity;

if (!activity.text && activity.value) {
    activity.text = JSON.stringify(activity.value);
}

我在帶有 WaterfallDialog 的 ComponentDialog 中使用 Adaptive Card,我想處理 Input.submit 操作。

我的問題是:如何處理響應、獲取輸入值並正確轉到下一個對話步驟?

我嘗試了 2 種方法來解決我的問題。

我的自適應卡的 json 像:

{
    "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
    "type": "AdaptiveCard",
    "version": "1.0",
    "body": [
        {
            "type": "TextBlock",
            "text": "Create Schedule",
            "size": "large",
            "weight": "bolder"
        },
        {
            "type": "TextBlock",
            "text": "Name",
            "size": "small"
        },
        {
            "type": "Input.Text",
            "id": "name"
        }
    ],
    "actions": [
        {
            "type": "Action.Submit",
            "title": "Save",
            "data": {
                "result": "save"
            }
        },
        {
            "type": "Action.Submit",
            "title": "Cancel",
            "data": {
                "result": "cancel"
            }
        }
    ] 
}

1.使用提示和提示驗證

這種方式使用提示驗證功能來處理 Input.submit 回發操作。

因為postback action不發送短信(不顯示在channel中),這使得TextPrompt的默認validate無法通過(發送retryPrompt),所以我寫了一個提示validate函數,validate響應是postback action。

class MyDialog extends ComponentDialog{
    constructor(dialogId) {
        // ...
        this.addDialog(new TextPrompt('textPropmt', this.promptValidator);
        this.addDialog(new WaterfallDailog(dialogId, [
            // dialog steps
            async function(step){
                await step.context.sendActivity({
                    attachments: [CardFactory.adaptiveCard(FormCard)]
                })
                await step.prompt('TextPrompt', 'waiting for your submit.')
            },

            async function(step){
                await step.context.sendActivity('get response.');

                // get adaptive card input value
                const resultValue = step.context.activity.value; 

                return await step.endDialog();
            }
        ]));
    }

    // prompt validate function
    async promptValidator(promptContext){
        const activity = promptContext.context.activity;
        return activity.type === 'message' && activity.channelData.postback;
    }

    // ..
}

2. 使用 Dialog.EndOfTurn

這種方式使用 Dialog.EndOfTurn 來結束轉彎。 如果用戶發送任何響應,機器人將進入下一個對話步驟。

請記住檢查響應是否為自適應卡片提交操作(回發),如果不是,請執行某些操作以拒絕它或重試。

class MyDialog extends ComponentDialog{
    constructor(dialogId) {
        // ...

        this.addDialog(new WaterfallDialog(dialogId, [
            // dialog steps
            async function(step) {
                await step.context.sendActivity({
                    attachments: [CardFactory.adaptiveCard(FormCard)]
                });

                return Dialog.EndOfTurn;
            },

            async function(step) {
                await step.context.sendActivity('get response.');
                const activity = step.context.activity;

                if (activity.channelData.postback) {
                    // get adaptive card input value
                    const resultValue = activity.value;
                } else {
                    await step.context.sendActivity("Sorry, I don't understand.");
                }

                return await step.endDialog();
            }
        ]));
    }
    // ...
}

最后,我會選擇第二種方式(Dialog.EndOfTurn)來解決這個問題,因為我認為控制對話步驟和處理用戶中斷更容易,例如當用戶想要取消這個動作並返回到main時對話。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM