LoginSignup
6
4

リモートワーク中に、気分転換のきっかけを与えてくれるLINEBot

Posted at

在宅勤務(リモートワーク)で「気分転換したい!」「リフレッシュしたい!」けど、つい集中しすぎてしまう・・・。
そんな方に気分転換のきっかけを与えるため、社内のメンバーがLINEBotでプロトタイプを作成しました。
おまけ要素として、たくさん褒めてくれる素敵なBotができました!

その名は、「りも助:sparkles:

まずは、完成品のイメージ画像です!

画像1.png

実装した機能は、以下のとおりです。
ユーザーの操作は、リッチメニュー(LINEの画面下に出てくるメニュー)を押すだけ。
※テキスト入力は不要。とっても簡単なんです!

↓リッチメニュー
image.png

機能紹介

①「出勤」ボタン

勤務開始時に、ボタンを押下。
勤務開始時刻(=ボタンを押した時刻) を、メッセージで返してくれます。

image.png

②「退勤」ボタン

勤務終了時に、ボタンを押下。
勤務終了時刻(=ボタンを押した時刻) を、メッセージで返してくれます。

image.png

③「お昼休憩」ボタン

休憩開始時に、ボタンを押下。
休憩終了時刻(ボタンを押した時刻から1時間後) を、メッセージで返してくれます。
image.png

④「褒めて!」ボタン

ひたすら褒めてくれます。
褒め言葉は、ランダムで返します!(現在、約20ワードを実装)
※ランダムのため、立て続けに同じワードが返ることもあります。それもご愛嬌。

image.png

⑤「おやつガチャ」ボタン

ボタンを押すたびに、「オススメのお菓子情報」が、ランダムで返ってきます。
地域限定や知らないお菓子情報が届く、毎回違う発見あり!
(職場メンバーと一緒に使えば、会話のネタにつながるかも・・・?)

URLをクリックすると、お菓子の情報ページに飛びます。

image.png

⑥おやつ休憩(自動通知)

15:00といえば、おやつタイム:lollipop:ですよね!
「りも助」がオススメのお菓子情報とともに、休憩を促してくれます。
(※毎日15時になると、自動通知されます。土日祝日は除く)
Image (8).jpg

開発に使用したツール等

①LINE
→Messaging APIを使用

②Google Apps Script(GAS)
→JavaScriptをベースとしたプログラム実行環境(ローコード)
※Googleアカウント(無料)の準備が必要です。

③お菓子の虜(Web API)
→コンビニ等のお菓子情報を検索できるAPI(その件数はなんと、2000種類以上!)
※参考サイト お菓子の虜 Web API
同サイト内に記載されている利用規約に基づいて使用させていただいています

作り方

①LINE Developers

LINE開発用のアカウント作成・チャネル作成等を実施します。
初めてLINEBotを作る方は、以下の記事が参考になりますのでご覧ください。

リッチメニューの作成は、以下の記事を参考にしました。
(任意設定ですが、メニューがあると、機能や見た目のクオリティがあがります!)

②開発コード(GAS)

処理を記述するプログラムを作成します。

プログラムコード(その1):メッセージ部分

If文を使って、指定のワード【※】がメッセージとして送信された場合のパターンを指定。
【※】「おやつガチャ」「勤務開始します!」「勤務終了します!」「休憩開始します!」「褒めて!」の5種類
万が一、想定外のワードが送信された場合、ランダムで相づちを返します。

function handleMessage(e) {
  var replyToken = JSON.parse(e.postData.contents).events[0].replyToken;
  var lineType = JSON.parse(e.postData.contents).events[0].type

  if (typeof replyToken === "undefined" || lineType === "follow") {
    return;
  }
  var userMessage = JSON.parse(e.postData.contents).events[0].message.text;

    //おやつボタン用
    if(userMessage==="おやつガチャ"){
        let {rName,rURL} = action();
        console.log(rName)
        console.log(rURL)
        //メッセージを定義する
        return reply(replyToken, "オススメのおやつはコレなり!\n*=*=*=*=*=*=*=*=*=*=*=*\n\n"+ rName+"\n\n"+rURL);

    }else if(userMessage==="勤務開始します!"){
      const msg8 =["今日もがんばりましょう!",,"お仕事はじめてえらいです!","お仕事はじめてえらいでし!","PCの電源いれてえらいでち!"];
      const msg8Count = msg8.length;
      const msg8Index = Math.floor(Math.random() * msg8Count);
      reply(replyToken,newtoday() + " " + newDate() + " 勤務開始\n\n" +msg8[msg8Index]);

    }else if(userMessage==="勤務終了します!"){
      const msg9 =["今日も一日お疲れさまなのです!","明日は良い日になるのです!","お仕事がんばってえらいです!"];
      const msg9Count = msg9.length;
      const msg9Index = Math.floor(Math.random() * msg9Count);
      reply(replyToken,newtoday() + " " + newDate() + " 勤務終了\n\n" +msg9[msg9Index]);

    }else if(userMessage==="休憩開始します!"){
      const msg10 =["ゆっくり休むのです","ちゃんと休んでえらいです!","ここまでがんばってえらいでし!"];
      const msg10Count = msg10.length;
      const msg10Index = Math.floor(Math.random() * msg10Count);
      reply(replyToken, "休憩時間 " + startkyukei() + "\n\n" +msg10[msg10Index]);

    }else if(userMessage==="褒めて!"){
      const msg11 =["お仕事してえらいです!","天才!","活動しているだけで優勝でし!","休憩してえらいです!","メールすぐ返してえらい!","たくさん文字打ってえらいです!","家でひとりでお仕事してえらいです!","生活していえらいでち!","あなたのがんばりを見てるの!","いっつもえらいです!","生きててえらいです!","まばたきできてえらいです!","がんばっててえらいの!","考えてえらいでし!","今日も生きててえらいですの!","みんなのこと考えてえらい~!","服を着ててえらい!","体調管理してえらいの!","手洗いうがいしてえらいです!","今日もえらいの!","笑えてえらいです!","明日もきっとえらいと思うの!"];
      const msg11Count = msg11.length;
      const msg11Index = Math.floor(Math.random() * msg11Count);
      reply(replyToken,msg11[msg11Index]);

    }else{
      const msg7 =["そうですか。","うんうん。","そうなんですね。","もっと話したい事があれば私に話して良いのですよ。","そんな事があったんですね。"];
      const msg7Count = msg7.length;
      const msg7Index = Math.floor(Math.random() * msg7Count);
      reply(replyToken,msg7[msg7Index]);
    }
  }
 function reply(replyToken, message) {
 var url = "https://api.line.me/v2/bot/message/reply";
   UrlFetchApp.fetch(url, {
    "headers": {
      "Content-Type": "application/json; charset=UTF-8",
      "Authorization": "Bearer " + CHANNEL_ACCESS_TOKEN,
    },
    "method": "post",
    "payload": JSON.stringify({
      "replyToken": replyToken,
      "messages": [{
        "type": "text",
        "text": message,
      }],
    }),
  });
  return ContentService.createTextOutput(JSON.stringify({"content": "post ok"})).setMimeType(ContentService.MimeType.JSON);
}

プログラムコード(その2):API取得部分

お菓子の虜APIより、お菓子の名前とURLを取得します。

//お菓子のAPI呼び出し
function action() {
  let okashiURL = "https://www.sysbird.jp/webapi/?apikey=guest&max=1&order=r&format=json";
  let okashiData = UrlFetchApp.fetch(okashiURL).getContentText();
  let okashiJson = JSON.parse(okashiData);
  console.log(okashiJson);

  let okashiName = okashiJson["item"]["name"];
  let okashiUrl = okashiJson["item"]["url"];
  console.log(okashiName);
  console.log(okashiUrl);

  return{
    rName:okashiName,
    rURL:okashiUrl
  }
}

プログラムコード(その3):営業日判定部分

15:00のおやつタイムの自動通知は、営業日のみ(土日祝は除く)としたいので、営業日判定処理を実装。祝日情報は、Googleカレンダーから取得しています。

また、指定時間(15:00)になったら通知する設定は、GAS上で「トリガー設定」をしています。(設定方法は、以下参照)

//営業日判定
function isBusinessDay(){
  let date = new Date();
  if (date.getDay() == 0 || date.getDay() == 6) {
    return false;
  }
  
  const calJa = CalendarApp.getCalendarById('ja.japanese#holiday@group.v.calendar.google.com');
  if(calJa.getEventsForDay(date).length > 0){
    return false;
  }
  return true;
}

//トリガー実行
function setTrigger(){

  const time = new Date();
  time.setHours(15);
  time.setMinutes(00);
  
  if(isBusinessDay()){
    ScriptApp.newTrigger('createDailyMessage').timeBased().at(time).create();
  }
}

■GASのトリガー設定
作成したsetTriggerを毎日実行するためのトリガーを、別途設定するものです。
以下のとおり、設定して保存しています。

項目 設定内容
実行する関数 setTrigger
イベントのソースを選択 時間主導型
時間ベースのトリガーのタイプ 日付ベースのタイマー
時刻を選択 午後12時~1時 ※setTriggerの時刻よりも前の時間帯

image.png

プログラムコード(その4):コード全文

長いので、セクションに折りたたみます。

コード(全文)
var CHANNEL_ACCESS_TOKEN = "*************************************";

function doPost(e) {

    handleMessage(e);
}

function handleMessage(e) {
  var replyToken = JSON.parse(e.postData.contents).events[0].replyToken;
  var lineType = JSON.parse(e.postData.contents).events[0].type

  if (typeof replyToken === "undefined" || lineType === "follow") {
    return;
  }
  var userMessage = JSON.parse(e.postData.contents).events[0].message.text;

    //おやつボタン用
    if(userMessage==="おやつガチャ"){
        let {rName,rURL} = action();
        console.log(rName)
        console.log(rURL)
        //メッセージを定義する
        return reply(replyToken, "オススメのおやつはコレなり!\n*=*=*=*=*=*=*=*=*=*=*=*\n\n"+ rName+"\n\n"+rURL);

    }else if(userMessage==="勤務開始します!"){
      const msg8 =["今日もがんばりましょう!",,"お仕事はじめてえらいです!","お仕事はじめてえらいでし!","PCの電源いれてえらいでち!"];
      const msg8Count = msg8.length;
      const msg8Index = Math.floor(Math.random() * msg8Count);
      reply(replyToken,newtoday() + " " + newDate() + " 勤務開始\n\n" +msg8[msg8Index]);

    }else if(userMessage==="勤務終了します!"){
      const msg9 =["今日も一日お疲れさまなのです!","明日は良い日になるのです!","お仕事がんばってえらいです!"];
      const msg9Count = msg9.length;
      const msg9Index = Math.floor(Math.random() * msg9Count);
      reply(replyToken,newtoday() + " " + newDate() + " 勤務終了\n\n" +msg9[msg9Index]);

    }else if(userMessage==="休憩開始します!"){
      const msg10 =["ゆっくり休むのです","ちゃんと休んでえらいです!","ここまでがんばってえらいでし!"];
      const msg10Count = msg10.length;
      const msg10Index = Math.floor(Math.random() * msg10Count);
      reply(replyToken, "休憩時間 " + startkyukei() + "\n\n" +msg10[msg10Index]);

    }else if(userMessage==="褒めて!"){
      const msg11 =["お仕事してえらいです!","天才!","活動しているだけで優勝でし!","休憩してえらいです!","メールすぐ返してえらい!","たくさん文字打ってえらいです!","家でひとりでお仕事してえらいです!","生活していえらいでち!","あなたのがんばりを見てるの!","いっつもえらいです!","生きててえらいです!","まばたきできてえらいです!","がんばっててえらいの!","考えてえらいでし!","今日も生きててえらいですの!","みんなのこと考えてえらい~!","服を着ててえらい!","体調管理してえらいの!","手洗いうがいしてえらいです!","今日もえらいの!","笑えてえらいです!","明日もきっとえらいと思うの!"];
      const msg11Count = msg11.length;
      const msg11Index = Math.floor(Math.random() * msg11Count);
      reply(replyToken,msg11[msg11Index]);

    }else{
      const msg7 =["そうですか。","うんうん。","そうなんですね。","もっと話したい事があれば私に話して良いのですよ。","そんな事があったんですね。"];
      const msg7Count = msg7.length;
      const msg7Index = Math.floor(Math.random() * msg7Count);
      reply(replyToken,msg7[msg7Index]);
    }
  }
function reply(replyToken, message) {
  var url = "https://api.line.me/v2/bot/message/reply";
  UrlFetchApp.fetch(url, {
    "headers": {
      "Content-Type": "application/json; charset=UTF-8",
      "Authorization": "Bearer " + CHANNEL_ACCESS_TOKEN,
    },
    "method": "post",
    "payload": JSON.stringify({
      "replyToken": replyToken,
      "messages": [{
        "type": "text",
        "text": message,
      }],
    }),
  });
  return ContentService.createTextOutput(JSON.stringify({"content": "post ok"})).setMimeType(ContentService.MimeType.JSON);
}

 function newtoday() {
  //Date型でオブジェクト生成(初期値は現在日時)
  var date3 = new Date();
  let kekkatoday = Utilities.formatDate(date3 , "Asia/Tokyo" , "yyyy/MM/dd");
  return kekkatoday;
}

function newDate() {
  //Date型でオブジェクト生成(初期値は現在日時)
  var date1 = new Date();
  let hou = Utilities.formatDate(date1 , "Asia/Tokyo" , "HH");
  let min = Utilities.formatDate(date1 , "Asia/Tokyo" , "mm");

  //今日の日付を表示
  let newtime = hou + ":" + min;

  return newtime;
}

function startkyukei() {
  //Date型でオブジェクト生成(初期値は現在日時)
  var date2 = new Date();
  let hiru_hou = Utilities.formatDate(date2 , "Asia/Tokyo" , "HH");
  let hiru_min = Utilities.formatDate(date2 , "Asia/Tokyo" , "mm");
  
  let hiru_hou2 = new Date();
  hiru_hou2.setHours(hiru_hou2.getHours() + 1);
  date2.setHours(date2.getHours() + 1);
  hiru_hou2 = Utilities.formatDate(hiru_hou2 , "Asia/Tokyo" , "HH");

  //今日の日付を表示
  let kyuukei = hiru_hou + ":" + hiru_min + "" + hiru_hou2 + ":" + hiru_min + "";

  return kyuukei;
}

//営業日判定
function isBusinessDay(){
let date = new Date();
  if (date.getDay() == 0 || date.getDay() == 6) {
    return false;
  }
  
  const calJa = CalendarApp.getCalendarById('ja.japanese#holiday@group.v.calendar.google.com');
  if(calJa.getEventsForDay(date).length > 0){
    return false;
  }
  return true;
}

//トリガー実行
function setTrigger(){

  const time = new Date();
  time.setHours(15);
  time.setMinutes(00);
  
  if(isBusinessDay()){
    ScriptApp.newTrigger('createDailyMessage').timeBased().at(time).create();
  }
}


//送信するメッセージ定義する関数を作成します。
function createDailyMessage() {
  let {rName,rURL} = action();
  console.log(rName)
  console.log(rURL)
  //メッセージを定義する
  return push("お疲れさまナリ。\nそろそろ休憩するのはどうナリか?\nオススメのお菓子を紹介するナリ!\n *+*+*+*+*+*+*+*+* \n"+ rName+"\n"+rURL);
}

//お菓子のAPI呼び出し
function action() {
  let okashiURL = "https://www.sysbird.jp/webapi/?apikey=guest&max=1&order=r&format=json";
  let okashiData = UrlFetchApp.fetch(okashiURL).getContentText();
  let okashiJson = JSON.parse(okashiData);
  console.log(okashiJson);

  let okashiName = okashiJson["item"]["name"];
  let okashiUrl = okashiJson["item"]["url"];
  console.log(okashiName);
  console.log(okashiUrl);

  return{
    rName:okashiName,
    rURL:okashiUrl
  }
}

//実際にメッセージを送信する関数を作成します。
function push(text) {
//メッセージを送信(push)する時に必要なurl。共通。
  var url = "https://api.line.me/v2/bot/message/broadcast";
  var headers = {
    "Content-Type" : "application/json; charset=UTF-8",
    'Authorization': 'Bearer ' + access_token,
  };

  //toのところにメッセージを送信したいユーザーのIDを指定。(toは最初の方で自分のIDを指定済み。linebotから自分あてに送信。)
  //textの部分は、送信されるメッセージが入る。createMessageという関数で定義したメッセージがここに入ります。
  var postData = {
    "messages" : [
      {
        'type':'text',
        'text':text,
      }
    ]
  };

  var options = {
    "method" : "post",
    "headers" : headers,
    "payload" : JSON.stringify(postData)
  };

  return UrlFetchApp.fetch(url, options);
}

③デプロイ

GASのプロジェクトをデプロイし、取得したURLをLINEDeveloperのWebhookに設定します。
設定方法は、以下の記事を参考にさせていただきました。

おまけ

「りも助」のアイコンは、お菓子をイメージして、社内メンバーが作成したオリジナルキャラクターです。
キャラクターが褒めてくれると、なんだか愛着が湧いてきますね!
プログラム内のメッセージ部分を変更すれば、オリジナルのLINEBotが作れますので、ぜひ参考にしてみてください!

6
4
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
6
4