薬、飲んだ？大丈夫！LINEが教えてくれる、GAS×Makeの超おせっかい服薬フォロー自動化！

この記事では、**GASとMakeを使用して、LINE通知を活用した服薬フォローシステムを構築する方法**を詳しく解説します。初心者の方でもわかりやすく進められるよう、ChatGPTを使った手順と、そのプロセスで直面した課題、そして改善方法を紹介します。

**「服薬フォロー」とは、薬の調剤・処方時だけでなく、服薬期間中にも、薬剤師が患者さんの薬の飲み方や体調を確認し、適切なアドバイスや指導を行うこと**を指します。

国の方針で義務化されてるのに全然できてないのが現状です。

## 実際に動作している動画

https://x.com/331824miyamoto/status/1830259951660634305

ここには、服薬フォローシステムが実際に動作している動画を貼り付けます。
使用しているアドレスはサンプル用に作成したアドレスで、すでに消去済みになります。
わかりにくいので、音声が入ってます。

上に動画が表示されない場合は下のリンクをクリックしてください。

[動画はここをクリック](https://x.com/331824miyamoto/status/1830259951660634305
)

## 服薬フォローシステムを作った理由と業務への活用

私が「服薬フォローシステム」を作った理由は、患者さんが薬を正しく飲んでいるかを確認し、必要なサポートを提供するためです。

薬は治療にとって非常に重要ですが、高齢の方や長期間薬を飲む必要がある方は、薬を飲み忘れたり、体調の変化に気づきにくいことがあります。これまでは、薬剤師が一人ひとりに連絡して確認していましたが、手作業では時間がかかり、すべての患者さんに十分なケアを行うのが難しいこともありました。

このシステムでは、**フォローアップメールの送信や患者さんからの返信処理を自動化すること**で、以下のような業務改善を目指しました。

- **自動化で業務を効率化**  
  1週間後に自動でフォローアップのメッセージを送信。
  手作業が減り、業務の効率化が図れる

- **体調変化の早期発見**  
  患者さんから体調の変化を報告してもらい、異常があればすぐに対応可能

- **患者満足度の向上**  
  定期的なフォローアップで安心感を提供し、信頼関係を強化

このシステムで、患者さんが安心して治療を続けられるよう、薬剤師としての役割をさらに充実させたいと考えています。



## GASのスクリプトの解説

<details>
<summary>⭐️完成形のスクリプトを表示する⭐️ </summary>

```javascript
// 1週間後にフォローアップメールを送信する関数
function sendFollowUpEmails() {

  // スプレッドシートの "FollowUpLog" シートを取得
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('FollowUpLog');

  // シート内のすべてのデータを取得
  var data = sheet.getDataRange().getValues();

  // 今日の日付を取得
  var today = new Date();

  // データの各行に対して処理を行う
  for (var i = 1; i < data.length; i++) {
    // 3列目 (C列) にある最後のフォローアップ日を取得
    var lastFollowUpDate = new Date(data[i][2]);

    // 2列目 (B列) のメールアドレスと、1列目 (A列) の患者名を取得
    var email = data[i][1];
    var patientName = data[i][0];

    // 最後のフォローアップ日から1週間経過しているか確認
    if ((today - lastFollowUpDate) >= 7 * 24 * 60 * 60 * 1000) {

      // フォローアップメールの内容を作成
      var message = "こんにちは " + patientName + " 様、\n\n" +
                    "1週間前にお薬をお渡ししましたが、体調に変化はありませんか？\n" +
                    "ご不明点がありましたらこのメールに返信してくださいね。\n\n" +
                    "お大事にしてください。";

      // メールを送信
      GmailApp.sendEmail(email, '体調確認のお願い', message);

      // 送信記録として4列目 (D列) に送信日を記録
      sheet.getRange(i + 1, 4).setValue('Sent on ' + today);
    }
  }
}

// 受信したメールを確認し、スプレッドシートに最新の返信内容を記録する関数
function checkEmails() {
    // スプレッドシートの "FollowUpLog" シートを取得
    var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('FollowUpLog');
    var data = sheet.getDataRange().getValues();

    data.forEach(function(row, i) {
        var email = row[1]; // B列のメールアドレスを取得

        if (email) {
            // メールを検索して取得 (指定した件名に該当する返信を検索)
            var threads = GmailApp.search('from:' + email + ' subject:"体調確認のお願い" is:inbox');

            // 最新の返信を保持する変数
            var latestMessageBody = "";
            var latestMessageDate = new Date(0); // 初期値を最も古い日付に設定

            threads.forEach(function(thread) {
                var messages = thread.getMessages();
                messages.forEach(function(message) {
                    var messageDate = message.getDate();
                    if (messageDate > latestMessageDate) {
                        latestMessageDate = messageDate;
                        latestMessageBody = message.getPlainBody();
                    }
                });
            });

            // 最新の返信が存在する場合、シートに記載
            if (latestMessageBody) {
                var cleanedMessageBody = cleanQuotedReplies(latestMessageBody);
                sheet.getRange(i + 1, 5).setValue(cleanedMessageBody + ' (Received on ' + latestMessageDate + ')');
                
                // Webhookを呼び出す
                sendWebhook(email, cleanedMessageBody);
            }
        }
    });
}

// 引用部分を削除するための関数
function cleanQuotedReplies(body) {
    var lines = body.split('\n');
    var cleanedLines = [];

    var quotePattern = /^(On .+ wrote:|-----|>)/;

    lines.forEach(function(line) {
        if (!quotePattern.test(line)) {
            cleanedLines.push(line);
        }
    });

    return cleanedLines.join('\n').trim();
}

// Webhook呼び出しの関数
function sendWebhook(email, message) {
    var url = 'https://hook.eu2.make.com/your-webhook-url'; // ここにMakeで作成するWebhookのURLを入れる
    var payload = JSON.stringify({
        email: email,
        message: message
    });

    var options = {
        method: 'POST',
        contentType: 'application/json',
        payload: payload
    };

    UrlFetchApp.fetch(url, options);
}
```
</details>
スクリプトの説明

- **sendFollowUpEmails**
患者さんに自動でフォローアップメールを送信し、送信日時をスプレッドシートに記録します。

- **checkEmails**
患者さんからの返信を確認し、最新の内容をスプレッドシートに記録。不要な引用部分を削除し、Makeと連携してLINE通知などを行います。

- **cleanQuotedReplies**
メール本文から引用部分を除去し、重要な内容だけを抽出します。

- **sendWebhook**
返信内容をWebhook経由でMakeに送信し、LINE通知などを実行します。

これらのスクリプトにより、服薬フォローが自動化され、効率的な患者ケアと通知の強化が可能になります。
## 使用したツール
- LINE Developers
- ChatGPT（GPT-4o）
- Make
- Google Apps Script
- Google スプレッドシート

## ChatGPT先生へのプロンプトとその返答
ここではプロンプトを紹介して、どんな返答があったのかを順番に紹介します。
順番通りにいけば、最終的な制作物になるという感じです。

### 教えて！ChatGPT先生！何かいい案ない？
![スクリーンショット 2024-08-26 143543.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839271/1c61f09e-7ac9-70c2-8a3b-d5067368900b.png)
![スクリーンショット 2024-08-26 143551.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839271/8b7ef029-72f0-3d56-30f4-dba5c35eb7fc.png)

アイデアも出してくれるなんてさすがすぎますね。
この段階で、GASの設定をして自動送信システムを作ろう！っと思いました。

### すごいぞChatGPT先生！手順の流れを教えて！
![スクリーンショット 2024-08-26 143638.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839271/b6ff779e-398a-a121-7edd-708d4c21ff92.png)
![スクリーンショット 2024-08-26 143648.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839271/56bc3f31-fc27-3bb8-3a75-2875fd1a6709.png)

手順の流れを簡単に教えてもらいました。

### できるぞChatGPT先生！GASの設定教えて！
![スクリーンショット 2024-08-26 104911.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839271/f5b2d3d2-3869-0e00-e950-f14a521c7a26.png)

こんな感じの質問をすると詳細に教えてくれます。
**スプレッドシートは以下のようにします**

![スクリーンショット 2024-08-26 110718.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839271/b300f522-80b4-3564-2ff7-55c04d47a724.png)
シートの名前は好きなのにしていいです。

**GASを開いて、作ってくれたスクリプトを貼り付けます**
<details>
<summary>⭐️ここをクリックしてコードを表示⭐️</summary>

```javascript
// 1週間後にフォローアップメールを送信する関数
function sendFollowUpEmails() {

  // スプレッドシートの "FollowUpLog" シートを取得
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('FollowUpLog');

  // シート内のすべてのデータを取得
  var data = sheet.getDataRange().getValues();

  // 今日の日付を取得
  var today = new Date();

  // データの各行に対して処理を行う
  for (var i = 1; i < data.length; i++) {
    // 3列目 (C列) にある最後のフォローアップ日を取得
    var lastFollowUpDate = new Date(data[i][2]);

    // 2列目 (B列) のメールアドレスと、1列目 (A列) の患者名を取得
    var email = data[i][1];
    var patientName = data[i][0];

    // 最後のフォローアップ日から1週間経過しているか確認
    if ((today - lastFollowUpDate) >= 7 * 24 * 60 * 60 * 1000) {

      // フォローアップメールの内容を作成
      var message = "こんにちは " + patientName + " 様、\n\n" +
                    "1週間前にお薬をお渡ししましたが、体調に変化はありませんか？\n" +
                    "ご不明点がありましたらこのメールに返信してくださいね。\n\n" +
                    "お大事にしてください。";

      // メールを送信
      GmailApp.sendEmail(email, '体調確認のお願い', message);

      // 送信記録として4列目 (D列) に送信日を記録
      sheet.getRange(i + 1, 4).setValue('Sent on ' + today);
    }
  }
}
```
</details>
こんな複雑そうなのも作ってくれるなんて・・・！

**トリガーの設定**

スクリプトエディタ内で「時計」アイコン「トリガーの管理」をクリック
関数を sendFollowUpEmails に設定時間主導型のトリガーを毎日または毎週に設定

これにより、スクリプトが自動的に実行され、1週間後にフォローアップメールが送られるようになります。

### やったぞChatGPT先生！返信内容がシートに自動記入！
患者さまの返信内容が自動でシートに入るようにします。
そうすることで、シートを確認するだけで内容の確認が出来るようになります。

![スクリーンショット 2024-08-26 113413.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839271/d6465042-8ef4-7d22-35d8-b3fcd1815502.png)
こんな感じで聞くとスクリプトを送ってくれます。
```javascript
function checkEmails() {
    // スプレッドシートの "FollowUpLog" シートを取得
    var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('FollowUpLog');
    var data = sheet.getDataRange().getValues();
    
    // データの各行に対して処理を行う
    data.forEach(function(row, i) {
        var email = row[1]; // B列のメールアドレスを取得

        if (email) {
            // メールを検索して取得 (指定した件名に該当する返信を検索)
            var threads = GmailApp.search('from:' + email + ' subject:"体調確認のお願い" is:inbox');
            
            threads.forEach(function(thread) {
                var messages = thread.getMessages();
                messages.forEach(function(message) {
                    var messageBody = message.getPlainBody();
                    var messageDate = message.getDate();
                    
                    // メッセージ内容と受信日時をスプレッドシートに記録
                    sheet.getRange(i + 1, 5).setValue(messageBody + ' (Received on ' + messageDate + ')');
                });
            });
        }
    });
}
```
これを入れて完成！

とはなりませんでした。

問題点

- 返信内容に要らない部分が多く入ってしまい、シートが非常に見にくくなった
引用部分も全部シートに入力されていた

- シートに記載される返信内容が最新の返信文にならない
一番古いのが常に選ばれて更新されない

それぞれChatGPT先生に問いただしてみましょう

![スクリーンショット 2024-08-26 115506.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839271/182aec62-68e4-ff70-4d48-04310e4a814c.png)

修正版がこちらのスクリプトになります
<details>
<summary>⭐️ここをクリックしてコードを表示⭐️</summary>

```javascript
function checkEmails() {
    // スプレッドシートの "FollowUpLog" シートを取得
    var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('FollowUpLog');
    var data = sheet.getDataRange().getValues();

    data.forEach(function(row, i) {
        var email = row[1]; // B列のメールアドレスを取得

        if (email) {
            // メールを検索して取得 (指定した件名に該当する返信を検索)
            var threads = GmailApp.search('from:' + email + ' subject:"体調確認のお願い" is:inbox');

            // 最新の返信を保持する変数
            var latestMessageBody = "";
            var latestMessageDate = new Date(0); // 初期値を最も古い日付に設定

            threads.forEach(function(thread) {
                var messages = thread.getMessages();
                messages.forEach(function(message) {
                    var messageDate = message.getDate();
                    if (messageDate > latestMessageDate) {
                        latestMessageDate = messageDate;
                        latestMessageBody = message.getPlainBody();
                    }
                });
            });

            // 最新の返信が存在する場合、シートに記載
            if (latestMessageBody) {
                var cleanedMessageBody = cleanQuotedReplies(latestMessageBody);
                sheet.getRange(i + 1, 5).setValue(cleanedMessageBody + ' (Received on ' + latestMessageDate + ')');
            }
        }
    });
}

// 引用部分を削除するための関数
function cleanQuotedReplies(body) {
    var lines = body.split('\n');
    var cleanedLines = [];

    var quotePattern = /^(On .+ wrote:|-----|>)/;

    lines.forEach(function(line) {
        if (!quotePattern.test(line)) {
            cleanedLines.push(line);
        }
    });

    return cleanedLines.join('\n').trim();
}
```
</details>


これにより、返信内容が最新のものになります。

トリガーは2分単位で発動するように設定をします

GASを使った服薬フォローシステムの大元は完成です！

## 同僚・患者さまからのフィードバック

- **同僚の感想**
最初は使いやすいと思ったが、実際に使ってみると、いつ返信が来たのかを都度確認しなければならないため、結局シートを何度も見直す必要があるとのことでした。そこに「面倒くさい」という気持ちが出てくるので、最終的に他と同様に使わなくなるんだろうとのことでした。

- **患者さまの感想**
特に嫌な感じはなかったとのこと。新しいアプリなどを登録しなくてもいいのが良かったとのことでした。

## 改善点　Makeを使った通知の強化

このフィードバックを受けて、Makeとの連携を取り入れることにしました。
GASとMakeを連携させて、返信があった際にLINEなどを通じてリアルタイムで通知を受け取る仕組みを追加しました。

## 改善した後の動画（LINEの通知部分）
https://x.com/331824miyamoto/status/1828092901647323255

通知するタイミングの動画になります。患者さまからの返信内容がLINEに届きます。


## Makeのシナリオ
![スクリーンショット 2024-08-26 124729.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839271/9160cab9-4fef-b5a6-e241-9094b3c97f21.png)



## 改善のためにChatGPT先生に聞いてみた
![スクリーンショット 2024-08-26 125521.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839271/87dd21df-da10-8505-98c5-cb14bb9000bf.png)

![スクリーンショット 2024-08-26 125710.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839271/09ea0df9-d99d-b316-bd0a-2809c12de2e9.png)

とのことでした。
早速やってみましょう！

### 助けてChatGPT先生！Makeのモジュールどうするの？

- Google SheetsのWatch Changesをトリガーに設定
- 次に、+アイコンを押してLINEモジュールのSend a Push Messageを選択
- 紐づけます

![スクリーンショット 2024-08-26 131102.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839271/2350af70-f512-b2c4-4902-136f611fa754.png)
基本の形はこんな感じになります

あとはRouterを接続して、特定の言葉に反応したり、メッセージ内容を変更できたりします。

### お願いChatGPT先生！MakeとGASを連動させて！
![スクリーンショット 2024-08-26 131919.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839271/f00c7288-425b-e024-421b-a15e94ed7133.png)
こちらが追加するスクリプトになります。
```javascript
// Webhook呼び出しの関数
function sendWebhook(email, message) {
    var url = 'https://hook.eu2.make.com/your-webhook-url'; // ここにMakeで作成するWebhookのURLを入れる
    var payload = JSON.stringify({
        email: email,
        message: message
    });

    var options = {
        method: 'POST',
        contentType: 'application/json',
        payload: payload
    };

    UrlFetchApp.fetch(url, options);
}
```
ポイント: urlの部分には、MakeのWebhook URLを入れます


また、返信内容がシートに入った時、自動でWebhook関数が呼び出されるために
追加するスクリプトになります
```javascript
 // Webhookを呼び出す
        sendWebhook(email, cleanedMessageBody);
```
これを返信内容をシートに入れるコードの一番最後に入れてください

これでMakeとGASが連携しました！
返信が来たタイミングに近い状態でLINEに通知が来ます。


初心者の自分でもここまで出来たのが本当に驚きです。
ChatGPTを上手く使えればもっと色々なことにチャレンジを出来ることがわかりました。

## もう一度同僚のフィードバック

- 返信が来たときにLINEの通知が来るのはすごい便利！
- 患者さまとのコミュニケーションに役立ちそう
- 服薬フォローという形だけじゃなくて、システム部分が他のことにも代用できそう

これで数値が伸びるかは実際に運用しないとわからないので、もう少し使ってみてまた意見を言いますとのことでした。


## ChatGPTを使って難しかったこと・苦労したこと
とにかく１回で答えが出るという事はなかったです。特にスクリプト！
何度もエラーが出て、そのたびにスクリプトを貼り付けて、エラーが出てるとAI相手に怒ってました。また、システムが一部古い時もあり、Makeに関しても「そんなモジュールないぞ！」という事も多々ありました。「これをやりたい！」とかをChatGPTに言っても、見当違いのことが返ってくることも多々あるとおもいますが、継続的にフィードバックを行い、その都度調整をして答えを出していくことが、上手く使いこなせる秘訣かと感じています。

## ChatGPTで楽できたこと
スクリプトの作成、手順の整理と説明、改善案の提供がChatGPTで簡単にできたことになります。そもそも、スクリプトの作成なんてChatGPTを使わなければ一生できないと思ってます。ここまで自動でやってくれるなんて、本当に便利な世の中になったと感じています。
また、考えをまとめてもらえることで時間の短縮にもなり、その分、フィードバックを受ける時間が多く取れたので、改良点を洗い出すこともできました。ChatGPTの活用で、より効率的で効果的なシステム開発が実現できました。

今回のシステムは、服薬フォローを自動化することで、仕事がスムーズに進み、同僚にもプロトタイプの作成に興味を持ってもらえるようになりました。このシステムを使えば、もっと他の場面でも役立つ可能性があります。読者の皆さんも、ぜひこのシステムを参考にして、自分の仕事や新しいプロジェクトに役立てていただけたら嬉しいです。


大変長くなりましたが、最後、ChatGPT先生に謝って締めたいと思います。

![スクリーンショット 2024-08-26 142023.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839271/ce67f22b-c895-89fd-5f63-32d6db44fabd.png)

優しい