14
7

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 5 years have passed since last update.

PORTAdvent Calendar 2018

Day 16

夫の帰宅時間をお知らせしてくれるLINE bot

Last updated at Posted at 2018-12-15

この記事は、PORT Advent Calendar 2018の16日目です。
Vue.jsかfirebaseかAMPについて書こうと思いつつ、、夫の帰宅時間連絡の手間を思いついたので、解消するものを考えました。

解決したい課題

旦那氏の帰宅時間がわかるようにしたい。私も旦那氏もお腹ペコペコ状態なので、ご飯をすぐ食べられる状態にしたいから。
旦那氏は日によって出向したりするので、毎日同じオフィスから帰宅するわけではありません。
なので、毎日帰宅時間をたずねていました。聞くのも手間だし、調べる方も手間。

解決方法

旦那氏「名古屋から乗ったよ」みたいな文章をLINEで送信したら、botが勝手に乗り換え検索してくれて、最寄駅の到着時間を返信してくれたらいいんじゃない?
よくないかもしれないけど、試しに作ってみようのモチベーション。初めてのLINE bot作成です。

参考

LINEのBot開発 超入門(前編) ゼロから応答ができるまで
こちらの記事を参考にさせていただきました。
環境Node.jsとHerokuだったので、それに従います。初めてのHeroku。
こちらがHeroku公式。デプロイまではこれも参考に。Getting Started on Heroku with Node.js

とりあえず参考の通りにした

めっちゃ飛ばしましたけど、、
LINEのBot開発 超入門(前編) ゼロから応答ができるまでさんが超優秀なので、ほとんどその通りにしました。ちょこちょこ詰まりはしたけれど、そこは公式を参考にしつつ、「こんにちは」って送信したら、「これはこれは」って返ってくるようになりました。
IMG_0569.PNG
アイコンはホシガメちゃんにしました。(向き反対の方が喋ってる感でたかもしれない)
「メッセージありがとうございます」みたいな返信はデフォルトメッセージで、LINE Developersの設定から削除することができました。

index.js
require('dotenv').config()
const express = require('express')
const path = require('path')
const PORT = process.env.PORT || 5000
const line = require('@line/bot-sdk')
const config = {
  channelAccessToken: process.env.LINE_ACCESS_TOKEN,
  channelSecret: process.env.LINE_CHANNEL_SECRET
}
const app = express()
const bot = new line.Client(config)

app.post('/webhook', line.middleware(config), (req, res, next) => {
  res.sendStatus(200)
  let events_processed = []
  req.body.events.forEach((event) => {
    if (event.type == "message" && event.message.type == "text"){
      if (event.message.text == "こんにちは"){
        events_processed.push(bot.replyMessage(event.replyToken, {
          type: "text",
          text: "これはこれは"
        }))
      }
   }
})

app.listen(PORT, () => console.log(`Listening on ${ PORT }`))

参考までにコードは確かだいたいこんな感じ。

Dialogflowにキーワードを登録

ここも詳しくは超入門見ていただければでてきますが、
Dialogflowってサービスにキーワードを登録すると、Node.jsからの判別が簡単になります。
表記揺れ登録で、言語処理が簡単になるって感じ。
私は以下の言葉について登録しました。

Entities登録

帰るって意味を汲み取る(kitaku)

スクリーンショット 2018-12-10 23.59.12.png

乗る駅(ekimei)

名古屋駅=>名古屋名駅なごや

Intentsに例文を登録

スクリーンショット 2018-12-11 0.03.12.png 例文登録すると、勝手にEntitiesと紐づけてくれます。

イベント登録

登録した単語が来たらフックになるようにAction and parametersイベント登録します。
スクリーンショット 2018-12-11 0.10.50.png

Node.jsに接続するのにGoogle Cloud Platformを介したりして、ちょっと面倒ですが、使えるようになります。

index.js
// 省略
app.post('/webhook', line.middleware(config), (req, res, next) => {
  res.sendStatus(200)
  let events_processed = []
  req.body.events.forEach((event) => {
    if (event.type == "message" && event.message.type == "text"){
      if (event.message.text == "こんにちは"){
        events_processed.push(bot.replyMessage(event.replyToken, {
          type: "text",
          text: "これはこれは"
        }))
      }

      events_processed.push(
        session_client.detectIntent({
          session: session_client.sessionPath(process.env.GOOGLE_PROJECT_ID, event.source.userId),
          queryInput: {
            text: {
              text: event.message.text,
              languageCode: "ja",
            }
          }
        }).then((responses) => {
          if (responses[0].queryResult && responses[0].queryResult.action == "handle-kitaku"){
            let message_text
            let from = responses[0].queryResult.parameters.fields.ekimei.stringValue
            let to = process.env.EKIMEI_TO
            if (from){
              message_text = `ご帰宅ですね!${from}からですね!`
              return bot.replyMessage(event.replyToken, {
                type: "text",
                text: message_text
              });
            } else {
              message_text = `ご帰宅ですね!どこから?`;
              return bot.replyMessage(event.replyToken, {
                type: "text",
                text: message_text
              })
            }
          }
        })
      )
    }
  })
})

名古屋駅から帰宅するのを察してくれるようになりました。
ここまでは、参考そのままな感じ。

乗り換え検索ができるようにならなければならない

旦那氏の帰宅時間をお知らせしてもらいたいので、経路検索のAPIを叩かなければいけません。
今回は駅すぱあとさんのフリープランを使用しました。
申し込みが必要でしたが、レスポンスが早く、サクッとアクセスキーが使えるようになりました。
検索結果のURLを返してくれるようになります。
スクリーンショット 2018-12-11 20.43.50.png
こちらを導入するにあたり、存在する駅名にDialogflowのキーワードを変更しておきました。

Entities 名古屋駅=>名古屋名駅なごや
にしていましたが、名古屋駅だと検索にひっからなかったので、名古屋に変更。

なんだかんだAPI叩けた

index.js
// events_processed.pushにapiを追加する
      events_processed.push(
        session_client.detectIntent({
          session: session_client.sessionPath(process.env.GOOGLE_PROJECT_ID, event.source.userId),
          queryInput: {
            text: {
              text: event.message.text,
              languageCode: "ja",
            }
          }
        }).then((responses) => {
          if (responses[0].queryResult && responses[0].queryResult.action == "handle-kitaku"){
            let message_text
            let date = moment().format('YYYYMMDD')
            let time = moment().format('HHmm')
            let from = responses[0].queryResult.parameters.fields.ekimei.stringValue
            let to = process.env.EKIMEI_TO
            if (from){
              const url = `https://api.ekispert.jp/v1/json/search/course/light?from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}&date=${date}&time=${time}&searchType=departure&plane=false&shinkansen=false&limitedExpress=true&redirect=false&contentsMode=sp&key=${process.env.EKISPERT_KEY}`
              axios.get(url).then((res) => {
                message_text = `ご帰宅ですね!${from}からですね!\n${res.data.ResultSet.ResourceURI}`
                return bot.replyMessage(event.replyToken, {
                  type: "text",
                  text: message_text
                })
              }).catch((err) => {
                message_text = `エラー!${err}`
                return bot.replyMessage(event.replyToken, {
                  type: "text",
                  text: message_text
                });
              })
            } else {
              // 略
            }
          }
        })
      )
    }
  })
IMG_0570.PNG やったー!と思ったのもつかの間。

時間が日本じゃないことは明白。
herokuの時間を日本に変更する必要がありました。
heroku config:add TZ=Asia/Tokyo --app [app_name]
参考にした

これで時間が合いました。

感想

帰宅連絡だけで埋め尽くされていたLINEが、botを含めたグループを作成したことで、帰宅用にスレッドが分かれたのが地味に良かったです。
これだと直近の電車しか探せないので、何分前に電車に乗ったのか、何分後に駅につくのかみたいな感じで、検索できるようにしたらいいかなと。
参考を見ると、botの対応ももっとチューニングできるらしいので、そこもやってもいいかもしれません。

旦那氏はそこそこ喜んでくれました。

最後になりますが、PORT株式会社では自社サービスを支えてくれる優秀なRubyエンジニアを募集しています(Rubyエンジニア以外も)。
もくもく会も行なっていますので、ぜひ一緒にもくもくしましょう!
PORTもくもく会
(私は残念ながらリモート勢なのでいませんが・・)

PORT Advent Calendarはまだまだ続きます。

14
7
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
14
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?