8
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

一日を振り返る「セルフチェッカー君」をline botで作ってみた

Last updated at Posted at 2020-08-26

セルフチェック大事

僕は昔から結構__「これもやりたい!」「あれもやりたい!」__と思うタイプでした。
その性格もあり、色々手を出した挙句時間と体力がなくてどれも極めないみたいなことが度々ありました。
面白いなあと思ったことは体力とか時間とか考えずに熱中してしまうんですよね。

プライベートであれば自業自得で終わるので良いと思うんですが、仕事とか他の人がかかわる場面であればまた話は別。
ちゃんと優先順位をつけて自己管理してということが求められます。

時間が無いと振り返りの時間を忘れがち。
一度立ち止まって__「今日はこんな一日だったなあ」「こんなこと考えたなあ」と考えたり記録することってとても大事だと思うんです。
そこでline botで一日の振り返りをする
「セルフチェッカー君」__を作ったので紹介しますね。

セルフチェックした内容は記録としてためれるような仕組みにしています。
自分用のメモをline botで作る際のベースにしていただければと思います。
コードは[こちら]
(https://gist.github.com/canonno/e55a71cc3b6ba0dd9d33d1c9ff449f2d)

完成デモ

夜21時にpush通知

夜21時になるとセルフチェッカー君から__「どんな一日だった?」とプッシュ通知__が来ます。
ここから振り返りスタートです。
Screenshot_20200826-172005.png

振り返りの質問

この後はいくつかの振り返りの質問をドンドコしてくれます。
今回は基本的に選択肢でサクッと応えられるような質問ばかりにしています。
この辺りは__自分の何を知りたいかに応じてカスタマイズすると良い__と思います。
Screenshot_20200826-180530.png

「今日あった楽しいこと・嬉しかったことを書こう」みたいな質問も作ってみました(写真はふざけて「ほい」と返事してます)。
そして最後は「今日一日よく頑張りました」とほめたたえてくれます。
ウッレシィィィィイオッヤスミィィィイ
Screenshot_20200826-180547.png

回答の記録

今回あまり見やすい形にはしてませんが、回答はすべてtxtファイルの中に記録するようにしています。
Google Spread Sheetを使ってもよかったんですが、データ保存の手段の勉強__という意味でtxtを使ってみてます。
ある程度たまったら
「こういう時は落ち込むんだな」「体調悪いときはこれが原因ぽい」__といったような分析ができるようになります。
Line botからの操作でExcelに出力とかの処理をいれてもいいかもしれませんね。
image.png

実装こまごま

lineへpush通知を送る

こちらのコードを実行するとユーザIDに紐づいたアカウントへpush通知を送ります。
通知の形式はいろいろカスタマイズできるようですので、詳しくはlineの公式ドキュメントをご覧ください!
定期的に通知する方法としてはGoogle cloud platformのcloud schedulerを利用しました。


'use strict';

const express = require('express');
const line = require('@line/bot-sdk');
const fs = require("fs")
const PORT = process.env.PORT || 3000;

const config = {
    channelSecret: 'シークレットトークン',
    channelAccessToken: 'アクセストークン'
};

const app = express();

const client = new line.Client(config);

const mode_dict = JSON.parse(fs.readFileSync('mode_config.txt', 'utf8'));
mode_dict["mode"] = 0;
var mode_JSON = JSON.stringify(mode_dict);

//modeのファイルを保存
fs.writeFile("mode_config.txt",mode_JSON,function(err) {
  if (err) {
      console.log(err);
  }
});
let response_list = ["どんな一日だった?","良い一日だった","良いほうでしょう","あまり良くなかった","最悪だったわ"];

client.pushMessage('ユーザID', {
  "type": "template",
  "altText": "どんな一日だったかい",
  "template": {
      "type": "buttons",
      "thumbnailImageUrl": "https://dreamy-poincare-ca5fd7.netlify.app/1.jpg",
      "imageAspectRatio": "rectangle",
      "imageSize": "cover",
      "imageBackgroundColor": "#FFFFFF",
      "title": "質問1",
      "text": response_list[0],
      
      "actions": [
          {
            "type": "message",
            "label": response_list[1],
            "text": response_list[1]
          },
          {
            "type": "message",
            "label": response_list[2],
            "text": response_list[2]
          },
          {
            "type": "message",
            "label": response_list[3],
            "text": response_list[3]
          },
          {
            "type": "message",
            "label": response_list[4],
            "text": response_list[4]
          },
      ]
  }
})

途中にmode_dict.txtというファイルが出てますが、こちらが今回試験的に使ってみるテキストファイルです。
Google Spreadsheetを使うほどのデータ量はないけれど、変数をどこかに保存しておきたい場合に結構便利だなあという印象。
他にスマートな手段があればコメントしていただけると嬉しいです。

{"mode":1}

line botのお作法

一回push通知して、それに対する回答を処理していきます。
line botへ回答されるとhandleEvent()が実行され、処理されていきます。


'use strict';

const express = require('express');
const line = require('@line/bot-sdk');
const PORT = process.env.PORT || 3000;
const fs = require("fs");

const config = {
    channelSecret: 'シークレットトークン',
    channelAccessToken: 'アクセストークン'
};

const app = express();

app.get('/', (req, res) => res.send('Hello LINE BOT!(GET)')); //ブラウザ確認用(無くても問題ない)
app.post('/webhook', line.middleware(config), (req, res) => {
    console.log(req.body.events);

    Promise
      .all(req.body.events.map(handleEvent))
      .then((result) => res.json(result));
});

const client = new line.Client(config);

async function handleEvent(event) {
  if (event.type !== 'message' || event.message.type !== 'text') {
    return Promise.resolve(null);
  }

  //line botへ回答した時の処理を書く

}

回答の内容を記録し質問を続ける

具体的な処理としては
①回答をnode_dict.txtへ保存
②今質問が何問目かをmode_config.txtで確認
③mode_config.txtの数字を一つ増やす
④質問をreturn
という形になっています。


async function handleEvent(event) {
  //modeの読み書き
  let mode_idx;
  let mode_JSON;

  //modeのファイルを読み込み
  const mode_dict = JSON.parse(fs.readFileSync('mode_config.txt', 'utf8'));
  mode_idx = mode_dict["mode"];
  
  //データ保存用ファイルを読み込み
  const base = JSON.parse(fs.readFileSync('node_dict.txt', 'utf8'));

  let data;

  //タイムスタンプ作成
  var now = new Date();
  var Year = now.getFullYear();
  var y = Year;
  var Month = now.getMonth()+1;
  var m = Month.length == 1 ? "0"+Month : Month;
  var Day = now.getDate();
  var d = Day.length == 1 ? "0"+Day : Day;
  var time = y.toString() + m.toString() + d.toString();

  //データの保存
  try{
    base[time][mode_idx] = event.message.text;
  }catch{
    base[time] = {};
    base[time][mode_idx] = event.message.text;
  }
    data = JSON.stringify(base);

  fs.writeFile("node_dict.txt",data,function(err) {
      if (err) {
          console.log(err);
      }
  });

  //質問のmodeを変える
  if (mode_idx < 6){
    mode_dict["mode"] = mode_idx +=1 ;
  }else{
    mode_dict["mode"] = 0;
  }
  mode_JSON = JSON.stringify(mode_dict);

  //modeのファイルを保存
  fs.writeFile("mode_config.txt",mode_JSON,function(err) {
      if (err) {
          console.log(err);
      }
  });
  
  var reply_dic = make_reply_dic(mode_dict["mode"]);
  console.log("success");

  return client.replyMessage(event.replyToken, reply_dic);
}

保存先のnode_dict.txtはこちら。
テキストファイルの名前が変なのは先日作成したものを流用したせいですゴメンナサイ

{"2020825":{"0":"良い一日だった","1":"良く寝れた!","2":"とれてる","3":"とれてる","4":"とれてる","5":"とれてる","6":"はあ"},
"2020826":{"0":"良い一日だった","1":"良く寝れた!","2":"微妙に睡眠不足","3":"とれてる","4":"ほい","5":"おい","6":"お疲れ様!"}}

コード最後のmake_reply_dicの中身はこちら。
質問に応じて選択肢を変えたり形式を変えれるようにしています。
質問と一緒に載せる画像はnetlifyにデプロイすると非常に簡単なので是非是非利用してみてくださいね。
画像はPAKUTASOからお借りしました。

function make_reply_dic(next_mode_idx){
  //質問文リスト
  let response_message;
  //左から質問、回答1、回答2、回答3、回答4
  let response_list = [
    ["どんな一日だった?","良い一日だった","良いほうでしょう","あまり良くなかった","最悪だったわ"],
    ["睡眠時間はとれてる?","良く寝れた!","まあ寝たほうだね","微妙に睡眠不足","眠かった・・・"],
    ["趣味の時間はとれてる?","とれてる","とるようにしてる","微妙にとれてない","とれてない"],
    ["運動する時間はとれてる?","とれてる","とるようにしてる","微妙にとれてない","とれてない"],
    ["今日あった楽しい事・嬉しかった事を書こう"],
    ["一日お疲れ様でした","お疲れ様!"],
    ["スルー"]
  ]

  //返事用の変数を定義
  response_message = response_list[next_mode_idx][0];

  if (next_mode_idx <4){
    //lineのレスポンスに載せる写真
    var imageuri = [
      "https://dreamy-poincare-ca5fd7.netlify.app/1.jpg",
      "https://dreamy-poincare-ca5fd7.netlify.app/2.jpg",
      "https://dreamy-poincare-ca5fd7.netlify.app/3.jpg",
      "https://dreamy-poincare-ca5fd7.netlify.app/4.jpg"
    ]

      var reply_dic = {
      "type": "template",
      "altText": "今日の振り返りをしよう",
      "template": {
          "type": "buttons",
          "thumbnailImageUrl": imageuri[next_mode_idx],
          "imageAspectRatio": "rectangle",
          "imageSize": "cover",
          "imageBackgroundColor": "#FFFFFF",
          "title": "質問"+(next_mode_idx+1),
          "text": response_message,
          "actions": [
              {
                "type": "message",
                "label": response_list[next_mode_idx][1],
                "text": response_list[next_mode_idx][1]
              },
              {
                "type": "message",
                "label": response_list[next_mode_idx][2],
                "text": response_list[next_mode_idx][2]
              },
              {
                "type": "message",
                "label": response_list[next_mode_idx][3],
                "text": response_list[next_mode_idx][3]
              },
              {
                "type": "message",
                "label": response_list[next_mode_idx][4],
                "text": response_list[next_mode_idx][4]
              },
          ]
      }
    }
    return reply_dic
  
  //ただのテキストにするとき
  }else if (next_mode_idx== 4){
    var reply_dic ={
      "type": "text",
      "text": response_message,
    }
    return reply_dic

  //最後の応答
  }else if (next_mode_idx == 5){
    var reply_dic = {
      "type": "template",
      "altText": "一日お疲れ様でした!",
      "template": {
          "type": "buttons",
          "thumbnailImageUrl": "https://dreamy-poincare-ca5fd7.netlify.app/5.jpg",
          "imageAspectRatio": "rectangle",
          "imageSize": "cover",
          "imageBackgroundColor": "#FFFFFF",
          "title": "今日一日よく頑張りました",
          "text": response_message,
          "defaultAction": {
              "type": "uri",
              "label": "View detail",
              "uri": "http://example.com/page/123"
          },
          "actions": [
              {
                "type": "message",
                "label": response_list[next_mode_idx][1],
                "text": response_list[next_mode_idx][1]
              },
          ]
      }
    }
      return reply_dic
    }else if (next_mode_idx== 6){
      console.log("スルー");
    }
  }

今後やりたいこと

line bot自体無限の可能性があるなあと思っているんですが、個人のGoogle Spread Sheetとかにつなげてしまうと一般公開するときに色々めんどくさいと思うんですよね。
その時の一つの手段として「テキストでデータ保存」を実験的にやってみました。
lineも色々カスタマイズできそうなのでちょっと深堀りしてみたいところですね。

最後までご覧いただきありがとうございました!
コードはこちらから利用してみてくださいね。
LGTMつけていただけると励みになりますので是非是非よろしくお願いします!

〇こちらも是非是非ご覧ください!
入社一年間で学んだ「DX」「UX」を整理してみたい
 DXって何だっけ、と頭の整理をしてみました
自宅で夏の散歩ができる「夏休み君」をYoutube Player APIで作ってみた
 夏っぽい気分を味わえるWebアプリを作ってみました。
好きなキー好きなBPMでパプれるスピーカーをline botとobnizで作ってみた
 パプリカオイシィィィイイイイ

8
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?