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.