うちのいぬ - うみちゃんと話せるbotを作りました 3 - LINE bot を Heroku と Rails を使って作ってみた
これまでFacebook botを作った経緯や作り方を書きました。 http://satomi.hatenablog.jp/entry/2016/06/26/093734satomi.hatenablog.jp
http://satomi.hatenablog.jp/entry/2016/06/25/213801satomi.hatenablog.jp
今回は
LINE bot の作り方を書きます
https://business.line.me/services/products/4/introduction
出来たもの
まだオウム返しです。メッセージ処理は別ドメインなので、別に作ります。
今回はbotを使うところまでを書きます。
基本的にこれを読んでおけばOK
ググればいっぱい出てくるのでググッてください。
もしHerokuを利用していなければ(固定IPをもっていたら) LINE Developers - BOT API Trial (Deprecated) - Getting started を使うのが一番手っ取り早いです。
ハマった点
Herokuだとめんどい
LINE botではIPアドレスでのWhite Listを必要とします。 つまり、botのサーバーの固定IPアドレスが必要になるわけです。 Herokuではデフォルトでそれが提供されていないので、FixieというAddonを使ったりして、対応する必要があります。
Fixie - Add-ons - Heroku Elements
LINE提供のSDKがそのままでは使えない
LINE Developers - BOT API Trial (Deprecated) - Getting started
SDKはいくつか提供されていて、はっきり言ってこれを使えば一番楽です。
でもHerokuでFixieを使う場合、proxyを設定する必要があって、そのままでは使えなかったです。
また、wrapperは出ていますが、
line-bot | RubyGems.org | your community gem host
その他のバージョンの違いの問題で、使えなかったです。
Railsじゃなかったら、すんなり使えたかもしれないです。
Callbackの疎通テストに惑わされる
Callbackの疎通テストボタンがあります。 そこでcompleteになっても、 サーバーログではbad requestが出たりして、なんかエラってるって怖くなります。
ですが、基本的にはそれでOKなようです。
疎通テストをパスしたら、LINEアプリでの会話テストに移るといいです。
そっちで会話したら、エラーがなく、普通にやりとりできました。
コードの例
class LineController < ApplicationController CHANNEL_ID = ENV['CHANNEL_ID'] CHANNEL_SECRET = ENV['CHANNEL_SECRET'] CHANNEL_MID = ENV['CHANNEL_MID'] OUTBOUND_PROXY = ENV['OUTBOUD_PROXY'] def callback unless is_validate_signature render :nothing => true, status: 470 end result = params[:result][0] if result['content']['opType'].present? mid = result['content']['params'][0] client = LineService.new(CHANNEL_ID, CHANNEL_SECRET, CHANNEL_MID, OUTBOUND_PROXY) res = client.profile(mid) else text_message = result['content']['text'] from_mid = result['content']['from'] arr = [from_mid] message = NlpService.make_response_text(text_message) client = LineService.new(CHANNEL_ID, CHANNEL_SECRET, CHANNEL_MID, OUTBOUND_PROXY) res = client.send(arr, message) end render :nothing => true, status: :ok end private def is_validate_signature signature = request.headers["X-LINE-ChannelSignature"] http_request_body = request.raw_post hash = OpenSSL::HMAC::digest(OpenSSL::Digest::SHA256.new, CHANNEL_SECRET, http_request_body) signature_answer = Base64.strict_encode64(hash) signature == signature_answer end end
require "faraday" require "faraday_middleware" require "json" require "pp" class LineService module ContentType TEXT = 1 IMAGE = 2 VIDEO = 3 AUDIO = 4 LOCATION = 7 STICKER = 8 CONTACT = 10 end module ToType USER = 1 end END_POINT = "https://trialbot-api.line.me" TO_CHANNEL = "1383378250" # Fixed value EVENT_TYPE = "138311608800106203" # Fixed value def initialize(channel_id, channel_secret, channel_mid, proxy = nil) @channel_id = channel_id @channel_secret = channel_secret @channel_mid = channel_mid @proxy = proxy end def post(path, data) client = Faraday.new(:url => END_POINT) do |conn| conn.request :json conn.response :json, :content_type => /\bjson$/ conn.adapter Faraday.default_adapter conn.proxy @proxy end res = client.post do |request| request.url path request.headers = { 'Content-type': 'application/json; charset=UTF-8', 'X-Line-ChannelID': @channel_id, 'X-Line-ChannelSecret': @channel_secret, 'X-Line-Trusted-User-With-ACL': @channel_mid } request.body = data end res end def send(line_ids, message) post('/v1/events', { to: line_ids, content: { contentType: ContentType::TEXT, toType: ToType::USER, text: message }, toChannel: TO_CHANNEL, eventType: EVENT_TYPE }) end end