【LINE BOT + COTOHA API】君の文章は相手を不快にしていないか？COTOHA先生にチェックしてもらおうぜ

## 0. はじめに
チャットツール、SNSが普及した今、文章でのコミュニケーションが爆発的に増えましたよね。
チャット(Slack)でしか関わったことのないお客さんと初めてお会いしたとき、こんなお話を頂きました。

```
「全く怒っているつもりないんですけど、チャットだとそんな印象与えてしまうんですよね～。」
```

いやーありますあります。お仕事だけでなく、プライベートでもありますよね！
印象の悪い文章が、印象の悪い返事を生み、負のスパイラルとなる。これって非常に悲しいことですよね。
ネガティブワードの存在は、無意識のうちに相手の心にダメージを与えます。
SNSの誹謗中傷とか最悪ですよね。

そんな文章を取り締まるべく、COTOHA先生というものを作ってみました！

- [**【Qiita x COTOHA APIプレゼント企画】COTOHA APIで、テキスト解析をしてみよう！**](https://zine.qiita.com/event/collaboration-cotoha-api/?utm_source=qiita&utm_medium=top_banner)

COTOHA APIを使ってこんなのも作ってます！

- [**【Nuxt.js + COTOHA API + microCMS】COTOHAチックなフラッシュカード作ってみた ※答えはCOTOHA先生が＼(^o^)／で隠してくれるよ**](https://qiita.com/i-tanaka730/items/3f97a9d1d668f424fc50)

~~ちなみに息子(2歳)へのクリスマスプレゼントを華麗に失敗した私が狙うのは「作ろうきのこの山」です。:santa:~~

## 1. COTOHA先生って？

[**COTOHA API**](https://api.ce-cotoha.com/contents/index.html)の[**感情分析**](https://api.ce-cotoha.com/contents/reference/apireference.html#sentiment)を使って、LINEで入力したメッセージにネガティブなワードが含まれていないかチェックするLINE BOTです。COTOHA先生が結果をリプライしてくれます。
結果は以下のパターンに分類されます。

- 「ネガティブワード有の場合」
- 「ネガティブワード無」かつ「ポジティブワード無」の場合
- 「ネガティブワード無」かつ「ポジティブワード有」の場合

## 2. 環境
- Python 3.8.1
- COTOHA API
- LINE Messaging API
- Heroku

## 3. プログラム

```python:line.py
import cotoha
import json
from codecs import decode
from os import environ, getenv
from flask import Flask, request, abort
from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError
from linebot.models import MessageEvent, TextMessage, TextSendMessage

app = Flask(__name__)
handler = WebhookHandler(environ["LINE_CHANNEL_SECRET"])
linebot_api = LineBotApi(environ["LINE_CHANNEL_ACCESS_TOKEN"])
cotoha_api = cotoha.CotohaApi()

@app.route("/callback", methods=['POST'])
def callback():
    signature = request.headers['X-Line-Signature']
    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)

    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        abort(400)

    return 'OK'

@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    sentiment = cotoha_api.sentiment(event.message.text)
    reply_message = make_reply_message(sentiment["result"])
    linebot_api.reply_message(event.reply_token, reply_message)

def make_reply_message(sentiment_result):
    positive_words = ""
    negative_words = ""

    for phrase in sentiment_result['emotional_phrase']:
        if phrase['emotion'] == 'P':
            positive_words = positive_words + '・' + phrase['form'] + '\n'
        if phrase['emotion'] == 'N':
            negative_words = negative_words + '・' + phrase['form'] + '\n'

    if len(negative_words) > 0:
        message = "君の文章、相手を不快にする可能性があります。\n以下のワードは使わないでちょ\uDBC0\uDC9E\n" + negative_words
    elif len(positive_words) < 1:
        message = "君の文章、悪くはないです。\nでもポジティブワードを1つは入れてちょ\uDBC0\uDC9D"
    else:
        message = "君の文章、完璧です。\n以下のワードがGood\uDBC0\uDC7F\n" + positive_words

    return TextSendMessage(text=message)

if __name__ == "__main__":
    port = int(getenv("PORT"))
    app.run(host="0.0.0.0", port=port)
```

```python:cotoha.py
import requests
import json
from os import environ
from codecs import decode

class CotohaApi:

    DEVELOPER_API_BASE_URL = "https://api.ce-cotoha.com/api/dev/nlp/"
    DEVELOPER_API_SENTIMENT_URL = DEVELOPER_API_BASE_URL + "v1/sentiment"
    ACCESS_TOKEN_PUBLISH_URL = "https://api.ce-cotoha.com/v1/oauth/accesstokens"

    def __init__(self, client_id = "", client_secret = ""):
        self.client_id = environ["CLIENT_ID"] if not client_id else client_id
        self.client_secret = environ["CLIENT_SECRET"] if not client_secret else client_secret

    def get_access_token(self):
        headers = {
            "Content-Type": "application/json;charset=UTF-8"
        }

        data = {
            "grantType": "client_credentials",
            "clientId": self.client_id,
            "clientSecret": self.client_secret
        }

        response = requests.post(self.ACCESS_TOKEN_PUBLISH_URL, headers=headers, data=json.dumps(data))
        return response.json()["access_token"]

    def sentiment(self, sentence):
        headers = {
            "Authorization": "Bearer " + self.get_access_token(),
            "Content-Type": "application/json;charset=UTF-8",
        }

        data = {
            "sentence": sentence
        }

        response = requests.post(self.DEVELOPER_API_SENTIMENT_URL, headers=headers, data=json.dumps(data))
        return response.json()

if __name__ == "__main__":
    # 以下のパラメータを設定して「python .\cotoha.py」を実行すれば、
    # 当モジュール単体での結果確認が可能
    client_id = ""
    client_secret = ""
    text = "今日は楽しい1日でした。"

    cotoha_api = CotohaApi(client_id, client_secret)
    sentiment_result = cotoha_api.sentiment(text)
    sentiment_formated = json.dumps(sentiment_result, indent=4)
    print (decode(sentiment_formated, 'unicode-escape'))
```

## 4. デモ
![COTOHA先生.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247638/c2d0cf09-dfb2-697f-7a2d-c9ed56442681.gif)

## 5. 参考
LINE BOTの作り方は以下の記事を参考にさせて頂きました。ありがとうございます！

- [**【初心者向け】PythonによるHeroku環境で簡単LINEBot開発**](https://miyabi-lab.space/blog/21)
- [**PythonでLine botを作ってみた**](https://qiita.com/kro/items/67f7510b36945eb9689b)

## 6. おわりに
感情分析などの技術が普及して、インターネットの世界から誹謗中傷を無くしていきたいですね！

・
・
・

あれっ？
![COTOHA先生2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247638/af65dfb5-9e85-41a2-cd5a-de457f6df71a.gif)