Google Homeに忖度させてみる

## はじめに
先日GoogleHomeをプレゼントとしていただきましたが、あまり使いこなせていないなと感じ、何か面白いことをさせたいと思いました。
Qiitaを見ていると、nodeのgoogle-home-notifierというライブラリーを使うと任意の言葉を話させることができるらしいと知って今回取り組んで見ました。
去年の流行語は**忖度**ですが、心を数値化できれば**忖度**しなくても良いと思い今回相手に対して思うことを数値化したいと思います。

* Qiita初投稿なので至らない点があれば修正します。

##忖度とは
他人の心をおしはかること。また、おしはかって相手に配慮すること。[
忖度(ソンタク)とは - コトバンク](https://kotobank.jp/word/%E5%BF%96%E5%BA%A6-555929)


## やろうと思ったこと
- GoogleHomeに何か話してもらう
- 2人1組で相手をどう思っているのか判定させてみる(原則として相手の印象を話す ex: 気前が良い　頭が良いなど)
- 話しかけた内容をTwitterに投稿して文章化する
- 話しかけたことを数値化し、その裏に隠れた相手に対して思うことを判定する

## 今回のシチュエーション
1. A、Bの2人が相手の気持ちがよくわからないでいる。
2. GoogleHomeに「相手についてどう思うか」を話しかける。
3. 2人は思い思いに相手について話す。
4. GoogleHomeはその言葉を聞き、その裏にある気持ちを数値化する


## 今回の実装イメージ
![スクリーンショット 2018-04-01 0.08.04.png](https://qiita-image-store.s3.amazonaws.com/0/221678/7e90a492-a1ac-eba6-a18d-5995b925939f.png)


## 必要な事
- Node.jsのgoogle-home-notifierの準備
- GoogleHomeに話しかけた文章を取得する
- 辞書データの準備

## 環境
- macOS Sierra 10.12.6

## google-home-notifierのインストール
### 作業ディレクトリの準備
```
$ mkdir googleHomeNotifier
$ cd googleHomeNotifier
```
### npmのアップデート
```
$ npm update -g npm
```
### npmの初期化
```
$ npm init
```
### npmでgoogle-home-notifierをインストール
```
$ npm install --save google-home-notifier
```
ここまででGoogleHomeに対する下準備は完了

もしうまくいかなければこちらの記事が詳しい手順を確認できます。
また、詳しい仕組みも解説されており大変参考になりました。
[Google Home開発入門 / google-home-notifier解説](https://qiita.com/SatoTakumi/items/c9de7ff27e5b70508066)

## 辞書データを準備する
今回辞書データとして「単語感情極性対応表」を使用して行きたいと思います。
辞書データをDBに入れていく作業をして行きます。
### MySQLのインストール
```
$ brew install mysql

$ # MySQL起動
$ mysql.server start

$ mysql_secure_installation

$ # MySQLに入る
$ mysql -uroot -p 

```
こちらが参考になりました。
[MacにMySQLをインストールして触ってみる](https://dev.classmethod.jp/etc/mac_mysql_install/)

### DBの作成
今回は辞書データを入れる`dictionary`というDBを作成します。

```
CREATE DATABASE dictionary;
```
使用するDBを選択する

```
USE dictionary
```

今回使用する辞書データは

```
優れる:すぐれる:動詞:1
良い:よい:形容詞:0.999995
喜ぶ:よろこぶ:動詞:0.999979
褒める:ほめる:動詞:0.999979
めでたい:めでたい:形容詞:0.999645
```
この形式で入っているので、作成するDBのカラムは`id, word, reading, speech, score`とする。

```
CREATE TABLE dictionary (
 id int(10) AUTO_INCREMENT primary key NOT NULL, 
word varchar(20) NOT NULL , 
reading varchar(20) NOT NULL, 
speech varchar(20) NOT NULL ,
 score float(10) NOT NULL 
); 
```
この後にCSVファイルにした辞書データを挿入し完了。
完成したテーブルの一部
![スクリーンショット 2018-04-01 13.13.36.png](https://qiita-image-store.s3.amazonaws.com/0/221678/908398e9-2fd7-dfad-93d9-35eb2c89f08b.png)

## GoogleHomeに話しかけた内容をTweetする
[Google HomeにつぶやくとTwitterでつぶやくやつ、IFTTTですぐできた。]
(https://qiita.com/kazunori279/items/fdadbfde58ed133bb9d5)
この記事を参考にしました。
ちなみに、GoogleHomeからTweetすると単語が形態素解析されたような形になるため、今回は形態素解析は行わない形にしました。
ここで投稿するツイートはメンション付きツイートにします。理由は後述
例
`@example あいうえお`

## Node.jsのTwitterモジュールを準備する
[node.jsのtwitterモジュールを使ってみた作業メモ (1)](https://qiita.com/rarewin/items/d38ba161864107f94f7d)
こちらを参考にしました。
このコマンドでインストールできるようです。

```
$ npm install twitter
```
インストール後にはTwitterAPIが使えるようにアクセストークン等の取得が必要。
私は事前に用意があったのでそちらを使います。


## 今回用意するコード
今回用意したコードは以下の通り
settimeを使用していますが、今回GoogleHomeを喋らせる関係で処理を遅延させなければならないため苦肉の作です。
何か良い方法あれば教えて欲しい・・・

```js:index.js
// twitterモジュール
var twitter = require('twitter');

var client = new twitter({
    consumer_key:        '取得したconsumer_key',
    consumer_secret:     '取得したconsumer_secret',
    access_token_key:    '取得したaccess_token_key',
    access_token_secret: '取得したaccess_token_secret',
});

// Google Homeに関する設定
var googlehome = require('google-home-notifier');
var language = 'ja';

// Public APIのstatuses/filterで取得したタイムラインを、自分のアカウント名を含む文字列でフィルターする
client.stream('statuses/filter', {track: '@example'}, function(stream) {
    // フィルターされたデータのストリームを受け取り、ツイートのテキストを表示する
    var count = 0;
    var tweetA = [];
    var tweetB = [];
    stream.on('data', function(data) {
        var text = data.text; // ツイートのテキスト
        var textCleaned = text.replace(/@example /g, "");
        if (count % 2 == 0) {
            tweetA = textCleaned.split(' ');
            count++;
        } else {
            tweetB = textCleaned.split(' ');
            count++;
        }

        var scoreOfA = 0;
        var scoreOfB = 0;
        // teetが偶数回取得できたら比較処理をする
        if (count % 2 == 0 && count != 0) {
            // DB処理
            var mysql = require('mysql');
            var TABLE = 'dictionary';
            //mysqlクライアント作成
            var client = mysql.createConnection({
              user: 'root',
              password: '設定したpassword',
              database: 'dictionary'
            });

            // A
            for (var i=0; i < array1.length; i++) {
                //データの検索
                client.query(
                  'select * from dictionary where word = ?;', tweetA[i],
                    function (err, rows, field) {
                        if (rows[0]) {
                            scoreOfA = parseFloat(scoreOfA) + parseFloat(rows[0].score);
                        }
                    }
                );
            }

            // B
            for (var i=0; i < array2.length; i++) {
                //データの検索
                client.query(
                  'select * from dictionary where word = ?;', tweetB[i],
                    function (err, rows, field) {
                        if (rows[0]) {
                            scoreOfB = parseFloat(scoreOfB) + parseFloat(rows[0].score);
                        }
                    }
                );
            }


            // スコアを表示
            setTimeout(function(){
                console.log('-------------Aのスコア-------------');
                console.log(scoreOfA);
                console.log('-------------Bのスコア-------------');
                console.log(scoreOfB);

                // 集計コメントを送信
                googlehome.device('Google-Home', language);
                googlehome.notify('思いやり指数を集計しています', function(res) {
                console.log(res);
                });
            },1000);


            // 結果の発表
            setTimeout(function(){
                if (scoreOfA == scoreOfB) {
                    // scoreが一緒だった場合
                    googlehome.device('Google-Home', language);
                    googlehome.notify('2人とも、相手を思いやることができています', function(res) {
                        console.log(res);
                    });
                } else if (scoreOfA > scoreOfB) {
                    // Aさんのscoreが高かった場合
                    googlehome.device('Google-Home', language);
                    googlehome.notify('Aが相手を思いやれています。相手のことが大好きなんですね', function(res) {
                        console.log(res);
                    });
                } else if (scoreOfA < scoreOfB) {
                    // Bさんのscoreが高かった場合
                    googlehome.device('Google-Home', language);
                    googlehome.notify('Bが相手を思いやれています。相手のことが大好きなんですね', function(res) {
                        console.log(res);
                    });
                }
            },12000);
            client.end();

        }
    });
});
```
少し詳しくみたいと思います。

```js
// twitterモジュール
var twitter = require('twitter');
```
ここでNode.jsにあるtwitterのモジュールを読み込む

```js

var client = new twitter({
    consumer_key:        '取得したconsumer_key',
    consumer_secret:     '取得したconsumer_secret',
    access_token_key:    '取得したaccess_token_key',
    access_token_secret: '取得したaccess_token_secret',
});

```
取得したapiのキーを入力

```js

// Google Homeに関する設定
var googlehome = require('google-home-notifier');
var language = 'ja';
```
ここではGoogleHomeに関する設定をします。
ちなみに言語設定をjaからenにすると流暢な英語を話してくれます。PPAPをうまくやろうと思いましたが、イントネーションが難しい・・・

```js
// Public APIのstatuses/filterで取得したタイムラインを、自分のアカウント名を含む文字列でフィルターする
client.stream('statuses/filter', {track: '@example'}, function(stream) {
    // フィルターされたデータのストリームを受け取り、ツイートのテキストを表示する
    var count = 0;
    var tweetA = [];
    var tweetB = [];
    stream.on('data', function(data) {
        var text = data.text; // ツイートのテキスト
        var textCleaned = text.replace(/@example /g, "");
        if (count % 2 == 0) {
            tweetA = textCleaned.split(' ');
            count++;
        } else {
            tweetB = textCleaned.split(' ');
            count++;
        }
```
今回は、ターミナルで実行を行なった際に、条件を満たせば名裁きを行うようにしたかった。そのため、メンション付きでTweetするようにして、`@example`のツイートを2回受け取った際に判定する。(いい感じにやるやり方が思いつかなかったので・・・)

```js
 var scoreOfA = 0;
        var scoreOfB = 0;
        // teetが偶数回取得できたら比較処理をする
        if (count % 2 == 0 && count != 0) {
            // DB処理
            var mysql = require('mysql');
            var TABLE = 'dictionary';
            //mysqlクライアント作成
            var client = mysql.createConnection({
              user: 'root',
              password: '設定したpassword',
              database: 'dictionary'
            });

            // A
            for (var i=0; i < array1.length; i++) {
                //データの検索
                client.query(
                  'select * from dictionary where word = ?;', tweetA[i],
                    function (err, rows, field) {
                        if (rows[0]) {
                            scoreOfA = parseFloat(scoreOfA) + parseFloat(rows[0].score);
                        }
                    }
                );
            }

            // B
            for (var i=0; i < array2.length; i++) {
                //データの検索
                client.query(
                  'select * from dictionary where word = ?;', tweetB[i],
                    function (err, rows, field) {
                        if (rows[0]) {
                            scoreOfB = parseFloat(scoreOfB) + parseFloat(rows[0].score);
                        }
                    }
                );
            }
```
ここでは、ツイート内容を点数化する処理に入ります。
ここで行なっている処理をわかりやすくすると以下の通り

```js

array1[i] = ['あなた', 'は', '良い', '人'];
```
ツイートを分割するとこんな感じ。ここからDBに検索をかけて点数を取得している感じです。
意外と簡単です。

```js
 // スコアを表示
            setTimeout(function(){
                console.log('-------------Aのスコア-------------');
                console.log(scoreOfA);
                console.log('-------------Bのスコア-------------');
                console.log(scoreOfB);

                // 集計コメントを送信
                googlehome.device('Google-Home', language);
                googlehome.notify('思いやり指数を集計しています', function(res) {
                console.log(res);
                });
            },1000);


            // 結果の発表
            setTimeout(function(){
                if (scoreOfA == scoreOfB) {
                    // scoreが一緒だった場合
                    googlehome.device('Google-Home', language);
                    googlehome.notify('2人とも、相手を思いやることができています', function(res) {
                        console.log(res);
                    });
                } else if (scoreOfA > scoreOfB) {
                    // Aさんのscoreが高かった場合
                    googlehome.device('Google-Home', language);
                    googlehome.notify('Aが相手を思いやれています。相手のことが大好きなんですね', function(res) {
                        console.log(res);
                    });
                } else if (scoreOfA < scoreOfB) {
                    // Bさんのscoreが高かった場合
                    googlehome.device('Google-Home', language);
                    googlehome.notify('Bが相手を思いやれています。相手のことが大好きなんですね', function(res) {
                        console.log(res);
                    });
                }
            },12000);
            client.end();

        }
    });
});
```
取得した点数を比較して、それに応じて名裁きっぽいものを話し始めます。

## 実際に動かしてみる

今回ツイートしてみたのは

AがBに対して思うことを相手に対して言う
`@example あなたは良い人`
BがAに対して
`@example あなたは悪い人`

結果は以下の通り
![スクリーンショット 2018-04-02 23.51.19.png](https://qiita-image-store.s3.amazonaws.com/0/221678/192aea14-9a81-0613-6b22-6a856849e692.png)

今回で言えばAの方が相手に対して良い印象を持っていたよという結果になった。
判定の結果は**「Aが相手を思いやれています。相手のことが大好きなんですね」**という言葉をGoogleHomeが話す。
これで、相手に対する思いが数値化されました。

##感想
今回それっぽいことはできたような気がします。
これは果たして忖度と言う日本語の表現であっているのかというとわからないですが、思っていたようなものを作ることができました。
ただ、改善点も多々あるような気がします。
###よかったこと
- 初めて、自分で環境構築から実装まで行うことができた。
- 想定していたような挙動をするものを作成できた。

###問題点
- 一方で、今辞書データに無い単語はscoreが取れない状況になってしまう。
- 例えば、文章全体では相手をディスっているような文章でも、positiveな単語が多く入っていれば、実際の意味にかけ離れて高いscoreになってしまう。

Qiita初心者のため、至らない点はコメントいただけると幸いです。