Twilio StudioでGatherの値を記憶させる方法

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

# はじめに

みなさん、こんにちは。
KDDIウェブコミュニケーションズのTwilio事業部エバンジェリストの高橋です。

今回は、Twilio Studioを使って、Gatherウィジェット（Gather Input On Callウィジェット）の入力値を記憶させる方法について解説します。

## どんなときに使うの？

Twilio Studioでは、ウィジェットと呼ばれる部品をつなげていくことで、簡単にコールフローが作れます。
たとえば、質問をいくつか実施して、その回答を自動的に応答させるなどが可能です。

質問が常に決まっているのであれば、その質問ごとにGaterウィジェットを作成することで、それぞれの質問で受け付けた結果はウィジェット名を指定することで取得が可能です。

![スクリーンショット 2020-06-19 07.53.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/d9b19bb2-0f66-6fd8-0890-a7a5e086ad24.png)

例えば上のGatherウィジェットを作ったとすれば、このウィジェットで入力された数字は、`{{widgets.Question_1.Digits}} `という感じで、`{{}}`で囲むことで参照することができます。

## 質問の数が不定の場合は？

では、質問が動的に変わる、もしくは繰り返し同じ質問を繰り返す場合などはどうするのがよいでしょう。
たとえば、好きな数字を何度も質問させたい場合などは、以下のようにGatherウィジェットをループさせることで実現することができます。

![スクリーンショット 2020-06-19 08.00.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/298bf230-49b4-9b90-129f-ba989bcfc14e.png)

このフローでは、好きな数字を入力させる`PushNumberウィジェット`で入力された数字を、`CheckDigitウィジェット`で判定し、入力値が`#`でなければ、再び`PushNumberウィジェット`を呼び出しています。
これにより、`#`が押されるか、何も入力しない状態になるまで処理はループします。

では、このようなループを作った場合、毎回入力された数字を記憶しておくにはどうしたら良いでしょうか。

## Set Variablesウィジェットを使う

Studio内で、変数を扱うためのウィジェットが、`Set Variables`ウィジェットです。
以下の例をみてください。

![スクリーンショット 2020-06-19 08.06.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/688f94c2-f3b8-09e1-d68c-5b9c6cd50ef4.png)

このウィジェットは、Studioフロー内に`digits`という名前の変数を定義しています。この変数の値は、このフローの中からは、``flow.variables.digits``という形で参照することができます。
そして、その値は以下のような計算式で設定されています。

```
{% if flow.variables.digits %}{{flow.variables.digits | append: '。' | append: widgets.PushNumber.Digits}} {% else %}{{widgets.PushNumber.Digits}}{% endif %}
```

これは、[Liquid templating language](https://www.twilio.com/docs/studio/user-guide/liquid-template-language?display=embedded)と呼ばれる書式に基づいて書かれています。
大体雰囲気でわかるかと思いますが、今回は次のような式になっています。

まず、すでにdigits変数が存在するかをifで判定し、もし存在するようであれば、その値に、「。」と新しく入力された数値（`widgets.PushNumber.Digits`）を連結し、digitsが存在しない場合は、`widgets.PushNumber.Digits`の値をそのまま設定しています。
これにより、初回は入力値がそのまま入った状態になり、２回目以降は、その数字に、「。」と新しい数字が連結されて、たとえば以下のような値になっていきます。
「１。２。３。・・・」

このようにループ内で生成された入力値を変数として保存しておくことで、後から値を参照することができます。
今回作ったフローの全体像は以下の通りです。
![スクリーンショット 2020-06-19 08.19.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/81d50fc3-3b79-9ce3-dd8f-4d5de4c52bb2.png)

このフローのJSONデータは以下の通りです。

```json
{
  "description": "A New Flow",
  "states": [
    {
      "name": "Trigger",
      "type": "trigger",
      "transitions": [
        {
          "event": "incomingMessage"
        },
        {
          "next": "PushNumber",
          "event": "incomingCall"
        },
        {
          "event": "incomingRequest"
        }
      ],
      "properties": {
        "offset": {
          "x": -160,
          "y": 60
        }
      }
    },
    {
      "name": "PushNumber",
      "type": "gather-input-on-call",
      "transitions": [
        {
          "next": "CheckDigit",
          "event": "keypress"
        },
        {
          "event": "speech"
        },
        {
          "next": "sayResult",
          "event": "timeout"
        }
      ],
      "properties": {
        "voice": "Polly.Mizuki",
        "number_of_digits": 1,
        "speech_timeout": "auto",
        "offset": {
          "x": -70,
          "y": 280
        },
        "loop": 1,
        "finish_on_key": "#",
        "say": "好きな数字を押してください。終わるにはシャープを押してください。",
        "language": "ja-JP",
        "stop_gather": false,
        "gather_language": "en",
        "profanity_filter": "true",
        "timeout": 5
      }
    },
    {
      "name": "CheckDigit",
      "type": "split-based-on",
      "transitions": [
        {
          "next": "SetVariables",
          "event": "noMatch"
        },
        {
          "next": "sayResult",
          "event": "match",
          "conditions": [
            {
              "friendly_name": "If value equal_to #",
              "arguments": [
                "{{widgets.PushNumber.Digits}}"
              ],
              "type": "equal_to",
              "value": "#"
            }
          ]
        }
      ],
      "properties": {
        "input": "{{widgets.PushNumber.Digits}}",
        "offset": {
          "x": -270,
          "y": 500
        }
      }
    },
    {
      "name": "SetVariables",
      "type": "set-variables",
      "transitions": [
        {
          "next": "PushNumber",
          "event": "next"
        }
      ],
      "properties": {
        "variables": [
          {
            "index": "0",
            "value": "{% if flow.variables.digits %}{{flow.variables.digits | append: '。' | append: widgets.PushNumber.Digits}} {% else %}{{widgets.PushNumber.Digits}}{% endif %}",
            "key": "digits"
          }
        ],
        "offset": {
          "x": -260,
          "y": 760
        }
      }
    },
    {
      "name": "sayResult",
      "type": "say-play",
      "transitions": [
        {
          "event": "audioComplete"
        }
      ],
      "properties": {
        "voice": "Polly.Mizuki",
        "offset": {
          "x": 160,
          "y": 760
        },
        "loop": 1,
        "say": "あなたの押した数字は、{{flow.variables.digits}} です。",
        "language": "ja-JP"
      }
    }
  ],
  "initial_state": "Trigger",
  "flags": {
    "allow_concurrent_calls": true
  }
}
```

このJSONを使って、新しくStudioフローを作成すると、上記のフローがそのまま複製されます。JSONファイルからフローを作成するには、Studioフローを新規作成するときに、`Import from JSON`を選択します。

![スクリーンショット 2020-06-19 08.22.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/6c3a6a84-d1ed-f49f-fdbb-912b0a271708.png)

# まとめ

今回は、Studioフロー内で変数を扱う方法をご紹介しました。
今回の例では、数字を永遠に押させるというシナリオなので、あまり現実的ではないですが、たとえば外部のボットエンジンなどを組み合わせて、質問を何度も行う場合などでも応用ができると思います。

Happy Twilio!

---
### Twilio（トゥイリオ）とは

https://cloudapi.kddi-web.com
Twilioは音声通話、メッセージング（SMS/チャット）、ビデオなどの 様々なコミュニケーション手段をアプリケーションやビジネスへ容易に組み込むことのできるクラウドAPIサービスです。初期費用不要な従量課金制で、各種開発言語に対応しているため、多くのハッカソンイベントやスタートアップなどにも、ご利用いただいております。