疑似親友、作りました。

　こちらの記事「[疑似彼氏、作りました。](https://qiita.com/mnana/items/3836aee1b749670804dc)」が面白かったので真似して作ってみました。

# 疑似親友とは
　良いこと(ポジティブ発言)に対して一緒に共感してくれて、嫌なこと(ネガティブ発言)に対しては励ましてくれて、それ以外に対しては適当な相槌を打ってくれて、向こうからは全く何も言ってこないとても ~~都合のいい~~ 素晴らしい親友です。

# 疑似親友の構成
　作りとしてはLINE Messaging APIで受けたテキストをAWS API Gateway経由でAWS Lambdaに渡しAmazon ComprehendでテキストをPOSITIVE(ポジティブ)、NEGATIVE(ネガティブ)、Neutral(中立)、Mixed(混在)の4種類に分類、その結果を元に返信メッセージを作成するという構成になります。
　感情分析に関しては以前自分で作成した[Pythonで感情極性辞書を用いたテキスト感情分析をつくってみた](https://qiita.com/miso_taku/items/c8e48401346eca23bae8)やcotoha APIでも良かったのですが、今回はAmazon Comprehendにしました。

![qiita_20211026_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350321/2daf028a-bdca-9bc2-c4b5-fa505cdf38ac.png)

# LINEアカウントの作成

LINE DEVELOPERSにてLINEアカウントの作成するのですが、それに関してはこちらの記事が参考になるので、アカウントの作成まで行って下さい。

[LINEBotをみんなで作ろう〜おうむ返しbotを作ろう編〜【3日目】](https://qiita.com/inoue2002/items/dcf40d5ebfe2454796fa)

チャネルアイコンは適当な画像を設定して下さい。私はいらすとやで ~~モブっぽい~~ 親友っぽい画像を使用しました。
チャネルシークレットとチャネルアクセストークンはあとで使用するので、コピーして控えておいて下さい。
webhookの設定は後でします。

# AWSアカウントの作成

AWSのアカウントに関しても上の記事と同じ方が書いているこちらの記事が参考になります。

[LINEBotをみんなで作ろう〜AWSアカウントを作るぞ編〜【6日目】](https://qiita.com/inoue2002/items/ad945981150c859911fc)

# aws-cliのインストール＆設定
ターミナルからpipでインストールして下さい。

```
pip install awscli
```

ついでにAWS CLIの設定もしてしまいましょう。

```
aws configure

AWS Access Key ID [None]: *************ID
AWS Secret Access Key [None]: ******************************KEY
Default region name [None]: ap-northeast-1
Default output format [None]: json
```


# sam-cliの設定
こちらもターミナルからpipでインストールして下さい。

```
pip install aws-sam-cli
```

# ディレクトリ構成
```
linebot
├── src
│   ├──requirements.txt
│   └──mylinebot.py
└──template.json
```
# ソースコード
```template.json
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Transform": "AWS::Serverless-2016-10-31",
  "Parameters": {
    "LineChannelAccessToken": {"Type": "String", "Description": "LINE のアクセストークン"},
    "LineChannelSecret": {"Type": "String", "Description": "LINE のチャンネルシークレット"}
  },
  "Resources": {
    "EndPointFunction": {
      "Type": "AWS::Serverless::Function",
      "Properties": {
        "Runtime": "python3.8",
        "CodeUri": "src",
        "Handler": "mylinebot.lambda_handler",
        "Environment": {"Variables": {
            "LINE_CHANNEL_ACCESS_TOKEN": {"Ref": "LineChannelAccessToken"},
            "LINE_CHANNEL_SECRET": {"Ref": "LineChannelSecret"}
        }},
        "Policies": [{"ComprehendBasicAccessPolicy": {}}],
        "Events": {
          "API": {
            "Type": "Api",
            "Properties": {"Path": "/api_endpoint", "Method": "post"}
          }
        }
      }
    }
  },
  "Outputs": {
    "ApiEndpointURL": {
      "Description": "API Endpoint URL",
      "Value": {"Fn::Sub": "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/${ServerlessRestApi.Stage}/api_endpoint"}
    }
  }
}

```

```requirements.txt
line-bot-sdk
boto3
```

```mylinebot.py
# 疑似親友 Line Bot

import os
import boto3
import random

from linebot import LineBotApi, WebhookHandler
from linebot.models import MessageEvent, TextMessage, TextSendMessage

handler = WebhookHandler(os.getenv('LINE_CHANNEL_SECRET'))
line_bot_api = LineBotApi(os.getenv('LINE_CHANNEL_ACCESS_TOKEN'))

comprehend = boto3.client('comprehend')

def lambda_handler(event, context):
    headers = event["headers"]
    body = event["body"]

    # get X-Line-Signature header value
    signature = headers['x-line-signature']

    # handle webhook body
    handler.handle(body, signature)

    return {"statusCode": 200, "body": "OK"}


@handler.add(MessageEvent, message=TextMessage)
def handle_text_message(event):
    input_text = event.message.text

    result = comprehend.detect_sentiment(Text=input_text, LanguageCode='ja')
    senti = result['Sentiment']

    if senti == 'POSITIVE':
        message = random.choice(('良かったじゃん', 'マジか！やったやん', 'え～、めっちゃええやん'))
    elif senti == 'NEGATIVE':
        message = random.choice(('うわ、それ辛い', 'キツいなそれ', '大変だったな'))
    elif senti == 'NEUTRAL':
        message = 'それな'
    elif senti == 'MIXED':
        message = 'まあ、いろいろあるわな'
    else:
        message = 'ちょっと何言ってるかわからない'
    
    # 感情分析値テスト用
    # senti_score = result['SentimentScore']
    # posi_score = round(senti_score['Positive'], 4)
    # nega_score = round(senti_score['Negative'], 4)
    # neu_score = round(senti_score['Neutral'], 4)
    # mix_score = round(senti_score['Mixed'], 4)
    # message = "ポジティブ度："+ str(posi_score) + "\nネガティブ度："+str(nega_score) + "\n中立度："+str(neu_score) + "\n混在度："+str(mix_score)

    line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(text=message))
```


# ビルド＆デプロイ
まずはターミナルからビルドを行います。

```
sam build -t template.json
```

ビルドが完了したらデプロイを行います。

```
sam deploy --guided
```

ビルド中に色々聞いてくるので入力して下さい。

```
Stack Name []:************(API Gateway　Lambdaにつける名前を設定)
AWS Region []:ap-northeast-1(東京リージョンを指定)
Parameter LineChannelAccessToken []: ************(LINEのアクセストークン)
Parameter LineChannelSecret []:************(LINEのチャネルシークレット)
Confirm changes before deploy [Y/n]: y
Allow SAM CLI IAM role creation [Y/n]: y
EndPointFunction may not have authorization defined, Is this okay? [y/N]: y
Save arguments to configuration file [Y/n]:y
```

```
Outputs
----------------------------------------------------------------------------------------------
Key               ApiEndpointURL
Description       API Endpoint URL
Value             https://*********.execute-api.ap-northeast-1.amazonaws.com/Prod/api_endpoint
----------------------------------------------------------------------------------------------
```

出力の最後のURL （https://*********.execute-api～～～） をコピーしてLINE Messaging APIのWebhook設定のWebhook URLに入力してWebhookを有効にして下さい。

これでLINE botの作成は終了です。


# 動作確認

それでは疑似親友Botと会話してみましょう。

実行結果
![Screenshot_20211026-205446 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350321/744db73f-12ef-bb7e-a587-5419a9bc8ec8.png)

といった感じでそれなりに動いています。返信メッセージにはもう少しバリエーションを持たせた方が良いかな。あとは本家の「[疑似彼氏、作りました。](https://qiita.com/mnana/items/3836aee1b749670804dc)」みたいに特定の単語があれば別のAPIを呼んで情報を取ってくるみたいなことをすればさらに ~~使い勝手の良い~~ 有能な親友になりそうです。