Azure Bot Service ✕ Cognitive Servicesで英語に翻訳するChat Botを作ってみる

この記事は、[Microsoft Azure Advent Calendar](https://qiita.com/advent-calendar/2017/azure) 24日目の記事です。

# 今回作ったもの
さっそく今回作ったデモアプリをご紹介します。
<img width="525" alt="Screen Shot 0029-12-24 at 22.46.24.png" src="https://qiita-image-store.s3.amazonaws.com/0/43421/488552a3-17c1-393d-461c-252356cff98e.png">

日本語をつぶやけば英語に翻訳し、英語をつぶやけば日本語に翻訳してくれるChat Botを作ってみました。一応想定通りの動きをしています。ちょっとした英語の表現を調べたりする時に役立ちそうです。

# 想定読者
Chat BotもCognitive Servicesもどちらもさくっと触ってみたい初心者の方向けです。

# 使った技術要素
簡単に実現するために以下のSaaSを利用しました。

### [Azure Bot Service](https://azure.microsoft.com/ja-jp/services/bot-service/)
Azure Bot Serviceは2017年12月についにGAされました。
Azure Bot ServiceはMicrosoftが提供するChatbot開発フレームワークです。GUIでポチポチしながら作成してしまえば、Chat Botに必要な仕組みは既に用意されているため簡単に使い始めることができます。また、Webインタフェースだけでなく、Slack、Facebookメッセンジャー、Twilioなど主要なChannelへのインタフェースを持っているのでBotの機能開発に集中することが可能です。

Bot Frameworkという名前の方が知れ渡っている気がしますが、2018年3月末にはAzure Bot Serviceに統合されるそう（[参考](https://docs.microsoft.com/en-us/Bot-Framework/bot-service-migrate-bot)）なので <b>Azure Bot Service</b> としてちゃんと覚えておきましょう。。

さくっと試す分には気にしなくていいですが、本番運用など細かくチューニングして使いたい場合はApp ServiceやAzure Functionsなどを理解しておくとよさそうです。

### [Translator Text API](https://azure.microsoft.com/ja-jp/services/cognitive-services/translator-text-api/)

Translator Text APIは、Cognitive Servicesの1つで、テキストの機械翻訳をしてくれるREST APIです。

[Cognitive Services](https://azure.microsoft.com/ja-jp/services/cognitive-services/)には、Translator Text API以外にもテキスト解析・画像解析・音声解析などたくさんのサービスがあります。どんなことができるのか知っておくだけでもサービスのつくり手としての引き出しが広がるので、実際にさわってみることをおすすめします。

# 作ってみる
## 1. Azureのアカウントを用意する
持っていない場合はそれぞれ作成して下さい。

- [Microsoftアカウント新規作成](https://www.microsoft.com/ja-jp/msaccount/signup/default.aspx)
- [Azure新規サブスクリプション作成](https://azure.microsoft.com/ja-jp/free/)

無料試用版で十分ですが、既に作成済みの場合も大抵のサービスには無料プランがあるため、素振りをするだけならコストをかけずに遊ぶことができます。

## 2. Azure Bot Serviceをつくる
まずはAzure Bot Serviceをつくってみましょう。

![Screen Shot 0029-12-25 at 0.08.59.png](https://qiita-image-store.s3.amazonaws.com/0/43421/e771c94d-0d62-34e3-8680-e3293344d7da.png)
Azure Portalに移動し、「Web App Bot」を作成します。
他にもBotをつくる選択肢が存在しますが、今回はAzure Web Appをベースとした「Web App Bot」を選択します。

![Screen Shot 0029-12-25 at 0.23.37.png](https://qiita-image-store.s3.amazonaws.com/0/43421/6572f2d3-d827-919d-ef74-d1f47126f769.png)
必要な項目を埋めます。

- Bot name : ボット名
    - Bot Channelの登録名です
    - Bot Channelの中でユニークである必要があります
- Subscription : サブスクリプション
    - 先程作成したサブスクリプションが選択されていればOKです
- Resource Group : リソースグループ
    - Resource GroupはAzure Serviceをまとめる箱のようなものです
    - 好きな名前をつけて下さい
- Location : 場所
    - Botアプリケーションが置かれるRegionを指定できます
    - 日本で試す場合は「Japan East」か「Japan West」で良いと思います
- Pricing tier : 価格レベル
    - 「F0（無料プラン）」を選択してください
- App name : アプリ名
    - Bot nameと同じ名前が自動で入力されます
    - Botアプリが置かれるAzure Web Appの名前になり、URLの一部となるため、ユニークである必要があります
- Bot template : ボットテンプレート
    - 言語は「C#」と「Node.js」から選択できます
    - 今回は「Node.js」「Basic」の組み合わせを選んでいます
- App Service Plan
    - 好きな名前をつけて下さい
- App Service Plan/Location
    - 好きな名前をつけて下さい
    - 日本で試す場合は「Japan East」か「Japan West」で良いと思います
- Azure Storage
    - Azure Bot Serviceを作成する時に同時につくる必要があるようです
    - 好きな名前をつけて下さい
- Application Insights
    - 今回はお試しなので「OFF」でOKです

埋め終わったら「Create」をクリックします。
複数のサービスを作成するため、多少時間がかかります。

![Screen Shot 0029-12-25 at 0.46.07.png](https://qiita-image-store.s3.amazonaws.com/0/43421/4c20b5d9-8091-0240-f5f8-adf717d92d45.png)
展開が終わったら、作成したWeb App Botに移動します。
Azureは複数サービスを利用しているとどこにあるのかわからなくなるので、レフトナビの「All resouces」か「Resource groups」あたりからリンクをたどることをおすすめします。

![Screen Shot 0029-12-25 at 0.58.00.png](https://qiita-image-store.s3.amazonaws.com/0/43421/abada2fe-4a34-703c-c9e3-91d90978e5b3.png)
作成したWeb App Botに移動し、試しにChat Botのテストをしてみましょう。
デフォルトでは入力したテキストをそのままオウム返しするだけですが、既にChat Botとして動作しています。

## 3. Translator Text APIをつくる
次にTranslator Text APIをつくります。

![Screen Shot 0029-12-25 at 1.05.49.png](https://qiita-image-store.s3.amazonaws.com/0/43421/4bb546a2-4e55-65f1-091d-d94429e5e9a9.png)
先程と同じように、「Translator Text API」を検索して選択します。

![Screen Shot 0029-12-25 at 1.11.16.png](https://qiita-image-store.s3.amazonaws.com/0/43421/4c29e8f9-b117-ae79-ea99-3d4abc3f391e.png)
必要な項目を埋めます。

- Name
    - Translator Text APIの登録名です
- Subscription : サブスクリプション
    - 先程作成したサブスクリプションが選択されていればOKです
- Pricing tier : 価格レベル
    - 「F0（無料プラン）」を選択してください
- Resource Group : リソースグループ
    - 「既存のものを使用」から先程作成したResource Groupを選択して下さい

埋め終わったら「Create」をクリックします。

![Screen Shot 0029-12-25 at 1.20.50.png](https://qiita-image-store.s3.amazonaws.com/0/43421/cb856120-e092-ff58-be67-7599fecd875d.png)
作成したTranslator Text APIに移動し、必要なKey情報を控えておいて下さい。

## 4. Chat Botを実装する
いよいよ実装です。

![Screen Shot 0029-12-25 at 1.25.25.png](https://qiita-image-store.s3.amazonaws.com/0/43421/0a4d23b8-8159-0ad7-3f31-967b71dc3cc3.png)
Azure Bot Serviceに戻り、実装していきます。
Azure Portal上でCodingすることが可能です。「オンラインコードエディターを開く」をクリックします。

<img width="1003" alt="Screen Shot 0029-12-25 at 2.16.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/43421/4888f0eb-4f6e-5139-a28a-751622cd0cab.png">
app.jsのbot.dialogの中身を見てみましょう。

```javascript:app.js
bot.dialog('/', function (session) {
    session.send('You said ' + session.message.text);
});
```

ここが先程オウム返ししていた実装です。
ということでさっそく中身を実装していきます。

```javascript:app.js
var co = require('co')
var request = require('request');

bot.dialog('/', function (session) {
    // 送られてきたテキストが日本語かどうか判定する関数
    function isJapanese(text) {
        return new Promise(function(resolve, reject) {
            var isJapanese = false;
            for (var i = 0; i < text.length; i++) {
                // 簡易的にtext.charCodeAt(i)の返り値が256よりも大きかった場合は日本語として判定
                if(text.charCodeAt(i) >= 256) {
                    isJapanese = true;
                    break;
                }
            }
            resolve(isJapanese); 
        });
    }

    function getCognitiveApiToken(key) {
        return new Promise(function(resolve, reject) {
            var options = {
                url : "https://api.cognitive.microsoft.com/sts/v1.0/issueToken",
                method : 'POST',
                headers : {
                    'Content-Type' : 'application/jwt',
                    'Ocp-Apim-Subscription-Key' : key
                },
                json : true
            };
            request(options, function (error, response, body) {
                if (error) {
                    reject(error);
                } else {
                    resolve(body);
                }
            });
        });
    }

    function translateText(lang, text, token) {
        return new Promise(function(resolve, reject) {
            var options = {
                url : "https://api.microsofttranslator.com/V2/Http.svc/Translate",
                qs : {
                    'to' : lang,
                    'text' : text
                },
                method : 'GET',
                headers : {
                    'Authorization' : 'Bearer ' + token
                },
                json : true
            };
            request(options, function (error, response, body) {
                if (error) {
                    reject(error);
                } else {
                    // Translator Text Apiからのレスポンスはstringタグで囲まれているのでタグを除去する
                    text = body.replace(/<(.+?)>|<\/string>/g, '');
                    resolve(text);
                }
            });
        });
    }

    co(function*() {
        var text = session.message.text;
        var api_key = "*************"; // Translator Text Api Key
        if (yield isJapanese(text)) {
            var to_lang = "en";
        } else {
            var to_lang = "ja";        
        }
        try {
            var token = yield getCognitiveApiToken(api_key);
            var result = yield translateText(to_lang, text, token);
            session.send(result);
        } catch(error) {
            context.log(error);
        }
    });
});
```

簡単ですね。
Azure Portalを使い慣れているからかもしれませんが、全体で1時間程度でさくっと作れてしまいました。

上記のChat Bot自体の実装を問い合わせ形式にしたり、様々なChatインタフェースに合わせたりしていくことで、機能を充実していくことが可能です。

簡単過ぎて恐縮ですが、一応上記のサンプルコードをGithubにあげておきましたので、ご自由にお使い下さい。

- https://github.com/TAKAKING22/AzureBotService-TranslatorTextAPI

# いろいろやれそうなこと

### 多言語対応
今回は自分の使い勝手を考えて、Inputを日本語or英語に絞ってOutputの言語を動的に切り替えていますが、Translator Text APIはOutputの言語を指定するだけでInputの言語を自動的に判定してくれます。

### 任意のチャットサービスとの連携
前述の通り、Azure Chat Serviceは主要なチャットサービスとのインタフェースが存在しているので簡単に連携することができます。

### スマートスピーカー連携
今回はChat BotということでBotをインタフェースに利用しましたが、Azure Chat Serviceも結局のところAzure Web AppやAzure Functions上で動作するWebアプリケーションなので、IFTTTなどから呼び出すことでスマートスピーカーとの連携もできそうです。
後述の裏話の通り、実は当初はこれを今回試してみようと考えていました。

# 裏話
最初は、

1. Google Homeで日本語を話す
2. Bing Speech APIを使って音声をテキストに変換する
3. Translator Text APIを使って英語に変換する
4. Bing Speech APIを使ってテキストを音声に変換する
5. Google Homeから音声で返す

みたいなものを作ってみようと考えていたんですが、試しに

「OK Google」
「"こんにちは、世界" を英語で」

と呼びかけてみたらものの見事に

『Hello World』

と返ってきたので止めましたｗ
でも同じようなものは比較的に簡単に実装できそうです。