Ứng dụng Rails chat tự động sử dụng LINE Bot API

ABIBOT2en.png

Khoảng 2 tháng trước tôi được giao cho nhiệm vụ tìm hiểu một công cụ dùng để chat tự động thông qua ứng dụng LINE, lúc đầu mới tìm hiểu thật sự khá khó khăn vì chưa có kiến thức gì cũng như luồng hoạt động của công cụ chat tự động. Vì vậy hôm nay tôi viết bài viết này để chia sẻ về cách tạo ra một ứng dụng Rails sử dụng LINE BOT API để có thể chat tự động.

Trong bài viết này tôi sẽ giới thiệu tổng quan về LINE BOT API, luồng hoạt động và demo một ứng dụng Rails chat trực tiếp trên ứng dụng LINE.

LINE BOT API là gì?

LINE Bot API cho phép ta tương tác trực tiếp với người dùng cá nhân thông qua tài khoản Line chính thức, với BOT API ta có thể tự động gửi những phản hồi được tùy chỉnh đến người dùng nếu họ kết bạn với tài khoản BOT cũng như gửi tin nhắn đến. Và ta có thể gửi những tin nhắn tương tác từ server BOT API tới người dùng bất cứ lúc nào.

BOT API làm việc như thế nào?

Sử dụng BOT API, ta có thể gửi thông tin giữa server và ứng dụng LINE của người dùng thông qua LINE platform. Các request được gửi sử dụng dựa trên nền JSON API.

bot_img001.png

Kiến trúc

Server của chúng ta được liên kết với LINE platform. Khi ứng dụng LINE của người dùng gửi kết bạn hay gửi tin nhắn với tài khoản BOT hay gọi chung là có request gửi cho server, BOT API sẽ xử lý để biến các request đó thành JSON request và gửi cho URL của server mà ta đã đăng ký, khi đó, tùy từng cách xử lý thì ta sẽ gửi lại phản hồi cho người dùng. Và đương nhiên, phản hồi đó sẽ hiện trực tiếp trên box chat giữa người dùng và BOT trên ứng dụng LINE.

Nhận các tin nhắn/thao tác

Có hai loại thông tin được gửi từ LINE platform tới server khi người dùng tương tác với tài khoản BOT của bạn.

  • Người dùng gửi tin nhắn (message)
  • Người dùng thực hiện một thao tác như kết bạn (operation)

Thông tin được gửi thông qua giao thức HTTP tới đường dẫn URL mà ta đã đăng ký. Một xâu JSON được tạo ra trong phần thân của request cho thao tác đó, nó phụ thuộc mà kiểu thao tác mà người dùng thực hiện.

Đây là một ví dụ về JSON format khi người dùng gửi request cho server BOT API sẽ có dạng:

{
  "result":[
    {
      "from":"u206d25c2ea6bd87c17655609a1c37cb8",
      "fromChannel":1341301815,
      "to":["u0cc15697597f61dd8b01cea8b027050e"],
      "toChannel":1441301333,
      "eventType":"138311609000106303",
      "id":"ABCDEF-12345678901",
      "content":{
        ...
      }
    }
  ]
}
|_.Tên thuộc tính|_.Giá trị (Ví dụ)|_.Mô tả|
|from|"u206d25c2ea6bd87c17655609a1c37cb8"|MID của người gửi, giá trị này được LINE fix sẵn|
|fromChannel|1341301815|Channel ID của người gửi, giá trị này được LINE fix sẵn|
|to|["u0cc15697597f61dd8b01cea8b027050e"]|Một mảng các MID gửi đến|
|toChannel|1441301333|Channel ID của BOT|
|eventType|“138311609000106303”|Kiểu dữ liệu người dùng gửi: “138311609000106303”: Message, “138311609100106403”: Operation|
POST /callback HTTP/1.1
Host: YOUR_SERVER_HOST_NAME
Content-type: application/json; charset=UTF-8
X-LINE-ChannelSignature: /xZcekiWAiCrwq5dC+wBwBf6gQ33i1jRAo01KAVO3/U=

{"result":[{...}, {...}]}

Tất cả các request bao gồm phần chữ kí ở trên header. Server BOT API sẽ sử dụng chữ kí đó để kiểm tra những request đó được gửi từ LINE platform. Nếu request không được gửi từ LINE platform, thì request đó sẽ không hợp lệ thì một sự kiện xử lý không hợp lệ được kích hoạt.

Lời gọi API

LINE platform cung cấp các API cho phép gửi thông tin từ server BOT API tới người dùng:

  • Gửi tin nhắn tới nhiều người dùng mà đã kết bạn với tài khoản BOT
  • Lấy nickname của người dùng

Server BOT có thể gọi các API để gửi tin nhắn tới người dùng bất cứ lúc nào. Khi lời gọi API được tạo ra, một Channel access token hay Channel ID, Channel secretMID cho Channel của BOT và được đặt ở phần header của request để xác minh rằng lời gọi được gọi từ server BOT API. Ta có thể lấy các thông tin của Channel như ID, secret và MID ở https://developers.line.me/channels/xxx khi ta đăng ký một Channel, chi tiết tôi sẽ trình bày ở phần demo sau.

Ta có thể làm gì với LINE BOT API?

  • Gửi và nhận tin nhắn từ người dùng mà đã kết bạn
  • Gửi các tin nhắn đa phương tiện như hình ảnh, link...
  • Gửi các sticker
  • Cho người dùng duyệt các link trên chính ứng dụng LINE

Demo ứng dụng Rails chat tự động

Trong phần này tôi sẽ hướng dẫn cách tạo một Channel LINE cũng như ứng dụng Rails để xử lý request cho phép tự động gửi lại tin nhắn cho người dùng, để đơn giản tôi sẽ gửi lại những gì người dùng gửi cho BOT.

Tạo tài khoản LINE

Bước đầu tiên ta phải tải ứng dụng LINE về điện thoại, đăng ký một tài khoản và sử dụng tài khoản đó để đăng nhập ở LINE đăng nhập (ở phần này LINE sẽ gửi code về điện thoại để xác nhận).

Tiếp theo ta sẽ tạo ra một Channel bằng cách vào trang Line Business Center, khi tạo xong LINE sẽ cung cấp cho ta Channel ID, Channel Secret và MID tương tự như:

Screenshot from 2016-08-28 00:12:47.png

Những thông tin này sẽ cần thiết khi ta tạo server dùng để xác minh.

Tạo ứng dụng Rails

Để đơn giản ta tạo một ứng dụng Rails gửi lại phản hồi cho người dùng những gì mà người dùng nhập, và không cần phải lưu vào cơ sở dữ liệu. Ứng dụng sẽ được deploy lên Heroku và sẽ được setting ở trong LINE Channel.

Tùy vào từng mục đích khác nhau thì ta có thể chọn cách xử lý.

Tạo một ứng dụng Rails:

rails new line-bot-api

Đầu tiên, ta cài đặt đường dẫn CallbackURL để cài đặt những thông tin cơ bản config/routes.rb

Rails.application.routes.draw do
  post "/callback", to: "webhook#callback"
end

Tiếp theo ta tạo một thư viện để gọi LINE BOT API lib/line_bot.rb và đừng quên thêm config.autoload_paths += %W(#{config.root}/lib) trong config/application.rb

# lib/line_bot.rb
require "faraday"
require "faraday_middleware"
require "json"
require "pp"

class LineBot
  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" # Fixed value
  TO_CHANNEL = 1383378250 # Fixed value
  EVENT_TYPE = "138311608800106203" # Fixed value

  def initialize
    @channel_id = ENV["LINE_CHANNEL_ID"]
    @channel_secret = ENV["LINE_CHANNEL_SECRET"]
    @channel_mid = ENV["LINE_CHANNEL_MID"]
    @proxy = ENV["LINE_OUTBOUND_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, contentType, message, options = nil
    message_type_name = case contentType
      when ContentType::TEXT
        "text"
      when ContentType::IMAGE, ContentType::VIDEO
        ""
      when ContentType::AUDIO, ContentType::STICKER
        "contentMetadata"
      else
        "text"
      end

    content = {
      contentType: contentType,
      toType: ToType::USER,
      "#{message_type_name}": message
    }
    if options
      options.each do |key, value|
        content[key] = value
      end
    end
    post "/v1/events", {
      to: line_ids,
      content: content,
      toChannel: TO_CHANNEL,
      eventType: EVENT_TYPE
    }
  end
end

Ở hàm send ta có thể tùy chỉnh việc server có thể gửi những loại dữ liệu nào cho người dùng, chi tiết có thể xem tại LINE BOT api reference.

Tiếp theo, ta tạo controller webhook_controller.rb xử lý các request đến server. Ta phải disable CSRF (Cross-site request forgery), hàm is_validate_signature được hướng dẫn ở trang chủ Line document, ta chỉ việc copy thôi. app/controller/webhook_controller.rb

require "line_bot"
class WebhookController < ApplicationController
  protect_from_forgery with: :null_session

  def callback
    unless is_validate_signature
      render nothing: true, status: 470
    end
    result = params[:result][0]
    content = result["content"]

    LineBot.new.send [content["from"]], 1, content["text"] # 1: Text
    render nothing: true, status: :ok
  end

  private
  def is_validate_signature
    signature = request.headers["X-LINE-ChannelSignature"]
    channel_secret = ENV["LINE_CHANNEL_SECRET"]
    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

ở câu lệnh

LineBot.new.send [content["from"]], 1, content["text"]

Đơn giản là lấy thông tin người nhận và gửi lại đúng đoạn tin nhắn họ gửi cho BOT.

Vậy là ta đã viết xong phần server xử lý tin nhắn, tiếp theo ta cần phải deploy lên production (sử dụng Heroku) và config đường dẫn callback cho Channel. Callback URL mặc định là tenduongdan:443/callback

Screenshot from 2016-08-28 09:13:57.png

Mọi người có thể tham khảo project mẫu https://github.com/NeverSmileK57CLC/line-bot-frm và LINE BOT chat mà tôi đã demo.

bot_report.png

Tổng kết

LINE BOT là một bộ API khá hay khi mà ta có thể tạo một server BOT để xử lý những tin nhắn mà người dùng gửi. Trong bài viết này do chưa có kinh nghiệm tôi chỉ giới thiệu sơ qua về LINE BOT API và demo một ví dụ đơn giản. Chủ đề này có ứng dụng khá cao khi có thể áp dụng Data Mining, Machine Learning vào để tạo ra những con BOT thông minh như Cortana, Siri hay đơn giản chỉ là một BOT hỏi đáp trên chính ứng dụng chat LINE.

Tham khảo: