見出し画像

GASとChatGPTで実現するスマートなLINEBOT開発②〜毎日のゴミ出しを通知してもらおう〜

前回はGASとChatgptを使って、基本的な会話が可能なLINEBOTの開発しました。

基本的な会話ができたところで、次に定期的に日々のゴミ出しを知らせてくれる通知機能をつけたいと思います。

LINE BOTで実現したいこと(再掲)
普通に会話ができる(済)
・家計簿を管理、スプレッドシートにまとめてくれる
日々のゴミ出しを定期的に知らせてくれる←(今回)
・天気予報を定期的に知らせてくれる
・買い物リストをメモしてくれる
・タスクの管理
・スケジュールの管理
・画像解析
・その他(思いついたら羅列していく)

僕自身最近引越したのですが、忘れっぽいので、こう思う時がありました。

「今日は何ゴミの日だっけ・・・?」

「燃えるゴミ」「燃えないごみ」「資源ごみ」・・・などなど、引越し当初は朝寝ぼけていたせいもあって、相方に迷惑をかけてしまうことが多々ありました・・・。メモれよ(笑) 夜準備しておけ(笑)

「すずめほどのポンコツ記憶力だね☆」

相方にこう言われる始末です。すずめって何やねん!!めっちゃ悔しい…(笑)

何かいい手はないかと考え抜いた末、LINE BOTにゴミ出し機能をつけてやろうと思いました。

努力の方向を間違えてる気がしますが、皆さんも毎日ゴミ出しを伝えてくれると便利ですよね?(笑)

実際に、このゴミ出し通知機能を導入してからは、毎日忘れずにきちんとゴミ出しが出来ています(まじです)。

そんな経験を皆さんに共有していきたいと思い、今回はLINEBOTのゴミ出し通知機能を導入する方法を記事にしてみました。

ちなみにこれまでの僕の実績↓


・Pythonによるデータ分析、及び自動化の実現
・友人と数多のアプリを共同開発
・GASを使った画期的なLINE BOT開発←今ここ


ゴミ出し通知機能を導入する

早速ですが、前回導入したKAEDEのスクリプトにコードに追加してみました。
相変わらずPythonとかってが違うので苦労した

//APIキーやパラメーター調整
const OPENAI_APIKEY = 'XXXXXXXXXXXX'; //発行したChatGPTのAPIキーを入力
const LINE_ACCESS_TOKEN = 'XXXXXXXXXXXX';    // 発行したLINEのAPIキーを入力
const LINE_ENDPOINT = "https://api.line.me/v2/bot/message/reply";
//今回導入部分
const LINE_ENDPOINT_PUSH = 'https://api.line.me/v2/bot/message/push'; //追加
const USER_ID = 'XXXXXXXXXXXX';//追加
//ここまで
const GPT_ENDPOINT = 'https://api.openai.com/v1/chat/completions';
const MODEL_NAME = 'gpt-3.5-turbo';
const MODEL_TEMP = 0.7;
const MAX_TOKENS = 500;

// LINEからリクエストが渡されてきたときに実行する関数
function doPost(e) {
  // LINEからのJSONデータをGASで扱える形式に変換
  const json = JSON.parse(e.postData.contents);
  // LINE側へ応答するためのトークン作成
  const reply_token = json.events[0].replyToken;
  if (typeof reply_token === 'undefined') {
    return;
  }
  // LINEから送られてきたメッセージを取得
  const user_message = json.events[0].message.text;
  // 改行で区切って配列にする
  const user_msgarray = user_message.split(/\r\n|\n/);

//今回導入部分
  switch (user_msgarray[0]) {
    case "ゴミ出し":
    case "ゴミの日":
      TakingOutTheTrash()
      break;
    default:
      // LINEのメッセージをChatGPTにメッセージ
      const messages = [{ "role": "user", "content": user_msgarray[0] }]
      const headers = {
        'Authorization': 'Bearer ' + OPENAI_APIKEY,
        'Content-type': 'application/json',
      };
      const options = {
        'method': 'POST',
        'headers': headers,
        'payload': JSON.stringify({
          'model': MODEL_NAME,        // 使用するGPTモデル
          'max_tokens': MAX_TOKENS,   // 最大トークン
          'temperature': MODEL_TEMP,  // ランダム性
          'messages': messages
        })
      };
      //ChatGPTのAPIを呼び出す
      const res = JSON.parse(UrlFetchApp.fetch(GPT_ENDPOINT, options).getContentText());
      //ChatGPTから返却されたメッセージをLINEに
      lineReply(json, res.choices[0].message.content.trimStart());
  }
}

function TakingOutTheTrash() {
  const message = getTrashMessage_(new Date());
  if (!message) return; 
  const payload = {
    to: USER_ID, //ユーザーID
    messages: [
      { type: 'text', text: message }
    ]
  };
  const params = {
    method: 'post',
    contentType: 'application/json',
    headers: {
      Authorization: 'Bearer ' + LINE_ACCESS_TOKEN
    },
    payload: JSON.stringify(payload)
  };
  UrlFetchApp.fetch(LINE_ENDPOINT_PUSH, params);
}

function getTrashMessage_(date) {
  const weekOfMonth = WeekOfMonth_(date);
  const dayOfWeekString = DayOfWeekString_(date);
  if (['火曜日', '木曜日', '土曜日'].includes(dayOfWeekString)) {
    return `おはようございます!本日は${dayOfWeekString}!燃えるゴミの日ですよ!`;
  } else if(dayOfWeekString === '水曜日'){
    return `おはようございます!本日は${dayOfWeekString}!ゴミ出しはなしですよ!`;
  } else if (dayOfWeekString === '月曜日') {
    return `おはようございます!本日は${dayOfWeekString}!資源ゴミの日ですよ!`;
  } else if (dayOfWeekString === '金曜日') {
    if (weekOfMonth === 1) {
      return `おはようございます!本日は${dayOfWeekString}!燃えないゴミの日ですよ!`;
    } else if (weekOfMonth === 2) {
      if (date.getDate() <= 14) {
        return `おはようございます!本日は${dayOfWeekString}!燃えないゴミの日ですよ!`;
      } else {
        return `おはようございます!本日は${dayOfWeekString}!有害ごみの日ですよ!`;
      }
    }
  }
  // ゴミ出しの日ではない場合
  return "今日のゴミ出しは何もありません";
}

function WeekOfMonth_(date) {
  return Math.floor((date.getDate() - 1) / 7) + 1;
}

function DayOfWeekString_(date) {
  const dayOfWeeks = ['日曜日', '月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日'];
  const dayOfWeek = date.getDay();
  return dayOfWeeks[dayOfWeek];
}
//ここまで

//LINEへの応答を実施する関数
function lineReply(json, replyText) {
  const message = {
    "replyToken": json.events[0].replyToken,
    "messages": [{
      "type": "text",         
      "text": replyText
    }]
  };
  options = {
    "method": "post",
    "headers": {
      "Content-Type": "application/json; charset=UTF-8",  
      "Authorization": "Bearer " + LINE_ACCESS_TOKEN          
    },
    "payload": JSON.stringify(message)      
  };
  UrlFetchApp.fetch(LINE_ENDPOINT, options);
}

7行目の「const USER_ID = 'XXXXXXXXXXXX';」のユーザーIDはLINE Developerの画面で見ることが出来るのでコピペします。

LINEで通知してもらう際には「https://api.line.me/v2/bot/message/push」と入れるみたいですね、ふむふむ。

以下のコードは自身の市町村のゴミ出し日に対応しています。もし自身のゴミ出し日と異なる場合は変更しましょう。

function getTrashMessage_(date) {
  const weekOfMonth = WeekOfMonth_(date);
  const dayOfWeekString = DayOfWeekString_(date);
  if (['火曜日', '木曜日', '土曜日'].includes(dayOfWeekString)) {
    return `おはようございます!本日は${dayOfWeekString}!燃えるゴミの日ですよ!`;
  } else if(dayOfWeekString === '水曜日'){
    return `おはようございます!本日は${dayOfWeekString}!ゴミ出しはなしですよ!`;
  } else if (dayOfWeekString === '月曜日') {
    return `おはようございます!本日は${dayOfWeekString}!資源ゴミの日ですよ!`;
  } else if (dayOfWeekString === '金曜日') {
    if (weekOfMonth === 1) {
      return `おはようございます!本日は${dayOfWeekString}!燃えないゴミの日ですよ!`;
    } else if (weekOfMonth === 2) {
      if (date.getDate() <= 14) {
        return `おはようございます!本日は${dayOfWeekString}!有害ごみの日ですよ!`;
      } else {
        return `おはようございます!本日は${dayOfWeekString}!燃えないゴミの日ですよ!`;
      }
    }
  }
  // ゴミ出しの日ではない場合
  return "今日のゴミ出しは何もありません";
}

function WeekOfMonth_(date) {
  return Math.floor((date.getDate() - 1) / 7) + 1;
}

function DayOfWeekString_(date) {
  const dayOfWeeks = ['日曜日', '月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日'];
  const dayOfWeek = date.getDay();
  return dayOfWeeks[dayOfWeek];
}

上記のコードは、特定の日付に基づき、特定の日がゴミ出しの日であるかどうかを判定しています。

○getTrashMessage_(date) 関数について
この関数は、特定の日付 (date パラメータ) を受け取り、その日がゴミ出しの日であるかどうかを判定し、対応するメッセージを生成します。以下に、この関数の詳細な説明を示します。

  1. WeekOfMonth_(date) 関数を使って、与えられた日付 date が月の何週目にあるかを計算します。これは、月初から数えて1週目、2週目、3週目、といったように、週を特定するための計算です。

  2. DayOfWeekString_(date) 関数を使用して、与えられた日付 date の曜日を取得します。たとえば、日曜日、月曜日、火曜日などの曜日名を取得します。

  3. dayOfWeekString の値と weekOfMonth の値に基づいて、条件分岐を行います。

    • もし dayOfWeekString が '火曜日'、'木曜日'、または '土曜日' に一致する場合、燃えるゴミの日であるというメッセージが生成されます。

    • もし dayOfWeekString が '水曜日' に一致する場合、ゴミ出しはないというメッセージが生成されます。

    • もし dayOfWeekString が '月曜日' に一致する場合、資源ゴミの日であるというメッセージが生成されます。

    • もし dayOfWeekString が '金曜日' に一致する場合、さらに条件分岐を行います。weekOfMonth が1週目の場合、燃えないゴミの日というメッセージが生成され、2週目の場合は日付に応じて有害ごみまたは燃えないゴミの日というメッセージが生成されます。

  4. 上記の条件に当てはまらない場合、デフォルトのメッセージとして "今日のゴミ出しは何もありません" が返されます。

これでコード面は完了です。
「ゴミ出し」または「ゴミの日」と入力すると今日のゴミ出しが通知されるはずです。

なお、他のメッセージを打つと従来通り質問に対して適切な答えを返してくれます。

定期的に通知してもらいたい時

さらに定期的に通知してもらいたいと考えたので、トリガー設定を行いました。

Apps script画面の左側の時計マークをクリック

このような画面が出たら、「トリガーを追加」をクリック

毎日9時くらいに通知して欲しいなと思ったので、以下のような条件で保存を押します。

以下のように、トリガーが追加されたら完了。これで毎日定期的に通知してくれます。

実際に朝LINEを見てみると…

うん、いいかんじですね。これは便利です。

今回はここまでとさせていただきます。ちょっとずつですが、着実にAIBOTが出来上がっていると感じますね・・・!

これだけに満足せず、まだまだ機能を追加していくので、お楽しみに!次回は天気予報の通知機能でもつけてみようと思います。

何か質問があれば遠慮なくコメントお願いします。何かしらの手助けができるかと思います。

それでは!!

次の記事↓

※本記事は許可なく第三者へ公開すること、または本記事の内容を転載することは禁止しております。場合によっては法的措置をとらせていただきますのでご注意ください。

この記事が気に入ったらサポートをしてみませんか?