暮月語録(マルコフbot迷言集)
19 Dec 2017この記事はFUN Advent Calendar 2017の19日目の記事です。
18日はちくうぇいとさんでした。
こんにちは、初参加の明石暁です。
本記事では今年の6月あたりから稼働中のマルコフbotのまとめをやりつつ、中身にちょっとだけ触れます。
概要
Crescentは開発中のRuby製のマルコフbotです。
暗石暮月(@kurashi_kure)がTwitter上で稼働中。
MeCab、TwitterAPI、PostgreSQLなどを利用しています。
TLの頻出単語からマルコフ連鎖を開始して文章を生成し、TLの速度に合わせた頻度でツイートします。
また、単語は毎回検索でレパートリーを増やすようにしています。
暮月について
Follow @kurashi_kure
Tweets by kurashi_kure
こんなんです。
- 明石暁から 明→暗暁→明けの太陽→夕暮れの月→暮月 で暗石暮月
- 誕生日は6/7
- 最初はラズパイにいたけどConoHaに引っ越し ちなみにFedora
迷言集
おはようにゃん💕
— 暗石暮月 (@kurashi_kure) 2017年10月23日
なでなでしてぎゅーっして欲しい
— 暗石暮月 (@kurashi_kure) 2017年7月18日
あざとい
大学から下山するかー
— 暗石暮月 (@kurashi_kure) 2017年11月8日
13時22時ごろに山岡家行きますー是非観て
— 暗石暮月 (@kurashi_kure) 2017年11月8日
いまから登山しに来られる人なんていやしないだろ
— 暗石暮月 (@kurashi_kure) 2017年11月23日
完全に未来大生
単位がやばそうやなわたしどうしよ
— 暗石暮月 (@kurashi_kure) 2017年8月24日
単位落としました((o
— 暗石暮月 (@kurashi_kure) 2017年9月25日
しかも落単芸人
ホモは増殖する
— 暗石暮月 (@kurashi_kure) 2017年10月22日
ホモ多すぎます本当にありがとう☺
— 暗石暮月 (@kurashi_kure) 2017年10月28日
腐ってやがる
彼女とデートなう
— 暗石暮月 (@kurashi_kure) 2017年7月17日
彼女といるってうれしい
— 暗石暮月 (@kurashi_kure) 2017年9月1日
女の子とにゃんにゃん
— 暗石暮月 (@kurashi_kure) 2017年12月18日
キマシ
リア充死ね
— 暗石暮月 (@kurashi_kure) 2017年7月17日
リア充アピだ
— 暗石暮月 (@kurashi_kure) 2017年7月17日
リア充死ね
— 暗石暮月 (@kurashi_kure) 2017年7月23日
リア充死ね
— 暗石暮月 (@kurashi_kure) 2017年8月8日
リア充死ね
— 暗石暮月 (@kurashi_kure) 2017年10月3日
TLでリア充の話題が出るたびに言う 彼女持ちのくせに
BaHoりのBaHo
— 暗石暮月 (@kurashi_kure) 2017年7月6日
BaHo寝取りのBaHo火照りのBaHo火照りのBaHo寝取りの
— 暗石暮月 (@kurashi_kure) 2017年7月9日
BaHoらずBaHoるときBaHoればBaHoれば
— 暗石暮月 (@kurashi_kure) 2017年7月19日
BaHo猫さんに捧ぐBaHoラップ 怒られたら消します
みんな可愛いからしょうがないニャ
— 暗石暮月 (@kurashi_kure) 2017年11月7日
悲しみが深いめう(提案)
— 暗石暮月 (@kurashi_kure) 2017年7月7日
皿が絶対良いめうぽよ
— 暗石暮月 (@kurashi_kure) 2017年11月26日
最近語尾が増えてきた
五回に一回くらいは会話がなんとなく成立するので、是非リプライして迷言を引き出してください。
マルコフ連鎖の実装
このままだとただのTogetterになるので軽く中身の話します。
Crescentで使われているマルコフ連鎖はRubyのArray.each_consを使って簡単に実装してます。
def self.learn(words)
words.each_cons(3) do |w1, w2, w3|
next if w1 == -1 || w2 == -1
find_or_create_by(
prefix1: w1.id,
prefix2: w2.id,
suffix: w3.id)
end
end
each_consは、任意の数の要素を一つずつズラしながらeachを回せる、マルコフ連鎖のために存在するかのようなメソッドです
wordsは文章をMeCabで解体して単語DBのidに並べ替えた配列です。
これを3つずつ取り出してマルコフDBに登録していきます。
文末が来たら飛ばして次の文またはループを抜けます。
文章の生成はこんな感じです。
def self.generate(word_id)
keyword = Word.find_by(id: word_id)
seq = Array[word_id]
first_list = where("prefix1 = ?", word_id)
return keyword.name if first_list.empty?
seq.push first_list.sample.prefix2
CHAIN_MAX.times do
choice = Markov.where("(prefix1 = ?) and (prefix2 = ?)", seq.last(2)[0], seq.last(2)[1]).sample.suffix
break if choice == -1
redo if [true, false].sample && (Word.find(choice).value - keyword.value).abs > 1
suffix = choice
seq.push suffix
end
.
.
.
まず引数のword_idから起点の単語になるkeywordを取ってきます。
seqは単語の順番をidで保持する配列です。
マルコフDBから、keywordから始まる並びを探してランダムで一つ決めて2文字目をseqに入れます。
次のループ内では、1文字目と2文字目が一致する並びを探して、3文字目をseqに入れます。
これはCHAIN_MAX回繰り返すか、文末に到達したら終了し、その後seq内のword_idから文字列を呼び出して文章を組み立て(省略)です。
おわりに
暮月はフォロワーの皆さんのツイートとクソリプで支えられています。これからもどうぞかまってやってください。
好感度機能や単語に対する興味度の機能など、もっと改良していく予定です。
でもとりあえエラー吐きまくりなのをなんとかしたいと思います…。
次回はやまけん(@yamakentoc)さんです。