Azure Bot Service + micro.jsでボットアプリ作成
Azure Bot Serviceを利用してbotアプリを作ってみました。
環境構築は慣れてなくても一瞬で完了します。
Azure Bot serviceをnode.jsで実装する際にサンプルがrestifyで実装されていましたが
micro.js(zeit)での実装に変更してみました。
環境は以下のようになります。
開発言語 :typescript v3.1.6
実行環境 :Node.js v8.9.4
アプリケーションフレームワーク :Asynchronous HTTP microservices zeit/micro
BOtフレームワーク :Azure Bot Framework | Microsoft Azure
環境構築(Azure側)
Azure bot frameworkで検索すると以下のサイトに行きつきこれを手掛かりに
Azure Bot serviceに足を踏み入れることにしました。
Azure Bot Framework | Microsoft Azure
まずは環境を整えるためFrameworkを入手するところから始めようと思いましたが
上記URLにモノを落とすようなURLがない。
他にこのページでやることがないようなので
MyBot → createでBot アプリケーションを作成してみる。
app serviceが作成されます。
設定→メッセージングエンドポイントで受け付けるURLを設定
今回は
https://xxxxxxxxxxx.azurewebsites.net/api/messages
としました。
サンプルのソースコードを入手します。
Microsoft/BotBuilder-Samples
必要なモジュールのインストール
入手したpackage.jsonを以下のように編集しnpm installを実行
package.json
{
"name": "natural-bot",
"version": "1.0.0",
"description": "",
"main": "./dist/index.js",
"dependencies": {
"@types/micro": "^7.3.3",
"botbuilder": "^4.2.0",
"botframework-config": "^4.2.0",
"config": "^1.31.0",
"dotenv": "^6.1.0",
"js-yaml": "^3.8.4",
"micro": "^9.3.3",
"micro-http-router": "^1.3.0"
},
"devDependencies": {
"@types/dotenv": "6.1.0",
"@types/micro": "7.3.3",
"nodemon": "^1.18.6",
"tslint": "^5.11.0",
"typescript": "^3.1.6"
}
}
ソースを編集してデプロイ
サンプルはrestifyで実装されているためmicroに入れ替えます。
tsconfig.json,echobot.botは変更点なしでそのまま流用します。
今回は取り合えず動けば良しとします(編集中)
index.ts
microを導入します。ルーティングはmicro-http-routerを利用して以下のRouter.tsにて実装しました。
const micro = require('micro')
const server = micro(async (req:any, res:any) => {
// リクエスト受付(各ルーティング実行)
let router:any
let Router = require('./gateway/Router')
router = await Router(req,res)
return await router.handle(req, res);
})
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 echobot.bot file in the Emulator.`);
});
gateway/Router.ts
const Router = require('micro-http-router')
import { config } from 'dotenv';
import * as path from 'path';
import { BotConfiguration, IEndpointService } from 'botframework-config';
import { BotFrameworkAdapter } from 'botbuilder';
import { MyBot } from '../bot';
const ENV_FILE = path.join(__dirname, '../..', '.env');
config({ path: ENV_FILE });
const BOT_CONFIGURATION = (process.env.NODE_ENV || DEV_ENVIRONMENT);
module.exports = async (req:any, res:any) => {
const router = new Router()
// bot設定ファイルの読み込(サンプルではプロジェクトルートのechobot.botが読み込まれます。)
// パスは上記.envファイル内で指定
const BOT_FILE = path.join(__dirname, '../..', (process.env.botFilePath || ''));
let botConfig;
try {
botConfig = BotConfiguration.loadSync(BOT_FILE, process.env.botFileSecret);
const endpointConfig = botConfig.findServiceByNameOrId(BOT_CONFIGURATION) as IEndpointService;
const adapter = new BotFrameworkAdapter({
appId: endpointConfig.appId || process.env.microsoftAppID,
appPassword: endpointConfig.appPassword || process.env.microsoftAppPassword,
});
// on error
adapter.onTurnError = async (context, error) => {
console.error(`\n [onTurnError]: ${ error }`);
await context.sendActivity(`Oops. Something went wrong!`);
};
// app service の『設定』で指定したエンドポイント
router.post('/api/messages', (req:any, res:any) => {
adapter.processActivity(req, res, async (context) => {
// Route to main dialog.
let myBot = new MyBot();
await myBot.onTurn(context);
});
});
} 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.\n\n`);
process.exit();
}
return router;
};
bot.ts
適当な返事をしてくれるメソッドを用意。util.jsは以下を使用。
eustia - A Tool for Generating JavaScript Utility Libraries:
turnContext.activity.textが受信されたテキストメッセージを保持、
turnContext.sendActivity()でテキストメッセージの送信が可能です。
import {
ActivityTypes,
TurnContext
} from 'botbuilder';
const natural = require('natural');
let util = require("./util/Util.js");
export class MyBot {
/**
* Use onTurn to handle an incoming activity
*
* @param {TurnContext} context on turn context object.
*/
async onTurn(turnContext: TurnContext) {
if (turnContext.activity.type === ActivityTypes.Message) {
let message = turnContext.activity.text
// 結果の返却
await turnContext.sendActivity(`${ this.greet(message)}`);
} else {
Generic handler for all other activity types.
await turnContext.sendActivity(`[${ turnContext.activity.type } event detected]`);
}
}
greet(text:string):string{
const goodMorning = "おはようございます、"
const hello = "こんにちは、"
const goodEveinning = "こんばんは、"
if(util.isStr(text)){
if(text.indexOf("おはよう") > -1){
return goodMorning
}else if(text.indexOf("こんにちは") > -1){
return hello
}else if(text.indexOf("こんちは") > -1){
return hello
}else if(text.indexOf("こんばんは") > -1){
return goodEveinning
}
}
return ""
}
}
あとはgit等でデプロイします。
デフォルトでsdk等が大量に用意されていて若干戸惑いますが、デプロイは通常のApp Serviceと同様になります。