Stacks and implementation
Yann LEFLOUR
Deputy CTO @ BAM
@yleflour
yleflour
slides.com/yleflour
What we won't be talking about
Answer: It's code
Universal Chatbot Architecture
Bot Builder
Bot Builder
Some bot builder librairies (JS only)
Botkit
Microsoft
Botbuilder
Microsoft Bot Builder
Connector
Connector service (input)
Connector service (ouput)
Some connector services
export default class MessengerConnector {
Pure JS (for the win)
/** onInvoke, onEvent, startConversation, update, delete, isInvoke */
}
listenMessengerEvent() {
// Express listener
return async (req, res) => {
// Respond immediately to messenger to to prevent it from getting stuck
res.send();
const events = await mapMessengerPostToEvents(req.body);
this.onEventHandler(events);
};
}
async send(messages, done) {
const messengerMessages = mapBotBuilderToMessengerMessages(messages);
await sendMessengerMessages(messengerMessages);
done(null, []);
}
Recognizer
Recognizer
Example: "I want to book a restaurant in Verona"
Some NLU Services
export default class RecastRecognizer {
async recognize(context, callback) {
try {
const recastResults = await recast.analyseText(context.message.text);
const output = mapRecastToBotBuilderIntent(recastResults);
callback(null, output);
} catch(err) {
callback(err);
}
}
}
Recast.ai + JS mapper
A root dialog which resets the bot to its initial state at the end
export const bookRestaurantConversation = [
];
(session, results) => {
session.dialogData.restaurantId = results.response.restaurantId;
session.beginDialog('/getDateTimeDialog', session);
},
(session, results, next) => {
session.dialogData.dateTime = results.response.dateTime;
next();
},
async (session) => {
const { restaurantId, dateTime } = session.dialogData;
await bookingAPI.bookRestaurant(restaurantId, dateTime);
session.endConversation();
}}
(session, args) => {
session.beginDialog('/getRestaurantDialog', session);
},
A branch in your conversation tree
export const getRestaurantDialog = [
];
(session, args, next) => {
session.beginDialog(
session'/locationPrompt',
{ prompt: "Where do you want to book?" }
);
},
(session, results, next) => {
const location = results.response;
session.beginDialog(
session'/locationPrompt',
{ prompt: "Which restaurant?", location }
);
},
(session, results) => {
const restaurantId = results.response;
const output = { response: restaurantId };
session.endDialogWithResults(output);
},
A single step dialog which handles user input
export const restaurantPrompt = new Prompt()
// Used to display the prompt message
.onFormatMessage(async (session, text, _speak, callback) => {
const location = session.dialogData.options.location;
const restaurants = await getRestaurantsFromAPI(location)
const message = formatRestaurantCarouselMessage(text, restaurants);
return callback(null, message);
})
// Used to handle the user input
.onRecognize((context, callback) => {
const entities = context.intent.entities;
const restaurantId = EntityRecognizer.findEntity(entities, 'restaurant_id');
if (!restaurantId) return callback(null, 0);
return callback(null, 1, { restaurantId });
})
const connector = new MessengerConnector();
const bot = new UniversalBot(connector).recognizer(new RecastRecognizer());
// Root Dialog
bot.dialog('/', /** ... */)
.beginDialogAction(
'bookRestaurantFromIntentAction',
'/bookRestaurantConversation',
{ matches: 'book_restaurant' }
);
// Setup Conversations
bot.dialog('/bookRestaurantConversation', bookRestaurantConversation);
// Setup Dialogs
bot.dialog('/getRestaurantDialog', getRestaurantDialog);
bot.dialog('/getDateTimeDialog', getDateTimeDialog);
// Setup Prompts
bot.dialog('/locationPrompt', LocationPrompt);
bot.dialog('/restaurantPrompt', restaurantPrompt);
bot.dialog('/dateTimePrompt', dateTimePrompt);
const app = express();
const server = http.createServer(app);
const port = process.env.PORT || 80;
/**
* Declare the bot and its connector
*/
// Listen to messages
app.use(bodyParser.json());
app.post('/api/messages', connector.listenMessengerEvent());
// start the server
server.listen(port, () => {
console.log('Listening on %s', port);
});
Want to checkout some more?