LoginSignup
6
4

More than 3 years have passed since last update.

急性中耳炎診断支援LINE Botを改良しHerokuにデプロイ

Last updated at Posted at 2019-11-19

概要

プログラムの勉強を始めて4か月ほどの開業医です。

以前、忙しい臨床現場でも診療ガイドラインに沿った治療を簡単に行えるようにするため、医療者向けに急性中耳炎の重症度と推奨治療が簡単に分かるLINE Botを作成しました。

以前のものは初診の患者さんに対して重症度判定と推奨治療の提示を行うものだったのですが、今回は再診時の推奨治療を提示する機能を追加しました。

さらに、LINE Developersのリッチメニューを使用しUIを向上させ、Herokuにデプロイしました。今回も医療者向けのBotになっています。

実装

小児急性中耳炎診療ガイドライン(2018年 日本耳科学会)に沿った診療を支援するLINE Bot。
①初診時LINE上で質問に答えていくとスコアリングが行われ、急性中耳炎の重症度と推奨治療が提示される。
②再診時は前回行われた治療を選択すると今回の推奨治療が提示される。

概念図

node.jsでBot開発しLINE bot APIと連携。Herokuにデプロイ。
heruku nodeja line.jpg

動画

リッチメニューから選択ができ、クイックリプライボタンで表示されます。

作成方法

1. Botアカウントの作成

2. Node.jsでBot開発

3. ngrokでトンネリング

上記の1~3を以下の参考記事の通りに行います。
1時間でLINE BOTを作るハンズオン (資料+レポート) in Node学園祭2017

4. プログラム作成

コードを以下のように書き換えます。
LINE Developersのクリックリプライを使用しています。
LINE Developers

'use strict';

// モジュールのインポート
const express = require('express');
const line = require('@line/bot-sdk');
const PORT = process.env.PORT || 3000;
const app = express();

// パラメータ設定
const config = {
  channelSecret: '自分のchannelSecret',
  channelAccessToken: '自分のchannelAccessToken'
};

// Webサーバー設定
app.listen(PORT);

// APIコールのためのクライアントインスタンスを作成
const client = new line.Client(config);

// ルーター設定
app.post('/bot/webhook', line.middleware(config), (req, res, next) => {
  res.sendStatus(200);
  console.log(req.body.events);  

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

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

  // LINE botのプログラム 
  let message = event.message.text;
  let question = "";
  let label1, label2, label3 = "";
  let text1, text2, text3 = "";

  let [mes, currentScore] = message.split(":");  

  if (message == "初診") {    
    currentScore = 0;
    question = "2歳未満ですか?";
    label1 = "いいえ";//0
    text1 = "2歳以上 トータルスコア:"+String(currentScore);
    message = text1;
    label2 = "はい";//3
    text2 = "2歳未満 トータルスコア:"+String(currentScore+3);
    message = text2;
    label3 = "選択できません";
    text3= "開始";
    message = text3;
  } else if (mes == "2歳以上 トータルスコア"|| mes==  "2歳未満 トータルスコア") {
    question = "耳は痛いですか?";
    label1 = "いいえ";//0
    text1 = "耳は痛くない トータルスコア:"+String(currentScore);
    message = text1;
    label2 = "痛い、痛かった";//1
    text2 = "耳が痛い、痛かった トータルスコア:" + String(Number(currentScore)+ 1);
    message = text2;
    label3 = "とても痛いのが続いている";//2
    text3= "耳がとても痛いのが続いている トータルスコア:" + String(Number(currentScore)+2);
    message = text3;
  } else if (mes == "耳は痛くない トータルスコア"||mes=="耳が痛い、痛かった トータルスコア" ||mes== "耳がとても痛いのが続いている トータルスコア" ) {
    question = "熱はありますか?";
    label1 = "37.5未満";//0
    text1 = "37.5未満 トータルスコア:" + String(currentScore);
    message = text1;
    label2 = "38.5未満";//1
    text2 = "38.5未満 トータルスコア:" + String(Number(currentScore)+1);
    message = text2;
    label3 = "38.5以上";//2
    text3= "38.5以上 トータルスコア:" + String(Number(currentScore)+2);
    message = text3;
  } else if (mes == "37.5未満 トータルスコア"||mes== "38.5未満 トータルスコア"||mes== "38.5以上 トータルスコア") {
    question = "泣いたり、機嫌が悪いですか?";
    label1 = "いいえ"//0
    text1 = "機嫌は悪くない トータルスコア:" + String(currentScore);
    message = text1;
    label2 = "はい";//1
    text2 = "泣いたり、機嫌が悪い トータルスコア:" + String(Number(currentScore)+1);
    message = text2;
    label3 = "選択できません";
    text3= "開始";
    message = text3;
  } else if (mes == "機嫌は悪くない トータルスコア" ||mes== "泣いたり、機嫌が悪い トータルスコア" ) {
    question = "鼓膜が赤いですか?";
    label1 = "いいえ";//0
    text1 = "鼓膜は赤くない トータルスコア:" + String(currentScore);
    message = text1;
    label2 = "一部だけ赤い";//2
    text2 = "一部だけ赤い トータルスコア:" + String(Number(currentScore)+2);
    message = text2;
    label3 = "全体に赤い";//4
    text3= "全体に赤い トータルスコア:" + String(Number(currentScore)+4);
    message = text3;
  } else if (mes ==  "鼓膜は赤くない トータルスコア" ||mes== "一部だけ赤い トータルスコア" ||mes== "全体に赤い トータルスコア") {
    question = "鼓膜は腫れていますか?";
    label1 = "いいえ";//0
    text1 = "鼓膜は腫れていない トータルスコア:" + String(currentScore);
    message = text1;
    label2 = "一部だけ腫れている";//4
    text2 = "一部だけ腫れている トータルスコア:" + String(Number(currentScore)+4);
    message = text2;
    label3 = "全体に腫れている";//8
    text3= "全体に腫れている トータルスコア:" + String(Number(currentScore)+8);
    message = text3;
  } else if (mes == "鼓膜は腫れていない トータルスコア"||mes=="一部だけ腫れている トータルスコア" ||mes== "全体に腫れている トータルスコア" ) {
    question = "耳垂れは出ていますか?";
    label1 = "いいえ";//0
    text1 = "耳垂れは出ていない トータルスコア:" + String(currentScore);
    message = text1;
    label2 = "少し出ている";//2
    text2 = "少し出ている トータルスコア:" + String(Number(currentScore)+2);
    message = text2;
    label3 = "たくさん出ている";//4
    text3= "たくさん出ている トータルスコア:" + String(Number(currentScore)+4);
    message = text3;
  } 
  console.log(message);
  let result;
  if (mes == "耳垂れは出ていない トータルスコア"  || mes == "少し出ている トータルスコア" || mes == "たくさん出ている トータルスコア" ) {

    if (currentScore <= 5) {
      result="急性中耳炎は軽症です。抗生物質は使わずに3日間様子を見ましょう。"
    } else if (currentScore < 11) {
      result="急性中耳炎は中等症です。 AMPCを高用量で3~5日間投与しましょう。"
    } else {
      result="急性中耳炎は重症です。AMPCを高用量で使うか、CVA / AMPC1:14製剤を通常量で使うか、CDTR-PIを高用量で使いましょう。鼓膜切開も考慮しましょう。"
    }
    return client.replyMessage(event.replyToken, {
        type: 'text', 
        text:result    
    });

  }

//再診時プログラム
  if (message == "抗生剤非投与") {
    result = "推奨治療:AMPC常用量3~5日投与";
    return client.replyMessage(event.replyToken, {
      type: 'text', 
      text:result    
  });
  }else if (message=="AMPC常用量"){
    result = "推奨治療:感受性を考慮し以下のいずれかを3~5日間投与。 AMPC高用量 or CVA / AMPC1:14製剤 or CDTR-PI常用量";
    return client.replyMessage(event.replyToken, {
      type: 'text', 
      text:result    
  });
  }else if (message=="AMPC高用量 または CDTR-PI常用量"){
    result = "推奨治療:感受性を考慮し以下のいずれかを3~5日間投与+鼓膜切開を考慮。AMPC高用量 or CVA / AMPC1:14製剤 or CDTR-PI高用量";
    return client.replyMessage(event.replyToken, {
      type: 'text', 
      text:result    
  });
  }else if(message=="CVA / AMPC1:14製剤 または CDTR-PI高用量"){
    result = "推奨治療:感受性を考慮し以下のいずれかを3~5日間投与+鼓膜切開考慮。CVA / AMPC1:14製剤 or CDTR-PI高用量 or TBPM-PI常用量 or TFLX常用量";
    return client.replyMessage(event.replyToken, {
      type: 'text', 
      text:result    
  });
  }else if(message=="TBPM-PI常用量 または TFLX常用量"){
    result = "推奨治療:感受性を考慮し以下のいずれかを3~5日間投与+鼓膜切開考慮。TBPM-PI高用量 or TFLX常用量。または下記のいずれかを3日間点滴静注。ABPC 150mg/kg/日,分3 or CTRX 60mg/kg/日,分2または分3(新生児は50mg/kg/日以下)";
    return client.replyMessage(event.replyToken, {
      type: 'text', 
      text:result    
  });
  }


  else {
    return client.replyMessage(event.replyToken, {
      "type": "text", 
      "text": question,
      "quickReply": { 
        "items": [
          {
            "type": "action", 
              "action": {
              "type": "message",
              "label": label1,
              "text": text1
            }
          },
          {
            "type": "action",
              "action": {
              "type": "message",
              "label": label2,
              "text": text2
            }
          },
          {
            "type": "action", 
            "action": {
              "type": "message",
              "label": label3,
              "text": text3
            }
          }
        ]
      }
    });
   } 
}

5.Bot本体をHerokuにデプロイ
こちらの記事を参考にしました。
LINEのBot開発 超入門(前編) ゼロから応答ができるまで

6.Webhookを設定

上記の5.6の作業をこちらの記事を参考に行いました。
LINEのBot開発 超入門(前編) ゼロから応答ができるまで

7.リッチメニューの設定
こちらを参考に行いました。
リッチメニューの画像作成はこうやる!

8.LINEアプリへのQRコード
ガイドラインQRコード.png

考察

LINE Developersのクリックリプライとリッチメニュー使いUIをさらに改善させたLINE Botを作ることができました。
今回も医療者向けのBotになっていますが、一般の方が使えるようなものを開発していきたいと思います。

追記 (2019.11.21)
一般向けの急性中耳炎重症判定LINE Bot作成しました。
一般の方でも鼓膜を観察できる方法と、豊富なサンプル画像と比較することで自分の鼓膜の状態を判断できる方法を掲載しているWEBサイト(私が管理人)とリンクさせました。
質問に答えていくと急性中耳炎の重症度がわかり、耳鼻咽喉科を受診すべきかどうか分かります。

動画


LINEアプリへのQRコード

一般用QR.png

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