Amazon Connectで架電システム（プロトタイプ）構築

## 目的
* 監視活動（自動による架電）に必要な経費の削減

## 経緯
* 障害発生時に監視システムから発報したアラートをハンドリングし、緊急性の高いアラートは自動でシステム管理責任者へ架電する仕組みは、数年前から稼働していたものの、年間費用が非常に高額（年間数十万円）である事と、制約が多い（特定の文言でなければトリガーが機能しないなど）ため、代替できるサービスを探していたが、なかなか見つからなかった。
* awsでAmazon Connectというサービスが開始となり、これを導入したとする話題を、ネット上で時折みかけるようになった。費用面でもかなり安く（年間1,500円くらい）、導入コストもかなり低いように見受けられた。

## 方針
* サンプルコードなどをベースにプロトタイプ版を構築し、経費削減案として会社に提案することとした。
##### 参考
https://zenn.dev/t_kakei/articles/700348ed161a49

:::note info
今回のプロトタイプ環境が構築できれば、それをベースに、管理画面をウェブアプリで作るなどして、現場に適合するように整えていけば良いです。※今回、このドキュメントではそこまでは触れません。
:::

## 実装の中身（共有したいノウハウ）
## ①Amazon Connectの構築方法
以下の５つのチュートリアルをそのまま進めて行けば、Amazon Connectの構築と動作確認まで完了できます。

[チュートリアル1 - ステップ 1: Amazon Connect を開始する](https://docs.aws.amazon.com/ja_jp/connect/latest/adminguide/tutorial1-login-aws.html)
[チュートリアル1 - ステップ 2: インスタンスを作成する](https://docs.aws.amazon.com/ja_jp/connect/latest/adminguide/tutorial1-create-instance.html
)
[チュートリアル1 - ステップ 3: 電話番号を取得する](https://docs.aws.amazon.com/ja_jp/connect/latest/adminguide/tutorial1-claim-phone-number.html
)
[チュートリアル2 - ステップ 1: 音声問い合わせを処理する](https://docs.aws.amazon.com/ja_jp/connect/latest/adminguide/tutorial1-explore-voice-and-chat.html)
[チュートリアル2 - ステップ 2: CCP を使用してチャットコンタクトを処理する](https://docs.aws.amazon.com/ja_jp/connect/latest/adminguide/tutorial1-test-2.html)

## ②Amazon Connectを使ってフローを作成する
1\. [awsコンソール]→[サービス]→[Amazon Connect]を選択すると以下のような画面となり、「①Amazon Connectの設定方法」で構築したインスタンスが表示されます。赤枠部分のURLを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374511/3555b5a8-af5d-dcbe-12b0-0cfb1ce6735a.png)

2\. 以下のようにログイン画面が表示されるので、ユーザー名とパスワードを入力してログインしてください。ユーザー名とパスワードは「①Amazon Connectの構築方法」で設定したものを使用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374511/1e41095e-2465-001a-2ca7-886208275dc9.png)

3\. [ルーティング]→[フロー]を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374511/12aaf2ad-518b-2dfb-593e-db322a7fa350.png)

4\. 「フローを作成」ボタンを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374511/0313009a-4112-8ddb-5c36-5faa3edcdfec.png)

5\.  以下の画面が表示されるので、フローを作っていきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374511/50ccb3d0-cc72-286b-42ad-4537dfe8aad1.png)

私は参考資料（[https://zenn.dev/t_kakei/articles/700348ed161a49](https://zenn.dev/t_kakei/articles/700348ed161a49)）にならって以下のように作りました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374511/e4545529-71df-9d43-99be-2ba2621f6785.png)

:::note info
作成できるフローにはいくつか種類があるようですが、「フローを作成」ボタンを選択して作られる、「コンタクトフロー（インバウンド）」で問題ありません。
:::

:::note info
必ず「保存」し、「公開」する事を忘れないようにしましょう。
:::

6\. 画面左下の「追加のフロー情報を表示」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374511/9eda375f-8552-8753-9b47-db446515e8b9.png)

以下のようにARNの情報が表示されますので、メモってください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374511/6cf81408-e4dd-d15d-889d-8c1dda7a2745.png)

instance/〇〇〇〇〇〇〇〇〇〇/contact-flow/〇〇〇〇〇〇〇〇〇/
のようになっている箇所は、それぞれ後ほど、Lambdaを作成するところで使用します。

## ③Lambda関数の作成
1\. Lambda関数を作成します。
ランタイムは、Python3.9としました。
以下のソースコードをLambda関数として作成します。
参考資料（[https://zenn.dev/t_kakei/articles/700348ed161a49](https://zenn.dev/t_kakei/articles/700348ed161a49)）そのままだと動かなかったので、少し修正を加えています。

ソースコードの以下の部分の4つの引数それぞれに何を設定すべきかは、以下にまとめました。
`aws_contact_service.start_outbound_voice_contact('+81xxxxxxxxxx','xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx','xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx','+1xxxxxxxxxx')`

| 引数 | 値 | 備考 |
|:-----------|:------------|:------------|
| 第1| 着信先の電話番号|社用携帯などの電話番号 |
| 第2| contact-flow|Amazon Connectのフロー作成した際のARNより取得|
| 第3| instance|同上 |
| 第4| 発信元の電話番号|任意。①Amazon Connectの構築方法で取得した電話番号|

:::note info
Lambda関数の作成方法については、ネット上に沢山ありますので、ここでは割愛します。
:::

```python
import logging
import traceback
from typing import Dict, List, Optional

import boto3.session
from botocore.config import Config
from mypy_boto3_connect.client import ConnectClient

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def lambda_handler(event, context):
    # TODO implement
    aws_contact_service = ConnectService()
    aws_contact_service.start_outbound_voice_contact('+81xxxxxxxxxx','xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx','xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx','+1xxxxxxxxxx')
    return {
        'statusCode': 200,
    }
    
    
def _format_traceback_str(exception: Exception) -> str:
    tb = traceback.TracebackException.from_exception(exception)
    return "".join(list(tb.format()))


class ConnectService:
    def __init__(self):
        self.session = boto3.session.Session()
        self.client: ConnectClient = self.session.client("connect", config=Config())


    def start_outbound_voice_contact(
        self,
        destination_phone_number: str,
        contact_flow_id: str,
        instance_id: str,
        source_phone_number: str,
    ) -> str:
        """
        refs: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/connect.html#Connect.Client.start_outbound_voice_contact
        """
        resp = self.client.start_outbound_voice_contact(
            DestinationPhoneNumber=str(destination_phone_number),
            ContactFlowId=str(contact_flow_id),
            InstanceId=str(instance_id),
            SourcePhoneNumber=str(source_phone_number),
        )
        return resp["ContactId"]
```
2\.Lambda関数をデプロイ後、テスト実行すると、「mypy_boto3_connect」モジュールがLambdaのライブラリに無くてエラーになる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374511/b205c031-162a-f8f0-e2c1-a4e002a7c039.png)

3\.cloud9を最小スペックのインスタンスで作り、以下のコマンドを実行。

```
> python3 -m pip install mypy-boto3-connect -t python/
```
```
> zip -r layer.zip python
```
```
> aws lambda publish-layer-version --layer-name aws_contact_test --zip-file fileb://layer.zip --compatible-runtimes python3.9 --region ap-northeast-1
```
:::note info
今回はcloud9のpythonはバージョン3.9.16で入っていたので、何も考えずにLambdaのランタイムバージョンは3.9に合わせて作業を進めています。
:::

:::note info
layer-nameはaws_contact_testとしていますが、自由に変更可能です。
compatible-runtimes、regionは、環境に合わせて設定してください。
:::

4\.対象のLambda関数にレイヤーを追加する
[サービス]→[Lambda]→[関数名選択]→[レイヤーの追加]→[上記3で作成した aws_contact_test]

無事レイヤーの設定に成功すると、以下のように「(1)」と表示されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374511/95208451-9a7c-30a4-8c34-43008fec16ee.png)

## ④権限の追加

1\. Lambdaをテスト実行するが、権限不足のエラーが発生し、処理が中断。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374511/455ac588-b79a-6bbe-5aff-74bdbc0950d9.png)

2\. アクセス権を付与してください。
* [サービス]→[Lambda]→[関数名選択]→[アクセス権限]

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374511/8a541df0-68f0-db08-a1f9-39031dda9e3d.png)

* ロール名を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374511/d279c44f-d50d-6aef-b0f5-a887105bf8c1.png)

* [許可を追加]より、「AmazonConnect_FullAccess ポリシー」を追加してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374511/3628cae5-9f3e-f93e-72a3-b61d758ee501.png)


## ⑤サービスクオーター、引き上げリクエスト
1\. Lambdaを実行するが、サービスクオーターが不足しているため、エラー発生。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374511/f70f98be-6196-5880-3457-b3a385c0b96f.png)

:::note info
Amazon Connectはデフォルトでは、日本の携帯電話に架電できないように、制限されています。
:::

2\. [awsコンソール上部？マーク]→[サポートセンター]を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374511/0f2e292a-3cd9-4cb0-6360-f4d30fce433b.png)

3\. [ケースを作成]→[アカウントと請求]→[サービスクォータの増加をお考えですか?]を選択
4\. サービス「Amazon Connect」、リージョン「お使いのリージョン」、クオータ「日本（東京）の電話番号」、新しいクオータ値「使用する電話番号の数」

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374511/a6d23164-4fe1-847c-3fd2-25e68de8bce7.png)

5\. ケースの説明
私は以下のように記載しました。

* 対象となるARNの情報を共有
* リクエスト内容、利用目的、利用頻度は以下

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374511/f789a855-2439-eb0d-008e-854474934c73.png)

6\. Amazonからの回答待ちとなりました。気長に待ちましょう。

7\. 1週間程度でAmazonから設定完了の連絡がありました。

## ⑥動作検証
1\. Lambdaを実行すると、今回はエラーとならず正常終了し、無事に架電されました。

:::note info
スマホ本体の着信設定が、サイレントモードになっているとうまく着信が確かめられないかもしれませんので、Lambdaは正常終了しているのに、うまく自動音声メッセージを聴く事ができない場合は、スマホ本体の設定を疑ってみてください。
:::