Help us understand the problem. What is going on with this article?

LINE Botで感情分析して返答してみる

More than 3 years have passed since last update.

LINE Botで返答するときに、Botに投げかけられたメッセージを感情分析して、テキストとスタンプで返答してみました。

LINE Botの準備

CodeZineの「日本一わかりやすいLINE Bot開発講座」を参考にして準備しました。
http://codezine.jp/article/corner/686

利用した言語とサーバも同様です。

利用言語 サーバ
PHP Heroku

利用した感情分析API

Google Cloud PlatformのCLOUD NATURAL LANGUAGE APIを利用。
https://cloud.google.com/natural-language/

※現在ベータ期間中で、テキスト レコードと呼ばれる測定単位を利用して無料、有料を判断しています。以下のページをご覧ください。
https://cloud.google.com/natural-language/pricing

感情分析APIを利用するための準備 1

まずはGoogle Cloud Plaformサイト上で準備が必要です。

  1. Google Cloud Platformへの申し込み ※1
  2. LINE Bot向けのプロジェクトの作成 ※1
  3. サービスアカウントの作成とダウンロード ※2

※1 1と2の参考サイト
http://www.apps-gcp.com/gcp-startup/

※2 3の参考サイト
https://www.magellanic-clouds.com/blocks/guide/create-gcp-service-account-key/
この例の通り、JSONファイルを保存します。

「3. サービスアカウントの作成とダウンロード」の補足

3で用意したJSONファイルをBotの処理を記述するPHP上で、環境変数に設定することで、CLOUD NATURAL LANGUAGE APIを利用できるようになります。

JSONファイルを、サーバ上のBotの処理を行うPHPが読み取れる場所にアップロードしてください。

感情分析APIを利用するための準備 2

CLOUD NATURAL LANGUAGE APIをPHP上から呼び出すために、Google Cloud Client Library for PHPを利用します。
https://github.com/GoogleCloudPlatform/google-cloud-php

ダウンロードは、上記サイトのREADME.mdのQuick Startにあるように、ローカルPC上のBotのPHPファイルがあるディレクトリで、composerで行いました。

$ composer require google/cloud

感情分析APIを盛り込んだソース

CodeZineの「日本一わかりやすいLINE Bot開発講座」2回目「LINE Bot開発の概要と実装の基本」で紹介されている、スタンプとメッセージを返答するソースを元に作成しました。感情分析用に追加したのは主に1〜5の処理です。

<?php

require_once __DIR__ . '/vendor/autoload.php';

# 1. Google Cloud client libraryをインポート
use Google\Cloud\Language\LanguageClient;

# 2. Google Cloud Natural Languageのクライアントを生成
$language = new LanguageClient([
    'projectId' => '[Google Cloud Platformのプロジェクト名を記載]'
]);

# 3. Google Cloud Platformのプロジェクトのサービスアカウントに関する設定
# 環境変数にサービスアカウントのJSONファイルの置き場所を指定する
putenv('GOOGLE_APPLICATION_CREDENTIALS='.dirname(__FILE__) . '[アップロードしたサービスアカウントのJSONファイルを指定]');

# LINE BOTの処理
$httpClient = new \LINE\LINEBot\HTTPClient\CurlHTTPClient(getenv('CHANNEL_ACCESS_TOKEN'));
$bot = new \LINE\LINEBot($httpClient, ['channelSecret' => getenv('CHANNEL_SECRET')]);

$signature = $_SERVER["HTTP_" . \LINE\LINEBot\Constant\HTTPHeader::LINE_SIGNATURE];
try {
  $events = $bot->parseEventRequest(file_get_contents('php://input'), $signature);
} catch(\LINE\LINEBot\Exception\InvalidSignatureException $e) {
  error_log("parseEventRequest failed. InvalidSignatureException => ".var_export($e, true));
} catch(\LINE\LINEBot\Exception\UnknownEventTypeException $e) {
  error_log("parseEventRequest failed. UnknownEventTypeException => ".var_export($e, true));
} catch(\LINE\LINEBot\Exception\UnknownMessageTypeException $e) {
  error_log("parseEventRequest failed. UnknownMessageTypeException => ".var_export($e, true));
} catch(\LINE\LINEBot\Exception\InvalidEventRequestException $e) {
  error_log("parseEventRequest failed. InvalidEventRequestException => ".var_export($e, true));
}

foreach ($events as $event) {
  if (!($event instanceof \LINE\LINEBot\Event\MessageEvent)) {
    error_log('Non message event has come');
    continue;
  }
  if (!($event instanceof \LINE\LINEBot\Event\MessageEvent\TextMessage)) {
    error_log('Non text message has come');
    continue;
  }
  $profile = $bot->getProfile($event->getUserId())->getJSONDecodedBody();
  $text = $event->getText();

  # 4. BOTに送られてきたテキストの感情を調べる
  $annotation = $language->analyzeSentiment($text);
  $sentiment = $annotation->sentiment();
  $score = $sentiment['score']; //scoreの範囲は-1から1

  # 5. scoreに応じて返信するテキストとスタンプを設定する
  if ($score >= 0) {
    $message = "楽しそうですね!";
    $stkid = 138;
  }
  else {
    $message = "悲しそうですね…";
    $stkid = 111;
  }
  $message .= "(スコア:".$score.")";

  # 回答する
  $bot->replyMessage($event->getReplyToken(),
    (new \LINE\LINEBot\MessageBuilder\MultiMessageBuilder())
      ->add(new \LINE\LINEBot\MessageBuilder\TextMessageBuilder($message))
      ->add(new \LINE\LINEBot\MessageBuilder\StickerMessageBuilder(1, $stkid))
  );
}

?>

CLOUD NATURAL LANGUAGE APIのレスポンス

感情分析した結果については以下を参照してください。
https://cloud.google.com/natural-language/docs/reference/rest/v1beta1/Sentiment
今のところ利用できるのはscoreだけかなと思いました。

LINE Botの実行結果

Botにメッセージを送ると以下のように返答が来ます。
linebot.jpg

補足:Herokuを利用する場合

CodeZineの記事の通り、サーバにHerokuを利用する場合、「Google Cloud Client Library for PHP」内のRequestBuilder.phpでエラーが発生しました。

デバッグしたところ、Herokuであるディレクトリ階層以下でPHPの関数file_get_contentsがエラーとなっていたため、読み込もうとしていたJSONファイルの場所と、RequestBuilder.phpの処理を一部変更することで対応しました。

RequestBuilder.phpの場所(composerを利用した場合)

[BotのPHPを置いてある場所]/vendor/google/cloud/src/Core/RequestBuilder.php

エラー内容

2017-05-14T08:03:55.072470+00:00 app[web.1]: [14-May-2017 08:03:55 UTC] PHP Warning:  file_get_contents(/app/vendor/google/cloud/src/language/Connection/ServiceDefinition/language-v1.json): failed to open stream: No such file or directory in /app/vendor/google/cloud/src/Core/RequestBuilder.php on line 139

対応内容1

デバッグの結果、[BotのPHPを置いてある場所]/vendor/google/cloud/src/languageまではfile_get_contentsが正常に動いていたので、[BotのPHPを置いてある場所]/vendor/google/cloud/src/language/Connection/ServiceDefinition/language-v1.jsonを、[BotのPHPを置いてある場所]/vendor/google/cloud/src/languageにコピーしました。

対応内容2

RequestBuilder.phpで対応内容1のJSONファイルを読み込むように以下のように変更しました。

RequestBuilder.php
    /**
     * @param string $servicePath
     * @return array
     */
    private function loadServiceDefinition($servicePath)
    {
        if ($servicePath == "/app/vendor/google/cloud/src/language/Connection/ServiceDefinition/language-v1.json") {
          $servicePath = str_replace("language/Connection/ServiceDefinition", "Language", $servicePath);
        }

        return $this->jsonDecode(
            file_get_contents($servicePath, true),
            true
        );
    }

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away