Skip to content

Instantly share code, notes, and snippets.

@lapis-zero09
Last active March 5, 2016 04:25
Show Gist options
  • Save lapis-zero09/4b750992f46a9a2e174d to your computer and use it in GitHub Desktop.
Save lapis-zero09/4b750992f46a9a2e174d to your computer and use it in GitHub Desktop.
一人暮らしの寂しさを紛らわす彼女(bot)を作った話 ref: http://qiita.com/lapis_zero09/items/cdde08576abbcbedad4d
$ ruby -v
ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-linux]
$ gem install twitter
$ gem install tweetstream
$ gem install docomoru
$ mkdir bot
$ cd bot
$ touch twcon.rb
$ irb
irb(main):001:0> require './twcon.rb'
=> true
irb(main):002:0> eve = Eve.new
=> ~省略~
irb(main):003:0> eve.say("test", "")
=> #<Twitter::Tweet id=705644033196994561>
(↑こんな感じのが出たら成功)
irb(main):004:0>
$ touch main.rb
$ touch ~/bot/r-recipe.rb
require './r-recipe.rb'
~省略~
begin
eve.timeline.userstream{|status|
contents=status.text
next if(contents=~/^RT/)
id=status.user.screen_name
id='@' + id + ' '
# reply_answer
if(contents=~/@lapis_ko/)&&(status.user.screen_name!='lapis_ko')
postmatch=$'
# 料理推薦
if(contents=~/飯/)
food=RecommendRecipe.new
if(contents=~/:|:/)
eve.say(id+food.call("#{$'}"), status.id)
else
eve.say(id+"ご飯にする?\n"+food.call("なんでもいい")+"食べたいものがあれば「ご飯:食べたいもの」で指定してね!", status.id)
end
# 会話
else
postmatch.gsub!(/\s|[ ]|\?|\?/, "")
# QandA
if(postmatch=~/誰|何処|だれ|どこ|何時|いつ|どうやって|どうして|何故|なぜ|どの|何|なに|どれ|は$/)
eve.say(id+eve.docomoru_create_knowledge(postmatch), status.id)
# 会話
else
eve.say(id+eve.docomoru_create_dialogue(postmatch), status.id)
end
end
next
end
# メンション以外の名前に反応
if(contents=~/eve|Eve|イヴ|イブ|いぶ/)&&(status.user.screen_name!='lapis_ko')
called_name=['なに?', '呼んだ?','どうしたの?']
eve.say(id+called_name.sample, status.id)
next
end
# 料理推薦
if(contents=~/飯|お腹すいた/)&&(status.user.screen_name!='lapis_ko')
food=RecommendRecipe.new
eve.say(id+"ご飯にする?\n"+food.call("なんでもいい")+"食べたいものがあれば「ご飯:食べたいもの」で指定してね!", status.id)
next
end
#zero09がつぶやいたらリプライ
~省略~
# coding: utf-8
require 'open-uri'
require 'json'
require 'yaml'
#nattoかMeCabどっちでもいい
require 'natto'
# require 'MeCab'
class RecommendRecipe
keys=YAML.load_file('./config.yml')
RECIPE_CATEGORY_URL="https://app.rakuten.co.jp/services/api/Recipe/CategoryList/20121121?format=json&elements=categoryName%2CcategoryId%2CparentCategoryId&categoryType=medium&applicationId=#{keys['rakuten_api_id']}"
RECIPES_URL="https://app.rakuten.co.jp/services/api/Recipe/CategoryRanking/20121121?format=json&formatVersion=2&applicationId=#{keys['rakuten_api_id']}&categoryId="
def call(food)
hearing(food)
end
private
def hearing(food)
results = recipe_categories
if(food=='なんでもいい')
recipe_category_id = results[results.keys.sample]
recipe = choose_recipe(recipe_category_id)
return "#{food}なら、#{recipe['recipeTitle']} とかはどう? #{recipe['recipeUrl']}"+' <Supported by RWS>'
else
recipe_category_id = results.fetch(food, nil)
if(recipe_category_id.nil?)
words=[]
#require 'MeCab'の場合
# mc=MeCab::Tagger.new()
# n=mc.parseToNode(food)
# while(n)
# if(n.feature.split(',')[0]=="名詞")
# words.push(n.surface)
# elsif(words.size>0)
# food=words.join("")
# break
# end
# n=n.next
# end
#require 'natto'の場合
nt=Natto::MeCab.new
nt.parse(food){|n|
if(n.feature.split(',')[0]=="名詞")
words.push(n.surface)
elsif(words.size>0)
food=words.join("")
break
end
}
recipe_category_id = results.fetch(food, nil)
if(recipe_category_id.nil?)
return "#{food}だとわからないからもうちょっと詳しく教えて(漢字⇆ひらがなにするといいかも)"
else
recipe = choose_recipe(recipe_category_id)
return "#{food}だと、#{recipe['recipeTitle']} とかはどう? #{recipe['recipeUrl']}"+' <Supported by RWS>'
end
else
recipe = choose_recipe(recipe_category_id)
return "#{food}だと、#{recipe['recipeTitle']} とかはどう? #{recipe['recipeUrl']}"+' <Supported by RWS>'
end
end
end
def recipe_categories
response=open(RECIPE_CATEGORY_URL).read
results=JSON.parse(response.force_encoding('UTF-8'))
return results["result"]["medium"].map{|result| [result['categoryName'], "#{result['parentCategoryId']}-#{result['categoryId']}"]}.to_h
end
def choose_recipe(recipe_category_id)
response=open("#{RECIPES_URL}#{recipe_category_id}").read
results=JSON.parse(response.force_encoding('UTF-8'))
return results['result'][Random.rand(1 .. results['result'].count-1)]
end
end
# coding:utf-8
require 'yaml'
require 'twitter'
require 'tweetstream'
require 'docomoru'
class Eve
# 外部から参照できるメンバ変数
attr_accessor :client, :timeline
def initialize
keys=YAML.load_file('./config.yml')
# restAPI初期化
@client=Twitter::REST::Client.new{|config|
config.consumer_key=keys["api_key"]
config.consumer_secret=keys["api_secret"]
config.access_token=keys["access_token"]
config.access_token_secret=keys["access_token_secret"]
}
# StreamAPI初期化
TweetStream.configure{|config|
config.consumer_key=keys["api_key"]
config.consumer_secret=keys["api_secret"]
config.oauth_token=keys["access_token"]
config.oauth_token_secret=keys["access_token_secret"]
config.auth_method=:oauth
}
@timeline=TweetStream::Client.new
# docomoAPI初期化
@docomoru=Docomoru::Client.new(api_key: keys["docomo_api_key"])
end
# 引数を投稿するメソッド
def say(words, id)
@client.update(words, :in_reply_to_status_id => id)
end
# 会話を生成する(docomoru)
def docomoru_create_dialogue(str)
response=@docomoru.create_dialogue(str)
return response.body["utt"]
end
# QandA(docomoru)
def docomoru_create_knowledge(str)
response=@docomoru.create_knowledge(str)
if(response.body["code"]=="E020010")
return response.body["message"]["textForDisplay"]
else
if(response.body["answers"][0]["linkUrl"]==nil)
return response.body["message"]["textForDisplay"]
else
return response.body["message"]["textForDisplay"]+"<"+response.body["answers"][0]["linkUrl"]+">"
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment