Ruby Kurosawa is cute, isn't it?
I made Ruby who speaks on LINE. In Ruby.
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
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.
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.
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.
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.
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.
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
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
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.
Add to the LINE group. It responds nicely.
――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.
I made Ruby Kurosawa using LINE Messaging API
and Ruby
.
LINE Bot is surprisingly easy to make, so please try it.
Recommended Posts