Now, after we have successfully generated our Chatbot TypeScript code with Yeoman, we must take a closer look to understand what’s happening.
index.ts
src/index.ts is responsible for setting up the bot and provide a web-server that we can send chat requests to. Our bot logic – and by that I mean instructions what the bot is actually supposed to do – is handled in src/bot.ts instead.
src/index.ts imports the required bot services and bot configuration, loads environment files and sets environment constants.
import { config } from 'dotenv';
import * as path from 'path';
import * as restify from 'restify';
import { BotFrameworkAdapter } from 'botbuilder';
import { BotConfiguration, IEndpointService } from 'botframework-config';
import { MyBot } from './bot';
const ENV_FILE = path.join(__dirname, '..', '.env');
config({ path: ENV_FILE });
const DEV_ENVIRONMENT = 'development';
const BOT_CONFIGURATION = (process.env.NODE_ENV || DEV_ENVIRONMENT);
It creates a web server (using the package restify) by default on port 3978
const server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, () => {
console.log(`\n${server.name} listening to ${server.url}`);
console.log(`\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator`);
console.log(`\nTo talk to your bot, open bothe-bot.bot file in the Emulator.`);
});
tries to load bot configuration
const BOT_FILE = path.join(__dirname, '..', (process.env.botFilePath || ''));
let botConfig;
try {
botConfig = BotConfiguration.loadSync(BOT_FILE, process.env.botFileSecret);
} catch (err) {
console.error(`\nError reading bot file. Please ensure you have valid botFilePath and botFileSecret set for your environment.`);
console.error(`\n - The botFileSecret is available under appsettings for your Azure Bot Service bot.`);
console.error(`\n - If you are running this bot locally, consider adding a .env file with botFilePath and botFileSecret.`);
console.error(`\n - See https://aka.ms/about-bot-file to learn more about .bot file its use and bot configuration.\n\n`);
process.exit();
}
const endpointConfig = botConfig.findServiceByNameOrId(BOT_CONFIGURATION) as IEndpointService;
The file also creates an adapter from the bot configuration:
const endpointConfig = botConfig.findServiceByNameOrId(BOT_CONFIGURATION) as IEndpointService;
const adapter = new BotFrameworkAdapter({
appId: endpointConfig.appId || process.env.microsoftAppID,
appPassword: endpointConfig.appPassword || process.env.microsoftAppPassword,
});
Then it creates a catch-all error handler:
adapter.onTurnError = async (context, error) => {
console.error(`\n [onTurnError]: ${ error }`);
await context.sendActivity(`Oops. Something went wrong!`);
};
Finally it calls our bot logic whenever there is a request to /api/messages
const myBot = new MyBot();
server.post('/api/messages', (req, res) => {
adapter.processActivity(req, res, async (context) => {
await myBot.onTurn(context);
});
});
src/bot.ts
import { ActivityTypes, TurnContext } from 'botbuilder';
export class MyBot {
/**
* Use onTurn to handle an incoming activity, received from a user, process it, and reply as needed
*
* @param {TurnContext} context on turn context object.
*/
public onTurn = async (turnContext: TurnContext) => {
if (turnContext.activity.type === ActivityTypes.Message) {
await turnContext.sendActivity(`You said '${ turnContext.activity.text }'`);
} else {
await turnContext.sendActivity(`[${ turnContext.activity.type } event detected]`);
}
}
}
As you can see we use the TurnContext to get information and also to send an activity back to the user. Very powerful, that’s why is worth having a closer look at TurnContext in the next post.
No comments yet.