仕事の Teams にボットでも作ろうかと思い、初めて Bot Framework SDK を使ってみました。
実は Teams のボットは Outgoing Webhook でも作れます。
しかし、Outgoing Webhook に対するボット アプリからのメッセージは、その Webhook リクエストに対するレスポンスで返す必要があること、そしてそのレスポンスは 5 秒以内に返す必要がある、など制限があります。
これをAzure Functions の HTTP トリガー関数で実装すると、関数処理自体が 5 秒以内に限定されてしまいますし、利用プランによってはコールド スタートするのでもっと処理時間は短くなり (最悪、処理を開始する前にタイムアウトする)、あまり相性がいいとは言えません。
なので、今回は Bot Framework SDK を使ったボット作成にチャレンジしました。
今のバージョンは v4 らしいです。
とりあえず Web 検索すると、下記の Qiita の記事がヒットします。
「Function Bot」というリソースからテンプレートがダウンロードできそうなので Azure デプロイしてみます。
。。。
もうないみたいです orz
上の記事が書かれた当時は Bot Framework が v3 のようですが、FUnction Bot は v3 のみに対応してて、そして v3 は 2019 年 8 月にディスコンになったようです😥
ないものはしょうがないので、試しに Web App Bot をデプロイして、Web App Bot のテンプレートをダウンロードしてみます。
所詮 HTTP サーバー。そんな大変なことはないはず。
メインの index.js
を開いてみると、express ベースみたいです。
const express = require('express'); // Import required bot services. // See https://aka.ms/bot-services to learn more about the different parts of a bot. const { BotFrameworkAdapter } = require('botbuilder'); // Import bot definitions const { BotActivityHandler } = require('./botActivityHandler'); // (略) // Create adapter. // See https://aka.ms/about-bot-adapter to learn more about adapters. const adapter = new BotFrameworkAdapter({ appId: process.env.BotId, appPassword: process.env.BotPassword }); // (略) // Create HTTP server. const server = express(); const port = process.env.port || process.env.PORT || 3978; server.listen(port, () => console.log(`\Bot/ME service listening at http://localhost:${port}`) ); // Listen for incoming requests. server.post('/api/messages', (req, res) => { adapter.processActivity(req, res, async (context) => { // Process bot activity await botActivityHandler.run(context); }); });
最後の方の BotFrameworkAdapter#adapter
にリクエストとレスポンスをセットで渡せればいい感じです。
何も考えず、HTTP トリガーに置き換えてみます。typescript です。
// (いろいろ省略) const httpTrigger: AzureFunction = async function (context:Context) { await adapter.processActivity(context.req, context.res, async (context:TurnContext) => { // Process bot activity await botActivityHandler.run(context); }); }; export default httpTrigger;
はい、怒られました。型が違うようです。さすが typescript。
ここでようやくリファレンスの登場です。
やっぱり Express (か Restify) ライクなオブジェクトが必要とのこと。
この azure-function-express を使えば、Azure Functions でも Express が使えます。
でも正直ルーティングを必要とするほど HTTP トリガー関数を複数作るわけではないので express の組み込みまではしたくありません。
そこで、azure-function-express からリクエスト/レスポンスのラッパー オブジェクトのみを拝借&BotFrameworkAdapter#adapter
が受け取れるよう微修正したテンプレート リポジトリを公開しました。
Express は一切使用しておりません。
実際にボットとしての動作確認は、Azure で Bot Channels Registration
をデプロイして、Teams/LINE で確認しました。