Typescript 使用BotFrameworkV4中的瀑布对话框从自适应卡获取用户输入

Typescript 使用BotFrameworkV4中的瀑布对话框从自适应卡获取用户输入,typescript,botframework,adaptive-cards,Typescript,Botframework,Adaptive Cards,我正试图在我的聊天机器人中放置一张简单的自适应卡,用于收集用户名和电子邮件。我不知道如何从卡中获取输入 在我显示对话框的瀑布步骤中。我不知道什么属性应该从Action.Submit按钮返回JSON字符串 我已经包括了json对话框和我的TypeScript文件。 My Main Dialog在第146行启动ClientCheckDialog,ClientCheckDialog在第86行启动GetContactInfoDialog 这是json文件对话框: { "$schema": "http

我正试图在我的聊天机器人中放置一张简单的自适应卡,用于收集用户名和电子邮件。我不知道如何从卡中获取输入

在我显示对话框的瀑布步骤中。我不知道什么属性应该从Action.Submit按钮返回JSON字符串

我已经包括了json对话框和我的TypeScript文件。 My Main Dialog在第146行启动ClientCheckDialog,ClientCheckDialog在第86行启动GetContactInfoDialog

这是json文件对话框:

{
  "$schema": "https://adaptivecards.io/schemas/adaptive-card.json",
  "type": "AdaptiveCard",
  "version": "1.0",
  "body": [
    {
      "type": "TextBlock",
      "text": "Name",
      "wrap": true
    },
    {
      "type": "Input.Text",
      "id": "id_name"
    },
    {
      "type": "TextBlock",
      "text": "Email Address",
      "wrap": true
    },
    {
      "type": "Input.Text",
      "id": "id_email",
      "style": "email",
      "placeholder": "youremail@example.com"
    }
  ],
  "actions": [
    {
      "type": "Action.Submit",
      "title": "Submit",
      "data": {
        "clickedSubmit" : true
      }
    }
  ]
}
Bot文件

import {
    ActivityHandler,
    BotTelemetryClient,
    ConversationState,
    EndOfConversationCodes,
    Severity,
    TurnContext } from 'botbuilder';
import {
    Dialog,
    DialogContext,
    DialogSet,
    DialogState } from 'botbuilder-dialogs';

export class DialogBot<T extends Dialog> extends ActivityHandler {
    private readonly telemetryClient: BotTelemetryClient;
    private readonly solutionName: string = 'tcsBot';
    private readonly rootDialogId: string;
    private readonly dialogs: DialogSet;

    public constructor(
        conversationState: ConversationState,
        telemetryClient: BotTelemetryClient,
        dialog: T) {
        super();

        this.rootDialogId = dialog.id;
        this.telemetryClient = telemetryClient;
        this.dialogs = new DialogSet(conversationState.createProperty<DialogState>(this.solutionName));
        this.dialogs.add(dialog);
        this.onTurn(this.turn.bind(this));
        this.onDialog(this.activityToText.bind(this));
    }

    // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/tslint/config
    public async turn(turnContext: TurnContext, next: () => Promise<void>): Promise<any> {

        // Client notifying this bot took to long to respond (timed out)
        if (turnContext.activity.code === EndOfConversationCodes.BotTimedOut) {
            this.telemetryClient.trackTrace({
                message: `Timeout in ${ turnContext.activity.channelId } channel: Bot took too long to respond`,
                severityLevel: Severity.Information
            });
            return;
        }

        const dc: DialogContext = await this.dialogs.createContext(turnContext);

        if (dc.activeDialog !== undefined) {
            await dc.continueDialog();
        } else {
            await dc.beginDialog(this.rootDialogId);
        }

        await next();
    }

    public async activityToText(turnContext: TurnContext, next: () => Promise<void>): Promise<any> {
        const activity = turnContext.activity;

        if (!activity.text.trim() && activity.value) {
            activity.text = JSON.stringify(activity.value);
        }
        turnContext.activity.text = JSON.stringify(turnContext.activity.value);
        await next();
    }
}

导入{
ActivityHandler,
BotTelemetry客户端,
会话状态,
EndOfConversationCodes,
严重程度,
来自“botbuilder”的TurnContext};
进口{
对话
对话背景,
对话集,
来自“botbuilder对话框”的DialogState};
导出类DialogBot扩展ActivityHandler{
专用只读遥测客户端:BotTelemetryClient;
私有只读解决方案名称:字符串='tcsBot';
私有只读rootDialogId:string;
专用只读对话框:DialogSet;
公共构造函数(
会话状态:会话状态,
遥测客户端:BotTelemetryClient,
对话:T){
超级();
this.rootDialogId=dialog.id;
this.遥测客户端=遥测客户端;
this.dialogs=newdialogset(conversationState.createProperty(this.solutionName));
this.dialogs.add(dialog);
this.onTurn(this.turn.bind(this));
this.onDialog(this.activityToText.bind(this));
}
//eslint禁用下一行@typescript eslint/no explicit any,@typescript eslint/tslint/config
公共异步转向(turnContext:turnContext,next:()=>Promise):Promise{
//通知此bot的客户端需要很长时间才能响应(超时)
if(turnContext.activity.code==EndOfConversationCodes.BotTimedOut){
此文件为.telemetryClient.trackTrace({
消息:`在${turnContext.activity.channelId}通道中超时:Bot花了太长时间来响应`,
严重级别:严重性。信息
});
返回;
}
const dc:DialogContext=wait this.dialogs.createContext(turnContext);
if(dc.activeDialog!==未定义){
等待dc.continueDialog();
}否则{
等待dc.beginDialog(this.rootDialogId);
}
等待下一个();
}
公共异步activityToText(turnContext:turnContext,next:()=>Promise):Promise{
const activity=turnContext.activity;
如果(!activity.text.trim()&&activity.value){
activity.text=JSON.stringify(activity.value);
}
turnContext.activity.text=JSON.stringify(turnContext.activity.value);
等待下一个();
}
}
index.ts文件

import {
    BotFrameworkAdapterSettings,
    BotTelemetryClient,
    ConversationState,
    NullTelemetryClient,
    TurnContext,
    UserState
} from 'botbuilder';
import { ApplicationInsightsTelemetryClient, ApplicationInsightsWebserverMiddleware } from 'botbuilder-applicationinsights';
import { LuisApplication } from 'botbuilder-ai';
import {
    CosmosDbStorage,
    CosmosDbStorageSettings
} from 'botbuilder-azure';
import { Dialog } from 'botbuilder-dialogs';
import {
    ISkillManifest
} from 'botbuilder-skills';
import {
    ICognitiveModelConfiguration,
    Locales
} from 'botbuilder-solutions';;
import i18next from 'i18next';
import i18nextNodeFsBackend from 'i18next-node-fs-backend';
import * as path from 'path';
import * as restify from 'restify';
import { DefaultAdapter } from './adapters/defaultAdapter';
import * as appsettings from './appsettings.json';
import { DialogBot } from './bots/dialogBot';
import * as cognitiveModelsRaw from './cognitivemodels.json';
import { MainDialog } from './dialogs/mainDialog';
import { IBotSettings } from './services/botSettings';
import { skills as skillsRaw } from './skills.json';

import { WelcomeDialog } from './dialogs/welcomeDialog'
import { GetContactInfoDialog } from './dialogs/getContactInfoDialog'
import { ServicesDialog } from './dialogs/servicesDialog'
import { ClientCheckDialog } from './dialogs/clientCheckDialog'

// Configure internationalization and default locale
// tslint:disable-next-line: no-floating-promises
i18next.use(i18nextNodeFsBackend)
    .init({
        fallbackLng: 'en',
        preload: ['en', 'fr'],
        backend: {
            loadPath: path.join(__dirname, 'locales', '{{lng}}.json')
        }
    })
    .then(async (): Promise<void> => {
        await Locales.addResourcesFromPath(i18next, 'common');
    });

const skills: ISkillManifest[] = skillsRaw;
const cognitiveModels: Map<string, ICognitiveModelConfiguration> = new Map();
const cognitiveModelDictionary: { [key: string]: Object } = cognitiveModelsRaw.cognitiveModels;
const cognitiveModelMap: Map<string, Object> = new Map(Object.entries(cognitiveModelDictionary));
cognitiveModelMap.forEach((value: Object, key: string): void => {
    cognitiveModels.set(key, <ICognitiveModelConfiguration>value);
});

const botSettings: Partial<IBotSettings> = {
    appInsights: appsettings.appInsights,
    blobStorage: appsettings.blobStorage,
    cognitiveModels: cognitiveModels,
    cosmosDb: appsettings.cosmosDb,
    defaultLocale: cognitiveModelsRaw.defaultLocale,
    microsoftAppId: appsettings.microsoftAppId,
    microsoftAppPassword: appsettings.microsoftAppPassword,
    skills: skills
};

function getTelemetryClient(settings: Partial<IBotSettings>): BotTelemetryClient {
    if (settings !== undefined && settings.appInsights !== undefined && settings.appInsights.instrumentationKey !== undefined) {
        const instrumentationKey: string = settings.appInsights.instrumentationKey;

        return new ApplicationInsightsTelemetryClient(instrumentationKey);
    }

    return new NullTelemetryClient();
}

const telemetryClient: BotTelemetryClient = getTelemetryClient(botSettings);

const adapterSettings: Partial<BotFrameworkAdapterSettings> = {
    appId: botSettings.microsoftAppId,
    appPassword: botSettings.microsoftAppPassword
};

let cosmosDbStorageSettings: CosmosDbStorageSettings;
if (botSettings.cosmosDb === undefined) {
    throw new Error();
}
cosmosDbStorageSettings = {
    authKey: botSettings.cosmosDb.authKey,
    collectionId: botSettings.cosmosDb.collectionId,
    databaseId: botSettings.cosmosDb.databaseId,
    serviceEndpoint: botSettings.cosmosDb.cosmosDBEndpoint
};

const storage: CosmosDbStorage = new CosmosDbStorage(cosmosDbStorageSettings);
const userState: UserState = new UserState(storage);
const conversationState: ConversationState = new ConversationState(storage);

const adapter: DefaultAdapter = new DefaultAdapter(
    botSettings,
    adapterSettings,
    telemetryClient,
    userState,
    conversationState
);

let bot: DialogBot<Dialog>;
try {
    const luisConfig: LuisApplication = { applicationId: appsettings.luis.appId, endpointKey: appsettings.luis.key, endpoint: appsettings.luis.endpoint };

    const welcomeDialog: WelcomeDialog = new WelcomeDialog();
    const servicesDialog: ServicesDialog = new ServicesDialog();
    const getContactInfoDialog: GetContactInfoDialog = new GetContactInfoDialog()
    const clientCheckDialog: ClientCheckDialog = new ClientCheckDialog(getContactInfoDialog)


    const mainDialog: MainDialog = new MainDialog(
        luisConfig, welcomeDialog, servicesDialog, clientCheckDialog
    );

    bot = new DialogBot(conversationState, telemetryClient, mainDialog);


} catch (err) {
    throw err;
}

// Create server
const server: restify.Server = restify.createServer();

// Enable the Application Insights middleware, which helps correlate all activity
// based on the incoming request.
server.use(restify.plugins.bodyParser());
// tslint:disable-next-line:no-unsafe-any
server.use(ApplicationInsightsWebserverMiddleware);

server.listen(process.env.port || process.env.PORT || '3979', (): void => {
    // tslint:disable-next-line:no-console
    console.log(`${server.name} listening to ${server.url}`);
    // tslint:disable-next-line:no-console
    console.log(`Get the Emulator: https://aka.ms/botframework-emulator`);
    // tslint:disable-next-line:no-console
    console.log(`To talk to your bot, open your '.bot' file in the Emulator`);
});

// Listen for incoming requests
server.post('/api/messages', async (req: restify.Request, res: restify.Response): Promise<void> => {
    // Route received a request to adapter for processing
    await adapter.processActivity(req, res, async (turnContext: TurnContext): Promise<void> => {
        // route to bot activity handler.
        await bot.run(turnContext);
    });
});
导入{
两个框架适配器设置,
BotTelemetry客户端,
会话状态,
NullTelemetryClient,
TurnContext,
户状态表
}来自“僵尸建造者”;
从“botbuilder applicationinsights”导入{ApplicationInsightsTelemetryClient,ApplicationInsightsWebserverMiddleware};
从“botbuilder ai”导入{LuisApplication};
进口{
宇宙数据库,
宇宙存储设置
}来自“botbuilder azure”;
从“botbuilder对话框”导入{Dialog};
进口{
ISkillManifest
}来自“botbuilder技能”;
进口{
ICognitiveModelConfiguration,
地区
}来自“botbuilder解决方案”;;
从“i18next”导入i18next;
从“i18next node fs后端”导入I18NextNode fs后端;
从“路径”导入*作为路径;
从“restify”导入*作为restify;
从“./adapters/DefaultAdapter”导入{DefaultAdapter};
从“./appsettings.json”导入*作为appsettings;
从“./bots/DialogBot”导入{DialogBot};
从“./cognitivemodels.json”导入*作为cognitiveModelsRaw;
从“./dialogs/MainDialog”导入{MainDialog};
从“/services/botSettings”导入{IBotSettings};
从“./skills.json”导入{skillasskillsraw}技能;
从“./dialogs/WelcomeDialog”导入{WelcomeDialog}
从“./dialogs/GetContactInfoDialog”导入{GetContactInfoDialog}
从“./dialogs/ServicesDialog”导入{ServicesDialog}
从“./dialogs/ClientCheckDialog”导入{ClientCheckDialog}
//配置国际化和默认区域设置
//tslint:禁用下一行:无浮动承诺
i18next.use(i18nextNodeFsBackend)
.init({
撤退:“恩”,
预加载:['en','fr'],
后端:{
loadPath:path.join(uu dirname,'locales','{lng}}}.json')
}
})
。然后(异步():承诺=>{
等待Locales.addResourcesFromPath(i18next,“common”);
});
const skills:ISkillManifest[]=skillsRaw;
常量认知模型:Map=newmap();
const cognitiveModelDictionary:{[key:string]:Object}=cognitiveModelsRaw.cognitiveModels;
const cognitiveModelMap:Map=新映射(Object.entries(cognitiveModelDictionary));
forEach((值:对象,键:字符串):void=>{
认知模型集(键、值);
});
常数设置:部分={
appInsights:appsettings.appInsights,
blobStorage:appsettings.blobStorage,
认知模型:认知模型,
cosmosDb:appsettings.cosmosDb,
defaultLocale:cognitiveModelsRaw.defaultLocale,
microsoftAppId:appsettings.microsoftAppId,
microsoftAppPassword:appsettings.microsoftAppPassword,
技能:技能
};
函数getTelemetryClient(设置:部分):BotTelemetryClient{
如果(设置!==未定义和设置.appInsights!==未定义和设置.appInsights.instrumentationKey!==未定义){
const instrumentationKey:string=settings.appInsights.instrumentationKey;
返回新的ApplicationInsightsTelemetryClient(instrumentationKey);
}
返回新的NullTelemetryClient();
}
常量遥测客户端:BotTelemetryClient=getTelemetryClient(botSettings);
常量适配器设置:部分={
appId:botSettings.microsoftAppId,
应用程序密码:
import { InputHints, MessageFactory, StatePropertyAccessor, TurnContext } from 'botbuilder';
import { LuisApplication, LuisRecognizer } from 'botbuilder-ai';

import {
    ComponentDialog,
    DialogSet,
    DialogState,
    DialogTurnResult,
    DialogTurnStatus,
    TextPrompt,
    WaterfallDialog,
    WaterfallStepContext,
    ChoicePrompt,
    ListStyle,
    ConfirmPrompt
} from 'botbuilder-dialogs';

import { WelcomeDialog } from '../dialogs/welcomeDialog'
import { ClientCheckDialog } from '../dialogs/clientCheckDialog'
import { ServicesDialog } from '../dialogs/servicesDialog'
import { Conversation } from './conversation'

import msg from '../resources/enMsg.json';
import { ClientInfo } from './clientInfo';

const CHOICE_PROMPT = 'choicePrompt';
const MAIN_WATERFALL_DIALOG = 'mainWaterfallDialog';
const TEXT_PROMPT = 'textPrompt';
const CONFIRM_PROMPT = 'confirmPrompt';

export class MainDialog extends ComponentDialog {
    private luisRecognizer: LuisRecognizer;
    private conversation: Conversation;
    private clientInfo: ClientInfo;


    public constructor(config: LuisApplication, welcomeDialog: WelcomeDialog, servicesDialog: ServicesDialog, clientCheckDialog: ClientCheckDialog) {
        super('MainDialog');


        const luisIsConfigured = config && config.applicationId && config.endpoint && config.endpointKey;
        if (luisIsConfigured) {
            this.luisRecognizer = new LuisRecognizer(config, {}, true);
        }
        else {
            throw new Error('[MainDialog]: Missing parameter \'luisRecognizer\' is required');
        }

        this.conversation = new Conversation()
        this.clientInfo = new ClientInfo()

        const choicePrompt = new ChoicePrompt(CHOICE_PROMPT);
        choicePrompt.style = ListStyle.suggestedAction;

        this.addDialog(new TextPrompt(TEXT_PROMPT))
            .addDialog(new ConfirmPrompt(CONFIRM_PROMPT))
            .addDialog(choicePrompt)
            .addDialog(welcomeDialog)
            .addDialog(servicesDialog)
            .addDialog(clientCheckDialog)
            .addDialog(new WaterfallDialog(MAIN_WATERFALL_DIALOG, [
                this.introStep1.bind(this),
                this.introStep2.bind(this),
                this.getIntentStep.bind(this),
                this.followUpStep.bind(this),
                this.checkForContactInfo.bind(this),
                this.checkIfHelpfulStep.bind(this),
                this.finalStep.bind(this)
            ]));

        this.initialDialogId = MAIN_WATERFALL_DIALOG;
    }

    public async run(context: TurnContext, accessor: StatePropertyAccessor<DialogState>) {
        const dialogSet = new DialogSet(accessor);
        dialogSet.add(this);

        const dialogContext = await dialogSet.createContext(context);
        const results = await dialogContext.continueDialog();
        if (results.status === DialogTurnStatus.empty) {
            await dialogContext.beginDialog(this.id);
        }
    }

    private async introStep1(stepContext: WaterfallStepContext): Promise<DialogTurnResult> {

        if (!this.luisRecognizer) {
            const luisConfigMsg = 'NOTE: LUIS is not configured. To enable all capabilities, add `LuisAppId`, `LuisAPIKey` and `LuisAPIHostName` to the .env file.';
            await stepContext.context.sendActivity(luisConfigMsg);
            return await stepContext.next();
        }


        const messageText = (stepContext.options as any).restartMsg ? (stepContext.options as any).restartMsg : msg.welcome;
        this.conversation.addSpeech(Conversation.Speaker.Bot, messageText)

        return await stepContext.beginDialog('welcomeDialog', { messageText: messageText })
    }

    private async introStep2(stepContext: WaterfallStepContext): Promise<DialogTurnResult> {


        var messageText = msg.clickOrType
        const promptMessage = MessageFactory.text(messageText, messageText, InputHints.ExpectingInput);
        return await stepContext.prompt(TEXT_PROMPT, { prompt: promptMessage });
    }


    private async getIntentStep(stepContext: WaterfallStepContext): Promise<DialogTurnResult> {

        this.conversation.addSpeech(Conversation.Speaker.Client, stepContext.result)

        this.clientInfo.question = stepContext.result

        if (this.luisRecognizer) {
            const luisResult = await this.luisRecognizer.recognize(stepContext.context);
            switch (LuisRecognizer.topIntent(luisResult)) {
                case 'Services':
                    this.clientInfo.intent = ClientInfo.Intent.Services
                    break

                default:
                    this.clientInfo.intent = ClientInfo.Intent.Other
                    // Catch all for unhandled intents
                    return await stepContext.replaceDialog(this.initialDialogId, { restartMsg: msg.didNotUnderstandIntent });

            }

            if (this.clientInfo.intent === ClientInfo.Intent.Services) {
                return await stepContext.beginDialog('servicesDialog', { clientInfo: this.clientInfo, repeat: false })
            }

        }
        return await stepContext.next();
    }

    private async followUpStep(stepContext: WaterfallStepContext): Promise<DialogTurnResult> {
        if (stepContext.result) {
            var getIntentResult = stepContext.result as { clientInfo: ClientInfo | undefined; conversation: Conversation };
            if (getIntentResult.clientInfo)
                this.clientInfo = getIntentResult.clientInfo

            this.conversation.addSubConversation(getIntentResult.conversation)
            if (getIntentResult.clientInfo) {
                if (getIntentResult.clientInfo.intent === ClientInfo.Intent.Services) {
                    return await stepContext.beginDialog('checkClientDialog', this.clientInfo)
                }
            }
        }

        return await stepContext.next();
    }

    private async checkForContactInfo(stepContext: WaterfallStepContext): Promise<DialogTurnResult> {

        if (stepContext.result) {
            var followUpResult = stepContext.result as { clientInfo: ClientInfo | undefined; conversation: Conversation };
            this.conversation.addSubConversation(followUpResult.conversation)

        }

        return await stepContext.next();
    }

    //ask user if bot was able to help them
    private async checkIfHelpfulStep(stepContext: WaterfallStepContext): Promise<DialogTurnResult> {
        const messageText = msg.wasThisHelpful
        const message = MessageFactory.text(messageText, messageText, InputHints.ExpectingInput);
        this.conversation.addSpeech(Conversation.Speaker.Bot, messageText)
        return await stepContext.prompt(CONFIRM_PROMPT, { prompt: message });
    }


    //restart
    private async finalStep(stepContext: WaterfallStepContext): Promise<DialogTurnResult> {
        this.clientInfo.wasHelpful = stepContext.result
        // Restart the main dialog waterfall with a different message the second time around
        return await stepContext.replaceDialog(this.initialDialogId, { restartMsg: msg.restartMain });
    }
}
import {
    ComponentDialog,
    DialogTurnResult,
    WaterfallDialog,
    WaterfallStepContext,
    ChoiceFactory,
    ConfirmPrompt
} from 'botbuilder-dialogs';
import { ClientInfo } from './clientInfo';

import { InputHints, MessageFactory } from 'botbuilder';

import { GetContactInfoDialog } from '../dialogs/getContactInfoDialog'
import { Conversation } from './conversation'

import msg from '../resources/enMsg.json';
const CONFIRM_PROMPT = 'confirmPrompt'
const WATERFALL_DIALOG = 'waterfallDialog';

export class ClientCheckDialog extends ComponentDialog {

    private conversation: Conversation;

    // Constructor
    public constructor(getContactInfoDialog: GetContactInfoDialog) {
        super('ClientCheckDialog');

        this.conversation = new Conversation()

        this.addDialog(new ConfirmPrompt(CONFIRM_PROMPT))
            .addDialog(getContactInfoDialog)
            .addDialog(new WaterfallDialog(WATERFALL_DIALOG, [
                this.introStep.bind(this),
                this.generalInfoStep.bind(this),
                this.getContactInfoStep.bind(this),
                this.finalStep.bind(this)
            ]));

        this.initialDialogId = WATERFALL_DIALOG;
    }

    private async introStep(stepContext: WaterfallStepContext): Promise<DialogTurnResult> {
        const messageText = msg.workWithUs
        const message = MessageFactory.text(messageText, messageText, InputHints.ExpectingInput);
        this.conversation.addSpeech(Conversation.Speaker.Bot, messageText)

        return await stepContext.prompt(CONFIRM_PROMPT, { prompt: message });
    }

    private async generalInfoStep(stepContext: WaterfallStepContext): Promise<DialogTurnResult> {

        const clientInfo = stepContext.options as ClientInfo;
        this.conversation.addSpeech(Conversation.Speaker.Client, stepContext.result)
        clientInfo.isQualified = stepContext.result

        //start list of recources
        var bulletPoints = [msg.benefit1, msg.benefit2, msg.benefit3]

        //check for more cases to add info 
        const messageText1 = msg.general
        const message = ChoiceFactory.list(bulletPoints, messageText1, InputHints.IgnoringInput);

        //collecting bot output for conversation 
        var botOutput = messageText1
        for (var point in bulletPoints) {
            botOutput.concat(" -", point)
        }
        this.conversation.addSpeech(Conversation.Speaker.Bot, botOutput)
        await stepContext.context.sendActivity(message);

        if (clientInfo.isQualified) {
            const messageText2 = msg.becomeAClient
            const messageContact = MessageFactory.text(messageText2, messageText2, InputHints.ExpectingInput);
            this.conversation.addSpeech(Conversation.Speaker.Bot, messageText2)
            return await stepContext.prompt(CONFIRM_PROMPT, { prompt: messageContact });
        }
        else {
            return await stepContext.endDialog({ clientInfo: clientInfo, conversation: this.conversation });
        }
    }

    private async getContactInfoStep(stepContext: WaterfallStepContext): Promise<DialogTurnResult> {
        this.conversation.addSpeech(Conversation.Speaker.Client, stepContext.result)
        const clientInfo = stepContext.options as ClientInfo;
        if (stepContext.result) {
            return await stepContext.beginDialog("getContactInfoDialog")
        }
        return await stepContext.endDialog({ clientInfo: clientInfo, conversation: this.conversation });
    }

    private async finalStep(stepContext: WaterfallStepContext): Promise<DialogTurnResult> {
        const clientInfo = stepContext.options as ClientInfo;
        return await stepContext.endDialog({ clientInfo: clientInfo, conversation: this.conversation });
    }
}
import {
    ComponentDialog,
    DialogTurnResult,
    WaterfallDialog,
    WaterfallStepContext,
    TextPrompt
} from 'botbuilder-dialogs';
import { CardFactory, MessageFactory } from 'botbuilder';

const WATERFALL_DIALOG = 'waterfallDialog';
const TEXT_PROMPT = 'textPrompt';

import getContactInfoCard from '../cards/getContactInfoCard.json'

export class GetContactInfoDialog extends ComponentDialog {
    public constructor() {
        super('getContactInfoDialog')

        this.addDialog(new TextPrompt(TEXT_PROMPT))
        this.addDialog(new WaterfallDialog(WATERFALL_DIALOG, [
            this.firstStep.bind(this),
            this.secondStep.bind(this)
        ]))
        this.initialDialogId = WATERFALL_DIALOG;
    }

    public async firstStep(stepContext: WaterfallStepContext): Promise<DialogTurnResult> {
        const cardPrompt = MessageFactory.text('');
        cardPrompt.attachments = [CardFactory.adaptiveCard(getContactInfoCard)];
        return await stepContext.prompt(TEXT_PROMPT, cardPrompt);
    }

    public async secondStep(stepContext: WaterfallStepContext): Promise<DialogTurnResult> {
        //process adaptive card input here
        const messageText = 'What else can I do for you?'
        const messageContact = MessageFactory.text(messageText, messageText);
        return await stepContext.prompt(TEXT_PROMPT, { prompt: messageContact });
    }
}