[RAILS] Make Ruby Kurosawa with Ruby (Ruby + LINE Messaging API)

Ruby Kurosawa is cute, isn't it?

I made Ruby who speaks on LINE. In Ruby.

Rubyボット01.png

It works with the following mechanism.

--Use LINE Messaging API to receive and send LINE messages as" Ruby Kurosawa ". --Create an API server that communicates with LINE Messaging API withRuby (Ruby on rails). --Morphological analysis of the message and generation of a new sentence in Markov chain based on the result

Create a LINE account

As a preliminary preparation, you need an account that works as Ruby (strictly speaking, a channel of Messaging API). Make it.

Register from LINE Developers. Rubyボット02.png Create a new one from Create a new channel. In addition, you will be asked what type it is when you make it. The one you want to make this time can be made with Messaging API, so please select the appropriate one.

If you can create it successfully, you can get an access token. You can also set the account icon and self-introduction column. [^ 1]

[^ 1]: I also create a development account. By the way, the image is the one drawn by a friend.

Create an API server

I don't plan to have a screen, so I'll create a Rails project in API mode. Enter line-bot-api gem [^ 2]. You will be able to interact with LINE using the access token of the account you created earlier.

Make a controller

If you set the Webhook URL for the account you created earlier, LINE will send a request triggered by the message sent to that account. See the Messaging API Reference (https://developers.line.biz/ja/reference/messaging-api/#message-event) for specific request content. The following example is a mechanism that responds to a text message and simply returns a "message".

def client
  @client ||= Line::Bot::Client.new { |config|
    config.channel_secret = ENV["LINE_CHANNEL_SECRET"]
    config.channel_token = ENV["LINE_CHANNEL_TOKEN"]
  }
end

def callback
  body = request.body.read

  signature = request.env['HTTP_X_LINE_SIGNATURE']
  head :bad_request unless client.validate_signature(body, signature)

  events = client.parse_events_from(body)

  events.each do |event|
    next unless event.is_a?(Line::Bot::Event::Message)
    next unless event.type == Line::Bot::Event::MessageType::Text

    client.reply_message(event['replyToken'], message)
  end
  head :ok
end

def message
  # cf. https://developers.line.biz/ja/reference/messaging-api/#text-message
  {
    "type": 'text',
    "text": 'message'
  }
end

Let the part corresponding to this message be a sentence generated by a Markov chain.

Make sentences with Markov chains

There are many explanations about the outline of sentence creation by Markov chain, so please search for "Markov chain sentence creation" for details.

Roughly speaking, by learning the connection of words in advance by morphological analysis (decomposing into the smallest unit that has meaning in the language), and probabilistically selecting the following words for a certain word from past learning. It's a guy who can write like that.

Morphological analysis

For morphological analysis, Japanese morphological analysis provided by Yahoo! is used. I think it would be ant to use MeCab (Natto) to put in a dictionary specializing in otaku terms.

When a LINE message is sent, the message is morphologically analyzed as it is. Parse the result into an array of hashes with words and part of speech. [^ 3] [^ 3]: I referred to the following. Using Yahoo's Text Analysis API with Ruby on Rails-Sukero's Story

Create a Word model to save as a word and aMarkovDic model to save the connection, and save each.

Word model

Column name Mold Explanation
pos String Part of speech (eg noun)
surface String Words (eg garden)

Markov Dic model

Column name Mold Explanation
prefix_1 String Word connection A-B-A when expressed as C (example: me)
prefix_2 String Word connection A-B-B when expressed as C (example: ha)
suffix String Word connection A-B-C when expressed as C (example: dog)
  #Perform morphological analysis and create Word records and MarkovDic records. Returns an array of nouns.
  def record(text, user)
    text = remove_url(text)  #I'm removing the URL
    morphological_words = exec(text)

    poses = save_words(morphological_words, user)
    save_markov_dics(morphological_words)

    poses
  end

  #Save the word.
  def save_words(morphological_words)
    words = []

    morphological_words.each do |word|
      w = Word.new(word)
      words << w.attributes.compact!.merge({ created_at: now, updated_at: now })
    end
    Word.insert_all(words) if words.present?
  end

  def save_markov_dics(morphological_words)
    markov_dics = []
    morphological_words.each_cons(3) do |p1, p2, suf|
      next if p1['surface'] == "\n"
      next if p2['surface'] == "\n"

      md = MarkovDic.new(prefix_1: p1['surface'], prefix_2: p2['surface'], suffix: suf['surface'])
      md.suffix = 'END_OF_SENTENCE' if md.suffix == "\n" #Flag that means the end of the sentence
      markov_dics << md.attributes.compact!.merge({ created_at: now, updated_at: now })
    end
    eos = morphological_words.last(2)
    if eos.size == 2
      p1 = eos[0]
      p2 = eos[1]
      md = MarkovDic.new(prefix_1: p1['surface'], prefix_2: p2['surface'], suffix: 'END_OF_SENTENCE')
      markov_dics << md.attributes.compact!.merge({ created_at: now, updated_at: now })
    end
    MarkovDic.insert_all(markov_dics) if markov_dics.present?
  end

Make a sentence

Now that I've saved the message sent to LINE, I'll make a sentence. For the starting word, we randomly select MarkovDic that starts with a noun from the received LINE message. It looks like the following.

  def create_sentence(text, markov_dic)
    return text if markov_dic.suffix == 'END_OF_SENTENCE'

    next_markov_dic = MarkovDic.where(prefix_1: markov_dic.prefix_2, prefix_2: markov_dic.suffix).sample(1).first
    return text unless next_markov_dic

    text << markov_dic.suffix
    create_sentence(text, next_markov_dic)
  end

  def prefixes
    prefix_1 + prefix_2
  end

Set the webhook URL

Deploy the created API server. (This time, I deployed it on Heroku.) Set the Webhook URL on the setting screen of the account you created first so that LINE will send you a request when a message arrives. Rubyボット03.png

Add to the LINE group. It responds nicely.

Rubyボット05.png

Other

――When Ruby was mixed in the group line, it was very popular as "cute", "chimera was born", and "new toy". -There was a person who made me remember Fucking Big Rashomon and it was messed up. ――It seems that you can only have one bot account on the group line. I couldn't talk with the Kurosawa sisters. ――Whenever you receive a reply, the group line becomes noisy, so I make it post or not at random. (By the way, if you talk to Ruby directly, you will get a 100% reply.) -You can also talk to Ruby by using push_message. ――I'd really like to introduce you to an account, but considering the personal information contained in the recorded words, it can be difficult. ――For now, the element of Ruby is 0, so I want to make it look like Ruby.

Summary

I made Ruby Kurosawa using LINE Messaging API and Ruby.

LINE Bot is surprisingly easy to make, so please try it.

Recommended Posts

Make Ruby Kurosawa with Ruby (Ruby + LINE Messaging API)
How to make LINE messaging function made with Ruby
Let's make a LINE Bot with Ruby + Sinatra --Part 2
Let's make a LINE Bot with Ruby + Sinatra --Part 1
Make a typing game with ruby
Let's make draw poker with ruby ~ Preparation ~
Let's make a smart home with Ruby!
[LINE @] I tried to make a Japanese calendar Western calendar conversion BOT [Messaging API]
Interact with LINE Message API using Lambda (Java)
ruby API problem
Let's make draw poker with ruby ~ test-unit preparation ~
Procedure for operating google spreadsheet with API (ruby)
Make Java Stream line breaks nice with eclipse
[Ruby] Ruby API problem
ruby API problem
Try to get redmine API key with ruby
Easy to make LINE BOT with Java Servlet
Make PUSH notifications with images in Firebase Cloud Messaging
Install Ruby 3.0.0 with asdf
Compatible with Android 10 (API 29)
Getting Started with Ruby
11th, Classification with Ruby
Evolve Eevee with Ruby
Let's write how to make API with SpringBoot + Docker from 0
[Rails] Create an echo bot using the LINE Messaging API.
Learning Ruby with AtCoder 13 How to make a two-dimensional array
Let's make a simple API with EC2 + RDS + Spring boot ①
Make facebook messenger with talk API of api.ai and a3rt
[Ruby on Rails] Implement login function by add_token_to_users with API
[swift5] Try to make an API client with various methods