Twilioと駅すぱあとを使って、音声で経路探索を行う

:::note alert
2023年5月1日を持ちまして、株式会社KDDIウェブコミュニケーションズのTwilioリセール事業が終了したため、本記事に記載されている内容は正確ではないことを予めご了承ください。
:::

# はじめに

経路探索で有名なヴァル研究所の「駅すぱあと」と、コミュニケーションAPIの「Twilio」を組み合わせることで、音声を使って経路探索を行い、その結果をSMSを受け取る仕組みを作成します。
[完成動画](https://glaucous-alpaca-2342.twil.io/assets/Ekispert.mp4)

なお、本記事は2018年9月1日現在の情報に基づいて作られています。

## 準備

本ハンズオンには、以下のアカウントが必要です。

- 駅すぱあとアカウント
 - [こちらのリンク](https://ekiworld.net/free_provision/index.php)から、フリープラン（無料）のAPIキーを申請してください。
 - 申請後、一両日中にフリープランのAPIキーがメールで届きます。 
- Twilioアカウント
 - [こちらのリンク](https://twilio.kddi-web.com/signup/)から、トライアルアカウントを作成してください。アカウントの作成に関しては、[こちらの動画](https://www.youtube.com/watch?v=rNiaLjnhlB4)も御覧ください。
- Google Cloud platformアカウント
 - [こちらのリンク](https://cloud.google.com/)から、無料トライアルアカウントを作成してください。作成には、クレジットカードが必要です。
 - アカウントができたら、プロジェクトを作成して、Cloud Natural Language APIを有効にします。
 - さらに、このAPIを利用するためのAPIキーを生成してください。こちらのAPIキーを後ほど利用します。

## 全体のフロー

今回作成するコールフローは以下のようなものです。
<img width="992" alt="スクリーンショット 2018-08-31 11.43.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/86046/fb2e076b-12bc-b4de-298c-514b421d9180.png">

1. 電話が着信します。
2. 応答メッセージが流れるので、どこからどこに行きたいかを音声で話してもらいます。
3. 音声認識した結果を、Googleの自然言語分析にかけて、駅名にあたる部分を抽出します。
4. 駅すぱあと WebAPIを利用して、経路を探索します。
5. 探索結果のURLを短縮します（URLが長いとSMSで送れないため）。
6. 短縮URLをSMSで送信します。

# ハンズオン

## ログイン＆電話番号の購入

### 手順1. Twilioの管理コンソールにログインします。

- ブラウザで[ログイン画面](https://jp.twilio.com/login/kddi-web)を表示し、配布されたIDとパスワードでログインをします。
- ログインID： twiliohandson@kddi-web.com
- パスワード: 講師の指示に従ってください

![スクリーンショット 2018-05-04 10.13.08.png](https://qiita-image-store.s3.amazonaws.com/0/86046/c0111212-a218-c0f9-9fcb-8838ca68ec84.png)

**今回のハンズオンでは、ログインIDはすべて共通となります。パスワードを間違えると他の方がロックアウトされてしまうので、間違えないようにしてください。**
**また、二要素認証を有効にしないように注意してください。**

- 右上の歯車アイコンをクリックし、**Subaccounts**を選択します。
![スクリーンショット 2018-05-04 10.14.46.png](https://qiita-image-store.s3.amazonaws.com/0/86046/ced963f3-f45b-b9fe-794b-64510fab9423.png)

- サブアカウントの一覧が表示されたら、ご自分のユーザ名（userXX）の右側にある**サブアカウントを表示**をクリックします。
- 右上にご自分のユーザ名が表示されることを確認します。
- ブラウザを閉じてしまった場合やログアウトしてしまった場合は、再度サブアカウントにログインしてください。

### 手順2. 着信用電話番号を購入します。

- 管理コンソールの左側にあるボタンアイコンを押すと、スライドメニューが表示されます。

![002 (1).png](https://qiita-image-store.s3.amazonaws.com/0/86046/e9bd6295-1b6e-9eb7-fdf4-1075b4d610c3.png)

- スライドメニューの一覧から、**電話番号**を選択します。

![005 (1).png](https://qiita-image-store.s3.amazonaws.com/0/86046/7a3e89e8-540a-8c9e-2340-fdcbecdc80d6.png)
- **Phone Numbers**メニューの中の**Buy a Number**を選択します。
- 国のプルダウンから「Japan（+81）」を選択し、**検索**ボタンを押します。

![006.png](https://qiita-image-store.s3.amazonaws.com/0/86046/e3e0c258-960e-f8fa-5301-62c4c28b2834.png)

- 一覧表示されたリストの中から、TYPEがローカルになっている（108円）の番号を一つ選び、**購入**ボタンを押します。
- この番号を購入しますか？というダイアログが出たら、**この番号を購入する。**を押します。
- Congratulationのダイアログが表示されたら、購入完了です。**閉じる**ボタンを押します。
- Phone Numbersの中のManage Numbersを選択し、今購入した電話番号が表示されることを確認します。購入した電話番号は後ほど使いますので、メモ帳などに控えておきます。

### 手順3. SMS送信用電話番号を購入します。

- **Phone Numbers**メニューの中の**Buy a Number**を選択します。
- 国のプルダウンから「United States（+1）」を選択し、さらに、**SMS**のチェックを入れてから**検索**ボタンを押します。
- 一覧表示されたリストの中から、TYPEがローカルになっている（150円）の番号を一つ選び、**購入**ボタンを押します。
- この番号を購入しますか？というダイアログが出たら、**この番号を購入する。**を押します。
- Congratulationのダイアログが表示されたら、購入完了です。**閉じる**ボタンを押します。
- Phone Numbersの中のManage Numbersを選択し、今購入した電話番号が表示されることを確認します。こちらの電話番号も後ほど使いますので、メモ帳などに控えておきます。

```lang:電話番号の表記方法について
Twilioは、世界100カ国と接続されていて、それぞれの国に直接電話をかけることができます。
そのため、発信・着信の電話番号は、全世界で利用可能な「E.164形式」と呼ばれる表記方法を使います。
E.164形式とは、先頭が+から始まる国番号と電話番号の組み合わせです。
例えば、日本は国番号が+81となっており、その後の電話番号を続けて記述します。
※電話番号の先頭の0は削除します。
「09012345678」は、E.164形式だと「+819012345678」となります。
```

## 自然言語解析で出発点と到着点を抽出する

Twilioには、会話中に音声を文字に変えるためのSpeech Recognition機能があり、それを利用することで例えば「銀座から渋谷まで」といった文字列に変換することができます。
ただ、この文字列から「銀座」とか「渋谷」を抜き出すことはできないため、今回はGoogleの[Natural Language API](https://cloud.google.com/natural-language/)を利用して、自然言語の中から場所を抜き出します。

### 手順1. Google APIキーの設定

このAPIを利用するためには、予めGoogle Cloudのアカウントと、Cloud Natural Languageのサービス有効化、さらにはAPIキーが必要になります。
このあたりの手順については、[こちらのドキュメント](https://cloud.google.com/natural-language/docs/quickstart-client-libraries)を参照してください。

- スライドメニューから、**Runtime**を選択します。

![003 (1).png](https://qiita-image-store.s3.amazonaws.com/0/86046/148ec908-e67c-e9d7-f498-9d63cae2a1db.png)

- Runtimeメニューの中から**Functions**を選択し、さらに**Configure**を選択します。

![004 (1).png](https://qiita-image-store.s3.amazonaws.com/0/86046/c5fb8453-e962-e8b1-9a34-b31b8de3d760.png)

- **Enable ACCOUNT_SID and AUTH_TOKEN**のチェックボックスをONにします。

![スクリーンショット 2018-07-03 10.06.47.png](https://qiita-image-store.s3.amazonaws.com/0/86046/5913d0f6-0c75-11fd-8344-3cec6ddfa186.png)

- Environment Variablesの赤いプラスアイコンを2回押して、以下の変数を設定します。

|KEY|VALUE|
|:--|:--|
|GOOGLE_API_KEY|*取得したGoogleAPIキーを入力してください*|
|NEAR_STATION|*自分の自宅、もしくは会社の最寄り駅を入れてください（例：外苑前）*|

- **Dependencies**項目の赤いプラスボタンを1回押して、以下の値を設定します。

|NAME|VERSION|
|:--|:--|
|request-promise|4.2.2|

- さらに、**twilio**のバージョンを「3.19.1」に変更します。
- 設定が完了したら、**Save**ボタンを押します。

![駅すぱあと Dependencies.png](https://qiita-image-store.s3.amazonaws.com/0/86046/d88fa3a1-0566-feae-36ac-9ddc224f066f.png)

### 手順2. Functionの作成

- 管理コンソールにスライドメニューを開き、**Runtime**を選択します。

![007 (1).png](https://qiita-image-store.s3.amazonaws.com/0/86046/8e006277-a734-bf8d-081b-d110455070d0.png)
- Runtimeメニューの中から、**Functions**を選択します。
- **Create a Function**ボタンを押して、新規にFunctionを作成します。
- **New Function**ダイアログが表示されますので、**Blank**を選択して、**Create**ボタンを押します。
- **FUNCTION NAME**に、「GoogleNLApi」と入力します。
- **PATH**に、「/google-nl-api」（すべて小文字）と入力します。
- **ACCESS CONTROL**のチェックはOFFにします。
- **EVENT**はそのままでOKです。
- **CODE**に書かれているデフォルトのコードを削除し、以下のコードを貼り付けます。

```javascript

const request = require('request-promise');

exports.handler = function(context, event, callback) {
    console.log(`event.text: ${event.text}`);  // 元の文字列
    var options = { 
        method: 'POST',
        url: 'https://language.googleapis.com/v1/documents:analyzeEntities',
        qs: { key: context.GOOGLE_API_KEY },
        headers: { 
            'cache-control': 'no-cache',
            'content-type': 'application/json' 
        },
        json: { 
            document: { 
                type: 'PLAIN_TEXT', 
                content: event.text || '', 
                language: 'ja-JP' },
            encodingType: 'UTF8' },
    };
  
    request(options)
    .then((parsedBody) => {
        console.log(parsedBody);
        console.log(`${parsedBody.entities.length} entities.`);
        for (const entity in parsedBody.entities) {
            console.log(`${parsedBody.entities[entity].name}`);
        }
        if (parsedBody.entities.length == 1) { // 場所が１つしか抽出できなかった場合は、出発駅をNEAR_STATIONにする
            callback(null, {from:context.NEAR_STATION,to:parsedBody.entities[0].name});
        } else if (parsedBody.entities.length > 1) {  // 2つ以上の場所が抽出できた場合は、最初を出発駅、次の到着駅にする
            callback(null, {from:parsedBody.entities[0].name,to:parsedBody.entities[1].name});
        } else {
            callback(null, {from:'',to:''});
        }
    })
    .catch((err) => {
        console.error(`problem with request: ${err.message}`);
        callback(err.message);
    });

};
```

- 「Save」ボタンを押して、保存とデプロイを行います。

### 手順3. テスト

- *PATH*欄の右側にあるコピーアイコンを押して、URLをコピーします。
- ブラウザの別のタブを開き、今コピーしたURLを貼り付けます。
- URLの最後に```?text=銀座から渋谷まで```と付加して実行します。
- 次のようなjsonが戻れば成功です。

<img width="180" alt="スクリーンショット 2018-08-31 10.03.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/86046/c27bb8d3-e755-52e2-d4a4-ee2cba41a90f.png">

## 駅すぱあとWebサービスAPIを使って経路探索する

「駅すぱあとWebサービス」とは、株式会社ヴァル研究所が提供する「駅すぱあと」経路検索の機能を、Webサイトやモバイルアプリなどに組み込み可能なクラウド型APIです。
メンテナンス不要で、常に最新情報をAPIで提供し、保守費用を軽減します。また、「駅情報」や「路線情報」などは無料のフリープランで商用利用可能です。
フリープランで利用できるAPIは以下の通りです。

|分類|API|説明|
|:----|:----|:----|
|探索|駅すぱあと for web URL生成|探索結果を表示するためのURLを生成します。|
|駅の情報|駅情報|指定された条件に当てはまる駅の情報を返します。|
||駅簡易情報|このAPIは主に候補駅の確定を想定しているため、必要最低限の簡易データのみ返します。 |
|付加情報|駅付加情報|指定した駅の付加情報を取得します。|
|路線の情報|運行路線情報|「駅すぱあと」の保持する運行路線の情報(鉄道のみ)を取得します。|
||平均路線情報|「駅すぱあと」の保持する平均路線の情報を取得します。|
|会社の情報|会社情報|交通機関の会社情報を取得します。|

フリープランのドキュメントは、[こちら](http://docs.ekispert.com/v1/le/index.html)を参照してください。

今回は、この中の「駅すぱあと for web URL生成」のAPIを利用します。

#### リクエストURL

```GET /v1/{format}/search/course/light```

#### パラメータ

Name|Type|Required|Description
:--|:--:|:--:|:--
format|string|◯|レスポンスのデータ形式（'xml' or 'json'）の指定。
key|string|◯|アクセスキー。
from|string|---|出発駅(地)。駅コード、駅の名称を指定可能です。
to|string|---|到着駅(地)。駅コード、駅の名称を指定可能です。
via|string|---|経由駅(地)。駅コード、駅の名称を指定可能です。省略可。省略時は指定なしとなります。
date|int|---|探索日付。省略可。
searchType|string|---|探索種別。省略可。
plane|string|---|飛行機。省略可。
shinkansen|string|---|新幹線(のぞみ含む)。省略可。
limitedExpress|string|---|特急。省略可。
redirect|string|---|結果をリダイレクトするかどうか。省略可。
contentsMode|string|---|生成するURLの種類。省略可。

### 手順1. APIキーの設定

- Runtimeメニューの中から**Functions**を選択し、さらに**Configure**を選択します。
- Environment Variablesの赤いプラスアイコンを1回押して、以下の変数を設定します。

|KEY|VALUE|
|:--|:--|
|EKISPERT_API_KEY|*取得した駅すぱあとWebサービスAPIキーを入力してください*|

- 設定が完了したら、**Save**ボタンを押します。

### 手順2. Functionの作成

- Runtimeメニューの中から、**Functions**を選択します。
- **Create a Function**ボタンを押して、新規にFunctionを作成します。
- **New Function**ダイアログが表示されますので、**Blank**を選択して、**Create**ボタンを押します。
- **FUNCTION NAME**に、「EkispertApi」と入力します。
- **PATH**に、「/ekispert-api」（すべて小文字）と入力します。
- **ACCESS CONTROL**のチェックはOFFにします。
- **EVENT**はそのままでOKです。
- **CODE**に書かれているデフォルトのコードを削除し、以下のコードを貼り付けます。

```javascript
var request = require("request-promise");

exports.handler = function(context, event, callback) {
    const from = event.from || '';
    const to = event.to || '';
    console.log(`from: ${from} to:${to}`);
    var options = { 
        method: 'GET',
        url: 'https://api.ekispert.jp/v1/json/search/course/light',
        qs: { key: context.EKISPERT_API_KEY, from: from, to: to },
        headers: { 
            'cache-control': 'no-cache' } 
    };

    request(options)
    .then(body => {
        console.log(body);
        callback(null, JSON.parse(body).ResultSet.ResourceURI);
    })
    .catch(error => {
        callback(error, 'Error');
    });
};
```

- 「Save」ボタンを押して、保存とデプロイを行います。

### 手順3. テスト

- *PATH*欄の右側にあるコピーアイコンを押して、URLをコピーします。
- ブラウザの別のタブを開き、今コピーしたURLを貼り付けます。
- URLの最後に```?from=銀座&to=渋谷```と付加して実行します。
- 次のようなURLが戻れば成功です。

<img width="1115" alt="スクリーンショット 2018-08-31 10.13.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/86046/c32a61f2-fe43-e2a5-c63e-fbe2e137ea92.png">

- 表示されたURLをコピーしてブラウザで表示すると、銀座から渋谷までの経路が表示されます。

## 探索結果のURLを短縮する

駅すぱあとWebサービスAPIを使うことで、経路情報のURLを取得することができましたが、取得したURLが長すぎるため、このままではSMSで送ることができません。そのため、URLを短縮する仕組みを作ります。
短縮URLは、ランダムな短い文字列と、元々のURLの2つを、Key/Value形式でデータベースに格納したいと思います。Twilioにはデータベース機能はありませんが、Twilio Syncというサービスがあります。

#### <参考> Twilio Syncとは

- [Twilio Sync](https://jp.twilio.com/sync)
- 複数のデバイス間で情報を同期させるためのサービス
- WebSocketやSocket.ioのようなリアルタイム通信プラットフォーム
- Syncは、受け取ったデータをTwilio上に保存してから配信する
- Sync上のデータは、明示的に削除しない限り消えない
- 月10,000アクションまでは無料、それ以降は1000アクション単位で1.5円
- Documents / Lists / Maps / Message Streams の4種類のデータを扱うことが可能

今回は、Twilio SyncのMapsオブジェクトを使って、短縮URLを管理したいと思います。

### 手順1. Functionの作成

- Runtimeメニューの中から、**Functions**を選択します。
- **Create a Function**ボタンを押して、新規にFunctionを作成します。
- **New Function**ダイアログが表示されますので、**Blank**を選択して、**Create**ボタンを押します。
- **FUNCTION NAME**に、「MakeShortUrl」と入力します。
- **PATH**に、「/make-short-url」（すべて小文字）と入力します。
- **ACCESS CONTROL**のチェックはOFFにします。
- **EVENT**はそのままでOKです。
- **CODE**に書かれているデフォルトのコードを削除し、以下のコードを貼り付けます。

```javascript
exports.handler = function(context, event, callback) {
    const longUrl = event.url || '';
    if (longUrl === '') {
        callback(null, 'Error');
    }
    
    // 短縮URLを生成
    const key = Math.random().toString(36).slice(-6);
    const shortUrl = `https://${context.DOMAIN_NAME}/result?key=${key}`;

    let sync = Runtime.getSync();
    let payload = {
        url: longUrl,
    };
  
    sync.maps.create({  // Mapsオブジェクトを作成
        uniqueName: 'url_map'
    })
    .then(response => {
        console.log(`Sync map url_map created.`);
    })
    .catch(error => {   // Mapsオブジェクトがすでにある場合
        console.log(`Sync map url_map already exists.`);
    })
    .then(() => {   // データの書き込み
        return sync.maps('url_map').syncMapItems.create({
            key: key,
            data: payload
        });      
    })
    .then(response =>{  // 書き込み成功
        console.log(response);
        callback(null, shortUrl);
    })
    .catch(error => { // 書き込み失敗
        console.log(error);
        callback(error);
    });
};
```

- 「Save」ボタンを押して、保存とデプロイを行います。

### 手順2. テスト

- *PATH*欄の右側にあるコピーアイコンを押して、URLをコピーします。
- ブラウザの別のタブを開き、今コピーしたURLを貼り付けます。
- URLの最後に```?url=abcdefgf```と付加して実行します。
- 次のようなURLが戻れば成功です。

<img width="369" alt="スクリーンショット 2018-08-31 10.52.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/86046/02d0dc4b-4d2b-4dd8-3de9-45af727c62a8.png">

## 短縮URLをもとに経路結果ページにナビゲートする

では次に、今の短縮URLがクリックされた時に、元の長いURLにリダイレクトするためのFunctionを作っていきます。
先程のTwilio Sync Mapsオブジェクトを検索して元のURLを取得します。

### 手順1. Functionの作成

- Runtimeメニューの中から、**Functions**を選択します。
- **Create a Function**ボタンを押して、新規にFunctionを作成します。
- **New Function**ダイアログが表示されますので、**Blank**を選択して、**Create**ボタンを押します。
- **FUNCTION NAME**に、「Result」と入力します。
- **PATH**に、「/result」（すべて小文字）と入力します。
- **ACCESS CONTROL**のチェックはOFFにします。
- **EVENT**はそのままでOKです。
- **CODE**に書かれているデフォルトのコードを削除し、以下のコードを貼り付けます。

```javascript
exports.handler = function(context, event, callback) {
    const key = event.key || '';
    if (key === '') {
        callback(null, 'Error');
    }

    const response = new Twilio.Response();
    let sync = Runtime.getSync();
    sync.maps('url_map').syncMapItems.get(key).fetch()
    .then(res => {  // 正しくURLが取得できた 
        console.log(res.data.url);
        response.appendHeader('Location', res.data.url);
        callback(null, response);
    })
    .catch(err => {  // URLの取得に失敗
        console.log(err);
        callback(null, 'Error');
    });
    
};
```

- 「Save」ボタンを押して、保存とデプロイを行います。

## Twilio Studioを使ってコールフローを作成する

部品の準備が整いましたので、いよいよフローを作っていきたいと思います。
念の為、最初にご紹介した今回のフローのサンプルを再度載せておきます。

<img width="992" alt="スクリーンショット 2018-08-31 11.43.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/86046/fb2e076b-12bc-b4de-298c-514b421d9180.png">


### 手順1. フローを作成する

- 管理コンソールの左側のスライドメニューから、Studioを選択します。
- 赤いプラスアイコンをクリックするか、「Create a new flow」を選択して、新しいフローを作成します。
- FLOW NAMEに「Ekispert」と入力して、NEXTボタンを押します。
- **New Flow**ダイアログが表示されるので、**Start from scratch**が選択されていることを確認して、**Next**ボタンを押します。
- **Trigger**ボックスのみが表示されたフローが作成されます。

### 手順2. 応答メッセージと駅名の問い合わせ

- キャンパスが表示されたら、WIDGET LIBRARYから**Say/Play**をキャンパス上にドラッグアンドドロップします。
- Triggerボックスの**Incoming Call**と、今配置した「say_play_1」ボックスの左上の黒丸部分を結合します。
- 今ドロップしたウィジェットを選択し、**WIDGET NAME**を「SayHello」、**SAY OR PLAY MESSAGE**欄は、「Say a Message」を選択します。
- **TEXT TO SAY**欄に、「はい。こちらは、エキスパートです。」と入力します。
- **LANGUAGE**のプルダウンリストから「Japanese」を選択します。
- **MESSAGE VOICE**のプルダウンリストから好みの音声を選択します。
- **SAVE**ボタンを押します。
- 続いて、WIDGET LIBRARYから**Gather Input On Call**ウィジェットをキャンパス上にドラッグアンドドロップします。
- 先程作成したSayHelloボックスの**Audio Complete**と、今配置した「gather_input_on_call_1」ボックスの左上の黒丸部分を結合します。
- 今ドロップしたウィジェットを選択し、**WIDGET NAME**を「WhereWillYouGo」、**SAY OR PLAY MESSAGE**欄は、「Say a Message」を選択します。
- **TEXT TO SAY**欄に、「どこからどこに行きたいかを喋ってください。」と入力します。
- **LANGUAGE**のプルダウンリストから「Japanese」を選択します。
- **MESSAGE VOICE**のプルダウンリストから好みの音声を選択します。
- **SPEECH RECOGNITION LANGUAGE**のプルダウンリストから「Japanese（Japan）」を選択します。
- **SAVE**ボタンを押します。
- 続いて、WIDGET LIBRARYから**Say/Play**をキャンパス上にドラッグアンドドロップします。
- 今作成したWhereWillYouGoボックスの**No input**と、今配置したウィジェットの左上の黒丸部分を結合します。
- 今ドロップしたウィジェットを選択し、**WIDGET NAME**を「Retry」、**SAY OR PLAY MESSAGE**欄は、「Say a Message」を選択します。
- **TEXT TO SAY**欄に、「すみません。うまく聞き取れませんでした。」と入力します。
- **LANGUAGE**のプルダウンリストから「Japanese」を選択します。
- **MESSAGE VOICE**のプルダウンリストから好みの音声を選択します。
- **SAVE**ボタンを押します。

- 今作成したRetryボックスの**Audio Complete**と、WhereWillYouGoボックスの左上の黒丸部分を結合しておきます。

### 手順3. 一連のFunctionを呼び出し

- WIDGET LIBRARYから**Run Function**をキャンパス上にドラッグアンドドロップします。
- 先程作成したWhereWillYouGoボックスの**User Said Something**と、今配置したウィジェットの左上の黒丸部分を結合します。
- 今ドロップしたウィジェットを選択し、**WIDGET NAME**を「GoogleNLAPI」、**FUNCTION URL**欄は、「GoogleNLApi」を選択します。
- **Function Parameters**のプラスアイコンを押します。
- **Key**欄に「text」、Value欄には「{{widgets.WhereWillYouGo.SpeechResult}}」と入力します。
- **Add Parameter**をクリックして、値を保存します。
- **SAVE**ボタンを押します。
- 再度、WIDGET LIBRARYから**Run Function**をキャンパス上にドラッグアンドドロップします。
- 今作成したGoogleNLAPIボックスの**Success**と、今配置したウィジェットの左上の黒丸部分を結合します。
- 今ドロップしたウィジェットを選択し、**WIDGET NAME**を「EkispertApi」、**FUNCTION URL**欄は、「EkispertApi」を選択します。
- **Function Parameters**のプラスアイコンを押します。
- **Key**欄に「from」、Value欄には「{{widgets.GoogleNLAPI.parsed.from}}」と入力します。
- **Add Parameter**をクリックして、値を保存します。
- **Function Parameters**の**Add**を押します。
- **Key**欄に「to」、Value欄には「{{widgets.GoogleNLAPI.parsed.to}}」と入力します。
- **Add Parameter**をクリックして、値を保存します。
- **SAVE**ボタンを押します。
- 再度、WIDGET LIBRARYから**Run Function**をキャンパス上にドラッグアンドドロップします。
- 今作成したEkispertApiボックスの**Success**と、今配置したウィジェットの左上の黒丸部分を結合します。
- 今ドロップしたウィジェットを選択し、**WIDGET NAME**を「MakeShortUrl」、**FUNCTION URL**欄は、「MakeShortUrl」を選択します。
- **Function Parameters**のプラスアイコンを押します。
- **Key**欄に「url」、Value欄には「{{widgets.EkispertApi.body}}」と入力します。
- **Add Parameter**をクリックして、値を保存します。
- **SAVE**ボタンを押します。

### 手順4. SMS送信

- WIDGET LIBRARYから**Send Message**をキャンパス上にドラッグアンドドロップします。
- 先程作成したMakeShortUrlボックスの**Success**と、今配置したウィジェットの左上の黒丸部分を結合します。
- 今ドロップしたウィジェットを選択し、**WIDGET NAME**を「SendSMS」、**MESSAGE BODY**欄は、「{{widgets.MakeShortUrl.body}}」と入力します。
- **SEND MESSAGE FROM**欄には、購入したUS番号を入力します。**SEND MESSAGE TO**はそのままでOKです。
- **SAVE**ボタンを押します。

### 手順5. 終了メッセージ

- 最後に、WIDGET LIBRARYから**Say/Play**をキャンパス上にドラッグアンドドロップします。
- 先程作成したSendSMSボックスの**Sent**と、今配置したウィジェットの左上の黒丸部分を結合します。
- 今ドロップしたウィジェットを選択し、**WIDGET NAME**を「SayComplete」、**SAY OR PLAY MESSAGE**欄は、「Say a Message」を選択します。
- **TEXT TO SAY**欄に、「お待たせいたしました。経路の探索が完了しましたので、結果をエスエムエスでお送りします。またのご利用をお待ちしております。」と入力します。
- **LANGUAGE**のプルダウンリストから「Japanese」を選択します。
- **MESSAGE VOICE**のプルダウンリストから好みの音声を選択します。
- **SAVE**ボタンを押します。

### 手順6. パブリッシュ＆電話番号設定

- 画面上部にある**Publich**ボタンを押します。
- **Publish Flow?**ダイアログが表示されたら、**Publish**ボタンを押します。
<img width="541" alt="スクリーンショット 2018-07-13 00.11.44.png" src="https://qiita-image-store.s3.amazonaws.com/0/86046/d3f27a27-6480-3e32-771d-c4f65514952d.png">
- 左側のスライドメニューを開き、**Phone Numbers**を選択します。
- すでに購入済みの050番号を選択して、設定画面を表示します。
- **着信時の設定**で、「Studio Flow」を選択し、さらに今作成した「Ekispert」を選択します。
- 画面下部にある**保存**ボタンを押します。

## テスト

- 購入した050番号に電話を掛けてみて、経路情報を正しく表示できることを確認します。
- もしうまくいかない場合は、Studioのログを参照すると良いでしょう。
- 以下は、正しくできた場合のログです。

<img width="1165" alt="スクリーンショット 2018-08-31 13.32.28.png" src="https://qiita-image-store.s3.amazonaws.com/0/86046/f1096fd3-e36f-08b3-841d-9bedd59953fd.png">

## まとめ

今回は、自然言語解析を使って場所（駅名）を抜き出しました。
駅名によっては、全国に複数あったり、うまく抜き出せない場合などもあるので、実際にはもう少し改良が必要かと思いますが、Twilioの音声認識と、外部Webサービスとの連携によって、音声だけで色々なことができるということを体験していただければと思います。