您现在访问的是微软AZURE全球版技术文档网站,若需要访问由世纪互联运营的MICROSOFT AZURE中国区技术文档网站,请访问 https://docs.azure.cn.

JavaScript 迁移快速参考

适用于: SDK v4

BotBuilder Javascript SDK v4 引入了多项基本变更,这些变更影响我们创作机器人的方式。 本指南的目的是为用户提供快速参考,让他们了解在 v3 和 v4 SDK 中完成某个任务有哪些常见差异。

  • 在机器人和通道之间传递信息的方式已改变。 在 v3 中,我们使用“连接器” 和“会话” 对象。 在 v4 中,这些对象被“适配器” 和“轮次上下文” 对象替换。

  • 另外,我们已将对话和机器人实例进一步分离。 在 v3 中,对话直接注册到机器人的构造函数。 在 v4 中,现在可以将对话作为参数传递到机器人实例中,以便更灵活地进行组合。

  • 另外,v4 还提供了一个 ActivityHandler 类,用于自动处理不同类型的活动,例如消息、聊天更新和事件活动。

这些改进导致在 Javascript 中开发机器人的语法发生了变化,尤其是在创建机器人对象、定义对话和编码事件处理逻辑方面发生了变化。

本主题的其余部分将 JavaScript Bot Framework SDK v3 中的构造与 v4 中的相应构造进行了对比。

侦听传入请求

v3

var connector = new builder.ChatConnector({
    appId: process.env.MicrosoftAppId,
    appPassword: process.env.MicrosoftAppPassword
});

server.post('/api/messages', connector.listen());

v4

const adapter = new BotFrameworkAdapter({
    appId: process.env.MicrosoftAppId,
    appPassword: process.env.MicrosoftAppPassword
});

server.post('/api/messages', (req, res) => {
    adapter.processActivity(req, res, async (context) => {
        await bot.run(context);
    });
});

创建机器人实例

v3

var bot = new builder.UniversalBot(connector, [ ...DIALOG_STEPS ]);

v4

// Define the bot class as extending ActivityHandler.
const { ActivityHandler } = require('botbuilder');

class MyBot extends ActivityHandler {
    // ...
}

// Instantiate a new bot instance.
const bot = new MyBot(conversationState, dialog);

向用户发送消息

v3

session.send('Hello and welcome to the help desk bot.');

v4

await context.sendActivity('Hello and welcome to the help desk bot.');

定义默认对话

v3

var bot = new builder.UniversalBot(connector, [
    // Add default dialog waterfall steps...
]);

v4

// In the main dialog class, define a run method.
async run(turnContext, accessor) {
    const dialogSet = new DialogSet(accessor);
    dialogSet.add(this);

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

// Pass conversation state management and a main dialog objects to the bot (in index.js).
const bot = new MyBot(conversationState, dialog);

// Inside the bot's constructor, add the dialog as a member property and define a DialogState property accessor.
this.dialog = dialog;
this.dialogState = this.conversationState.createProperty('DialogState');

// Inside the bot's message handler, invoke the dialog's run method, passing in the turn context and DialogState accessor.
this.onMessage(async (context, next) => {
    // Run the Dialog with the new message Activity.
    await this.dialog.run(context, this.dialogState);
    await next();
});

启动子对话

子对话结束后,父对话会继续。

v3

session.beginDialog(DIALOG_ID);

v4

await context.beginDialog(DIALOG_ID);

替换对话

新对话替换堆栈上的当前对话。

v3

session.replaceDialog(DIALOG_ID);

v4

await context.replaceDialog(DIALOG_ID);

结束对话:

v3

session.endDialog();

v4

可以添加一个可选的返回值。

await context.endDialog(returnValue);

将对话注册到机器人实例

v3

// Create the bot.
var bot = new builder.UniversalBot(connector, [
    // ...
]};

// Add the dialog to the bot.
bot.dialog('myDialog', require('./mydialog'));

v4

// In the main dialog class constructor.
this.addDialog(new MyDialog(DIALOG_ID));

// In the app entry point file (index.js)
const { MainDialog } = require('./dialogs/main');

// Create the base dialog and bot, passing the main dialog as an argument.
const dialog = new MainDialog();
const reservationBot = new ReservationBot(conversationState, dialog);

提示用户输入

v3

var builder = require('botbuilder');
builder.Prompts.text(session, 'Please enter your destination');

v4

const { TextPrompt } = require('botbuilder-dialogs');

// In the dialog's constructor, register the prompt.
this.addDialog(new TextPrompt('initialPrompt'));

// In the dialog step, invoke the prompt.
return await stepContext.prompt(
    'initialPrompt', {
        prompt: 'Please enter your destination'
    }
);

检索用户对提示的响应

v3

function (session, result) {
    var destination = result.response;
    // ...
}

v4

// In the dialog step after the prompt step, retrieve the result from the waterfall step context.
async nextStep(stepContext) {
    const destination = stepContext.result;
    // ...
}

将信息保存到对话状态

v3

session.dialogData.destination = results.response;

v4

// In a dialog, set the value in the waterfall step context.
stepContext.values.destination = destination;

将状态更改写入持久性层

v3

// State data is saved by default at the end of the turn.
// Do this to save it manually.
session.save();

v4

// State changes are not saved automatically at the end of the turn.
await this.conversationState.saveChanges(context, false);
await this.userState.saveChanges(context, false);

创建并注册状态存储

v3

var builder = require('botbuilder');

// Create conversation state with in-memory storage provider.
var inMemoryStorage = new builder.MemoryBotStorage();

// Create the base dialog and bot
var bot = new builder.UniversalBot(connector, [ /*...*/ ]).set('storage', inMemoryStorage);

v4

const { MemoryStorage } = require('botbuilder');

// Create the memory layer object.
const memoryStorage = new MemoryStorage();

// Create the conversation state management object, using the storage provider.
const conversationState = new ConversationState(memoryStorage);

// Create the base dialog and bot.
const dialog = new MainDialog();
const reservationBot = new ReservationBot(conversationState, dialog);

捕获对话引发的错误

v3

// Set up the error handler.
session.on('error', function (err) {
    session.send('Failed with message:', err.message);
    session.endDialog();
});

// Throw an error.
session.error('An error has occurred.');

v4

// Set up the error handler, using the adapter.
adapter.onTurnError = async (context, error) => {
    const errorMsg = error.message

    // Clear out conversation state to avoid keeping the conversation in a corrupted bot state.
    await conversationState.delete(context);

    // Send a message to the user.
    await context.sendActivity(errorMsg);
};

// Throw an error.
async () => {
    throw new Error('An error has occurred.');
}

注册活动处理程序

v3

bot.on('conversationUpdate', function (message) {
    // ...
}

bot.on('contactRelationUpdate', function (message) {
    // ...
}

v4

// In the bot's constructor, add the handlers.
this.onMessage(async (context, next) => {
    // ...
}
  
this.onDialog(async (context, next) => {
    // ...
}

this.onMembersAdded(async (context, next) => {
    // ...
}

发送附件

v3

var message = new builder.Message()
    .attachments(hotelHeroCards
    .attachmentLayout(builder.AttachmentLayout.carousel));

v4

await context.sendActivity({
    attachments: hotelHeroCards,
    attachmentLayout: AttachmentLayoutTypes.Carousel
});

使用自然语言识别 (LUIS)

v3

// The LUIS recognizer was part of the 'botbuilder' library
var builder = require('botbuilder');

var recognizer = new builder.LuisRecognizer(LUIS_MODEL_URL);
bot.recognizer(recognizer);

v4

// The LUIS recognizer is now part of the 'botbuilder-ai' library
const { LuisRecognizer } = require('botbuilder-ai');

const luisApp = { applicationId: LuisAppId, endpointKey: LuisAPIKey, endpoint: `https://${ LuisAPIHostName }` };
const recognizer = new LuisRecognizer(luisApp);

const recognizerResult = await recognizer.recognize(context);
const intent = LuisRecognizer.topIntent(recognizerResult);

v3 意向对话框和 v4 等效项

v3

// Create a 'greetings' RegExpRecognizer that can be turned off
var greetings = new builder.RegExpRecognizer('Greetings', /hello|hi|hey|greetings/i)
    .onEnabled(function (session, callback) {
        // Check to see if this recognizer should be enabled
        if (session.conversationData.useGreetings) {
            callback(null, true);
        } else {
            callback(null, false);
        }
    });

// Create our IntentDialog and add recognizers
var intents = new builder.IntentDialog({ recognizers: [greetings] });

bot.dialog('/', intents);

// If no intent is recognized, direct user to Recognizer Menu
intents.onDefault('RecognizerMenu');

// Match our "Greetings" and "Farewell" intents with their dialogs
intents.matches('Greetings', 'Greetings');

// Add a greetings dialog
bot.dialog('Greetings', [
    function (session) {
        session.endDialog('Greetings!');
    }
]);

v4

this.onMessage(async (context, next) => {

    const recognizerResult = {
        text: context.activity.text,
        intents: []
    };

    const greetingRegex = RegExp(/hello|hi|hey|greetings/i);

    if (greetingRegex.test(context.activity.text)) {
      // greeting intent identified
      recognizerResult.intents.push('Greeting');
    }

    if (recognizerResult.intents.includes('Greeting')) {
        // Run the 'Greeting' dialog
        await context.beginDialog(GREETING_DIALOG_ID);
    }

    await next();
});