社内向けチャットボット プログラム説明

# 目次
- [1.はじめに](#1はじめに)
- [2.チャットボットの動き](#2チャットボットの動き)
- [3.処理の流れ](#3処理の流れ)
- [4.入力内容の確認](#4入力内容の確認)
  - [4-1.データの取り出し](#4-1データの取り出し)
  - [4-2.返答内容の決定](#4-2返答内容の決定)
- [5.メッセージの作成](#5メッセージの作成)
  - [5-1.質問・回答文の作成](#5-1質問回答文の作成)
  - [5-2.選択肢の作成](#5-2選択肢の作成)
- [6.まとめ](#6まとめ)<br>


# 1.はじめに
昨年作成した、Amazon lexとSlackを使った社内向けチャットボットのプログラムについて
自社のチーム内で説明、共有する機会がありました。
その際に自分の作成したプログラムを他者に分かりやすく説明することが難しいと実感し、
今回このQiitaの記事にそのプログラムについて、簡単な説明を備忘録も兼ねて投稿しようと思います。

昨年作成したチャットボットについての記事は以下になります。
https://qiita.com/k_yoshino/items/89c050a2641e20d7e92f


# 2.チャットボットの動き
プログラムについて説明をする前にチャットボットの動作を確認します。
Slackのダイレクトメッセージにて
「any-plus QA」を追加して、「質問」とメッセージを送ります。
メッセージを送るとチャットボットから
聞きたい内容のカテゴリーの選択肢が送られてきます。
<img width="400" alt="カテゴリー選択" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1850774/19bfced6-609d-037d-533b-8fc4ef715802.png"><br>
表示された選択肢を押下すると次の質問と選択肢が送られてきます。
<img width="400" alt="質問" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1850774/45ec168b-0f82-434e-d664-5211fa2a50e0.png"><br>
これを繰り返し、いくつかの質問に答えると最後に回答が送られてきます。
<img width="400" alt="回答" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1850774/872d3bb6-ed19-fff3-d82b-9d2ad0cdea2e.png"><br>
以上がチャットボットの動きとなります。

# 3.処理の流れ
チャットボットがどのような流れで動いているか説明します。
まずチャットボットにメッセージが入力された際に、プログラムが呼び出されます。
チャットボットから呼び出された際の大まかな処理の流れとしては、以下のようになります。<br>
**(呼び出し)→「現在までの入力内容の確認」→「次のメッセージの作成」→(結果を返す)** <br>　
つまり今回作成したチャットボットで使用しているLambdaのプログラムでは
それまでのユーザーの返答内容を見て、次の質問、回答を作るということを行っています。


# 4.入力内容の確認
入力内容の確認をする処理ではさらに細かくすると、以下の2つのことをしています。<br>
「Amazon lex側から受け取ったデータ(ユーザーの返答内容)の取り出し」
「取り出したデータをもとに次の返答内容の決定」<br>

### 4-1.データの取り出し
ではまず、データの取り出しを行っているコードを見ていきます。
```python
#intent_requestはLex側から受け取ったデータが格納されています。
select_category = intent_request['currentIntent']['slots']['Select_category']
select1 = intent_request['currentIntent']['slots']['Select_category_one']
select2 = intent_request['currentIntent']['slots']['Select_category_two']
select3 = intent_request['currentIntent']['slots']['Select_category_three']
```
「チャットボットへの質問のカテゴリー選択」（代入先変数名：select_category）
「1つ目の質問への回答」（代入先変数名：select1）
「2つ目の質問への回答」（代入先変数名：select2）
「3つ目の質問への回答」（代入先変数名：select3）
上から順に
「」の内容をチャットボットから受け取ったデータの中から取り出し、
（）の変数に代入しています。
データの取り出しに関してはこれで完了です。<br>


### 4-2.返答内容の決定
次に返答の決定を行っているコードがどのようになっているかを見ていきます。
```python
if not select_category:          #select_categoryが空の場合
    #処理

if select_category == '○○○○':    #select_categoryが特定の値の場合
    if not select1:              #select_categoryが空の場合
        #処理

    elif select1 == '○○○○':      #select_categoryがが特定の値の場合
        #処理
```
上記のようなif文を並べてカテゴリーが未選択ならカテゴリーを選ぶ質問を返答にする、
カテゴリーが選択されており1つ目の質問の回答が空なら1つ目の質問を行う、
1つ目の質問の回答も入っていれば2つ目の質問の回答はどうかと、
1つずつ確認していって次の返答内容を決定しています。<br>

以上が、入力内容の確認の処理となります。


# 5.メッセージの作成
次にメッセージの作成についてです。
メッセージの作成をする処理ではさらに細かくすると、以下の2つのことをしています。<br>
「質問・回答文の作成」
「質問の際に表示する選択肢の作成」<br>

### 5-1.質問・回答文の作成
ではまず、質問・回答文の作成を行っているコードを見ていきます。
この処理は質問の作成と、回答の作成で少し形が変わります。
```python:質問
if not select1:                                              #3-2で返答内容の決定をしている分岐
    return elicit_slot(
    	output_session_attributes,                           #返却時に必要となる値(本プログラム内では固定値)
    	intent_request['currentIntent']['name'],             #返却時に必要となる値(本プログラム内では固定値)
    	intent_request['currentIntent']['slots'],            #返却時に必要となる値(本プログラム内では固定値)
        'スロット名',                                         #このレスポンスに対して返答が予想されるスロットを指定
    	{'contentType': 'PlainText', 'content':'質問文'},     #「質問文」に文章を入れる
    	build_response_card(                                 #画面に表示するレスポンスカードの作成する関数
           	'タイトル',                                       #レスポンスカードに表示するタイトル
            'サブタイトル',                                   #レスポンスカードに表示するサブタイトル
        	make_choice('スロット名', select_category, select1, select2)
        )                                                    #6行目のスロット名と同値を指定
)
```

```python:回答
elif select1 == '○○○○':                                       #3-2で返答内容の決定をしている分岐
    return close(                                             #回答内容を返却する際に使用する関数
        output_session_attributes,                            #返却時に必要となる値(本プログラム内では固定値)
        'Fulfilled',                                          #返却時に必要となる値(本プログラム内では固定値)
        {
            'contentType': 'PlainText',
            'content': '回答文'                               #「回答文」に文章を入れる
        }    
    )
```
1つ目のコードの2行目で使用している関数の「elicit_slot」は質問を返す場合に使用し、
2つ目のコードの2行目で使用している関数の「close」は回答文のみを返す場合に使用します。
それぞれLex側に返却する際の形に当てはめる関数となります。
(返却用の形に整形するのみのため説明は省略します。)

'スロット名'と記載されている箇所では
今回の返却内容に対しての返答がどのスロットに入ると想定するかを入力します。
例えば、
カテゴリー選択のメッセージを返却した場合は
カテゴリーの選択内容を格納するスロットを指定します。
返答がくることを想定しているため、
回答のみの2つ目のプログラムでは'スロット名'の指定はありません。

「質問文」、「回答文」はそのまま画面に表示する文章となります。

質問側のコードにある「build_response_card」の関数は質問を表示する際に使用します。
下記画像の赤枠の範囲をレスポンスカードといい、
この関数ではタイトル、サブタイトル、選択肢の画面に表示する内容を引数として、
レスポンスカードを作成します。
(関数内の説明は返却用の形に整形するのみのため説明は省略します。)
<img width="400" alt="レスポンスカード" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1850774/7b160920-f102-457f-39aa-1a1909ffb369.png"><br>

「make_choice」の関数は
「質問の際に表示する選択肢の作成」を行っている関数となるため、
次の4-2で説明を行います。

「質問や回答文の作成」については以上で完了となります。<br>

### 5-2.選択肢の作成
選択肢の作成については4-1で出てきた「make_choice」の関数についての説明となります。
```python
# slot              ：その時回答の欲しいスロット名を入れる用(4-1で指定したスロット名)
# select_category   ：select_categoryに入っている回答内容を入れる用
# select1           ：select1に入っている回答内容を入れる用
# select2           ：select2に入っている回答内容を入れる用
def make_choice(slot, select_category, select1, select2):
    if slot == 'スロット名':                             # 引数を使用して表示する選択肢の作成を行う。
        return [
            {'text': '選択肢1', 'value': 'one'},         #選択肢
            {'text': '選択肢2', 'value': 'two'},         #選択肢
            {'text': '選択肢3', 'value': 'three'},       #選択肢
        ]
```
この関数では現在までのユーザーからの返答内容を引数として受け取り、
まずif文で次に表示する選択肢がどれかを選択します。

決定後は選択肢の作成を行います。
コード内で'選択肢1','選択肢2','選択肢3'となっている箇所が画面に表示される内容、
コード内で'one','two','three'となっている箇所が選択された際に
プログラム上で受け取る値となります。

この表示内容とプログラム上の値をセットとして画面に表示する選択肢を作成しています。
そして作成した選択肢を4-1の処理で整形してLex側に返却するという形になります。


# 6.まとめ

**・プログラムで「現在までの入力内容の確認」「次のメッセージの作成」を行っている。**<br>
**・入力内容の確認では「データの取り出し」「次の返答内容の決定」の処理をする。**<br>
**・メッセージの作成では「質問・回答文の作成」「選択肢の作成」の処理をする。**
<br>
難しい処理のあまりないプログラムではありますが、
人に向けて説明を行うことの難しさを感じました。
説明する情報の選択や伝わりやすい説明方法など、
もっと相手に上手く伝えられるよう資料の書き方や説明の仕方も学んでいきたいです。